3 """Plot panel for Hooke.
\r
7 Originally based on `this example`_.
\r
10 http://matplotlib.sourceforge.net/examples/user_interfaces/embedding_in_wx2.html
\r
14 matplotlib.use('WXAgg') # use wxpython with antigrain (agg) rendering
\r
15 from matplotlib.backends.backend_wxagg import FigureCanvasWxAgg as FigureCanvas
\r
16 from matplotlib.backends.backend_wx import NavigationToolbar2Wx as NavToolbar
\r
17 from matplotlib.figure import Figure
\r
18 from matplotlib.ticker import Formatter
\r
21 from ....util.callback import callback, in_callback
\r
22 from ....util.si import ppSI, split_data_label
\r
26 class HookeFormatter (Formatter):
\r
27 """:class:`matplotlib.ticker.Formatter` using SI prefixes.
\r
29 def __init__(self, unit='', decimals=2):
\r
30 self.decimals = decimals
\r
33 def __call__(self, x, pos=None):
\r
34 """Return the format for tick val `x` at position `pos`.
\r
38 return ppSI(value=x, unit=self.unit, decimals=self.decimals)
\r
41 class PlotPanel (Panel, wx.Panel):
\r
42 """UI for graphical curve display.
\r
44 def __init__(self, callbacks=None, **kwargs):
\r
45 self.display_coordinates = False
\r
48 super(PlotPanel, self).__init__(
\r
49 name='plot', callbacks=callbacks, **kwargs)
\r
51 self._c['figure'] = Figure()
\r
52 self._c['canvas'] = FigureCanvas(
\r
53 parent=self, id=wx.ID_ANY, figure=self._c['figure'])
\r
54 self._c['toolbar'] = NavToolbar(self._c['canvas'])
\r
56 self._set_color(wx.NamedColor('WHITE'))
\r
57 sizer = wx.BoxSizer(wx.VERTICAL)
\r
58 sizer.Add(self._c['canvas'], 1, wx.LEFT | wx.TOP | wx.GROW)
\r
59 self._setup_toolbar(toolbar=self._c['toolbar'], sizer=sizer)
\r
60 self.SetSizer(sizer)
\r
63 self.Bind(wx.EVT_SIZE, self._on_size)
\r
64 self._c['figure'].canvas.mpl_connect(
\r
65 'button_press_event', self._on_click)
\r
66 self._c['figure'].canvas.mpl_connect(
\r
67 'axes_enter_event', self._on_enter_axes)
\r
68 self._c['figure'].canvas.mpl_connect(
\r
69 'axes_leave_event', self._on_leave_axes)
\r
70 self._c['figure'].canvas.mpl_connect(
\r
71 'motion_notify_event', self._on_mouse_move)
\r
73 def _setup_toolbar(self, toolbar, sizer):
\r
74 self._c['toolbar'].Realize() # call after putting items in the toolbar
\r
75 if wx.Platform == '__WXMAC__':
\r
76 # Mac platform (OSX 10.3, MacPython) does not seem to cope with
\r
77 # having a toolbar in a sizer. This work-around gets the buttons
\r
78 # back, but at the expense of having the toolbar at the top
\r
79 self.SetToolBar(toolbar)
\r
80 elif wx.Platform == '__WXMSW__':
\r
81 # On Windows platform, default window size is incorrect, so set
\r
82 # toolbar width to figure width.
\r
83 tw, th = toolbar.GetSizeTuple()
\r
84 fw, fh = self._c['canvas'].GetSizeTuple()
\r
85 # By adding toolbar in sizer, we are able to put it at the bottom
\r
86 # of the frame - so appearance is closer to GTK version.
\r
87 # As noted above, doesn't work for Mac.
\r
88 toolbar.SetSize(wx.Size(fw, th))
\r
89 sizer.Add(toolbar, 0 , wx.LEFT | wx.EXPAND)
\r
91 sizer.Add(toolbar, 0 , wx.LEFT | wx.EXPAND)
\r
92 self._c['toolbar'].update() # update the axes menu on the toolbar
\r
94 def _set_color(self, rgbtuple=None):
\r
95 """Set both figure and canvas colors to `rgbtuple`.
\r
97 if rgbtuple == None:
\r
98 rgbtuple = wx.SystemSettings.GetColour(wx.SYS_COLOUR_BTNFACE).Get()
\r
99 col = [c/255.0 for c in rgbtuple]
\r
100 self._c['figure'].set_facecolor(col)
\r
101 self._c['figure'].set_edgecolor(col)
\r
102 self._c['canvas'].SetBackgroundColour(wx.Colour(*rgbtuple))
\r
104 #def SetStatusText(self, text, field=1):
\r
105 # self.Parent.Parent.statusbar.SetStatusText(text, field)
\r
107 def _on_size(self, event):
\r
109 wx.CallAfter(self._resize_canvas)
\r
111 def _on_click(self, event):
\r
112 #self.SetStatusText(str(event.xdata))
\r
113 #print 'button=%d, x=%d, y=%d, xdata=%f, ydata=%f'%(event.button, event.x, event.y, event.xdata, event.ydata)
\r
116 def _on_enter_axes(self, event):
\r
117 self.display_coordinates = True
\r
119 def _on_leave_axes(self, event):
\r
120 self.display_coordinates = False
\r
121 #self.SetStatusText('')
\r
123 def _on_mouse_move(self, event):
\r
124 if event.guiEvent.m_shiftDown:
\r
125 self._c['toolbar'].set_cursor(wx.CURSOR_RIGHT_ARROW)
\r
127 self._c['toolbar'].set_cursor(wx.CURSOR_ARROW)
\r
128 if self.display_coordinates:
\r
129 coordinateString = ''.join(
\r
130 ['x: ', str(event.xdata), ' y: ', str(event.ydata)])
\r
131 #TODO: pretty format
\r
132 #self.SetStatusText(coordinateString)
\r
134 def _resize_canvas(self):
\r
135 w,h = self.GetClientSize()
\r
136 tw,th = self._c['toolbar'].GetSizeTuple()
\r
137 dpi = float(self._c['figure'].get_dpi())
\r
138 self._c['figure'].set_figwidth(w/dpi)
\r
139 self._c['figure'].set_figheight((h-th)/dpi)
\r
140 self._c['canvas'].draw()
\r
143 def OnPaint(self, event):
\r
145 super(PlotPanel, self).OnPaint(event)
\r
146 self._c['canvas'].draw()
\r
148 def set_curve(self, curve, config={}):
\r
149 self._curve = curve
\r
150 self.update(config=config)
\r
152 def update(self, config={}):
\r
153 x_name = 'z piezo (m)'
\r
154 y_name = 'deflection (m)'
\r
156 self._c['figure'].clear()
\r
157 self._c['figure'].suptitle(
\r
158 self._hooke_frame._file_name(self._curve.name),
\r
160 axes = self._c['figure'].add_subplot(1, 1, 1)
\r
162 if config['plot si format'] == 'True': # TODO: config should convert
\r
163 d = int(config['plot decimals']) # TODO: config should convert
\r
164 x_n, x_unit = split_data_label(x_name)
\r
165 y_n, y_unit = split_data_label(y_name)
\r
166 fx = HookeFormatter(decimals=d, unit=x_unit)
\r
167 axes.xaxis.set_major_formatter(fx)
\r
168 fy = HookeFormatter(decimals=d, unit=y_unit)
\r
169 axes.yaxis.set_major_formatter(fy)
\r
170 axes.set_xlabel(x_n)
\r
171 axes.set_ylabel(y_n)
\r
173 axes.set_xlabel(x_name)
\r
174 axes.set_ylabel(y_name)
\r
176 self._c['figure'].hold(True)
\r
177 for i,data in enumerate(self._curve.data):
\r
178 axes.plot(data[:,data.info['columns'].index(x_name)],
\r
179 data[:,data.info['columns'].index(y_name)],
\r
181 label=data.info['name'])
\r
182 if config['plot legend'] == 'True': # HACK: config should convert
\r
183 axes.legend(loc='best')
\r
184 self._c['canvas'].draw()
\r
186 # LocalWords: matplotlib
\r