I want to draw the graph like the picture below. Its x-axis is the order of the data points, eg from 1 to 7. The y-axis is the scale from 0 to 25. If I want to draw a triangle, for example, with its data (1,22,20), then '1' gives the order among all data points(different triangles), the triangle should be drew in most left; "22,20" gives the "bottom-tip" of the triangle along the y-axis.
Does anyone know how to draw such triangle with multiple number in a graph using matplotlib python package?
Read this post and this post about drawing polygons with matplotlib.
EDIT1: Just saw @Poolka's answer. This was also my way to go, but notice that in one of the above links, it is stated, that adding single polygons ( p = pat.Polygon([[x1, y1], [x2, y2], [x3, y3]); ax.add_patch(p)
) to the figure can become very slow, and therefore collections are preferred.
EDIT 2: Also see TheImportanceOfBeingErnest's answer for a more elaborated version of this concept. Together with this snippet of code, it should get you going:
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()
Consider the following simple example:
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])
Using a PolyCollection
(as shown in @cripcate's answer ) is advantageous in this case. A more condensed version using a single numpy array could look like this:
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()
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.