본문 바로가기

Software/Python

Python Matplotlib의 Slider 위젯을 적용한 간편 예제

요즘 하도 문어발 식으로 학습을 진행해서 살짝 일관성이 없어 보이네요... 그러다 보니.. 이 스킨도 그런면에서는 약간 부족한듯 느껴지기도 합니다.ㅠㅠ(이 글이 예약글로 작성된 후에 스킨을 지금의 것으로 바꾸었습니다. 이제는 괜찮다는^^). 일단 그러나 단편적 글들이지고 그냥 허접한 예제이지만... 글 속에서 제가 최대한 링크를 넣을려고 하기 때문에 흐름을 잃지는 않도록 적고 있습니다.ㅠㅠ. 일단... 최근 저는 Python의 Matplotlib의 widget중에서 slideer와 button, radiobuttons의 예제를 다루었었는데요.[바로가기] 그 예제를 이용해서 예전에 다른 Craig의 로보틱스 책의 예제중 하나[바로가기]에 적용해 볼까합니다.

# Introduction to Robotics 3rd Edition by Craig
# Example 2-1.
# Figure 2.6 shows a frame {B} that is rotated relative to frame {A} about Z by 30 degrees.

import matplotlib.pyplot as plt
import drawRobotics as dR
import numpy as np
from matplotlib.widgets import Slider

axcolor = 'lightgoldenrodyellow'
initAngle = 30

P_atB = np.array([0,2,0])

AORG = np.array([0,0,0])
hat_X_atA = np.array([1,0,0])
hat_Y_atA = np.array([0,1,0])
hat_Z_atA = np.array([0,0,1])

def calcBCoordi(rotAngle, ORG, hat_X, hat_Y, hat_Z):
	Rot_AtoB = dR.RotZ(dR.conv2Rad(rotAngle))
	
	P_atA = np.dot(Rot_AtoB, P_atB)
	
	BORG = np.dot(Rot_AtoB, AORG)
	hat_X_atB = np.dot(Rot_AtoB, hat_X)
	hat_Y_atB = np.dot(Rot_AtoB, hat_Y)
	hat_Z_atB = np.dot(Rot_AtoB, hat_Z)

	return BORG, hat_X_atB, hat_Y_atB, hat_Z_atB, P_atA

BORG, hat_X_atB, hat_Y_atB, hat_Z_atB, P_atA = calcBCoordi(initAngle, AORG, hat_X_atA, hat_Y_atA, hat_Z_atA)

fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
plt.subplots_adjust(bottom=0.25)

axAngle = plt.axes([0.125, 0.15, 0.77, 0.03], axisbg=axcolor)
sAngle = Slider(axAngle, 'Angle', -90.0, 90.0, valinit=initAngle)

dR.drawPointWithAxis(ax, AORG, hat_X_atA, hat_Y_atA, hat_Z_atA, pointEnable=False)
dR.drawPointWithAxis(ax, BORG, hat_X_atB, hat_Y_atB, hat_Z_atB, pointEnable=False, lineStyle='--')
dR.drawVector(ax, AORG, P_atA, arrowstyle='-|>', annotationString=' $ ^{A}P $ ')

def update(val):
	updateAngle = sAngle.val

	BORG, hat_X_atB, hat_Y_atB, hat_Z_atB, P_atA = calcBCoordi(updateAngle, AORG, hat_X_atA, hat_Y_atA, hat_Z_atA)

	ax.cla()
	dR.drawPointWithAxis(ax, AORG, hat_X_atA, hat_Y_atA, hat_Z_atA, pointEnable=False)
	dR.drawPointWithAxis(ax, BORG, hat_X_atB, hat_Y_atB, hat_Z_atB, pointEnable=False, lineStyle='--')
	dR.drawVector(ax, AORG, P_atA, arrowstyle='-|>', annotationString=' $ ^{A}P $ ')

	ax.set_xlim([-2,2]), ax.set_ylim([-1,2]), ax.set_zlim([-2,2])

sAngle.on_changed(update)

ax.set_xlim([-2,2]), ax.set_ylim([-1,2]), ax.set_zlim([-2,2])
ax.set_xlabel('X axis'), ax.set_ylabel('Y axis'), ax.set_zlabel('Z axis')
ax.view_init(azim=-90, elev=90)
plt.show()

Slider 예제에서 다루었듯이... axAngle과 sAngle이라는 변수로 각각 슬라이더가 위치할 위치와 Slider 속성을 잡았습니다. 그리고 update 함수에서 슬라이더에서 읽은 각도를 반영해서 다시 계산하고 이를 그리도록 한 것이죠. 다시 그리는 방법을 고민하다가.. 축을 지워주는 ax.cla() 명령으로 그리기 전에 해당 그림을 모조리 지우고 다시 그리는 것으로 했습니다. 흠...ㅠㅠ. 일단 이렇게 하니 동작은 하는데요... ㅠㅠ. 지나가는 Python 고수님이 있으시다면.. 코드의 작성방향이나 허접한 부분에 대해 조언을 부탁드립니다. 약간 뭔가 안 깔끔한 뭔가가 있는데 손대지를 못하네요.ㅠㅠ. 아 그리고, drawRobotics 모듈은 제가 만든 것으로 [바로가기]에서 이야기했었습니다.

처음 실행한 화면이구요...

슬라이더 바를 이용해서 값을 변경한 후 그림입니다.

일단.. 로보틱스를 학습하면서 필요한 부분들은 그림으로 이해하기 위해서라는 목적에는 부합됩니다.^^. Python 스럽게 잘 짜여진 예제냐는 질문에는 아직 슬프지만요^^


반응형