SymPy Plotting Backends で複数の曲線を一気にグラフにする例とオプション設定例

Python の SymPy Plotting Backends を使って,パラメータを変えて複数の曲線を一気にグラフにする例。グラフを描く際のオプションの設定についても2通りの例をまとめた。

例:斜方投射

簡単のために(初速度 $v_0 \rightarrow 1$, 重力加速度 $g \rightarrow 1$ などとして)適宜無次元化した解は,以下のように時間 $t$ と投射角度 $\theta$ の関数となる。

\begin{eqnarray}
x(t, \theta) &=& t \cos\theta \\
y(t, \theta) &=& t \sin\theta -\frac{1}{2} t^2
\end{eqnarray}

$t=0$ で地上 $y=0$ から投射された物体がふたたび地上に落ちるまでの滞空時間 $t_d$ は
$$t_d(\theta) = 2 \sin\theta$$

必要なモジュールの import

必要なモジュールを import します。

In [1]:
from sympy.abc import *
from sympy import *
# SymPy Plotting Backends (SPB) 
from spb import *

# グラフを SVG で Notebook にインライン表示
%config InlineBackend.figure_formats = ['svg']

関数の定義

In [2]:
# 角度 th は度で 
def x(t, th):
    theta = th * pi/180
    return t*cos(theta)

def y(t, th):
    theta = th * pi/180
    return t*sin(theta) - t**2/2

def td(th):
    theta = th * pi/180
    return 2*sin(theta)

軌道のグラフ

SPB で媒介変数表示のグラフを描くには,

plot_parametric(x(t), y(t), (t, tmin, tmax))

デフォルトで use_cm = True になっているので,カラーマップが不要なら False に。

とりあえず 1 本の軌道を描く

$\theta = 45^{\circ}$ での斜方投射の軌道をグラフにしてみる。

まずは,とりあえずのグラフ:

In [3]:
# θ = 45° のグラフ
th = 45

plot_parametric(
    x(t, th), y(t, th), (t, 0, td(th)), use_cm=False);

オプション設定例

以下のようなオプションを設定して,もう少し体裁を整えます。

  • $\theta$ の値を凡例に
  • 座標軸のラベルとグラフのタイトル
  • 横軸縦軸の表示範囲
  • 縦軸横軸のアスペクト比
  • (座標軸の目盛の間隔… )

ここでは,plot_parametric() の中でオプションを設定しています。

In [4]:
# θ = 45° のグラフ
th = 45

plot_parametric(
    x(t, th), y(t, th), (t, 0, td(th)), 'θ = %2d°' % th, 
    legend = True,
    use_cm = False, 
    xlabel = "X", ylabel = "Y", title = "斜方投射",
    xlim = (0, 1.1), ylim = (0, 0.5), 
    aspect = "equal");

2 本の軌道を描く

$\theta = 30^{\circ}$ と $\theta = 45^{\circ}$ の2本のグラフを描く例。

In [5]:
plot_parametric(
    (x(t, 45), y(t, 45), (t, 0, td(45)), 'θ = %2d°' % 45), 
    (x(t, 30), y(t, 30), (t, 0, td(30)), 'θ = %2d°' % 30), 
    legend = True,
    use_cm = False, 
    xlabel = "X", ylabel = "Y", title = "斜方投射",
    xlim = (0, 1.1), ylim = (0, 0.5), 
    aspect = "equal");

2 本の軌道を描く別の例

$\theta = 30^{\circ}$ と $\theta = 45^{\circ}$ の2本のグラフを描くもう一つの方法。
p1p2 として別々に描いたグラフを

p = p1 + p2
p.show()

として重ねて表示させます。

In [6]:
th = 45
p1 = plot_parametric(
    (x(t, th), y(t, th), (t, 0, td(th)), 'θ = %2d°' % th), 
    xlabel = "X", ylabel = "Y", title = "斜方投射",
    xlim = (0, 1.1), ylim = (0, 0.5), 
    use_cm = False, aspect = "equal", show = False)

th = 30
p2 = plot_parametric(
    (x(t, th), y(t, th), (t, 0, td(th)), 'θ = %2d°' % th), 
    use_cm = False, show = False)

p = p1 + p2
p.show()

オプション設定の別の例

ここでは,ax を設定して,より細かなオプション設定を行ってみます。いったん ax を設定してしまえば,バックエンドの Matplotlib と同じ方法でオプション設定ができます。

SymPy Plotting Backends の関数である plot_parametric() の引数として設定できないオプションも,ax.___ で細かな設定が可能です。

In [7]:
th = 45
p1 = plot_parametric(
    (x(t, th), y(t, th), (t, 0, td(th)), 'θ = %2d°' % th), 
    use_cm = False, show = False)

th = 30
p2 = plot_parametric(
    (x(t, th), y(t, th), (t, 0, td(th)), 'θ = %2d°' % th), 
    use_cm = False, show = False)

p = p1 + p2
fig, ax = p.fig, p.ax
# グラフのサイズが微妙に小さくなるのを防ぐ
fig.tight_layout()
# いったん ax を定義すればより細かなオプション設定が可能
ax.set_aspect('equal')
ax.set_xlim(0, 1.1)
ax.set_ylim(0, 0.5)
ax.set_xlabel("X")
ax.set_ylabel("Y")
ax.set_title("斜方投射")
# グリッドを dotted で
ax.grid(linestyle = 'dotted')
# x の目盛を 0.1 刻みに
ax.set_xticks([0.1*i for i in range(11)])
# y の目盛を 0.1 刻みに
ax.set_yticks([0.1*i for i in range(6)])
ax.legend();

複数の軌道を一度に描く

$\theta$ の値を $30^{\circ}$ から $60^{\circ}$ まで $5^{\circ}$ 刻みで変えて,複数の曲線を一度に描く例。

In [8]:
thl = [th for th in range(60,29,-5)]

plots = [plot_parametric(
           x(t, th), y(t, th), (t, 0, td(th)), 'θ = %2d°' % th, 
           use_cm = False, show = False) 
         for th in thl]

p = sum(plots)
fig, ax = p.fig, p.ax
# グラフのサイズが微妙に小さくなるのを防ぐ
fig.tight_layout()
ax.set_aspect('equal')
ax.set_xlim(0, 1.1)
ax.set_ylim(0, 0.5)
ax.set_xlabel("X")
ax.set_ylabel("Y")
ax.set_title("斜方投射")
# グリッドを dotted で
ax.grid(linestyle = 'dotted')
# x の目盛を 0.1 刻みに
ax.set_xticks([0.1*i for i in range(11)])
# y の目盛を 0.1 刻みに
ax.set_yticks([0.1*i for i in range(6)])
ax.legend();