Как нарисовать несколько треугольников с различными размерами и направлениями на основе данных, используя инструменты построения, такие как Matplotlib - PullRequest
0 голосов
/ 08 мая 2019

Я хочу нарисовать график, как на картинке ниже.Его ось X - это порядок точек данных, например, от 1 до 7. Ось Y - это масштаб от 0 до 25. Если я хочу нарисовать треугольник, например, с его данными (1,22,20), затем «1» дает порядок среди всех точек данных (разных треугольников), треугольник должен быть нарисован в большинстве слева;«22,20» дает «нижнюю часть» треугольника вдоль оси y.

Кто-нибудь знает, как нарисовать такой треугольник с несколькими числами на графике, используя пакет python matplotlib?

enter image description here

Ответы [ 3 ]

2 голосов
/ 08 мая 2019

Читать этот пост и этот пост о рисовании полигонов с помощью matplotlib.

EDIT1: Только что видел ответ @ Poolka. Это был и мой путь, но обратите внимание, что в одной из приведенных выше ссылок указано, что добавление отдельных многоугольников (p = pat.Polygon([[x1, y1], [x2, y2], [x3, y3]); ax.add_patch(p)) к рисунку может стать очень медленным, и поэтому коллекции предпочтительнее.

РЕДАКТИРОВАТЬ 2: Также см. Ответ TheImportanceOfBeingErnest для более подробной версии этой концепции. Вместе с этим фрагментом кода он должен помочь вам:

import numpy as np
import matplotlib
import matplotlib.pyplot as plt
import matplotlib.patches as pat  # Patches like pat.Polygon()
from matplotlib.collections import PolyCollection  # Collections of patches

test = ((1, 22, 20),
        (2, 21, 19.5),
        (3, 18, 20))  # Test data

triangles = []
fig, ax = plt.subplots(1, 1)

for t in test:
    xmid = t[0]  # Middle x-coord
    xleft = t[0] - 0.5
    xright = t[0] + 0.5  # Use fixed width of 0.5

    y1 = t[1]  # y-coords
    y2 = t[2]

    coordinates = [[xleft, y1], [xright, y1], [xmid, y2]]

    print(coordinates) 
    triangles.append(coordinates)  # Append to collection

z = np.random.random(len(triangles))
collec = PolyCollection(triangles, array=z, cmap=matplotlib.cm.viridis)

ax.add_collection(collec)  # Plot polygon collection
ax.autoscale_view()
plt.show()

enter image description here

1 голос
/ 08 мая 2019

Использование PolyCollection (как показано в @ cripcate's answer ) является преимуществом в этом случае.Более сжатая версия, использующая один массив numpy, может выглядеть так:

import numpy as np
import matplotlib.pyplot as plt
from matplotlib.collections import PolyCollection

def triangle_collection(d, ax=None, width=0.4, **kwargs):
    ax = ax or plt.gca()
    verts = np.c_[d[:,0]-width/2, d[:,1], d[:,0]+width/2, 
                  d[:,1], d[:,0], d[:,2]].reshape(len(d),3,2)
    c = PolyCollection(verts, **kwargs)
    ax.add_collection(c)
    ax.autoscale()
    return c


data = np.array([(1,22,20), (2,21,19.5), (3,18,20),
                 (4,17,19), (5,15,17), (6,11,8.5), (7,14,12)])

fig, ax = plt.subplots()
fig.subplots_adjust(left=0.3, right=0.7)

triangle_collection(data, facecolors=plt.cm.tab10(np.arange(len(data))))

plt.show() 

enter image description here

1 голос
/ 08 мая 2019

Рассмотрим следующий простой пример:

import matplotlib.pyplot as plt

# data
data = [[1, 22, 20], [3, 20, 25]]

plt.figure()
for val in data:
    # coordinates
    dy = val[1] - val[2]
    dx = abs(dy) / 2
    x0 = val[0]
    y0 = val[1]
    # drawing
    triangle = plt.Polygon([[x0, y0], [x0 - dx, y0 + dy], [x0 + dx, y0 + dy]])
    plt.gca().add_patch(triangle)

# misc
plt.grid()
plt.axis('square')
# these 2 lines are needed because patches in matplotlib do not adjust axes limits automatically, another approach is to add some data to the figure with plot, scatter, etc.
plt.xlim([-20, 20])
plt.ylim([0, 40])

Результат: enter image description here

...