🖼️

matplotlibの極座標上に画像を円形にプロットしたい

2025/01/13に公開

matplotlibで円形の極座標プロット上に画像を円形にプロットする方法を調べたときのメモ

実装例

matplotlibの画像表示にはimshow()を普通は利用するが、直交座標(X,Y)ではない極座標(r,θ)上では期待するような円形表示はできない。ここではmatplotlibの極座標プロット(Polar Plot)上で、pcolormesh()で良い感じに画像を円形プロットする最小の実装コード例を以下に記載する。

import matplotlib.pyplot as plt
from matplotlib.projections.polar import PolarAxes
from PIL import Image
import numpy as np

# 極座標プロット用のPolarAxes定義
# Radian: 北(N)を始点とし、時計回りで値が増加するように設定
# Radius: 0 - 100の範囲に設定
fig = plt.figure(figsize=(8, 8), dpi=300, tight_layout=True)
ax: PolarAxes = fig.add_subplot(projection="polar")
ax.set_theta_zero_location("N")
ax.set_theta_direction(-1)
ax.set_rlim(bottom=0, top=100)
ax.axis(True) # True or False

# 極座標上にプロットする画像の読み込み
image_file = "cell.jpg"
img = Image.open(image_file).convert("RGBA")

# 極座標上の画像プロット領域(Radian, Radius)を定義
rad_start, rad_end = 0, np.pi / 2
rad_size = rad_end - rad_start
r_start, r_end = 50, 100
r_size = r_end - r_start

# pcolormeshで極座標上に画像プロットするためにプロット領域に合わせてリサイズ
pixel_w = int(rad_size / (np.pi / 1000))
pixel_h = int(r_size * 10)
resize_img = img.resize((pixel_w, pixel_h))

# pcolormeshで画像プロット
rad_list = np.linspace(rad_start, rad_end, resize_img.width)
r_list = np.linspace(r_end, r_start, resize_img.height)
ax.pcolormesh(rad_list, r_list, np.array(resize_img), zorder=2)

fig.savefig("polar_image.png")

上記のコードを実行すると、元の画像(cell.jpg)を
cell.jpg

極座標上にいい感じに引き伸ばしてプロットする。

polar_image.png

最後に

このコードを応用して個人開発OSSの円形プロットライブラリpyCirclizeに画像の円形プロット機能を組み込んでみた。興味があれば見てください。

pyCirclizeコード例
from pycirclize import Circos
from pycirclize.utils import load_example_image_file

logo_file = load_example_image_file("python_logo.png")

sectors = {"A": 10, "B": 15, "C": 12, "D": 20, "E": 15}
circos = Circos(sectors, space=5)
for sector in circos.sectors:
    sector.text(sector.name)
    track = sector.add_track((50, 100))
    track.axis()
    track.raster(logo_file, w=0.9, h=0.9)

circos.savefig("pycirclize_plot.png")

pyCirclizeプロット例

pycirclize_plot.png

Discussion