1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 """
17 The module contains extensions for GUI plot frame.
18 """
19
20 __id__ = "$Id: extendedplotframe.py 3018 2009-04-07 19:45:51Z juhas $"
21
22 import os.path
23
24 import matplotlib
25 matplotlib.use('WXAgg')
26 from matplotlib.backends.backend_wxagg import FigureCanvasWxAgg as FigureCanvas
27 from matplotlib.backends.backend_wxagg import NavigationToolbar2WxAgg as NavToolbar
28 from matplotlib.figure import Figure
29 from matplotlib.backends.backend_wx import _load_bitmap
30 from matplotlib.artist import setp
31 from matplotlib.font_manager import FontProperties
32 import wx
33
34
35 DATA_SAVE_ID = wx.NewId()
99
100
101
103 """An extended plotting frame with a save and close button.
104
105 The class has a matplotlib.figure.Figure data member named 'figure'.
106 It also has a matplotlib.axes.Axes data member named 'axes'.
107 The normal matplotlib plot manipulations can be performed with these two
108 data members. See the matplotlib API at:
109 http://matplotlib.sourceforge.net/classdocs.html
110 """
111
112 - def __init__(self, parent = None, *args, **kwargs):
113 """Initialize the CanvasFrame.
114
115 The frame uses ExtendedToolbar as a toolbar, which has a save data
116 button and a close button on the toolbar in addition to the normal
117 buttons.
118
119 args -- argument list
120 kwargs -- keyword argument list
121 """
122 wx.Frame.__init__(self,parent,-1,'ExtendedPlotFrame',size=(550,350))
123
124
125 self.figure = Figure(figsize=(0.5,0.5), dpi=72)
126
127
128 self.subplot = self.figure.add_subplot(111, autoscale_on=False)
129 self.canvas = FigureCanvas(self, -1, self.figure)
130
131
132 self.dirname = ''
133 self.filename = ''
134
135 self.sizer = wx.BoxSizer(wx.VERTICAL)
136 self.sizer.Add(self.canvas, 1, wx.TOP|wx.LEFT|wx.EXPAND)
137 self.toolbar = ExtendedToolbar(self.canvas, True)
138 self.toolbar.Realize()
139
140 self.coordLabel = wx.StaticText(self,-1,style = wx.ALIGN_RIGHT|wx.NO_BORDER)
141 if wx.Platform == '__WXMAC__':
142
143
144
145 self.SetToolBar(self.toolbar)
146 self.sizer.Add(self.coordLabel, 0, wx.EXPAND)
147 else:
148
149
150 tw, th = self.toolbar.GetSizeTuple()
151 sw, sh = self.coordLabel.GetSizeTuple()
152 fw, fh = self.canvas.GetSizeTuple()
153
154
155
156 self.coordLabel.SetSize(wx.Size(sw, th))
157
158 barSizer = wx.BoxSizer(wx.HORIZONTAL)
159 self.sizer.Add(barSizer, 0, wx.EXPAND|wx.CENTER)
160 barSizer.Add(self.toolbar, 0, wx.CENTER)
161 barSizer.Add((20,10),0)
162 barSizer.Add(self.coordLabel, 0, wx.CENTER)
163
164
165 self.toolbar.update()
166 self.SetSizer(self.sizer)
167 self.Fit()
168 self.SetSize((600,400))
169
170 self.SetBackgroundColour(self.toolbar.GetBackgroundColour())
171 self.canvas.mpl_connect('motion_notify_event', self.UpdateStatusBar)
172 wx.EVT_PAINT(self, self.OnPaint)
173 wx.EVT_TOOL(self, DATA_SAVE_ID, self.savePlotData)
174 wx.EVT_TOOL(self, wx.ID_CLOSE, self.onClose)
175 wx.EVT_CLOSE(self, self.onClose)
176 wx.EVT_TOOL(self, wx.ID_PRINT, self.onPrint)
177 wx.EVT_TOOL(self, wx.ID_PRINT_SETUP, self.onPrintSetup)
178 wx.EVT_TOOL(self, wx.ID_PREVIEW_PRINT, self.onPrintPreview)
179
180 self.datalims = {}
181
182
183
184
186 """Close the frame."""
187 if hasattr(self, 'plotter'):
188 self.plotter.onWindowClose()
189 self.Destroy()
190 return
191
193 self.canvas.draw()
194 event.Skip()
195
197 """Save the data in the plot in columns."""
198 d = wx.FileDialog(None, "Save as...", self.dirname, self.filename,
199 "(*.dat)|*.dat|(*.txt)|*.txt|(*)|*", wx.SAVE|wx.OVERWRITE_PROMPT)
200 if d.ShowModal() == wx.ID_OK:
201 fullname = d.GetPath()
202 self.dirname = os.path.dirname(fullname)
203 self.filename = os.path.basename(fullname)
204 self.plotter.export(fullname)
205
206 d.Destroy()
207 return
208
210 '''handle print event'''
211 self.canvas.Printer_Print(event=evt)
212
214 self.canvas.Printer_Setup(event=event)
215
217 self.canvas.Printer_Preview(event=event)
218
220 if event.inaxes:
221 x, y = event.xdata, event.ydata
222 xystr = "x = %g, y = %g" % (x, y)
223 self.coordLabel.SetLabel(xystr)
224
226 """officially call function in matplotlib to do drawing
227 """
228 self.canvas.draw()
229
231 """insert a new curve to the plot
232
233 xData, yData -- x, y data to used for the curve
234 style -- the way curve should be plotted
235 return: internal reference to the newly added curve
236 """
237 stylestr,properties = self.__translateStyles(style)
238 curveRef = self.subplot.plot(xData, yData, stylestr, **properties)[0]
239 self.subplot.legend(**legendBoxProperties())
240 try:
241 self.datalims[curveRef] = (min(xData), max(xData), min(yData), max(yData))
242 except ValueError:
243 self.datalims[curveRef] = (0, 0, 0, 0)
244 self.__updateViewLimits()
245 return curveRef
246
248 """update data for a existing curve
249
250 curveRef -- internal reference to a curve
251 xData, yData -- x, y data to used for the curve
252 """
253 curveRef.set_data(xData, yData)
254 try:
255 self.datalims[curveRef] = (min(xData), max(xData), min(yData), max(yData))
256 except ValueError:
257 self.datalims[curveRef] = (0, 0, 0, 0)
258 self.__updateViewLimits()
259
261 """change curve style
262
263 curveRef -- internal reference to curves
264 style -- style dictionary
265 """
266 stylestr, properties = self.__translateStyles(style)
267
268
269 setp((curveRef,), **properties)
270 self.subplot.legend(**legendBoxProperties())
271
273 """remove curve from plot
274
275 curveRef -- internal reference to curves
276 """
277 del self.datalims[curveRef]
278 self.figure.gca().lines.remove(curveRef)
279 self.subplot.legend(**legendBoxProperties())
280 self.__updateViewLimits()
281
283 """adjust the subplot range in order to show all curves correctly.
284 """
285
286
287
288
289 if len(self.datalims) == 0 :
290 return
291
292 self.subplot.dataLim.ignore(True)
293 bounds = self.datalims.values()
294 xmin = min([b[0] for b in bounds])
295 xmax = max([b[1] for b in bounds])
296 ymin = min([b[2] for b in bounds])
297 ymax = max([b[3] for b in bounds])
298
299
300
301
302
303
304
305
306 if xmax > xmin:
307 self.subplot.set_xlim(xmin, xmax)
308 if ymax > ymin:
309 self.subplot.set_ylim(ymin, ymax)
310
312 """Private function to translate general probabilities to
313 Matplotlib specific ones
314
315 style -- general curve style dictionary (defined in demoplot)
316 """
317
318 lineStyleDict ={'solid':'-','dash':'--','dot':':','dashDot':'-.'}
319 symbolDict ={'diamond':'d','square':'s','circle':'o',
320 'cross':'+','xCross':'x','triangle':'^'}
321 colorDict = {'blue':'b','green':'g','red':'r','cyan':'c',
322 'magenta':'m','yellow':'y','black':'k','white':'w',
323 'darkRed':'#8B0000', 'darkGreen':'#006400', 'darkCyan':'#008B8B',
324 'darkYellow':'#FFD700','darkBlue':'#00008B','darkMagenta':'#8B008B'}
325
326 properties = {}
327
328
329
330 stylestr = ''
331
332 color = colorDict.get(style['color'], 'k')
333
334 if style['with'] in ('points', 'linespoints'):
335
336 stylestr = '.'
337 symbol = symbolDict.get(style['symbol'],'s')
338 symbolSize = style['symbolSize']
339 symbolColor = colorDict.get(style['symbolColor'], 'k')
340 properties.update({
341 'markerfacecolor':symbolColor,
342 'markeredgecolor':color,
343 'marker':symbol,'markersize':symbolSize})
344 if style['with'] != 'points':
345
346 lineStyle = lineStyleDict.get(style['line'],'-')
347 lineWidth = style['width']
348 stylestr += lineStyle
349 properties.update({'color':color,'linestyle':lineStyle,
350 'linewidth':lineWidth})
351
352 if style.has_key('legend'):
353 properties['label'] = style['legend']
354 return stylestr, properties
355
356
358 """set graph labels
359
360 wt -- window title
361 gt -- graph title
362 """
363 self.SetTitle(wt)
364 self.figure.gca().set_title(gt)
365
367 """set label for x axis
368
369 x -- x label
370 """
371 self.figure.gca().set_xlabel(x)
372
374 """set label for y axis
375
376 y -- y label
377 """
378 self.figure.gca().set_ylabel(y)
379
381 """erase all curves"""
382 self.subplot.clear()
383 self.curverefs =[]
384 self.replot()
385
386
387
388
390 """Legend properties dictionary with keys consistent with MPL version.
391
392 The argument names have changed in matplotlib 0.98.5.
393 Old arguments do not work with later versions of matplotlib.
394
395 Return dictionary of legend properties.
396 """
397 global _lbp
398
399 if len(_lbp) > 0: return _lbp
400
401 from pkg_resources import parse_version
402 from matplotlib import __version__ as mplver
403 if parse_version(mplver) >= parse_version('0.98.5'):
404 _lbp = {
405 'loc' : 'upper right',
406 'numpoints' : 3,
407 'borderpad' : 0.25,
408 'labelspacing' : 0,
409 'handlelength' : 1.5,
410 'handletextpad' : 0.5,
411 'prop' : FontProperties(size='medium'),
412 }
413 else:
414 _lbp = {
415 'loc' : 'upper right',
416 'numpoints' : 3,
417 'pad' : 0.20,
418 'labelsep' : 0.005,
419 'handlelen' : 0.03,
420 'handletextsep' : 0.02,
421 'prop' : FontProperties(size='medium'),
422 }
423 return _lbp
424
425 _lbp = {}
426
427
428
429
430 if __name__ == "__main__":
431
434 from matplotlib.numerix import arange, sin, pi, cos
435 'Create the main window and insert the custom frame'
436 x = arange(0.0,3.0,0.01)
437 s = sin(2*pi*x)
438 c = cos(2*pi*x)
439 t = sin(2*pi*x) + cos(2*pi*x)
440 frame = ExtendedPlotFrame(None)
441 style = {'with':'lines', 'color':'blue','line':'solid','width':2}
442 style['legend'] = 'sin(x)'
443 frame.insertCurve(x,s, style)
444 style = {'with':'lines', 'color':'red','line':'solid','width':2}
445 style['legend'] = 'cos(x)'
446 frame.insertCurve(x,c, style)
447 style = {'with':'lines', 'color':'black','line':'solid','width':2}
448
449 frame.insertCurve(x,t, style)
450 frame.Show(True)
451 return True
452
453 app = MyApp(0)
454 app.MainLoop()
455
456
457
458