Краткое описание одного предложения: Используйте PolyCollection
.
Использование набора для рисования множества фигур, безусловно, более эффективно, чем рисование отдельных прямоугольников. другой ответ предлагает использовать PatchCollection
.Еще более эффективным является использование PolyCollection
.
Причина двоякая:
- В PolyCollection вам не нужно создавать каждый патч отдельно
- Достаточно определить ровно одну фигуру и указать только размеры, цвета и смещения.
Я внес некоторые изменения в код, касающийся определения цвета (лучше всего позволить коллекциисделайте это за вас) и цветовую панель (используйте коллекцию вместо независимой цветной панели)
import matplotlib.pyplot as plt
import matplotlib.patches as patches
import numpy as np
from matplotlib.collections import PatchCollection, PolyCollection
import matplotlib.transforms as mtrans
PatchCollection:
def patchcoll(N, show=False):
fig,ax=plt.subplots()
rng=6
plt.ylim(0,rng+1)
plt.xlim(0,rng+1)
x = np.random.rand(N)*rng
y = np.random.rand(N)*rng
s = np.random.rand(N)
c = np.random.rand(N)
norm = plt.Normalize(0,1) # my numbers from 0-1
cmap=plt.cm.RdYlBu_r
pat = []
for i in range(N):
rect=patches.Rectangle((x[i],y[i]),s[i],s[i])
pat.append(rect)
col = PatchCollection(pat, cmap=cmap, norm=norm)
col.set_array(c)
col.set_edgecolor('k')
col.set_linewidth(1.)
ax.add_collection(col)
fig.colorbar(col)
if show:
plt.show()
else:
fig.canvas.draw()
plt.close()
PolyCollection:
def polycoll(N, show=False):
fig,ax=plt.subplots()
rng=6
plt.ylim(0,rng)
plt.xlim(0,rng)
x = np.random.rand(N)*rng
y = np.random.rand(N)*rng
s = np.random.rand(N)
c = np.random.rand(N)
norm = plt.Normalize(0,1) # my numbers from 0-1
cmap=plt.cm.RdYlBu_r
offsets = np.c_[x,y]
verts = list(zip([0,1,1,0,0], [0,0,1,1,0]))
col = PolyCollection([verts], sizes=s, offsets=offsets,
transOffset=mtrans.IdentityTransform(),
offset_position="data", cmap=cmap, norm=norm)
col.set_array(c)
col.set_edgecolor('k')
col.set_linewidth(1.)
ax.add_collection(col)
fig.colorbar(col)
if show:
plt.show()
else:
fig.canvas.draw()
plt.close()
Одиночные прямоугольники:
def rectangles(N, show=False):
fig,ax=plt.subplots()
rng=6
plt.ylim(0,rng)
plt.xlim(0,rng)
x = np.random.rand(N)*rng
y = np.random.rand(N)*rng
s = np.random.rand(N)
c = np.random.rand(N)
norm = plt.Normalize(0,1) # my numbers from 0-1
cmap=plt.cm.RdYlBu_r
for i in range(N):
rect=patches.Rectangle((x[i],y[i]),s[i],s[i],
facecolor=cmap(norm(c[i])), edgecolor="k", linewidth=1)
ax.add_patch(rect)
sm = plt.cm.ScalarMappable(cmap=cmap, norm=norm)
sm.set_array([])
fig.colorbar(sm)
if show:
plt.show()
else:
fig.canvas.draw()
plt.close()
Выполнить все:
patchcoll(30, show=True)
polycoll(30,show=True)
rectangles(30,show=True)
Время
Для N=1000
Я получаю
%timeit(rectangles(1000))
757 ms ± 4.26 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
%timeit(patchcoll(1000))
184 ms ± 462 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)
%timeit(polycoll(1000))
58.3 ms ± 146 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)
Так что в этом случаеиспользование PatchCollection
в 3 раза эффективнее, чем одиночных прямоугольников, а использование PolyCollection
в 3 раза эффективнее, чем PatchCollection
.
Обзор времени, необходимого для создания фигуры сN
прямоугольников с 3 различными способами сверху:
