Python: Animating a vector using mplot3d and animation - python

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!

Since your problem is with the animation part, below you can see a snippet that animate an arrow that is rotating.
import numpy as np
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
import matplotlib.animation as animation
def data_gen(num):
"""Data generation"""
angle = num * np.pi/36
vx, vy, vz = np.cos(angle), np.sin(angle), 1
ax.cla()
ax.quiver(0, 0, 0, vx, vy, vz, pivot="tail", color="black")
ax.quiver(0, 0, 0, vx, vy, 0, pivot="tail", color="black",
linestyle="dashed")
ax.set_xlim(-1, 1)
ax.set_ylim(-1, 1)
ax.set_zlim(-1, 1)
ax.view_init(elev=30, azim=60)
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
data_gen(0)
ani = animation.FuncAnimation(fig, data_gen, range(72), blit=False)
plt.show()
The documentation on animations might not be the best. But there are several examples out there, for example, this one animates the Lorenz attractor.

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.

Related

Python qt5 matplotlb canvas animation with manual blit

So I'd like to integrate a matplotlib canvas in qt5 with manual blit.
I've found this thread:
Fast Live Plotting in Matplotlib / PyPlot
and the voted answer seems pretty nice however I need it in a qt5 window...
So I have tried to mash the code above together with the matplotlib qt5 tutorial into one script. https://matplotlib.org/gallery/user_interfaces/embedding_in_qt5_sgskip.html
It kinda works, however the animation only works when using the pan/zoom and the background is black :D and if blit is set to false it doesnt even draw...
If somebody could help me that would be amazing :) Its hilariously broken
from __future__ import unicode_literals
import random
import time
import matplotlib
from PyQt5.QtWidgets import QSizePolicy, QApplication, QWidget, QVBoxLayout
from matplotlib import pyplot as plt
import sys
import matplotlib
matplotlib.use('Qt5Agg')
from matplotlib.animation import FuncAnimation
from matplotlib.backends.backend_qt5agg import NavigationToolbar2QT as NavigationToolbar
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
import numpy as np
class MyMplCanvas(FigureCanvas):
# Ultimately, this is a QWidget (as well as a FigureCanvasAgg, etc.).
def __init__(self, parent=None, width=5, height=4, dpi=100):
self.fig = plt.figure()
FigureCanvas.__init__(self, self.fig)
self.setParent(parent)
FigureCanvas.setSizePolicy(self,
QSizePolicy.Expanding,
QSizePolicy.Expanding)
FigureCanvas.updateGeometry(self)
self.x = np.linspace(0, 50., num=100)
self.X, self.Y = np.meshgrid(self.x, self.x)
# self.fig = plt.figure()
self.ax1 = self.fig.add_subplot(2, 1, 1)
self.ax2 = self.fig.add_subplot(2, 1, 2)
self.img = self.ax1.imshow(self.X, vmin=-1, vmax=1, interpolation="None", cmap="RdBu")
self.line, = self.ax2.plot([], lw=3)
self.text = self.ax2.text(0.8, 0.5, "")
self.ax2.set_xlim(self.x.min(), self.x.max())
self.ax2.set_ylim([-1.1, 1.1])
self.t_start = time.time()
self.k = 0.
#self.fig.canvas.draw() # note that the first draw comes before setting data
#self.update(blit=False)
anim = FuncAnimation(self.fig, self.update, interval=20)
def update(self, blit=True):
if blit:
# cache the background
self.axbackground = self.fig.canvas.copy_from_bbox(self.ax1.bbox)
self.ax2background = self.fig.canvas.copy_from_bbox(self.ax2.bbox)
self.img.set_data(np.sin(self.X / 3. + self.k) * np.cos(self.Y / 3. + self.k))
self.line.set_data(self.x, np.sin(self.x / 3. + self.k))
self.k += 0.11
if blit:
# restore background
self.fig.canvas.restore_region(self.axbackground)
self.fig.canvas.restore_region(self.ax2background)
# redraw just the points
self.ax1.draw_artist(self.img)
self.ax2.draw_artist(self.line)
self.ax2.draw_artist(self.text)
# fill in the axes rectangle
self.fig.canvas.blit(self.ax1.bbox)
self.fig.canvas.blit(self.ax2.bbox)
# in this post http://bastibe.de/2013-05-30-speeding-up-matplotlib.html
# it is mentionned that blit causes strong memory leakage.
# however, I did not observe that.
else:
# redraw everything
self.fig.canvas.draw()
# self.fig.canvas.flush_events()
# alternatively you could use
# plt.pause(0.000000000001)
# however plt.pause calls canvas.draw(), as can be read here:
# http://bastibe.de/2013-05-30-speeding-up-matplotlib.html
class PlotDialog(QWidget):
def __init__(self):
QWidget.__init__(self)
self.plot_layout = QVBoxLayout(self)
self.plot_canvas = MyMplCanvas(self, width=5, height=4, dpi=100)
self.navi_toolbar = NavigationToolbar(self.plot_canvas, self)
self.plot_layout.addWidget(self.plot_canvas)
self.plot_layout.addWidget(self.navi_toolbar)
if __name__ == "__main__":
app = QApplication(sys.argv)
dialog0 = PlotDialog()
dialog0.show()
sys.exit(app.exec_())

How to effectively redraw multiple matplotlib plots with blit

I'm using matplotlib with pyqt5 to draw data into 3 axes, and than user can make selection in one plot that will be shown in other two plots too. Since I'm working with big data (up to 10 millions of points), drawing selection could be slow, especially when I need to draw to scatterplot.
I am trying to use matplotlib blit function, but have some issues with result. Here is minimum simple example.
import matplotlib
matplotlib.use('Qt5Agg')
import numpy as np
import sys
from matplotlib.backends.qt_compat import QtCore, QtWidgets
from matplotlib.backends.backend_qt5agg import (FigureCanvas, NavigationToolbar2QT as NavigationToolbar)
from matplotlib.figure import Figure
class ApplicationWindow(QtWidgets.QMainWindow):
def __init__(self):
super().__init__()
self._main = QtWidgets.QWidget()
self.setCentralWidget(self._main)
layout = QtWidgets.QVBoxLayout(self._main)
self.static_canvas = FigureCanvas(Figure(figsize=(10, 10)))
layout.addWidget(self.static_canvas)
layout.addWidget(NavigationToolbar(self.static_canvas, self))
axes = self.static_canvas.figure.subplots(2, 1)
self.ax1 = axes[0]
self.ax2 = axes[1]
self.ax1.cla()
self.ax2.cla()
button = QtWidgets.QPushButton('Click me!')
button.clicked.connect(self.update_canvas_blit)
layout.addWidget(button)
# Fixing random state for reproducibility
np.random.seed(19680801)
# Create random data
N = 50000
x = np.random.rand(N)
y = np.random.rand(N)
self.ax1.scatter(x, y)
self.points = self.ax1.scatter([],[], s=5, color='red')
x = np.linspace(0, 1000, 100000)
self.ax2.plot(x, np.sin(x))
self.lines, = self.ax2.plot([],[], color='red')
self.static_canvas.draw()
self.background1 = self.static_canvas.copy_from_bbox(self.ax1.bbox)
self.background2 = self.static_canvas.copy_from_bbox(self.ax2.bbox)
def update_canvas_blit(self):
N = 50
x = np.random.rand(N)
y = np.random.rand(N)
self.static_canvas.restore_region(self.background1)
self.points.set_offsets(np.c_[x,y])
self.ax1.draw_artist(self.points)
self.ax1.figure.canvas.blit(self.ax1.bbox)
self.static_canvas.restore_region(self.background2)
x = np.linspace(0, np.random.randint(500,1000), 1000)
self.lines.set_data(x, np.sin(x))
self.ax2.draw_artist(self.lines)
self.ax2.figure.canvas.blit(self.ax2.bbox)
if __name__ == "__main__":
qapp = QtWidgets.QApplication(sys.argv)
app = ApplicationWindow()
app.show()
qapp.exec_()
When clicking button, expected output should be still same background with random points/lines redrawing. In a way it is happening but there are some strange artifacts that looks like somehow axes are drawn to each other. But when I try to save it to .png, it will restore to good state.
The problem is that the snapshot of the background is taken at a moment in time where the figure has not yet been shown on screen. At that point the figure is 10 by 10 inches large. Later, it is shown inside the QMainWindow and resized to fit into the widget.
Only once that has happened, it makes sense to take the background snapshot.
One option is to use a timer of 1 second and only then copy the background. This would look as follows.
import numpy as np
import sys
from matplotlib.backends.qt_compat import QtCore, QtWidgets
from matplotlib.backends.backend_qt5agg import (FigureCanvas, NavigationToolbar2QT as NavigationToolbar)
from matplotlib.figure import Figure
class ApplicationWindow(QtWidgets.QMainWindow):
def __init__(self):
super().__init__()
self._main = QtWidgets.QWidget()
self.setCentralWidget(self._main)
layout = QtWidgets.QVBoxLayout(self._main)
self.static_canvas = FigureCanvas(Figure(figsize=(10, 10)))
layout.addWidget(self.static_canvas)
layout.addWidget(NavigationToolbar(self.static_canvas, self))
axes = self.static_canvas.figure.subplots(2, 1)
self.ax1 = axes[0]
self.ax2 = axes[1]
self.ax1.cla()
self.ax2.cla()
button = QtWidgets.QPushButton('Click me!')
button.clicked.connect(self.update_canvas_blit)
layout.addWidget(button)
# Fixing random state for reproducibility
np.random.seed(19680801)
# Create random data
N = 50000
x = np.random.rand(N)
y = np.random.rand(N)
self.ax1.scatter(x, y)
self.points = self.ax1.scatter([],[], s=5, color='red')
x = np.linspace(0, 1000, 100000)
self.ax2.plot(x, np.sin(x))
self.lines, = self.ax2.plot([],[], color='red')
self.static_canvas.draw()
self._later()
def _later(self, evt=None):
self.timer = self.static_canvas.new_timer(interval=1000)
self.timer.single_shot = True
self.timer.add_callback(self.update_background)
self.timer.start()
def update_background(self, evt=None):
self.background1 = self.static_canvas.copy_from_bbox(self.ax1.bbox)
self.background2 = self.static_canvas.copy_from_bbox(self.ax2.bbox)
def update_canvas_blit(self):
N = 50
x = np.random.rand(N)
y = np.random.rand(N)
self.static_canvas.restore_region(self.background1)
self.points.set_offsets(np.c_[x,y])
self.ax1.draw_artist(self.points)
self.ax1.figure.canvas.blit(self.ax1.bbox)
self.static_canvas.restore_region(self.background2)
x = np.linspace(0, np.random.randint(500,1000), 1000)
self.lines.set_data(x, np.sin(x))
self.ax2.draw_artist(self.lines)
self.ax2.figure.canvas.blit(self.ax2.bbox)
if __name__ == "__main__":
qapp = QtWidgets.QApplication(sys.argv)
app = ApplicationWindow()
app.show()
qapp.exec_()

PyQt5 with NavigationToolbar2QT missing change of color option for plt.fill_between()

how can I change the color of a plt.fill_between() in the according navigation toolbar? so basically add one more selection for the fill between curves additional to _line0 (see picture). alternatively, it would also be possible to change the error of fill_between according to the color of the line.
I tried the fill_between with facecolor=pl[0].get_color() but it did not change dynamically with a different color selection in the toolbar.
from PyQt5 import QtWidgets
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
from matplotlib.backends.backend_qt5agg import NavigationToolbar2QT as NavigationToolbar
import matplotlib.pyplot as plt
import sys
import pandas as pd
import numpy as np
from scipy import stats
class Example(QtWidgets.QWidget):
def __init__(self):
super().__init__()
self.initUI()
self.draw()
def initUI(self):
self.canvasFigure = plt.figure(1)
self.canvasWidget = FigureCanvas(self.canvasFigure)
self.toolbar = NavigationToolbar(self.canvasWidget, self)
lay = QtWidgets.QVBoxLayout(self)
lay.addWidget(self.canvasWidget)
lay.addWidget(self.toolbar)
self.resize(500, 400)
def draw(self):
### generate random data
df = pd.DataFrame(np.random.randint(0, 100, size=(100, 4)), columns=list('ABCD'))
df_group_error = stats.sem(df, axis=1, nan_policy='omit')
df_group = df.mean(axis=1)
### show in canvas
self.canvasFigure.clear()
fig = plt.figure(1)
pl = plt.plot(df_group)
plt.fill_between(df_group.index.tolist(), df_group - df_group_error, df_group + df_group_error, facecolor='red', alpha=0.2)
self.canvasWidget.draw()
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
ex = Example()
ex.show()
sys.exit(app.exec_())
where change of fill_between color should be possible
You can write a callback that, whenever the figure is drawn, matches the color of the fill with the color of the line.
import matplotlib
matplotlib.use("Qt5Agg")
import numpy as np; np.random.seed(42)
from matplotlib.colors import to_hex
import matplotlib.pyplot as plt
x = np.linspace(0,100)
y = np.cumsum(np.random.randn(len(x)))+4
err = np.random.rand(len(x))*0.5 + 1
fig, ax = plt.subplots()
fillb = ax.fill_between(x, y+err, y-err, alpha=0.4, facecolor="red", edgecolor="none")
line, = ax.plot(x,y, color="blue")
def update(evnt=None):
c1 = line.get_color()
c2 = fillb.get_facecolor().ravel()
if to_hex(c1) != to_hex(c2):
fillb.set_facecolor(line.get_color())
fig.canvas.draw_idle()
cid = fig.canvas.mpl_connect("draw_event", update)
update()
plt.show()

Dynamically update multiple axis in matplotlib

I want to display sensor data on a PyQT GUI with a matplotlib animation.
I already have a working Plot which gets updates every time I receive new sensor value from an external source with this code:
def __init__(self):
self.fig = Figure(figsize=(width, height), dpi=dpi)
self.axes = self.fig.add_subplot(111)
self.axes.grid()
self.xdata = []
self.ydata = []
self.entry_limit = 50
self.line, = self.axes.plot([0], [0], 'r')
def update_figure_with_new_value(self, xval: float, yval: float):
self.xdata.append(xval)
self.ydata.append(yval)
if len(self.xdata) > self.entry_limit:
self.xdata.pop(0)
self.ydata.pop(0)
self.line.set_data(self.xdata, self.ydata)
self.axes.relim()
self.axes.autoscale_view()
self.fig.canvas.draw()
self.fig.canvas.flush_events()
I want now to extend the plot to show another data series with the same x-axis. I tried to achieve this with the following additions to the init-code above:
self.axes2 = self.axes.twinx()
self.y2data = []
self.line2, = self.axes2.plot([0], [0], 'b')
and in the update_figure_with_new_value() function (for test purpose I just tried to add 1 to yval, I will extend the params of the function later):
self.y2data.append(yval+1)
if len(self.y2data) > self.entry_limit:
self.y2data.pop(0)
self.line2.set_data(self.xdata, self.ydata)
self.axes2.relim()
self.axes2.autoscale_view()
But instead of getting two lines in the plot which should have the exact same movement but just shifted by one I get vertical lines for the second plot axis (blue). The first axis (red) remains unchanged and is ok.
How can I use matplotlib to update multiple axis so that they display the right values?
I'm using python 3.4.0 with matplotlib 2.0.0.
Since there is no minimal example available, it's hard to tell the reason for this undesired behaviour. In principle ax.relim() and ax.autoscale_view() should do what you need.
So here is a complete example which works fine and updates both scales when being run with python 2.7, matplotlib 2.0 and PyQt4:
import numpy as np
import matplotlib.pyplot as plt
from PyQt4 import QtGui, QtCore
from matplotlib.figure import Figure
from matplotlib.backends.backend_qt4agg import FigureCanvasQTAgg as FigureCanvas
from matplotlib.backends.backend_qt4agg import NavigationToolbar2QT as NavigationToolbar
class Window(QtGui.QMainWindow):
def __init__(self):
QtGui.QMainWindow.__init__(self)
self.widget = QtGui.QWidget()
self.setCentralWidget(self.widget)
self.widget.setLayout(QtGui.QVBoxLayout())
self.widget.layout().setContentsMargins(0,0,0,0)
self.widget.layout().setSpacing(0)
self.fig = Figure(figsize=(5,4), dpi=100)
self.axes = self.fig.add_subplot(111)
self.axes.grid()
self.xdata = [0]
self.ydata = [0]
self.entry_limit = 50
self.line, = self.axes.plot([], [], 'r', lw=3)
self.axes2 = self.axes.twinx()
self.y2data = [0]
self.line2, = self.axes2.plot([], [], 'b')
self.canvas = FigureCanvas(self.fig)
self.canvas.draw()
self.nav = NavigationToolbar(self.canvas, self.widget)
self.widget.layout().addWidget(self.nav)
self.widget.layout().addWidget(self.canvas)
self.show()
self.ctimer = QtCore.QTimer()
self.ctimer.timeout.connect(self.update)
self.ctimer.start(150)
def update(self):
y = np.random.rand(1)
self.update_figure_with_new_value(self.xdata[-1]+1,y)
def update_figure_with_new_value(self, xval,yval):
self.xdata.append(xval)
self.ydata.append(yval)
if len(self.xdata) > self.entry_limit:
self.xdata.pop(0)
self.ydata.pop(0)
self.y2data.pop(0)
self.line.set_data(self.xdata, self.ydata)
self.axes.relim()
self.axes.autoscale_view()
self.y2data.append(yval+np.random.rand(1)*0.17)
self.line2.set_data(self.xdata, self.y2data)
self.axes2.relim()
self.axes2.autoscale_view()
self.fig.canvas.draw()
self.fig.canvas.flush_events()
if __name__ == "__main__":
qapp = QtGui.QApplication([])
a = Window()
exit(qapp.exec_())
You may want to test this and report back if it is working or not.

make a button for animation in matplotlib

I just made a simple gui using Qt Designer, the gui has 4 buttons and a widget. The widget will show the animation and the buttons are for pause animation,resume, clean the canvas and start animation. I made this code:
import sys
from PyQt4 import QtGui, uic
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation
from matplotlib.backends.backend_qt4agg import FigureCanvasQTAgg as FigureCanvas
def start():
def datos(t=0):
while True:
t += 0.1
yield t, np.cos(t)
def init():
ax.set_ylim(-1, 1)
ax.set_xlim(0, 5)
def run(data):
t,y = data
xdata.append(t)
ydata.append(y)
line.set_data(xdata, ydata)
xmin,xmax =ax.get_xlim()
if t > xmax:
ax.set_xlim(xmin, 1.5*xmax)
ax.figure.canvas.draw()
ani = animation.FuncAnimation(fig, run, datos, blit=False, interval=50,
repeat=False, init_func=init)
def stop():
ani.event_source.stop()
def borr():
plt.clf()
canvas.draw()
def anim():
ani.event_source.start()
window.resume.clicked.connect(anim)
window.pause.clicked.connect(stop)
window.clean.clicked.connect(borr)
return ani
layout=QtGui.QVBoxLayout()
fig=plt.figure()
canvas=FigureCanvas(fig)
layout.addWidget(canvas)
ax = fig.add_subplot(111)
line,=ax.plot([],[],lw=2)
ax.grid()
xdata, ydata = [], []
app = QtGui.QApplication(sys.argv)
window = uic.loadUi("animacion.ui")
window.start.clicked.connect(start)
window.widget.setLayout(layout)
window.show()
sys.exit(app.exec_())
this shows the grid, but when I press the start button it doesnt show the animation
I also made this code:
import sys
from PyQt4 import QtCore, QtGui, uic
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation
from matplotlib.backends.backend_qt4agg import FigureCanvasQTAgg as FigureCanvas
def datos(t=0):
while True:
t += 0.1
yield t, np.cos(t)
def init():
ax.set_ylim(-1, 1)
ax.set_xlim(0, 5)
def run(data):
t,y = data
xdata.append(t)
ydata.append(y)
line.set_data(xdata, ydata)
xmin,xmax =ax.get_xlim()
if t > xmax:
ax.set_xlim(xmin, 1.5*xmax)
ax.figure.canvas.draw()
def start():
window.widget.setLayout(layout)
def stop():
ani.event_source.stop()
def borr():
plt.clf()
canvas.draw()
def anim():
ani.event_source.start()
layout=QtGui.QVBoxLayout()
fig=plt.figure('test')
canvas=FigureCanvas(fig)
layout.addWidget(canvas)
ax = fig.add_subplot(111)
line,=ax.plot([],[],lw=2)
ax.grid()
xdata, ydata = [], []
app = QtGui.QApplication(sys.argv)
window = uic.loadUi("animacion.ui")
window.resume.clicked.connect(anim)
window.pause.clicked.connect(stop)
window.clean.clicked.connect(borr)
window.start.clicked.connect(start)
ani = animation.FuncAnimation(fig, run, datos, blit=False, interval=50,
repeat=False, init_func=init)
window.show()
sys.exit(app.exec_())
In this case, when I press start the animation begins, I can pause and resume. But when a clean the canvas an press start again it doesnt show the function.
How can I make it works?
thanks!
Try to provide minimal working examples. Without animacion.ui we cannot run you code.
Refering to the second code: The problem here seems to be that inside borr() you clear the figure (plt.clf()). If the figure is cleared, where should the animation be drawn to?
I solved the problem making a function with the animation
import sys
from PyQt4 import QtGui, uic
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation
from matplotlib.backends.backend_qt4agg import FigureCanvasQTAgg as FigureCanvas
def start():
def datos(t=0):
while True:
t += 0.1
yield t, np.cos(t)
def init():
ax.set_ylim(-1, 1)
ax.set_xlim(0, 5)
def run(data):
t,y = data
xdata.append(t)
ydata.append(y)
line.set_data(xdata, ydata)
xmin,xmax =ax.get_xlim()
if t > xmax:
ax.set_xlim(xmin, 1.5*xmax)
ax.figure.canvas.draw()
def stop():
ani.event_source.stop()
def borr():
plt.clf()
canvas.draw()
def anim():
ani.event_source.start()
window.resume.clicked.connect(anim)
window.pause.clicked.connect(stop)
window.clean.clicked.connect(borr)
ax = fig.add_subplot(111)
line,=ax.plot([],[],lw=2)
ax.grid()
xdata, ydata = [], []
ani = animation.FuncAnimation(fig, run, datos, blit=False, interval=50,
repeat=False, init_func=init)
canvas.draw()
layout=QtGui.QVBoxLayout()
fig=plt.figure()
canvas=FigureCanvas(fig)
layout.addWidget(canvas)
app = QtGui.QApplication(sys.argv)
window = uic.loadUi("animacion.ui")
window.start.clicked.connect(start)
window.widget.setLayout(layout)
window.show()
sys.exit(app.exec_())

Categories

Resources