matplotlib: collectionsを使って描画時間を短縮（2023.08.08）

## はじめに
2023年7月30日に、以下の記事を上げた。

[matplotlib ポリゴン塗りつぶし高速化（2023.07.30投稿）](https://qiita.com/damyarou/items/be77ad4e49b3e7d07026)

その後、思い直して、PatchCollectionとLineCollectionの使用例として、再整理してみた。


##### PatchCollectionの参考ページ

[https://matplotlib.org/stable/gallery/shapes_and_collections/patch_collection.html#sphx-glr-gallery-shapes-and-collections-patch-collection-py](https://matplotlib.org/stable/gallery/shapes_and_collections/patch_collection.html#sphx-glr-gallery-shapes-and-collections-patch-collection-py)

##### LineCollectionの参考ページ

[https://salad-bowl-of-knowledge.github.io/hp/python/2019/10/04/multilines.html](https://salad-bowl-of-knowledge.github.io/hp/python/2019/10/04/multilines.html)


## collectionsを使うプログラム例
下図に示す図を描画するコードを紹介する。
この図には特に意味はなく、色を付けた線分と三角形の塗りつぶしを入れ込むために適当に作ったものである。


![fig_test_0.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/129300/4ecedf24-831f-bea0-8ce5-3d71986c1569.jpeg)

下のコードの中で、
def draw0は、線分の描画にplt.plotを、三角形の塗りつぶしにplt.fillを使った関数であり、
def draw1は、線分の描画にLineCorrectionを、三角形の塗りつぶしにPatchCollectionを使った関数である。

```python
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の計算と作図プログラムが必要であり、長くなってしまうので、コードは省略する。

![fig_cont_a1.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/129300/4efcfea0-2069-a23f-ee32-2819605bac4f.jpeg)

以下に使った方法と描画にかかった概略時間を示す。
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秒 |


以　上