> > Main issue is Matplotlib's performance. I'm trying to plot a current > > trace from a physics experiment, containing about 300,000 data points. > > In LabVIEW, one can easily browse through a data set like this, but I > > haven't been able yet to get such a good performance with > > IPython+Matplotlib. Especially scrolling/panning through the data is > > sluggish. (Anyone knows how to add a scrollbar for this instead of > > panning with the mouse, btw?) > > > > http://matplotlib.sf.net/examples/embedding_in_gtk3.py shows an > example using a scrolled window. > > You could also use the "clipped line" approach to pass in a custom > class that only plots the data in the current view limits defined by > timemin, timemax. See > http://matplotlib.sf.net/examples/clippedline.py. This example > changes the marker and line style depending on how many points are in > the view port, but you could expand on this idea to do downsampling > when the number of points is too large.
Hi Onno and JDH, JDH, I have just started using matplotlib and love it. Thanks so much for your work. I have come across the same performance issues. My vote is for bringing clipped line back and even making it the default. A check may be needed in the constructor to make sure it is sorted, but I think it is worth it. If the program is used for its primary original intent (plotting), the vast majority are going to be increasing in x. I am including a class based on ClippedLine that does decimation. Please reply if you have improvements and please consider putting something like it in the code. This probably should not be used as default, though, because it may not be what the user expects. For example, if Onno is looking for very short duration spikes, they will not get plotted. That is the nature of the decimation beast. And, the filter requires the x data to be equally spaced. With decimation you not only get performance increases, but you also get rid of the smooching that occurs if the data is not monotonic so you can actually see something. Here are the performance results on my computer: it took -0.511511087418 seconds for matplotlib.lines.Line2D to draw() it took -0.4196870327 seconds for __main__.ClippedLine to draw() downsampling plotted line... it took -0.11829996109 seconds for __main__.DecimatedClippedLine to draw() from matplotlib.lines import Line2D import numpy as npy from pylab import figure, show, draw import scipy.signal import time # adjusted from /usr/share/doc/matplotlib-0.91.2/examples/clippedline.py class ClippedLine(Line2D): """ Clip the xlimits to the axes view limits -- this example assumes x is sorted """ def __init__(self, ax, *args, **kwargs): Line2D.__init__(self, *args, **kwargs) ## axes the line is plotted in self.ax = ax def set_data(self, *args, **kwargs): Line2D.set_data(self, *args, **kwargs) ## what is plotted pre-clipping self.xorig = npy.array(self._x) ## what is plotted pre-clipping self.yorig = npy.array(self._y) def draw(self, renderer): xlim = self.ax.get_xlim() ind0, ind1 = npy.searchsorted(self.xorig, xlim) self._x = self.xorig[ind0:ind1] self._y = self.yorig[ind0:ind1] Line2D.draw(self, renderer) class DecimatedClippedLine(Line2D): """ Decimate and clip the data so it does not take as long to plot. Assumes data is sorted and equally spaced. """ def __init__(self, ax, *args, **kwargs): """ *Parameters*: ax: axes the line is plotted on *args, **kwargs: Line2D args """ Line2D.__init__(self, *args, **kwargs) ## axes the line is plotted in self.ax = ax def set_data(self, *args, **kwargs): Line2D.set_data(self, *args, **kwargs) ## data preclipping and decimation self.xorig = npy.array(self._x) ## data pre clipping and decimation self.yorig = npy.array(self._y) def draw(self, renderer): bb = self.ax.get_window_extent() width = bb.width() xlim = self.ax.get_xlim() ind0, ind1 = npy.searchsorted(self.xorig, xlim) if self.ax.get_autoscale_on(): ylim = self.ax.get_xlim() self.ax.set_ylim( min([ylim[0], self._y.min()]), max([ylim[1], self._y.max()]) ) self._x = self.xorig[ind0:ind1] self._y = self.yorig[ind0:ind1] if width / float( ind1 - ind0 ) < 0.4: # if number of points to plot is much greater than the pixels in the plot b, a = scipy.signal.butter(5, width / float( ind1 - ind0 ) ) print 'downsampling plotted line...' filty = scipy.signal.lfilter( b, a, self._y ) step = int( ( ind1 - ind0 ) / width ) self._x = self._x[::step] self._y = filty[::step] Line2D.draw(self, renderer) t = npy.arange(0.0, 100.0, 0.0001) s = npy.sin(2*npy.pi*t) s += (npy.random.rand( len(t) ) - 0.5)*3.0 for i in xrange(3): starttime = time.time() fig = figure(i) ax = fig.add_subplot(111, autoscale_on=False) if i == 0: line = Line2D(t, s, color='g', ls='-', lw=2) elif i == 1: line = ClippedLine(ax, t, s, color='g', ls='-', lw=2) elif i == 2: line = DecimatedClippedLine(ax, t, s, color='g', ls='-', lw=2) ax.add_line(line) ax.set_xlim(10,20) ax.set_ylim(-3.3,3.3) ax.set_title( str(line.__class__).replace('_','\_') ) draw() endtime = time.time() print 'it took', starttime-endtime, 'seconds for', str(line.__class__), 'to draw()' show() ------------------------------------------------------------------------- This SF.net email is sponsored by the 2008 JavaOne(SM) Conference Don't miss this year's exciting event. There's still time to save $100. Use priority code J8TL2D2. http://ad.doubleclick.net/clk;198757673;13503038;p?http://java.sun.com/javaone _______________________________________________ Matplotlib-users mailing list Matplotlib-users@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/matplotlib-users