[matplotlib] 136. ペンローズの三角形

matplotlib

matplotlibでペンローズの三角形を描く方法

ペンローズの三角形は、不可能図形として知られる有名な幾何学的図形です。この記事では、Pythonのmatplotlibライブラリを使用して、ペンローズの三角形を描画する方法を解説します。

解説

必要なライブラリ

まず、必要なライブラリをインポートします。

import matplotlib.pyplot as plt
import numpy as np
from matplotlib.patches import Polygon

この例では、matplotlibnumpyを使用します。Polygonクラスを使って多角形を描画します。

基本的な構造

ペンローズの三角形は3つの面から構成されており、それぞれが異なる色で塗られています。各面は多角形として定義され、Polygonパッチを使って描画します。

図の初期化

fig, ax = plt.subplots(dpi=100)
ax.set_aspect('equal')

subplots()で図とaxesオブジェクトを作成し、set_aspect('equal')で縦横比を等しく設定します。これにより、図形が正しい形で表示されます。

第1の面(サーモンピンク)

最初の面を描画します。

p1 = np.array([(0,68), (69, 68), (64, 60), (14, 60), (48,0), (38,0), (0,68)])
polygon1 = Polygon(p1, closed=True, edgecolor="k", facecolor='salmon', linewidth=1)
ax.add_patch(polygon1)

np.array()で頂点の座標を定義し、Polygonオブジェクトを作成します。closed=Trueで多角形を閉じ、edgecolorfacecolorで枠線と塗りつぶしの色を指定します。

第2の面(スプリンググリーン)

2つ目の面を描画します。

p2 = np.array([(0,68), (4, 76), (84, 76), (48, 17), (43.5,23.5), (69,68), (0,68)])
polygon2 = Polygon(p2, closed=True, edgecolor="k", facecolor='springgreen', linewidth=1)
ax.add_patch(polygon2)

同様の方法で、異なる頂点座標と色を使って2つ目の面を作成します。

第3の面(カーキ)

最後の面を描画します。

p3 = np.array([(84,76), (88, 68), (48, 0), (14, 60), (23,60), (48,17), (84,76)])
polygon3 = Polygon(p3, closed=True, edgecolor="k", facecolor='khaki', linewidth=1)
ax.add_patch(polygon3)

3つ目の面も同じ手順で作成します。

図の表示

plt.show()

plt.show()で図を表示します。

完成コード

すべてをまとめた完成コードは以下の通りです。

import matplotlib.pyplot as plt
import numpy as np

from matplotlib.collections import PatchCollection
from matplotlib.patches import Polygon
patches = []

fig, ax = plt.subplots(dpi=100)
p1=np.array([(0,68), (69, 68), (64, 60), (14, 60),(48,0),(38,0),(0,68)])
polygon1 = Polygon(p1,closed=True, edgecolor="k",facecolor='salmon', linewidth=1)
ax.plot(p1[:,0],p1[:,1],alpha=0)
ax.add_patch(polygon1)

p2=np.array([(0,68), (4, 76), (84, 76), (48, 17),(43.5,23.5),(69,68),(0,68)])
polygon2 = Polygon(p2,closed=True, edgecolor="k",facecolor='springgreen', linewidth=1)
ax.plot(p2[:,0],p2[:,1],alpha=0)
ax.add_patch(polygon2)

p3=np.array([(84,76), (88, 68), (48, 0), (14, 60),(23,60),(48,17),(84,76)])
polygon3 = Polygon(p3,closed=True, edgecolor="k",facecolor='khaki', linewidth=1)
ax.plot(p3[:,0],p3[:,1],alpha=0)
ax.add_patch(polygon3)

ax.set_aspect('equal')
plt.savefig("penrose.png",dpi=100)
plt.show()

ax.plotの役割について

上記のコードでは、各多角形を描画した後にax.plot(p2[:,0],p2[:,1],alpha=0)のように透明なプロットを作成しています。これは、matplotlibのオートスケール機能を有効にするための工夫です。

Polygonパッチだけを追加した場合、matplotlibは自動的に軸の範囲を調整しません。そのため、透明度を0に設定した(alpha=0)プロットを追加することで、座標データを軸に認識させ、適切な表示範囲が自動的に設定されるようにしています。

つまり、この透明なプロットは視覚的には表示されませんが、オートスケールを機能させるために必要な処理となります。

まとめ

この記事では、matplotlibを使ってペンローズの三角形を描く方法を解説しました。Polygonパッチを使うことで、複雑な幾何学的図形も簡単に描画できます。

おまけ:色をランダムに変えたペンローズの三角形

以下のコードでは、各面の色をランダムに生成してペンローズの三角形を描画します。

import matplotlib.pyplot as plt
import numpy as np
import random
from matplotlib.patches import Polygon

# ランダムな色を生成する関数
def random_color():
    return (random.random(), random.random(), random.random())

fig, ax = plt.subplots(dpi=100)

# 第1の面
p1 = np.array([(0,68), (69, 68), (64, 60), (14, 60), (48,0), (38,0), (0,68)])
polygon1 = Polygon(p1, closed=True, edgecolor="k", facecolor=random_color(), linewidth=1)
ax.plot(p1[:,0], p1[:,1], alpha=0)
ax.add_patch(polygon1)

# 第2の面
p2 = np.array([(0,68), (4, 76), (84, 76), (48, 17), (43.5,23.5), (69,68), (0,68)])
polygon2 = Polygon(p2, closed=True, edgecolor="k", facecolor=random_color(), linewidth=1)
ax.plot(p2[:,0], p2[:,1], alpha=0)
ax.add_patch(polygon2)

# 第3の面
p3 = np.array([(84,76), (88, 68), (48, 0), (14, 60), (23,60), (48,17), (84,76)])
polygon3 = Polygon(p3, closed=True, edgecolor="k", facecolor=random_color(), linewidth=1)
ax.plot(p3[:,0], p3[:,1], alpha=0)
ax.add_patch(polygon3)

ax.set_aspect('equal')
plt.savefig("penrose_cc.png",dpi=100)
plt.show()

コードの説明

random_color()関数: この関数は、0から1の範囲でランダムなRGB値を生成し、タプルとして返します。matplotlibでは、RGB値を(R, G, B)の形式で指定でき、各値は0から1の範囲で指定します。

facecolor=random_color():Polygonオブジェクトのfacecolorパラメータにrandom_color()関数を使用することで、実行するたびに異なる色の組み合わせでペンローズの三角形が描画されます。

実行結果

このコードを実行すると、3つの面がそれぞれランダムな色で塗られたペンローズの三角形が表示されます。プログラムを実行するたびに異なる色の組み合わせが生成されるため、様々なバリエーションを楽しむことができます。

おまけ2:SVGファイルで書き出してベクターグラフィックソフトで自由に加工

matplotlibで作成した図は、SVG(Scalable Vector Graphics)形式で保存することができます。SVGはベクター形式なので、拡大しても画質が劣化せず、InkscapeやAdobe Illustratorなどのベクターグラフィックソフトで自由に編集・加工が可能です。

SVGファイルとして保存する方法

以下のように、plt.savefig()を使ってSVG形式で保存できます。

import matplotlib.pyplot as plt
import numpy as np
from matplotlib.patches import Polygon

fig, ax = plt.subplots(dpi=100)

p1 = np.array([(0,68), (69, 68), (64, 60), (14, 60), (48,0), (38,0), (0,68)])
polygon1 = Polygon(p1, closed=True, edgecolor="k", facecolor='salmon', linewidth=1)
ax.plot(p1[:,0], p1[:,1], alpha=0)
ax.add_patch(polygon1)

p2 = np.array([(0,68), (4, 76), (84, 76), (48, 17), (43.5,23.5), (69,68), (0,68)])
polygon2 = Polygon(p2, closed=True, edgecolor="k", facecolor='springgreen', linewidth=1)
ax.plot(p2[:,0], p2[:,1], alpha=0)
ax.add_patch(polygon2)

p3 = np.array([(84,76), (88, 68), (48, 0), (14, 60), (23,60), (48,17), (84,76)])
polygon3 = Polygon(p3, closed=True, edgecolor="k", facecolor='khaki', linewidth=1)
ax.plot(p3[:,0], p3[:,1], alpha=0)
ax.add_patch(polygon3)

ax.set_aspect('equal')
ax.axis('off')  # 軸を非表示にする

# SVG形式で保存
plt.savefig('penrose_triangle.svg', format='svg', bbox_inches='tight')
plt.show()

plt.savefig('penrose_triangle.svg', format='svg', bbox_inches='tight')により、カレントディレクトリに「penrose_triangle.svg」というファイルが保存されます。bbox_inches='tight'は余白を最小限にするオプションです。

Inkscapeでの編集

保存したSVGファイルをInkscapeで開くと、各多角形が個別のオブジェクトとして認識されます。これにより、以下のような編集が可能になります。

  • 各面の色を個別に変更
  • グラデーションやパターンの適用
  • 影やぼかし効果の追加
  • 線の太さやスタイルの調整
  • 他のグラフィック要素との組み合わせ

このように、プログラムで生成した図形をベクターグラフィックソフトで更に洗練させることができます。

noteマガジンのご案内

Inkscapeのノウハウについて、noteで定期的に記事を公開しています。より詳しい解説や応用例、実践的なテクニックについて知りたい方は、ぜひnoteマガジンをご購読ください。

Inkscape チュートリアル:基本(無料)|sabopyさん|note
このマガジンは、ベクターグラフィックスソフトInkscapeを体系的に学べる実践的な学習コンテンツです。基本操作について全14記事で段階的にスキルアップできる構成になっています。内容は5つの分野に分かれています。スクロールやズームなどの基本...
Inkscape チュートリアル: 上級編|sabopyさん|note
このマガジンは、Inkscapeの上級テクニックを習得したい方のための総合ガイドです。基本操作をマスターした方が、より高度なグラフィックデザインスキルを身につけるための実践的なチュートリアル集となっています。コピー&ペーストの効率的な使い方...
Inkscape チュートリアル: ヒントとコツ|sabopyさん|note
このマガジンは、Inkscapeを使いこなすための実践的なヒントとテクニックを集めたチュートリアル集です。初心者から中級者まで、幅広いユーザーに役立つ12のトピックを収録しています。タイルクローンによる放射状配置、メッシュグラデーションの活...
Inkscape チュートリアル: シェイプ|sabopyさん|note
このマガジンは、Inkscapeのシェイプツールを包括的に学ぶためのガイドです。矩形、円/弧、星型/多角形、らせんという4つの基本シェイプツールについて、それぞれの機能と実践的な使い方を段階的に解説しています。初心者から中級者まで、Inks...

参考資料

この記事の作成にあたり、以下のWebページを参考にしました。

コメント