Controlling an Embedded Plot with wx Scrollbars

When plotting a very long sequence in a matplotlib canvas embedded in a wxPython application, it sometimes is useful to be able to display a portion of the sequence without resorting to a scrollable window so that both axes remain visible. Here is how to do so:

   1 from numpy import arange, sin, pi, float, size
   2 
   3 import matplotlib
   4 matplotlib.use('WXAgg')
   5 from matplotlib.backends.backend_wxagg import FigureCanvasWxAgg
   6 from matplotlib.figure import Figure
   7 
   8 import wx
   9 
  10 class MyFrame(wx.Frame):
  11     def __init__(self, parent, id):
  12         wx.Frame.__init__(self,parent, id, 'scrollable plot',
  13                 style=wx.DEFAULT_FRAME_STYLE ^ wx.RESIZE_BORDER,
  14                 size=(800, 400))
  15         self.panel = wx.Panel(self, -1)
  16 
  17         self.fig = Figure((5, 4), 75)
  18         self.canvas = FigureCanvasWxAgg(self.panel, -1, self.fig)
  19         self.scroll_range = 400
  20         self.canvas.SetScrollbar(wx.HORIZONTAL, 0, 5,
  21                                  self.scroll_range)
  22 
  23         sizer = wx.BoxSizer(wx.VERTICAL)
  24         sizer.Add(self.canvas, -1, wx.EXPAND)
  25 
  26         self.panel.SetSizer(sizer)
  27         self.panel.Fit()
  28 
  29         self.init_data()
  30         self.init_plot()
  31 
  32         self.canvas.Bind(wx.EVT_SCROLLWIN, self.OnScrollEvt)
  33 
  34     def init_data(self):
  35 
  36         # Generate some data to plot:
  37         self.dt = 0.01
  38         self.t = arange(0,5,self.dt)
  39         self.x = sin(2*pi*self.t)
  40 
  41         # Extents of data sequence: 
  42         self.i_min = 0
  43         self.i_max = len(self.t)
  44 
  45         # Size of plot window:       
  46         self.i_window = 100
  47 
  48         # Indices of data interval to be plotted:
  49         self.i_start = 0
  50         self.i_end = self.i_start + self.i_window
  51 
  52     def init_plot(self):
  53         self.axes = self.fig.add_subplot(111)
  54         self.plot_data = \
                  self.axes.plot(self.t[self.i_start:self.i_end],
  55                                  self.x[self.i_start:self.i_end])[0]
  56 
  57     def draw_plot(self):
  58 
  59         # Update data in plot:
  60         self.plot_data.set_xdata(self.t[self.i_start:self.i_end])
  61         self.plot_data.set_ydata(self.x[self.i_start:self.i_end])
  62 
  63         # Adjust plot limits:
  64         self.axes.set_xlim((min(self.t[self.i_start:self.i_end]),
  65                            max(self.t[self.i_start:self.i_end])))
  66         self.axes.set_ylim((min(self.x[self.i_start:self.i_end]),
  67                             max(self.x[self.i_start:self.i_end])))
  68 
  69         # Redraw:                  
  70         self.canvas.draw()
  71 
  72     def OnScrollEvt(self, event):
  73 
  74         # Update the indices of the plot:
  75         self.i_start = self.i_min + event.GetPosition()
  76         self.i_end = self.i_min + self.i_window + event.GetPosition()
  77         self.draw_plot()
  78 
  79 class MyApp(wx.App):
  80     def OnInit(self):
  81         self.frame = MyFrame(parent=None,id=-1)
  82         self.frame.Show()
  83         self.SetTopWindow(self.frame)
  84         return True
  85 
  86 if __name__ == '__main__':
  87     app = MyApp()
  88     app.MainLoop()

Cookbook/Matplotlib/ScrollingPlot (last edited 2010-01-03 15:12:46 by LevGivon)