1
votes

Comment dessiner plusieurs triangles avec différentes tailles et directions en fonction des données à l'aide d'outils de traçage comme Matplotlib

Je veux dessiner le graphique comme l'image ci-dessous. Son axe x est l'ordre des points de données, par ex. de 1 à 7. L'axe des y est l'échelle de 0 à 25. Si je veux dessiner un triangle, par exemple, avec ses données (1,22,20), alors '1' donne l'ordre parmi tous les points de données (triangles différents), le triangle doit être dessiné le plus à gauche; "22,20" donne la "pointe inférieure" du triangle le long de l'axe y.

Est-ce que quelqu'un sait comment dessiner un tel triangle avec un nombre multiple dans un graphique en utilisant le package python matplotlib?

 entrez la description de l'image ici


0 commentaires

3 Réponses :


2
votes

Lisez ce message et ce post sur le dessin de polygones avec matplotlib.

EDIT1: Je viens de voir la réponse de @ Poolka. C'était aussi ma façon de procéder, mais notez que dans l'un des liens ci-dessus, il est indiqué que l'ajout de polygones simples ( p = pat.Polygon ([[x1, y1], [x2, y2], [ x3, y3]); ax.add_patch (p) ) à la figure peut devenir très lent, et donc les collections sont préférées.

EDIT 2: Voir aussi La réponse de TheImportanceOfBeingErnest pour une version plus élaborée de ce concept. Avec cet extrait de code, il devrait vous permettre de démarrer:

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()

entrez la description de l'image ici


3 commentaires

Il devrait toujours être coordonnées = [[xleft, y1], [xright, y1], [xmid, y2]] , indépendamment de l'ordre !!


J'ai supprimé cette ligne superflue maintenant. Notez que vos deux liens ont la même cible. Toujours voté.


Jésus, je suppose que j'étais un peu distrait, haha. Je vais mettre à jour le deuxième lien.



1
votes

Prenons l'exemple simple suivant:

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])

Le résultat est: entrez la description de l'image ici


0 commentaires

1
votes

Utilisation d'une PolyCollection ( comme indiqué dans la réponse de @ cripcate ) est avantageux dans ce cas. Une version plus condensée utilisant un seul tableau numpy pourrait ressembler à ceci:

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() 

 entrez la description de l'image ici


0 commentaires