[SciPy-user] Chaco & wxWindows

Peter Wang pwang at enthought.com
Tue Nov 29 15:49:21 CST 2005

(I'm moving this thread to the scipy-chaco list, and CCing this message to the 
general scipy-users list.)

Bas van Dijk wrote:

> The user should be able to zoom in and out and scroll over the plot 
> (Preferably by using the +,- and arrow keys).

There is a very flexible interaction mechanism to allow composing these sorts 
of behaviors.  The zoom and pan interactions are already implemented, and 
others can be derived easily from existing ones.  (The pan interaction is 
actually still on a branch and not the trunk, but it's easy enough to move 
that over.)

You just need to modify the previous code a little bit to add zooming:

from enthought.chaco.interaction.zoom_interaction import ZoomInteraction

class MyFrame ( wx.Frame ):
     def __init__ ( self, *args, **kw ):
         wx.Frame.__init__( *(self,) + args, **kw )
         data = sin(arange(-5.0, 5.0, 0.3))

         zoom = ZoomInteraction(reset_on_complete=True)
         x_axis = PlotAxis(title="X axis")
         y_axis = PlotAxis(title="Y axis")
         plot = PlotValue(data, type="scatter,line",
                          axis_index = x_axis, axis = y_axis,
         plot_window = Window(self, component=PlotComponent(plot))

There's a quirk in the zoom interaction that requires you to create the axes 
explicitly, instead of letting the canvas create it automatically.  Also, 
there is no limit to the amount that a user can try to zoom, so you need to do 
that yourself, e.g. by checking on the bound_low and bound_high of the axis 

As written, the zoom interaction allows the user to select a rectangular 
region with the left mouse button, and a single right-click will unzoom.  You 
can look at the code inside chaco/interactions/zoom_interaction to see how to 
make your own interaction that behaves somewhat differently.

It's pretty trivial to adapt the existing interactions to use keypresses. 
I've added a keyboard_pan_demo.py to chaco/demo/.  Here is what the panning 
interaction looks like:

class KeyboardPan(PlotInteraction):
     stepsize = 10  # number of pixels to move left or right
     accepts_focus = True
     def _key_changed(self, event):
         # event is an enable.events.KeyEvent; character is a simple char
         # or the name of a control char (see enable.wx.window.key_map).
         if event.character == "Right":
             delta = self.stepsize
         elif event.character == "Left":
             delta = -self.stepsize

         handled_axes = []
         for plotvalue in self.canvas.values:
             x_axis = plotvalue.axis_index
             # Check for auto-scaling and turn it off.
             if 'auto' in (x_axis.bound_low, x_axis.bound_high):
                 axis_info = plotvalue._axis_info_index
                 x_axis.bound_low = axis_info.min
                 x_axis.bound_high = axis_info.max

             xscale = plotvalue._plot_sxdx / (x_axis.bound_high - 
             if x_axis not in handled_axes:
                 x_axis.bound_low += delta/xscale
                 x_axis.bound_high += delta/xscale

Note that as you pan, the axis scale labels on the bottom change, and so the 
plot resizes a bit.  This behavior can be mitigated by creating the axis with 
a set format:

         x_axis = PlotAxis(title="X axis", label_format="%2d")

Also note that you have to click on the plot first before it starts receiving 
keyboard events.  This is a known issue that's on my list of things to fix.

> It would also be nice if the user can change other things like the scale of 
> the axes and maybe also the axes titles. But I already read in the excellent 
> Chaco tutorial how to do that.

Great!  But keep in mind that the tutorial is a little out of date with what's 
in the SVN. :)

> Another question I have is if the Chaco plots can be used in an interactive 
> manner? The application I developed is a logging program. It connects to a 
> scientific instrument and starts plotting the values it receives.

Yes, after you've updated data, just call canvas.update() to schedule a redraw.

> The reason I want to use another plotting package (I'm now using scipy.plt) is 
> that scipy.plt doesn't do double buffering. So when a new value comes in, the 
> screen flickers when it is plotted.
 > Do you know if Chaco can solve this problem?

Well, yes and no.  Chaco does do double buffering, because the draw process is 
  done to an internal bitmap that then gets blitted by WX.  However, if you 
update too quickly, then flicker simply gets translated into "sluggishness", 
i.e. things don't update in a responsive fashion.  At what rate is your data 
coming in?  Perhaps you need to be buffering data, and not the graphics drawing?


More information about the SciPy-user mailing list