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 = \
55 self.axes.plot(self.t[self.i_start:self.i_end],
56 self.x[self.i_start:self.i_end])[0]
57
58 def draw_plot(self):
59
60 # Update data in plot:
61 self.plot_data.set_xdata(self.t[self.i_start:self.i_end])
62 self.plot_data.set_ydata(self.x[self.i_start:self.i_end])
63
64 # Adjust plot limits:
65 self.axes.set_xlim((min(self.t[self.i_start:self.i_end]),
66 max(self.t[self.i_start:self.i_end])))
67 self.axes.set_ylim((min(self.x[self.i_start:self.i_end]),
68 max(self.x[self.i_start:self.i_end])))
69
70 # Redraw:
71 self.canvas.draw()
72
73 def OnScrollEvt(self, event):
74
75 # Update the indices of the plot:
76 self.i_start = self.i_min + event.GetPosition()
77 self.i_end = self.i_min + self.i_window + event.GetPosition()
78 self.draw_plot()
79
80 class MyApp(wx.App):
81 def OnInit(self):
82 self.frame = MyFrame(parent=None,id=-1)
83 self.frame.Show()
84 self.SetTopWindow(self.frame)
85 return True
86
87 if __name__ == '__main__':
88 app = MyApp()
89 app.MainLoop()