地面から高さ
Python の Matplotlib によるグラフ作成には,plt.***
という関数のみを使った plt (pyplot) 流(pyplot インターフェースとも)と,ax.***
という関数のみを使った ax 流(オブジェクト指向インターフェースとも)の2つの方法があります。ここでは ax.***
のみを使ってグラフを描きます。
ax.***
のみを使ってグラフを作成する方法については,以下のページにまとめています。
update: 2025.01.21
ライブラリの import
# NumPy を使います
import numpy as np
# Matplotlib でグラフを描きます
import matplotlib.pyplot as plt
# 方程式の数値解
from scipy.optimize import root_scalar
# グラフを SVG で Notebook にインライン表示させる設定
%config InlineBackend.figure_formats = ['svg']
関数の定義
無次元化された解
# 角度 th は度で
def X(T, th):
theta = np.radians(th)
return np.cos(theta) * T
def Y(T, th, H):
theta = np.radians(th)
return H + np.sin(theta)*T - T**2/2
def T1(th, H):
theta = np.radians(th)
return np.sin(theta) + np.sqrt(np.sin(theta)**2 + 2*H)
def L(th, H):
theta = np.radians(th)
return X(T1(th, H), th)
の場合の軌道
まずは,とりあえずのグラフ:
# ax を使う際の最初のおまじない
fig, ax = plt.subplots()
# θ = 45° のグラフ
th = 45
H = 0
# 滞空時間 T1
T_list = np.linspace(0, T1(th, H))
ax.plot(X(T_list, th), Y(T_list, th, H));
以下のようなオプションを設定して,もう少し体裁を整えます。
の値を凡例に- グリッド(格子線)をドットに
- 座標軸のラベルとグラフのタイトル
- 横軸縦軸の表示範囲
- 座標軸の目盛の間隔
- 縦軸横軸のアスペクト比
# ax を使う際の最初のおまじない
fig, ax = plt.subplots()
# θ = 45° のグラフ
th = 45
H = 0
# 滞空時間
T_list = np.linspace(0, T1(th, H))
# 凡例
key = 'θ = %2d°' % th
ax.plot(X(T_list, th), Y(T_list, th, H), label = key)
# グラフのオプション設定例
# グリッドをドットで
ax.grid(linestyle='dotted')
# 座標軸のラベル
ax.set_xlabel("X")
ax.set_ylabel("Y")
# グラフのタイトル
ax.set_title("H = 0 の場合の斜方投射")
# 横軸縦軸の表示範囲
ax.set_xlim(0, 1.1)
ax.set_ylim(0, 0.5)
# 座標軸の目盛の間隔を手動で設定する場合
# 間隔を指定して np.arange() を使う例
# 0 から 0.1 間隔で 1.1 未満(つまり 1.0)まで
ax.set_xticks(np.arange(0, 1.1, 0.1))
# 要素数を指定して np.linspace() を使う例
# (0, 0.5) 区間を 5 等分
ax.set_yticks(np.linspace(0, 0.5, 5+1))
# 45°が45°に見えるように
# 縦軸横軸のアスペクト比を 'equal' に。
ax.set_aspect('equal')
# 凡例を表示
ax.legend();
for
で繰り返し処理させてみます。
なお,細かいことですが,グラフの最高点は
# ax を使う際の最初のおまじない
fig, ax = plt.subplots()
H = 0
# 複数のグラフを一度に描く場合,
# for ループで繰り返し処理
for th in range(47, 42, -1):
# 滞空時間
T_list = np.linspace(0, T1(th, H))
# 凡例
key = 'θ = %2d°' % th
# plot でグラフを描く
ax.plot(X(T_list, th), Y(T_list, th, H), label = key)
ax.grid(linestyle='dotted')
# 座標軸のラベルとタイトル
ax.set_xlabel("X")
ax.set_ylabel("Y")
ax.set_title("H = 0 の場合の斜方投射")
# 横軸縦軸の表示範囲と目盛
ax.set_xlim(0, 1.1)
ax.set_ylim(0, 0.5)
ax.set_xticks(np.arange(0, 1.1, 0.1))
ax.set_aspect('equal')
# 凡例を表示
ax.legend();
最大到達距離となる角度
# ax を使う際の最初のおまじない
fig, ax = plt.subplots()
H = 0
# 複数のグラフを一度に描く場合,
# for ループで繰り返し処理
for th in range(47, 42, -1):
# 滞空時間
T_list = np.linspace(0, T1(th, H))
# 凡例
key = 'θ = %2d°' % th
# plot でグラフを描く
ax.plot(X(T_list, th), Y(T_list, th, H), label = key)
ax.grid(linestyle='dotted')
# 座標軸のラベルとタイトル
ax.set_xlabel("X")
ax.set_ylabel("Y")
ax.set_title("H = 0 の場合の斜方投射")
# 着地点付近を拡大表示
ax.set_xlim(0.99, 1.0)
ax.set_ylim(0, 0.01)
# 凡例を表示
ax.legend();
上のグラフから,
の場合の軌道
今度は,
# ax を使う際の最初のおまじない
fig, ax = plt.subplots()
H = 0.2
for th in range(47, 37, -1):
T_list = np.linspace(0, T1(th, H))
key = 'θ = %2d°' % th
ax.plot(X(T_list, th), Y(T_list, th, H), label = key)
ax.grid(linestyle='dotted')
# 座標軸のラベルとタイトル
ax.set_xlabel("X")
ax.set_ylabel("Y")
ax.set_title("H = 0.2 の場合の斜方投射")
# 横軸縦軸の表示範囲を調整する
ax.set_xlim(0, 1.5)
ax.set_ylim(0, 0.7)
ax.set_xticks(np.arange(0, 1.4, 0.1))
ax.set_aspect('equal')
# 凡例を表示
ax.legend();
最大到達距離となる角度
# ax を使う際の最初のおまじない
fig, ax = plt.subplots()
H = 0.2
for th in range(47, 37, -1):
T_list = np.linspace(0, T1(th, H))
key = 'θ = %2d°' % th
ax.plot(X(T_list, th), Y(T_list, th, H), label = key)
ax.grid(linestyle='dotted')
# 座標軸のラベルとタイトル
ax.set_xlabel("X")
ax.set_ylabel("Y")
ax.set_title("H = 0.2 の場合の斜方投射")
# 着地点付近を拡大表示
ax.set_xlim(1.15, 1.19)
ax.set_ylim(0, 0.02)
# 凡例を表示
ax.legend();
水平到達距離が最大となるのは
水平到達距離
定量的に調べるために,水平到達距離 L(th, H)
をグラフにしてみる。
# ax を使う際の最初のおまじない
fig, ax = plt.subplots()
H = 0.2
th_list = np.linspace(38, 48)
ax.plot(th_list, L(th_list, H))
ax.grid(linestyle='dotted')
# 座標軸のラベルとタイトル
ax.set_xlabel("打ち出し角度 (°)")
ax.set_ylabel("規格化された水平到達距離")
ax.set_title("H = 0.2 の場合の打ち出し角度と水平到達距離")
# 横軸縦軸の表示範囲を調整する
ax.set_xlim(38, 48)
ax.set_xticks(np.arange(38, 48, 1));
上のグラフをみると,
L が最大となる角度を数値微分で求める
数値微分して
# とりあえず,以下のように定義しておく。
# 数値微分: delta は小さいほどよい,というわけではない
# scipy.optimize.root_scalar を使うときは
# x の関数として定義
def dL(x, H, delta=1e-5):
return (L(x+delta, H) - L(x-delta, H))/(2*delta)
scipy.optimize.root_scalar
を使います。
H = 0.2
# delta がデフォルトの場合
print(root_scalar(dL, bracket = [38, 48], args=(H)).root)
# delta を変えてみる
for delta in [1.e-3, 1.e-4, 1.e-5, 1.e-6, 1.e-7]:
# x 以外の変数は args に
print(root_scalar(dL, bracket = [38, 48], args=(H, delta)).root)
上の結果から,delta = 1.e-5
にして以下のような関数を定義します。
def thm(H):
""" 高さ H からの斜方投射で最大到達距離になる角度(°)
"""
ans = root_scalar(dL, bracket = [1, 89], args=(H)).root
return ans
定義した thm(H)
を使って,H = 0.2
のときの最大到達距離となる軌道のグラフを描きます。
# 上の結果を使ってグラフを描く
# ax を使う際の最初のおまじない
fig, ax = plt.subplots()
H = 0.2
# 時間 T の範囲。滞空時間 T1 まで。
T_list = np.linspace(0, T1(thm(H), H), 100)
# 凡例の数値の桁数を揃える
key = 'H=%3.1f, θ=%6.3f°, Lmax=%6.3f' % (H, thm(H), L(thm(H), H))
ax.plot(X(T_list, thm(H)), Y(T_list, thm(H), H), label = key)
# グラフのオプション設定例
# グリッドをドットで
ax.grid(linestyle='dotted')
# 座標軸のラベルとタイトル
ax.set_xlabel("X")
ax.set_ylabel("Y")
ax.set_title("高さ H からの斜方投射の最大水平到達距離")
# 横軸縦軸の表示範囲
ax.set_xlim(0, 1.2)
ax.set_ylim(0, 0.5)
ax.set_xticks(np.arange(0, 1.3, 0.1))
ax.set_aspect('equal')
# 凡例を表示
ax.legend();
○練習: を変えて最大水平到達距離を求める
高さ
Hs = np.linspace(0.2, 1, 5)
Hs
# ax を使う際の最初のおまじない
fig, ax = plt.subplots()
...
# グラフのオプション設定例
# グリッドをドットで
...
# 座標軸のラベルとタイトル
ax.set_xlabel("X")
ax.set_ylabel("Y")
ax.set_title("高さ H からの斜方投射の最大水平到達距離")
# 横軸縦軸の表示範囲
ax.set_xlim(0, 2.4)
ax.set_ylim(0, 1.5)
ax.set_aspect('equal')
# 凡例を表示
ax.legend();
○練習:高さ と打ち出し角度 のグラフ
高さ
# ax を使う際の最初のおまじない
fig, ax = plt.subplots()
# 横軸は H
# (0, 1) 区間
...
# 縦軸は thm(H)
...
...
# グラフのオプション設定例
# グリッドをドットで
ax.grid(linestyle='dotted')
# 座標軸のラベルとタイトル
ax.set_title("水平到達距離が最大となる打ち出し角度");
ax.set_xlabel("規格化された高さ H")
ax.set_ylabel("打ち出し角度 (°)")
○練習:高さ と最大水平到達距離 のグラフ
高さ
# ax を使う際の最初のおまじない
fig, ax = plt.subplots()
...
...
...
# グラフのオプション設定例
# グリッドをドットで
ax.grid(linestyle='dotted')
# 座標軸のラベルとタイトル
ax.set_title("最大水平到達距離");
ax.set_xlabel("規格化された高さ H")
ax.set_ylabel("規格化された高さ最大水平到達距離")
○練習:水平到達距離を求める
ヒント:
重力加速度
h = 5
v0 = 10
g = 9.80665
...
...