はじめに
2023年7月30日に、以下の記事を上げた。
matplotlib ポリゴン塗りつぶし高速化(2023.07.30投稿)
その後、思い直して、PatchCollectionとLineCollectionの使用例として、再整理してみた。
PatchCollectionの参考ページ
LineCollectionの参考ページ
https://salad-bowl-of-knowledge.github.io/hp/python/2019/10/04/multilines.html
collectionsを使うプログラム例
下図に示す図を描画するコードを紹介する。
この図には特に意味はなく、色を付けた線分と三角形の塗りつぶしを入れ込むために適当に作ったものである。
下のコードの中で、
def draw0は、線分の描画にplt.plotを、三角形の塗りつぶしにplt.fillを使った関数であり、
def draw1は、線分の描画にLineCorrectionを、三角形の塗りつぶしにPatchCollectionを使った関数である。
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.patches import Polygon
from matplotlib.collections import PatchCollection
from matplotlib.collections import LineCollection
import time
def draw0(n,x1,y1,x2,y2,xt,yt):
# using plot and fill
# Color used
col=['#ff0000', '#00ff00', '#0000ff']
# Draw lines
for i in range(0,n):
icol=i%3
x=[x1[i],x2[i]]
y=[y1[i],y2[i]]
plt.plot(x,y,'-',color=col[icol],lw=2)
# Draw triangles
for i in range(0,n):
icol=i%3
x=[xt[i,0],xt[i,1],xt[i,2]]
y=[yt[i,0],yt[i,1],yt[i,2]]
plt.fill(x,y,facecolor=col[icol],edgecolor='#aaaaaa',lw=0.5)
def draw1(n,x1,y1,x2,y2,xt,yt):
# using collections
# Color used
col=['#ff0000', '#00ff00', '#0000ff']
# Draw lines
lines=[]
lcol=[]
for i in range(0,n):
icol=i%3
lns=[(x1[i],y1[i]),(x2[i],y2[i])]
lines.append(lns)
lcol.append(col[icol])
lc = LineCollection(lines,colors=col, lw=2)
plt.gca().add_collection(lc)
# Draw triangles
patches=[]
lcol=[]
for i in range(0,n):
icol=i%3
points=[[xt[i,0],yt[i,0]],[xt[i,1],yt[i,1]],[xt[i,2],yt[i,2]],[xt[i,0],yt[i,0]]]
polygon=Polygon(xy=points,closed=True)
patches.append(polygon)
lcol.append(col[icol])
p=PatchCollection(patches,facecolor=lcol,edgecolor='#aaaaaa',lw=0.5)
plt.gca().add_collection(p)
def main():
start = time.time()
# Definition of coordinates of triangles and lines
r1,r2,dr=3.0,7.0,1.0
theta=np.radians(np.arange(0,360,10))
xt0=np.array([r2,r2+dr,r2+dr])
yt0=np.array([0,-dr/2,dr/2])
n=len(theta)
xt=np.zeros((n,3),dtype=np.float64)
yt=np.zeros((n,3),dtype=np.float64)
for i in range(0,3):
xt[:,i]=xt0[i]*np.cos(theta)-yt0[i]*np.sin(theta)
yt[:,i]=xt0[i]*np.sin(theta)+yt0[i]*np.cos(theta)
x1,y1=r1*np.cos(theta),r1*np.sin(theta)
x2,y2=r2*np.cos(theta),r2*np.sin(theta)
# Draw figure
fsz=10
xmin,xmax=-10,10
ymin,ymax=-10,10
plt.figure(figsize=(5,5),facecolor='w')
plt.xlim([xmin,xmax])
plt.ylim([ymin,ymax])
#draw0(n,x1,y1,x2,y2,xt,yt) # plot,fill
draw1(n,x1,y1,x2,y2,xt,yt) # collections
fnameF='fig_test_0.jpg'
plt.savefig(fnameF, dpi=100, bbox_inches="tight", pad_inches=0.1)
#plt.show()
print(time.time() - start)
#---------------
# Execute
#---------------
if __name__ == '__main__': main()
この程度の描画では、collectionsを使っても使わなくても、描画時間は0.1秒程度であり、あまり有り難みはわからない。逆に、コードの表記が長くなる分、煩わしくさえ有る。
しかしながら、以下に示す図のように、大量の塗りつぶしと線分の描画を行うとなると、collectionの使用は時間短縮に効果を発揮する。この図の作成にはFEMの計算と作図プログラムが必要であり、長くなってしまうので、コードは省略する。
以下に使った方法と描画にかかった概略時間を示す。
collectionsの使用により大幅に描画時間が短縮されることがわかる。
Case-1 | Case-2 | Case-3 | |
---|---|---|---|
塗りつぶし fill | o | x | x |
線分 plot | o | o | x |
塗りつぶし PatchCollection | x | o | o |
線分 LineCollection | x | x | o |
描画時間 | 55秒 | 15秒 | 7秒 |
以 上