python - Matplotlib animation inside your own PyQt4 GUI -
i'm writing software in python. need embed matplotlib time-animation self-made gui. here more details them:
1. gui
the gui written in python well, using pyqt4 library. gui not different common guis can find on net. subclass qtgui.qmainwindow , add buttons, layout, ...
2. animation
the matplotlib animation based on animation.timedanimation class. here code animation:
import numpy np import matplotlib.pyplot plt matplotlib.lines import line2d import matplotlib.animation animation class customgraph(animation.timedanimation): def __init__(self): self.n = np.linspace(0, 1000, 1001) self.y = 1.5 + np.sin(self.n/20) #self.y = np.zeros(self.n.size) # window self.fig = plt.figure() ax1 = self.fig.add_subplot(1, 2, 1) self.mngr = plt.get_current_fig_manager() self.mngr.window.setgeometry(50,100,2000, 800) # ax1 settings ax1.set_xlabel('time') ax1.set_ylabel('raw data') self.line1 = line2d([], [], color='blue') ax1.add_line(self.line1) ax1.set_xlim(0, 1000) ax1.set_ylim(0, 4) animation.timedanimation.__init__(self, self.fig, interval=20, blit=true) def _draw_frame(self, framedata): = framedata print(i) self.line1.set_data(self.n[ 0 : ], self.y[ 0 : ]) self._drawn_artists = [self.line1] def new_frame_seq(self): return iter(range(self.n.size)) def _init_draw(self): lines = [self.line1] l in lines: l.set_data([], []) def showmyanimation(self): plt.show() ''' end class ''' if __name__== '__main__': print("define mygraph") mygraph = customgraph() mygraph.showmyanimation()
this code produces simple animation:
the animation works fine. run code, animation pops in small window , starts running. how embed animation in own self-made gui?
3. embedding animation in self-made gui
i have done research find out. here things tried. have added following code python file. note added code class definition:
from pyqt4 import qtgui pyqt4 import qtcore matplotlib.backends.backend_qt4agg import figurecanvasqtagg figurecanvas class customfigcanvas(figurecanvas): def __init__(self): self.mygraph = customgraph() figurecanvas.__init__(self, self.mygraph.fig)
what try here embedding customgraph() object - animation - figurecanvas.
i wrote gui in python file (but still in same folder). can add widgets gui. believe object class customfigcanvas(..) widget through inheritance. try in gui:
.. myfigcanvas = customfigcanvas() self.mylayout.addwidget(myfigcanvas) ..
it works extent. indeed figure displayed in gui. figure empty. animation doesn't run:
and there strange phenomenon going on. gui displays empty figure, simultaneously regular matplotlib popup window animation figure in it. animation not running.
there i'm missing here. please me figure out problem. appreciate help.
i think found solution. credit goes mr. harrison made python tutorial website https://pythonprogramming.net. helped me out.
so here did. 2 major changes:
1. structural change
i had 2 classes: customgraph(timedanimation) , customfigcanvas(figurecanvas). got 1 left, inherits both timedanimation , figurecanvas: customfigcanvas(timedanimation, figurecanvas)
2. change in making figure object
this how made figure previously:
self.fig = plt.figure()
with 'plt' coming import statement 'import matplotlib.pyplot plt'
. way of making figure apparently causes troubles when want embed own gui. there better way it:
self.fig = figure(figsize=(5,5), dpi=100)
and works!
here complete code:
import numpy np matplotlib.figure import figure matplotlib.animation import timedanimation matplotlib.lines import line2d matplotlib.backends.backend_qt4agg import figurecanvasqtagg figurecanvas class customfigcanvas(figurecanvas, timedanimation): def __init__(self): # data self.n = np.linspace(0, 1000, 1001) self.y = 1.5 + np.sin(self.n/20) # window self.fig = figure(figsize=(5,5), dpi=100) ax1 = self.fig.add_subplot(111) # ax1 settings ax1.set_xlabel('time') ax1.set_ylabel('raw data') self.line1 = line2d([], [], color='blue') ax1.add_line(self.line1) ax1.set_xlim(0, 1000) ax1.set_ylim(0, 4) figurecanvas.__init__(self, self.fig) timedanimation.__init__(self, self.fig, interval = 20, blit = true) def _draw_frame(self, framedata): = framedata print(i) self.line1.set_data(self.n[ 0 : ], self.y[ 0 : ]) self._drawn_artists = [self.line1] def new_frame_seq(self): return iter(range(self.n.size)) def _init_draw(self): lines = [self.line1] l in lines: l.set_data([], []) ''' end class '''
that's code make animation in matplotlib. can embed own qt gui:
.. myfigcanvas = customfigcanvas() self.mylayout.addwidget(myfigcanvas) ..
it seems work pretty fine. thank mr. harrison!
edit :
came question after many months. here complete code. copy-paste fresh .py
file, , run it:
################################################################### # # # plotting live graph # # ---------------------------- # # embed matplotlib animation inside # # own gui! # # # ################################################################### import sys import os pyqt4 import qtgui pyqt4 import qtcore import functools import numpy np import random rd import matplotlib matplotlib.use("qt4agg") matplotlib.figure import figure matplotlib.animation import timedanimation matplotlib.lines import line2d matplotlib.backends.backend_qt4agg import figurecanvasqtagg figurecanvas import time import threading def setcustomsize(x, width, height): sizepolicy = qtgui.qsizepolicy(qtgui.qsizepolicy.fixed, qtgui.qsizepolicy.fixed) sizepolicy.sethorizontalstretch(0) sizepolicy.setverticalstretch(0) sizepolicy.setheightforwidth(x.sizepolicy().hasheightforwidth()) x.setsizepolicy(sizepolicy) x.setminimumsize(qtcore.qsize(width, height)) x.setmaximumsize(qtcore.qsize(width, height)) '''''' class custommainwindow(qtgui.qmainwindow): def __init__(self): super(custommainwindow, self).__init__() # define geometry of main window self.setgeometry(300, 300, 800, 400) self.setwindowtitle("my first window") # create frame_a self.frame_a = qtgui.qframe(self) self.frame_a.setstylesheet("qwidget { background-color: %s }" % qtgui.qcolor(210,210,235,255).name()) self.layout_a = qtgui.qgridlayout() self.frame_a.setlayout(self.layout_a) self.setcentralwidget(self.frame_a) # place zoom button self.zoombtn = qtgui.qpushbutton(text = 'zoom') setcustomsize(self.zoombtn, 100, 50) self.zoombtn.clicked.connect(self.zoombtnaction) self.layout_a.addwidget(self.zoombtn, *(0,0)) # place matplotlib figure self.myfig = customfigcanvas() self.layout_a.addwidget(self.myfig, *(0,1)) # add callbackfunc .. mydataloop = threading.thread(name = 'mydataloop', target = datasendloop, daemon = true, args = (self.adddata_callbackfunc,)) mydataloop.start() self.show() '''''' def zoombtnaction(self): print("zoom in") self.myfig.zoomin(5) '''''' def adddata_callbackfunc(self, value): # print("add data: " + str(value)) self.myfig.adddata(value) ''' end class ''' class customfigcanvas(figurecanvas, timedanimation): def __init__(self): self.addeddata = [] print(matplotlib.__version__) # data self.xlim = 200 self.n = np.linspace(0, self.xlim - 1, self.xlim) = [] b = [] a.append(2.0) a.append(4.0) a.append(2.0) b.append(4.0) b.append(3.0) b.append(4.0) self.y = (self.n * 0.0) + 50 # window self.fig = figure(figsize=(5,5), dpi=100) self.ax1 = self.fig.add_subplot(111) # self.ax1 settings self.ax1.set_xlabel('time') self.ax1.set_ylabel('raw data') self.line1 = line2d([], [], color='blue') self.line1_tail = line2d([], [], color='red', linewidth=2) self.line1_head = line2d([], [], color='red', marker='o', markeredgecolor='r') self.ax1.add_line(self.line1) self.ax1.add_line(self.line1_tail) self.ax1.add_line(self.line1_head) self.ax1.set_xlim(0, self.xlim - 1) self.ax1.set_ylim(0, 100) figurecanvas.__init__(self, self.fig) timedanimation.__init__(self, self.fig, interval = 50, blit = true) def new_frame_seq(self): return iter(range(self.n.size)) def _init_draw(self): lines = [self.line1, self.line1_tail, self.line1_head] l in lines: l.set_data([], []) def adddata(self, value): self.addeddata.append(value) def zoomin(self, value): bottom = self.ax1.get_ylim()[0] top = self.ax1.get_ylim()[1] bottom += value top -= value self.ax1.set_ylim(bottom,top) self.draw() def _step(self, *args): # extends _step() method timedanimation class. try: timedanimation._step(self, *args) except exception e: self.abc += 1 print(str(self.abc)) timedanimation._stop(self) pass def _draw_frame(self, framedata): margin = 2 while(len(self.addeddata) > 0): self.y = np.roll(self.y, -1) self.y[-1] = self.addeddata[0] del(self.addeddata[0]) self.line1.set_data(self.n[ 0 : self.n.size - margin ], self.y[ 0 : self.n.size - margin ]) self.line1_tail.set_data(np.append(self.n[-10:-1 - margin], self.n[-1 - margin]), np.append(self.y[-10:-1 - margin], self.y[-1 - margin])) self.line1_head.set_data(self.n[-1 - margin], self.y[-1 - margin]) self._drawn_artists = [self.line1, self.line1_tail, self.line1_head] ''' end class ''' # need setup signal slot mechanism, # send data gui in thread-safe way. # believe me, if don't right, things # go very wrong.. class communicate(qtcore.qobject): data_signal = qtcore.pyqtsignal(float) ''' end class ''' def datasendloop(adddata_callbackfunc): # setup signal-slot mechanism. mysrc = communicate() mysrc.data_signal.connect(adddata_callbackfunc) # simulate data n = np.linspace(0, 499, 500) y = 50 + 25*(np.sin(n / 8.3)) + 10*(np.sin(n / 7.5)) - 5*(np.sin(n / 1.5)) = 0 while(true): if(i > 499): = 0 time.sleep(0.1) mysrc.data_signal.emit(y[i]) # <- here emit signal! += 1 ### ### if __name__== '__main__': app = qtgui.qapplication(sys.argv) qtgui.qapplication.setstyle(qtgui.qstylefactory.create('plastique')) mygui = custommainwindow() sys.exit(app.exec_()) ''''''
Comments
Post a Comment