From: Andrew S. <str...@as...> - 2004-06-26 07:56:31
Attachments:
dynamic_image_wxagg.py
|
Hi plotters, I've shamelessly modified dynamic_demo_wx.py to create dynamic_image_wxagg.py, attached. This is my initial attempt to get matplotlib to dynamically update images. Basically it all works hunky-dory except 1) an apparent memory leak and 2) flicker when I run this in linux (haven't tested other OSes). I offer #1 to John or other memory-leak hunters out there and ask if any WXpert can address #2. I've googled a bit and it appears the WX backend (from which WXAgg is derived) does the Right Thing and calls wxClientDC on a non-OS generated redraw request, which is supposed to reduce or eliminate flicker. The other tip is to catch EVT_ERASE_BACKGROUND, which I've also done to no apparent improvement. Thus, I ask for help -- any suggestions on how to eliminate this flicker? John -- feel free to stick this in examples if you think it's worthy. Cheers! Andrew |
From: Andrew S. <str...@as...> - 2004-06-26 08:32:11
|
Sorry, I also added the following line to backend_wxagg to get my demo to work: from backend_wx import FigureManager Anyhow, I've added this to CVS, but you can just as easily modify your copy of the affected file. Cheers! Andrew |
From: John H. <jdh...@ac...> - 2004-06-29 03:47:33
|
>>>>> "Andrew" == Andrew Straw <str...@as...> writes: Andrew> Hi plotters, I've shamelessly modified dynamic_demo_wx.py Andrew> to create dynamic_image_wxagg.py, attached. This is my Andrew> initial attempt to get matplotlib to dynamically update Andrew> images. Basically it all works hunky-dory except 1) an Andrew> apparent memory leak and 2) flicker when I run this in Andrew> linux (haven't tested other OSes). I offer #1 to John or Andrew> other memory-leak hunters out there and ask if any WXpert Andrew> can address #2. I've googled a bit and it appears the WX Andrew> backend (from which WXAgg is derived) does the Right Thing Andrew> and calls wxClientDC on a non-OS generated redraw request, Andrew> which is supposed to reduce or eliminate flicker. The Andrew> other tip is to catch EVT_ERASE_BACKGROUND, which I've Andrew> also done to no apparent improvement. Thus, I ask for help Andrew> -- any suggestions on how to eliminate this flicker? Hi Andrew, Haven't had a chance to test your example yet but hopefully I can take a look tomorrow. I haven't done much memory leak testing against the _image module yet so this will be a good opportunity. I very recently rewrote _image.cpp using cxx. I trust you have a fresh CVS checkout? As for the flicker problem, I've noticed it too, and would also be thankful if any wx gurus have some advice. BTW, wxagg currently uses a string copy in python to render agg to a wx bitmap via a wx image. It would be nice if some enterprising soul wrote some extension code ala _tkagg.cpp and _gtkagg.cpp which transfers the agg canvas to wx directly. Should be a pretty big win performance wise. We could keep the string method as a fallback in case the extension wasn't compiled, but it would help for people who want to use wxagg for dynamic applications (hint hint). This should at least be on the goals page. JDH |
From: John H. <jdh...@ac...> - 2004-07-01 13:49:52
|
>>>>> "John" == John Hunter <jdh...@ac...> writes: John> Haven't had a chance to test your example yet but hopefully John> I can take a look tomorrow. I haven't done much memory leak John> testing against the _image module yet so this will be a good John> opportunity. I very recently rewrote _image.cpp using cxx. John> I trust you have a fresh CVS checkout? Hi Andrew - found and fixed the memory leak. Can't really call it a leak - more like a "memory gusher". This was in the agg (and image) module "to string" methods. In my tests, the leak went from 600k per frame to approx 600 bytes per frame, which is on par for what I see in other agg memory leak tests. I made a number of comments in your example to point out places where you probably should be using matplotlib a little differently - most of these I flagged with my initials so you can search for them. Modified script is below. After you get the script in the final form you want and purge the comments and memory reporting stuff where appropriate, please add it to CVS. I liked the example so much I made an analogous one dynamic_image_gtk. It's faster than wxagg (13FPS vs 4FPS on my system) which is not surprising since gtkagg has extension code to transfer agg to the GUI canvas, and doesn't flicker. Very nice! I would really like to get that wxagg flicker problem figured out, and the extension code added... Did I hear you volunteering to be the wxagg maintainer :-)? #!/usr/bin/env python """ Copyright (C) 2003-2004 Jeremy O'Donoghue and others License: This work is licensed under the PSF. A copy should be included with this source code, and is also available at http://www.python.org/psf/license.html """ import sys, time, os, gc import matplotlib matplotlib.use('WXAgg') # jdh: you need to control Numeric vs numarray with numerix, otherwise # matplotlib may be using numeric under the hood and while you are # using numarray and this isn't efficient. Also, if you use # numerix=numarray, it is important to compile matplotlib for numarray # by setting NUMERIX = 'numarray' in setup.py before building from matplotlib import rcParams rcParams['numerix'] = 'numarray' # jdh: you can import cm directly, you don't need to go via # matplotlib.matlab import matplotlib.cm as cm from matplotlib.backends.backend_wxagg import Toolbar, FigureCanvasWxAgg # jdh: you don't need a figure manager in the GUI - this class was # designed for the matlab interface from matplotlib.figure import Figure import matplotlib.numerix as numerix from wxPython.wx import * TIMER_ID = wxNewId() # jdh: use this function, or something similar, when reporting a # memory leak def report_memory(i): pid = os.getpid() a2 = os.popen('ps -p %d -o rss,sz' % pid).readlines() print i, ' ', a2[1], return int(a2[1].split()[0]) class PlotFigure(wxFrame): def __init__(self): wxFrame.__init__(self, None, -1, "Test embedded wxFigure") self.fig = Figure((5,4), 75) self.canvas = FigureCanvasWxAgg(self, -1, self.fig) self.toolbar = Toolbar(self.canvas) self.toolbar.Realize() # On Windows, default frame size behaviour is incorrect # you don't need this under Linux tw, th = self.toolbar.GetSizeTuple() fw, fh = self.canvas.GetSizeTuple() self.toolbar.SetSize(wxSize(fw, th)) # Create a figure manager to manage things # Now put all into a sizer sizer = wxBoxSizer(wxVERTICAL) # This way of adding to sizer allows resizing sizer.Add(self.canvas, 1, wxLEFT|wxTOP|wxGROW) # Best to allow the toolbar to resize! sizer.Add(self.toolbar, 0, wxGROW) self.SetSizer(sizer) self.Fit() EVT_TIMER(self, TIMER_ID, self.onTimer) self.cnt = 0 def init_plot_data(self): # jdh you can add a subplot directly from the fig rather than # the fig manager a = self.fig.add_subplot(111) self.x = numerix.arange(120.0)*2*numerix.pi/120.0 self.x.resize((100,120)) self.y = numerix.arange(100.0)*2*numerix.pi/100.0 self.y.resize((120,100)) self.y = numerix.transpose(self.y) z = numerix.sin(self.x) + numerix.cos(self.y) self.im = a.imshow( z, cmap=cm.jet)#, interpolation='nearest') def GetToolBar(self): # You will need to override GetToolBar if you are using an # unmanaged toolbar in your frame return self.toolbar def onTimer(self, evt): self.x += numerix.pi/15 self.y += numerix.pi/20 z = numerix.sin(self.x) + numerix.cos(self.y) self.im.set_array(z) self.canvas.draw() #self.canvas.gui_repaint() # jdh wxagg_draw calls this already val = report_memory(self.cnt) if self.cnt==1: self.start = val # skip cnt=0 self.tstart = time.time() elif self.cnt==50: end = val print 'Average memory consumed per loop: %1.4f\n' % ((end-self.start)/float(self.cnt)) print 'FPS', self.cnt/(time.time() - self.tstart) sys.exit() self.cnt += 1 gc.collect() def onEraseBackground(self, evt): # this is supposed to prevent redraw flicker on some X servers... pass if __name__ == '__main__': app = wxPySimpleApp() frame = PlotFigure() frame.init_plot_data() # Initialise the timer - wxPython requires this to be connected to the # receivicng event handler t = wxTimer(frame, TIMER_ID) t.Start(200) frame.Show() app.MainLoop() |
From: Jim B. <jb...@se...> - 2004-07-01 21:37:53
|
Hi John, Today i finally got around to trying a suggestion that you made on May 22...on how to put a legend on a Figure (outside of the axis). So i hacked up the example legendDemo.py to experiment with: # Haked up legendDemp.py # Thanks to Charles Twardy for this example from matplotlib.matlab import * a = arange(0,3,.02) b = arange(0,3,.02) c=exp(a) d=c.tolist() d.reverse() d = array(d) ax = subplot(111) lines = plot(a,c,'k--',a,d,'k:',a,c+d,'k') #legend(('Model length', 'Data length', 'Total message length'), 'upper left') fig = gcf() line1 = lines[0] line2 = lines[1] line3 = lines[2] fig.legend((line1, line2, line3), ('Model length', 'Data length', 'Total message length'), 'upper left') ax.set_ylim([-1,20]) ax.grid(0) xlabel('Model complexity --->') ylabel('Message length --->') title('Minimum Message Length') set(gca(), 'yticklabels', []) set(gca(), 'xticklabels', []) savefig('legend_demo_small', dpi=60) savefig('legend_demo_large', dpi=120) show() # End of: Haked up legendDemp.py I then go the following error: clavius:/home/jbenson/python>python legendDemo.py Traceback (most recent call last): File "legendDemo.py", line 22, in ? 'upper left') File "/usr/local/lib/python2.3/site-packages/matplotlib/figure.py", line 179, in legend l = Legend(handles, labels, loc) TypeError: __init__() takes exactly 5 arguments (4 given) clavius:/home/jbenson/python> Should that line 179 in figure.py be: l = Legend(self, handles, labels, loc) # -added ->self<- ? Just for fun, i tried that change and re-ran: clavius:/home/jbenson/python>python legendDemo.py Traceback (most recent call last): File "legendDemo.py", line 22, in ? 'upper left') File "/usr/local/lib/python2.3/site-packages/matplotlib/figure.py", line 179, in legend l = Legend(self, handles, labels, loc) File "/usr/local/lib/python2.3/site-packages/matplotlib/legend.py", line 107, in __init__ self._texts = self._get_texts(labels, textleft, upper) File "/usr/local/lib/python2.3/site-packages/matplotlib/legend.py", line 215, in _get_texts HEIGHT = self._approx_text_height() File "/usr/local/lib/python2.3/site-packages/matplotlib/legend.py", line 126, in _approx_text_height return self.FONTSIZE/72.0*self.figure.dpi.get()/self.parent.bbox.height() AttributeError: 'NoneType' object has no attribute 'dpi' clavius:/home/jbenson/python> ...so those errors look worse. (i'm using matplotlib-0.54.2) Any more hints? Thanks, Jim |
From: John H. <jdh...@ac...> - 2004-07-03 21:42:00
|
>>>>> "Jim" == Jim Benson <jb...@se...> writes: Jim> Any more hints? Make that l = Legend(self, handles, labels, loc) Should work - let me know if you have any more troubles. JDH |
From: Jim B. <jb...@se...> - 2004-07-04 02:14:44
|
On Sat, 3 Jul 2004, John Hunter wrote: > Make that > > l = Legend(self, handles, labels, loc) > > Should work - let me know if you have any more troubles. > Thanks John...i did actually try that before i sent my previous email...sorry that the error messages were buried under a bunch of other stuff. I did have a problem after i added the self. Here is what i get (my hacked up legendDemp.py follows the error messages): floyd:/home/jbenson/python>python legendDemo.py Traceback (most recent call last): File "legendDemo.py", line 30, in ? 'upper left') File "/usr/local/lib/python2.3/site-packages/matplotlib/figure.py", line 179, in legend l = Legend(self, handles, labels, loc) File "/usr/local/lib/python2.3/site-packages/matplotlib/legend.py", line 107, in __init__ self._texts = self._get_texts(labels, textleft, upper) File "/usr/local/lib/python2.3/site-packages/matplotlib/legend.py", line 215, in _get_texts HEIGHT = self._approx_text_height() File "/usr/local/lib/python2.3/site-packages/matplotlib/legend.py", line 126, in _approx_text_height return self.FONTSIZE/72.0*self.figure.dpi.get()/self.parent.bbox.height() AttributeError: 'NoneType' object has no attribute 'dpi' floyd:/home/jbenson/python> # legendDemo.py from matplotlib.matlab import * a = arange(0,3,.02) b = arange(0,3,.02) c=exp(a) d=c.tolist() d.reverse() d = array(d) ax = subplot(111) lines = plot(a,c,'k--',a,d,'k:',a,c+d,'k') bNotHacked = False if bNotHacked: legend(('Model length', 'Data length', 'Total message length'), 'upper left') else: fig = gcf() line1 = lines[0] line2 = lines[1] line3 = lines[2] fig.legend((line1, line2, line3), ('Model length', 'Data length', 'Total message length'), 'upper left') ax.set_ylim([-1,20]) ax.grid(0) xlabel('Model complexity --->') ylabel('Message length --->') title('Minimum Message Length') set(gca(), 'yticklabels', []) set(gca(), 'xticklabels', []) savefig('legend_demo_small', dpi=60) savefig('legend_demo_large', dpi=120) show() ~ Jim |
From: Andrew S. <str...@as...> - 2004-07-10 06:31:30
|
John Hunter wrote: >>>>>>"John" == John Hunter <jdh...@ac...> writes: >>>>>> >>>>>> > > John> Haven't had a chance to test your example yet but hopefully > John> I can take a look tomorrow. I haven't done much memory leak > John> testing against the _image module yet so this will be a good > John> opportunity. I very recently rewrote _image.cpp using cxx. > John> I trust you have a fresh CVS checkout? > >Hi Andrew - found and fixed the memory leak. Can't really call it a >leak - more like a "memory gusher". This was in the agg (and image) > > That makes a HUGE difference -- great! >I made a number of comments in your example to point out places where >you probably should be using matplotlib a little differently. > > OK, I see I have a lot of learning to do! It's a lot cleaner now, but I left comments in for "common pitfalls to avoid when embedding in wx" enthusiasts. >Please add it to CVS. > > Done. >I liked the example so much I made an analogous one dynamic_image_gtk. > > Cool! The GTK demo is nice because of the simplicity allowed by not embedding in a foreign GUI, but mainly using the matplotlib interface. >It's faster than wxagg (13FPS vs 4FPS on my system) which is not >surprising since gtkagg has extension code to transfer agg to the GUI >canvas, > It's even less surprising given that the wxagg app is driven by a timer callback set to run at 5 FPS! :) >and doesn't flicker. Very nice! I would really like to get >that wxagg flicker problem figured out, and the extension code >added... Did I hear you volunteering to be the wxagg maintainer :-)? > > Well, I'll hopefully have a chance to poke around in wxagg once in a while, but "maintainer" may be a bit grandiose for my time availability in the forseeable futurue... Cheers! Andrew |