物理の駅 Physics station by 現役研究者

テクノロジーは共有されてこそ栄える

Python+matplotlibで2次元ヒストグラムをモルワイデ図法で描画する方法

stackoverflow.com

を参考にした。

2Dヒストグラムのbinデータを自力で用意し、pcolormesh で描画する。その方法は

pythonのmatplotlibで2次元ヒストグラム(hist2d)のビンの値を直接操作する - 物理の駅 Physics station by 現役研究者

で解説している。

モルワイデ図法にするコードは plt.subplot(111, projection="mollweide")

import matplotlib.pyplot as plt
import numpy as np


def f(x, y, constant, mu_x, mu_y, sigma_x, sigma_y):
    return np.exp(-((x-mu_x) ** 2) / (2 * sigma_x ** 2)) * np.exp(-((y-mu_y) ** 2) / (2 * sigma_y ** 2)) * constant


plt.figure()
plt.subplot(111, projection="mollweide")

lon = np.linspace(-np.pi, np.pi, 360)
lat = np.linspace(-np.pi/2., np.pi/2., 180)
Lon, Lat = np.meshgrid(lon, lat)
arr = f(Lon, Lat, 1, 0, 0, 0.6, 0.2)
arr += f(Lon, Lat, 0.5, 1.5, 0, 0.2, 0.2)

plt.pcolormesh(Lon, Lat, arr, cmap='Reds', shading='auto')
plt.grid(True)

plt.savefig("projection_mollweide.pdf")
plt.show()

Pythonでモルワイデ図法で描いた図

Python+matplotlib の plt.quiver で矢印を描画する

矢印を描画 matplotlib.pyplot.quiver

matplotlib.pyplot.arrowではなくmatplotlib.pyplot.quiverを使う。

矢印の始点(px, py)、矢印のベクトル(vx, vy)をquiverに与えればよいが、科学目的の場合デフォルトの引数だとやや問題が起きがちなので一つ一つ説明する。なお、矢印ごとに線の太さを変えることはできない。

基本コードは以下の通り。

import matplotlib.pyplot as plt

figsize = 5
fig, ax = plt.subplots(figsize=(figsize,figsize))

ax.quiver([0,1,2,3],[0,0,0,0],[0,1,2,3],[0,1,2,3])
ax.set_xlim(-1,6)
ax.set_ylim(-1,6)
ax.grid(alpha=0.4)
plt.show()

矢印のベクトルとして vx=[0,1,2,3], vy=[0,1,2,3] と与えているのに、ベクトル長はそうなっていない。仕様書によるとベクトル長は自動調整される。つまり、ベクトルの長さを10倍にしても、生成されるグラフは同じである。確認してみてほしい。

#ax.quiver([0,1,2,3],[0,0,0,0],[0,1,2,3],[0,1,2,3]) のかわりに
ax.quiver([0,1,2,3],[0,0,0,0],[0,10,20,30],[0,10,20,30])

これでは困るので、仕様書で提示された引数 angles='xy', scale_units='xy', scale=1 を使う。

scale_units='xy', scale=1 で vx, vyを軸のスケール通りに描画する、angles=xyで軸の向き通りに描画する (もっとも軸の正負を反転させるという特殊な事例でしか効かないが科学目的であれば設定しておいたほうが良いだろう)。

矢印の長さを軸通りに描画したコード

import matplotlib.pyplot as plt

figsize = 5
fig, ax = plt.subplots(figsize=(figsize,figsize))

ax.quiver([0,1,2,3],[0,0,0,0],[0,1,2,3],[0,1,2,3],angles='xy',scale_units='xy',scale=1)
ax.set_xlim(-1,6)
ax.set_ylim(-1,6)
ax.grid(alpha=0.4)
ax.set_aspect(1)
plt.show()

矢印のベクトル vx=[0,1,2,3], vy=[0,1,2,3] どおりに描画された。

次に、矢印の太さについて知るために、少し複雑なグラフを描いてみる。

import matplotlib.pyplot as plt
import numpy as np

xmax = 4.0
ymax = 4.0

figsize=15
fig,axs = plt.subplots(1,3,figsize=(figsize,figsize/4))
for ax,N in zip(axs,[5,10,25]):
    x = np.linspace(-xmax, xmax, N)
    y = np.linspace(-ymax, ymax, N)
    X, Y = np.meshgrid(x, y)
    U = np.cos(X)
    V = np.sin(Y)
    ax.quiver(X, Y, U, V,angles='xy',scale_units='xy',scale=1)
    ax.set_aspect(1)
    ax.set_xlim(5,-5)
plt.show()

quiverは、矢印の数(たぶん密度)が多くなると矢印の太さを自動調整する仕様である。科学目的だと勝手に変えられると困るので、引数 units='xy', width=0.1 を使って太さを制御する。

#ax.quiver(X, Y, U, V,angles='xy',scale_units='xy',scale=1) のかわりに
    ax.quiver(X, Y, U, V,angles='xy',scale_units='xy',scale=1, units='xy', width=0.1)

次に、矢印の色を制御する。色に相当する配列を作り第5引数にいれて、カラーマップを指定すれば良い。ここでは カラーマップ Reds を使った。

#ax.quiver(X, Y, U, V,angles='xy',scale_units='xy',scale=1, units='xy', width=0.1) のかわりに
    C = (U**2+V**2)**0.5
    ax.quiver(X, Y, U, V, C, angles='xy',scale_units='xy',scale=1, units='xy', width=0.1, cmap='Reds')

カラーマップの描画やその範囲指定も含めた全体コード(完成形)を示す。

import matplotlib.pyplot as plt
import numpy as np

xmax = 4.0
ymax = 4.0

figsize=15
fig,axs = plt.subplots(1,3,figsize=(figsize,figsize/4))
for ax,N in zip(axs,[5,10,25]):
    x = np.linspace(-xmax, xmax, N)
    y = np.linspace(-ymax, ymax, N)
    X, Y = np.meshgrid(x, y)
    U = np.cos(X)
    V = np.sin(Y)
    C = (U**2+V**2)**0.5
    im = ax.quiver(X, Y, U, V, C, angles='xy',scale_units='xy',scale=1, units='xy', width=0.1, cmap='Reds')
    fig.colorbar(im)
    im.set_clim(0,N*0.1)
    ax.set_aspect(1)
    ax.set_xlim(5,-5)
plt.show()

その他のサンプルコード

import matplotlib.pyplot as plt

px=[]
py=[]
vx=[]
vy=[]
colors=[]

for yi in range(10):
    for xi in range(10):
        px.append(xi)
        py.append(yi)
        vx.append(yi*0.1)
        vy.append(xi*0.1)
        colors.append((xi**2+yi**2)**0.5)

fig = plt.figure()
plt.gca().set_aspect('equal')
im = plt.quiver(px,py,vx,vy,colors, cmap='Reds', scale = 1,scale_units='xy',angles='xy')
plt.xlim(0,10)
plt.ylim(0,10)
fig.colorbar(im)
im.set_clim(0,16)
plt.savefig("save.pdf")
plt.show()

できる絵

pythonでquiverを使った矢印の描画

px=[0,1,2,3,4,5,6,7,8]
py=[0,1,2,3,4,5,6,7,8]
vx=[1,1,1,1,1,1,1,1,1]
vy=[0,0,0,0,0,0,0,0,0]
color=[-1,2,3,4,5,6,7,8,11]

import matplotlib.pyplot as plt
import matplotlib
import copy

cmap = copy.copy(matplotlib.colormaps.get_cmap("tab10"))
cmap.set_under('black')
cmap.set_over('black')

im = plt.quiver(px,py,vx,vy,color, cmap=cmap, scale = 1, scale_units='xy',angles='xy')
im.set_clim(0,10)

plt.xlim(-1,10)
plt.ylim(-1,10)
plt.colorbar(im,extend='both')
plt.gca().set_aspect('equal')
plt.show()

できる絵

漫画のEPUBファイルから画像をPythonで取得する方法

pypi.org

が便利だった。

pip install EbookLib でインストール

カバーebooklib.ITEM_COVERと、画像ebooklib.ITEM_IMAGEをそれぞれ開き、バイナリ形式で出力する。

import ebooklib
from ebooklib import epub
import os

book = epub.read_epub('filename.epub')

for image in book.get_items_of_type(ebooklib.ITEM_COVER):
    print(image.file_name,os.path.basename(image.file_name))

    with open(os.path.basename(image.file_name),"wb") as f:
        f.write(image.get_content())

for image in book.get_items_of_type(ebooklib.ITEM_IMAGE):
    print(image.file_name,os.path.basename(image.file_name))
    
    with open(os.path.basename(image.file_name),"wb") as f:
        f.write(image.get_content())