Python matplotlib でクリスマスカード風画像を作る

明日はクリスマス！　自宅で迎えるクリスマスは８年ぶりのような気がする。とは言ってもクリスチャンではないのでどうということもないのですが。
とはいえ、せっかくのクリスマスなので、マレーシア滞在時代にお世話になったカラオケスナックのママにメッセージでも送ろうと思ったのですが、ただのテキストではつまらないので、画像を作ってみました。作例は下に示す通り。メールに添付するとか、facebookに投稿するとかの使いようがあります。

![fig_mico.jpg](https://qiita-image-store.s3.amazonaws.com/0/129300/3678254e-ebbe-b37e-f42d-be030fa19f60.jpeg)

プログラム本文を下に示します。matplotlib では、デフォルトのフォントとして、'fantasy'、'cursive' というのが準備されています。作例で使っているフォントは 'cursive' です。少しおしゃれな感じです。
プログラミングとしては大したことはやっていませんが、難しい顔をしながら計算してグラフを作るのみではなく、こういうことに凝ってみるのも、気分転換としては、面白いですね。


```py
import numpy as np
import matplotlib.pyplot as plt
from PIL import Image, ImageChops


def trim(im, border):
    # 余白削除
    bg = Image.new(im.mode, im.size, border)
    diff = ImageChops.difference(im, bg)
    bbox = diff.getbbox()
    # 余白が残るので少し画像領域に食い込んだ領域を指定する
    b=[]
    dd=15
    for i in range(0,4):
        b=b+[bbox[i]]
    bbox=(b[0]+dd,b[1]+dd,b[2]-dd,b[3]-dd)
    if bbox:
        return im.crop(bbox)

    
def elli(x0,y0,b,a,ang):
    # サンタの帽子を描く（角度 ang だけ回転させる）
    ang=np.radians(ang)
    dt=np.pi/90; theta=np.arange(0,2*np.pi+dt,dt)
    # 帽子本体（赤い三角形）
    h=2*a
    x=np.array([-a,a,0,-a])
    y=np.array([0,0,h,0])    
    xp=np.cos(ang)*x-np.sin(ang)*y+x0
    yp=np.sin(ang)*x+np.cos(ang)*y+y0
    plt.fill(xp,yp,'-',facecolor='#ff0000')
    # 天辺のボンボン
    rr=1.5*b
    x=rr*np.cos(theta)
    y=rr*np.sin(theta)+h
    xp=np.cos(ang)*x-np.sin(ang)*y+x0
    yp=np.sin(ang)*x+np.cos(ang)*y+y0
    plt.fill(xp,yp,'-',facecolor='#ffffff',edgecolor='#bbbbbb',lw=1)
    # かぶる部分
    rr=np.sqrt(a**2*b**2/(b**2*np.cos(theta)**2+a**2*np.sin(theta)**2))
    x=rr*np.cos(theta)
    y=rr*np.sin(theta)
    xp=np.cos(ang)*x-np.sin(ang)*y+x0
    yp=np.sin(ang)*x+np.cos(ang)*y+y0
    plt.fill(xp,yp,'-',facecolor='#ffffff',edgecolor='#bbbbbb',lw=2)



def main():
    xmin=0; xmax=6; dx=1
    ymin=0; ymax=2; dy=1
    cols='#fffafa' # snow
    coln='#191970' # midnight blue
    fsz=20
    iw=8

    ih=iw*(ymax-ymin)/(xmax-xmin)
    fig=plt.figure(figsize=(iw,ih),facecolor=cols)
    plt.rcParams['font.size']=fsz
#    plt.rcParams['font.family']='fantasy'
    plt.rcParams['font.family']='cursive'
    plt.axis('off')
    plt.xlim([xmin,xmax])
    plt.ylim([ymin,ymax])
    plt.gca().set_aspect('equal',adjustable='box')

    # 空を濃紺で塗りつぶし雪を描く（雪粒の数は n=50 個）
    yb=ymin+0.45*(ymax-ymin)
    plt.axhspan(yb, ymax, facecolor=coln)
    n=50; rd=np.random.rand(n,2)
    x=xmin+rd[:,0]*(xmax-xmin)
    y=yb+rd[:,1]*(ymax-yb)
    plt.plot(x,y,'o',markersize=3,color=cols)    

    # 文字を描画（フォントは cursive）
    bbox_props = dict(boxstyle='square,pad=0.1', fc=coln, ec=coln, lw=0)
    plt.text(xmin+0.50*(xmax-xmin),ymin+0.70*(ymax-ymin), 'Merry Christmas',color='#ffffff',ha='center', va='center', rotation=0,size=fsz,bbox=bbox_props)
    plt.text(xmin+0.95*(xmax-xmin),ymin+0.25*(ymax-ymin), 'December 2018', rotation=0,color='#000080',fontsize=fsz-8,va='bottom', ha='right')
    plt.text(xmin+0.95*(xmax-xmin),ymin+0.03*(ymax-ymin), 'To Mico chan', rotation=0,color='#000080',fontsize=fsz-4,va='bottom', ha='right')

    # 余白削除のためのマークを右下に打つ
    plt.plot([xmax],[ymin], '.',color=coln)

    # サンタの帽子を描画
    x0=0.8; y0=0.3; b=0.05; a=0.3; ang=40    
    elli(x0,y0,b,a,ang)

    # 一度画像として保存
    plt.tight_layout()
    fnameF='fig_mico.jpg'
    plt.savefig(fnameF, dpi=200, bbox_inches="tight", pad_inches=0.1)
    plt.show()

    # 保存した画像を読み込み余白を削除
    img_org=Image.open(fnameF,'r')
    img_new=trim(img_org,'#ffffff')
    img_new.save(fnameF, 'JPEG', quality=100, optimize=True)
    img_new.show()


#==============
# Execution
#==============
if __name__ == '__main__': main()
```

以　上