LoginSignup
9
6

More than 3 years have passed since last update.

Pythonで動く点Pを可視化する

Last updated at Posted at 2019-12-21

やったこと

Pythonで動く点Pを描画し、gifとして出力しました。

ugokutenP02.gif

例題

以下のような動く点Pの問題を可視化してみます。

AB=4cm, BC=6cmの長方形ABCDがあり、点PはAを出発して毎秒1cmでA→B→C→Dと進む。 出発から$x$秒後の△APDの面積を$y$ cm2とする。

出典
https://math.005net.com/yoten/doten.php
(ただし、毎秒2cmを毎秒1cmとしています。)

描画

環境

  • Anaconda3 + jupyter notebook
  • Python 3.6
  • matplotlib 3.1.1
  • numpy 1.16.5

1.空っぽの図をつくる

まず、図形を描画するための下準備をします。

import matplotlib.pyplot as plt

fig = plt.figure()
ax1 = fig.add_subplot(111)

plt.show()

image.png

2.長方形を表示する

縦4cm、横6cmの長方形を作ります。ここで、座標原点$O$をどこにおくかにはいろいろな選び方があります。今回は長方形の重心(縦2cm、横3cmのところ)を原点$O$に選び、点A,B,C,Dの座標を決めます。こうしておくと、あとで長方形の一回り外側にラベルを表示させたいときにコードが簡単になります。
1576855216649.jpg

  • 図形を描画するためにmatplotlib.patchesを用います。また点の座標をベクトルとして扱いたいのでnumpyも入れます。

  • 長方形が枠に収まるようにset_xlim,set_ylimでx軸、y軸の範囲を長方形よりやや大きめにしておきます。

  • 点A,B,C,Dの座標をnp.array型で定義します。

  • pat.Polygonで長方形を作り、ax1に追加します。


import numpy as np #追加
import matplotlib.pyplot as plt
import matplotlib.patches as pat #追加

fig = plt.figure()

ax1 = fig.add_subplot(111)

ax1.set_xlim(-4,4)
ax1.set_ylim(-3,3)

A=np.array([-3,2])
B=np.array([-3,-2])
C=np.array([3,-2])
D=np.array([3,2])

p = pat.Polygon(xy = [A,B,C,D],
                edgecolor='black',
                facecolor='white',
                linewidth=1.6)

ax1.add_patch(p)

plt.show()

image.png

3.辺の長さ・頂点の名前を表示する

辺の長さを描画します
textは第一引数にx座標、第二引数にy座標、第三引数に名前を指定することで文字を描画できます。

#辺の長さを表示する
ax1.text(-3.5,0.0,"4cm",horizontalalignment='center',verticalalignment='center')
ax1.text(0.0,-2.5,"6cm",horizontalalignment='center',verticalalignment='center')

配置は好みに合わせて微調整してください。

つづいて、点の名前を長方形の一回り外側に表示します。辺の長さと同様に手打ちで表示位置を決めてもよいです。

import numpy as np
import matplotlib.pyplot as plt
import matplotlib.patches as pat

fig = plt.figure()
ax1 = fig.add_subplot(111)

ax1.set_xlim(-4,4)
ax1.set_ylim(-3,3)

A=np.array([-3,2])
B=np.array([-3,-2])
C=np.array([3,-2])
D=np.array([3,2])

pol = pat.Polygon(xy = [A,B,C,D],
                edgecolor='black',
                facecolor='white',
                linewidth=1.6)

ax1.add_patch(pol)

#辺の長さを表示させる
ax1.text(-3.5,0.0,"4cm",horizontalalignment='center',verticalalignment='center')
ax1.text(0.0,-2.5,"6cm",horizontalalignment='center',verticalalignment='center')

#頂点の名前を表示させる
scale=1.1
ax1.text(A[0]*scale,A[1]*scale,"A",fontsize=15,horizontalalignment='center',verticalalignment='center')
ax1.text(B[0]*scale,B[1]*scale,"B",fontsize=15,horizontalalignment='center',verticalalignment='center')
ax1.text(C[0]*scale,C[1]*scale,"C",fontsize=15,horizontalalignment='center',verticalalignment='center')
ax1.text(D[0]*scale,D[1]*scale,"D",fontsize=15,horizontalalignment='center',verticalalignment='center')

plt.show()

image.png

4.点Pを表示する

いよいよ主役の登場です。
点Pの座標を定義し、ax1.plot()で点を表示します。点Pの名前の表示のさせ方は点A,B,C,Dと同じです。

import numpy as np
import matplotlib.pyplot as plt
import matplotlib.patches as pat

fig = plt.figure()

ax1 = fig.add_subplot(111)

ax1.set_xlim(-4,4)
ax1.set_ylim(-3,3)

A=np.array([-3,2])
B=np.array([-3,-2])
C=np.array([3,-2])
D=np.array([3,2])

pol = pat.Polygon(xy = [A,B,C,D],
                edgecolor='black',
                facecolor='white',
                linewidth=1.6)

ax1.add_patch(pol)

ax1.text(-3.5,0.0,"4cm",horizontalalignment='center',verticalalignment='center')
ax1.text(0.0,-2.5,"6cm",horizontalalignment='center',verticalalignment='center')

scale=1.1
ax1.text(A[0]*scale,A[1]*scale,"A",fontsize=15,horizontalalignment='center',verticalalignment='center')
ax1.text(B[0]*scale,B[1]*scale,"B",fontsize=15,horizontalalignment='center',verticalalignment='center')
ax1.text(C[0]*scale,C[1]*scale,"C",fontsize=15,horizontalalignment='center',verticalalignment='center')
ax1.text(D[0]*scale,D[1]*scale,"D",fontsize=15,horizontalalignment='center',verticalalignment='center')

P=np.array([-3.0,1.0])

#動く点Pを表示する
scale_P=1.2
ax1.plot(P[0],P[1],marker='o',color='black')
ax1.text(P[0]*scale_P,P[1]*scale_P,"P",fontsize=15,horizontalalignment='center',verticalalignment='center')

plt.show()

5.△APDを表示する

長方形ABCDをつくったときと同様に三角形APDをつくり図に追加します、ついでにx軸とy軸を消しておきます。

%matplotlib nbagg
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.patches as pat

fig = plt.figure()

ax1 = fig.add_subplot(111)

ax1.set_xlim(-4,4)
ax1.set_ylim(-3,3)

A=np.array([-3,2])
B=np.array([-3,-2])
C=np.array([3,-2])
D=np.array([3,2])

pol = pat.Polygon(xy = [A,B,C,D],
                edgecolor='black',
                facecolor='white',
                linewidth=1.6)

ax1.add_patch(pol)

ax1.text(-3.5,0.0,"4cm",horizontalalignment='center',verticalalignment='center')
ax1.text(0.0,-2.5,"6cm",horizontalalignment='center',verticalalignment='center')

scale=1.1
ax1.text(A[0]*scale,A[1]*scale,"A",fontsize=15,horizontalalignment='center',verticalalignment='center')
ax1.text(B[0]*scale,B[1]*scale,"B",fontsize=15,horizontalalignment='center',verticalalignment='center')
ax1.text(C[0]*scale,C[1]*scale,"C",fontsize=15,horizontalalignment='center',verticalalignment='center')
ax1.text(D[0]*scale,D[1]*scale,"D",fontsize=15,horizontalalignment='center',verticalalignment='center')

P=np.array([-3.0,1.0])

scale_P=1.2
ax1.plot(P[0],P[1],marker='o',color='black')
ax1.text(P[0]*scale_P,P[1]*scale_P,"P",fontsize=15,horizontalalignment='center',verticalalignment='center')

#△APDを追加
S = pat.Polygon(xy = [A,P,D],
                    edgecolor='black',
                    facecolor='lightgray',
                    linewidth=1.6)

ax1.add_patch(S)

#枠を消す
plt.axis('off')

plt.show()

6.動かす

動く点Pを動かし、それをgif形式のアニメーションで出力します。
$x$秒後の動く点Pの座標を毎回更新し、コマ送りで描画することによってアニメーションをつくります。

  • あらかじめ長方形ABCDの描画など時間が経過しても変わらない操作をinitialize()にまとめておきます。
  • moveP(x)は経過時間から動く点Pが線分AB、BC、CDのどこにいるか場合分けを行い、動く点Pの座標を返します。
  • 動く点Pの速度(velocity)は秒速1cmとし、描画間隔(timestep)は0.1秒とします。
  • アニメーション作成にはPillowWriterFuncAnimationを使います。 animate(i)に一回の描画更新で行う操作をすべてまとめておき、FuncAnimationの引数にとることでアニメーションをつくります。
  • anim.save()で動画の出力ができます。
%matplotlib nbagg #jupyter notebook上でアニメーション表示させるために必要
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.patches as pat
from matplotlib.animation import PillowWriter,FuncAnimation #動画作成用に追加

fig = plt.figure()
ax1 = fig.add_subplot(111)

A=np.array([-3,2])
B=np.array([-3,-2])
C=np.array([3,-2])
D=np.array([3,2])

scale=1.1
scaleP=1.2

p = pat.Polygon(xy = [A,B,C,D],
                edgecolor='black',
                facecolor='white',
                linewidth=1.6)

def initialize():
    ax1.set_xlim(-4,4)
    ax1.set_ylim(-3,3)
    ax1.add_patch(p)


    ax1.text(A[0]*scale,A[1]*scale,"A",fontsize=15,horizontalalignment='center',verticalalignment='center')
    ax1.text(B[0]*scale,B[1]*scale,"B",fontsize=15,horizontalalignment='center',verticalalignment='center')
    ax1.text(C[0]*scale,C[1]*scale,"C",fontsize=15,horizontalalignment='center',verticalalignment='center')
    ax1.text(D[0]*scale,D[1]*scale,"D",fontsize=15,horizontalalignment='center',verticalalignment='center')

    ax1.text(-3.5,0.0,"4cm",horizontalalignment='center',verticalalignment='center')
    ax1.text(0.0,-2.5,"6cm",horizontalalignment='center',verticalalignment='center')


def moveP(x):
    if 0<= x <4:
        return A+np.array([0,-1])*x*velocity
    elif 4<=x <10:
        return B+np.array([1,0])*(x-4)*velocity
    elif 10<= x <14:
        return C+np.array([0,1])*(x-10)*velocity
    else:
        return D

velocity=1.0
timestep=0.1

def animate(t):
    plt.cla()
    initialize()

    x=timestep*t
    P=moveP(x)

    ax1.plot(P[0],P[1],marker='o',color='black')
    ax1.text(P[0]*scaleP,P[1]*scaleP,"P",fontsize=15,horizontalalignment='center',verticalalignment='center')

    S = pat.Polygon(xy = [A,P,D],
                    edgecolor='black',
                    facecolor='lightgray',
                    linewidth=1.6)

    ax1.add_patch(S)

    plt.axis('off')
    plt.title('x=' + '{:.1f}'.format(x)+'sec')

anim = FuncAnimation(fig,animate,frames=140,repeat=True,interval=timestep*1000)
#anim.save("ugokutenP.gif", writer='pillow',fps=10)
plt.show()

ugokutenP02.gif

9
6
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
9
6