Plotting Release on change data

Hello Matplotlib users, I only just discovered Matplotlib

    > and I'm having great fun with it. Wonderful package. Thank
    > you to all contributors and maintainers.

    > I have an application where the data that I want to plot is
    > only released when it changes. So when this time tagged
    > data is plotted it should be "flat" until the next data
    > value that the application receives at which point the line
    > should go instantaneously vertical to the new y-value, and
    > then go horizontal until it changes again. Some graphics
    > packages that I've used can handle this type of data
    > automatically. I haven't found anything in the
    > documentation or examples that shows this kind of feature
    > in Matplotlib. Has anyone implemented a similar type of
    > data handling application or is there something I've missed
    > in Matplotlib? Any help or direction to this newbie would
    > be very appreciated.

Here is an example that does something close to what you are trying to
do. It takes advantage of the new animation drawing techniques
described at http://www.scipy.org/wikis/topical_software/Animations
and requires matplotlib CVS. These techniques work with GTKAgg, WXAgg
and TkAgg.

To do this right, you will probably want to take advantage of your GUI
event handling framework, eg an idle handler or a timer. The example
below uses the gtk idle handler, but this approach should work fine
with other toolkits.

There are some refinements. Eg you could make the redrawing more
efficient potentially by narrowing the bbox you want to redraw in the
call to self.canvas.blit(self.ax.bbox). You could also tweak this to
preserve the old line (eg the 0-10 second data) while you are
redrawing the new line (eg the 10-20 second data) in the way many
oscilloscopes do.

But this should get you started. If you refine it or generalize it,
please post the fruits of your labors.

import gobject, gtk
import matplotlib
matplotlib.use('GTKAgg')
import matplotlib.numerix as nx
from matplotlib.lines import Line2D

class Scope:
    def __init__(self, ax, maxt=10, dt=0.01):
        self.ax = ax
        self.canvas = ax.figure.canvas
        self.dt = dt
        self.maxt = maxt
        self.tdata = [0]
        self.ydata = [0]
        self.line = Line2D(self.tdata, self.ydata, animated=True)
        self.ax.add_line(self.line)
        self.background = None
        self.canvas.mpl_connect('draw_event', self.update_background)
        self.ax.set_ylim(-.1, 1.1)
        self.ax.set_xlim(0, self.maxt)

    def update_background(self, event):
        self.background = self.canvas.copy_from_bbox(self.ax.bbox)
    
    def emitter(self, p=0.01):
        'return a random value with probability p, else 0'
        v = nx.mlab.rand(1)
        if v>p: return 0.
        else: return nx.mlab.rand(1)

    def update(self, *args):
        if self.background is None: return True
        y = self.emitter()
        lastt = self.tdata[-1]
        if lastt>self.tdata[0]+self.maxt: # reset the arrays
            self.tdata = [self.tdata[-1]]
            self.ydata = [self.ydata[-1]]
            self.ax.set_xlim(self.tdata[0], self.tdata[0]+self.maxt)
            self.ax.figure.canvas.draw()
            
        self.canvas.restore_region(self.background)
        
        t = self.tdata[-1] + self.dt
        self.tdata.append(t)
        self.ydata.append(y)
        self.line.set_data(self.tdata, self.ydata)
        self.ax.draw_artist(self.line)
        self.canvas.blit(self.ax.bbox)
        return True

from pylab import figure, show

fig = figure()
ax = fig.add_subplot(111)
scope = Scope(ax)
gobject.idle_add(scope.update)

show()