Issue
I'm trying to make a 3d plot with Matplotlib and the animation package from matplotlib. In addition, the animation should be a part of a Gui generated using PyQt and Qt-Designer. Currently I'm stuck on using the "animation.Funcnimation()" correctly, at least i think so... So here is my code:
import sys
from PyQt4.uic import loadUiType
from PyQt4 import QtGui
from matplotlib import pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
from matplotlib.backends.backend_qt4agg import FigureCanvasQTAgg as FigureCanvas
from matplotlib import animation
import numpy as np
import Quaternion as qt
Ui_MainWindow, QMainWindow = loadUiType('Newsphere.ui')
class Kinematic(Ui_MainWindow, QMainWindow):
def __init__(self):
super(Kinematic, self).__init__()
self.setupUi(self)
self.fig = plt.figure()
self.ax = self.fig.add_subplot(111,projection = '3d')
self.fig.tight_layout()
self.ani = animation.FuncAnimation(self.fig, self.update,
init_func=self.setup_plot, blit=True)
self.canvas = FigureCanvas(self.fig)
self.mplvl.addWidget(self.canvas)
self.canvas.draw()
def setup_plot(self):
self.ax.view_init(40, 45)
self.ax.set_xlabel('X')
self.ax.set_ylabel('Y')
self.ax.set_zlabel('Z')
self.ax.set_xlim3d(-1,1)
self.ax.set_ylim3d(-1,1)
self.ax.set_zlim3d(-1,1)
g_x = np.matrix([[1.0],[0.0],[0.0]])
g_y = np.matrix([[0.0],[1.0],[0.0]])
g_z = np.matrix([[0.0],[0.0],[1.0]])
self.ax.plot([0,g_x[0]], [0,g_x[1]], [0,g_x[2]], label='$X_0$')
self.ax.plot([0,g_y[0]], [0,g_y[1]], [0,g_y[2]], label='$Y_0$')
self.ax.plot([0,g_z[0]], [0,g_z[1]], [0,g_z[2]], label='$Z_0$')
self.vek, = self.ax.plot([0,-1], [0,0], [0,0], label='$g \cdot R$', animated=True)
self.ax.legend(loc='best')
self.ax.scatter(0,0,0, color='k')
return self.vek,
def update(self, i):
b = self.bslider.value() / 100
g = np.matrix([[1.0],[0.0],[0.0]])
q = np.array([0,b,0.5,0])
R = qt.QtoR(q)
x, y, z = R*g
self.vek, = self.ax.plot([0,x], [0,y], [0,z], label='$g \cdot R$', animated=True) #the rotated vector
return self.vek,
if __name__ == '__main__':
app = QtGui.QApplication(sys.argv)
main = Kinematic()
main.show()
sys.exit(app.exec_())
You won't be able to run it by just copy-paste because you don't have the file "Newsphere.ui" (Line 13) and the Quaternion.py (Line 11). So when I run it, I get the following (actually like I wish!): Coordinate system
My goal is now to draw a vector (Line 50) and animate it (Line 66) using data which I get from the Gui-slider (Line 58). Can anyone help me with this? I'm stuck with this for days!
Solution
So if someone is interested in a solution of the mentioned problem, here we go: (again it is not a code for copy-paste because of the missing 'Newsphere.ui', but I try to explain the important snippets)
import sys
from PyQt4.uic import loadUiType
from PyQt4 import QtGui
from matplotlib import pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
from matplotlib.backends.backend_qt4agg import FigureCanvasQTAgg as FigureCanvas
from matplotlib import animation
import numpy as np
Ui_MainWindow, QMainWindow = loadUiType('Newsphere.ui')
class Kinematic(Ui_MainWindow, QMainWindow):
def __init__(self):
super(Kinematic, self).__init__()
self.setupUi(self)
self.fig = plt.figure()
self.ax = self.fig.add_subplot(111,projection = '3d')
self.fig.tight_layout()
self.ax.view_init(40, -45)
# dashed coordinate system
self.ax.plot([0,1], [0,0], [0,0], label='$X_0$', linestyle="dashed")
self.ax.plot([0,0], [0,-1], [0,0], label='$Y_0$', linestyle="dashed")
self.ax.plot([0,0], [0,0], [0,1], label='$Z_0$', linestyle="dashed")
self.ax.set_xlim3d(-1,1)
self.ax.set_ylim3d(-1,1)
self.ax.set_zlim3d(-1,1)
self.ax.set_xlabel('X')
self.ax.set_ylabel('Y')
self.ax.set_zlabel('Z')
self.ax.scatter(0,0,0, color='k') # black origin dot
self.canvas = FigureCanvas(self.fig)
self.mplvl.addWidget(self.canvas)
self.ani = animation.FuncAnimation(self.fig, self.data_gen, init_func=self.setup_plot, blit=True)
def setup_plot(self):
self.ax.legend(loc='best')
self.vek = self.ax.quiver(0, 0, 0, 0, 0, 0, label='$g \cdot R$', pivot="tail", color="black")
return self.vek,
def data_gen(self, i):
b = self.bslider.value() / 100
vx, vy, vz = np.cos(b), np.sin(b), 0
self.vek = self.ax.quiver(0, 0, 0, vx, vy, vz, label='$g \cdot R$', pivot="tail", color="black")
self.canvas.draw()
return self.vek,
if __name__ == '__main__':
app = QtGui.QApplication(sys.argv)
main = Kinematic()
main.show()
sys.exit(app.exec_())
By running the code I get
(These are two pictures combined in one showing the same process)
I generated a GUI file named Newsphere.ui
following this tutorial. Basically it contains just a Widget, a QSlider and a QSpinBox. The Widget has the layout-name "mplvl", which occures in line 41. This adds the generated figure to the widget (I think so...). The QSlider is connected with the QSpinBox (done in QtDesigner) and has the name "bslider", line 55. So in this line the slider-value gets divided by 100 because I didn't found a slider that generates me a float-value. The key-line for me was line 61, where the canvas is drawn. Now the animation.FuncAnimation
(line 43) draws a new vector when I change the slider value, compare the pics. Also it is important to draw the changing vector as a ax.quiver
and not as a ax.plot
like in my previous attempt.
If there are questions or suggestions for improvement please ask/post.
Answered By - Michael
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.