wxmpl-2.0.0/0002755000175000017500000000000011647105502013117 5ustar segresegre00000000000000wxmpl-2.0.0/demos/0002755000175000017500000000000011647105502014226 5ustar segresegre00000000000000wxmpl-2.0.0/demos/picking_points.py0000755000175000017500000000775711647105364017647 0ustar segresegre00000000000000#!/usr/bin/env python # Name: WxMplPoints.py # Purpose: Demonstrates point picking in WxMpl # Author: Ken McIvor # # Copyright 2005 Illinois Institute of Technology # # See the file "LICENSE" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. import wx import wxmpl import numpy as NumPy import matplotlib.patches class MyApp(wx.App): def OnInit(self): self.frame = panel = MyFrame(None, -1, 'Point Picker') self.frame.Show(True) return True class MyFrame(wx.Frame): def __init__(self, parent, id, title, **kwds): wx.Frame.__init__(self, parent, id, title, **kwds) self.points = [] self.selectionPoints = [] self.plotPanel = wxmpl.PlotPanel(self, -1) self.regionButton = wx.ToggleButton(self, -1, 'Pick Region') self.pointButton = wx.ToggleButton(self, -1, 'Pick Point') wx.EVT_TOGGLEBUTTON(self, self.regionButton.GetId(), self._on_regionButton) wxmpl.EVT_POINT(self, self.plotPanel.GetId(), self._on_point) wxmpl.EVT_SELECTION(self, self.plotPanel.GetId(), self._on_selection) self._layout() self._replot() def _layout(self): btnSizer = wx.BoxSizer(wx.HORIZONTAL) btnSizer.Add((1, 1), 1, 0, 0) btnSizer.Add(self.regionButton, 0, wx.RIGHT, 5) btnSizer.Add(self.pointButton, 0) btnSizer.Add((20, 1), 0, 0, 0) sizer = wx.BoxSizer(wx.VERTICAL) sizer.Add(self.plotPanel, 1, wx.EXPAND, 5) sizer.Add(btnSizer, 0, wx.ALIGN_RIGHT|wx.ALL, 5) self.SetSizer(sizer) self.Fit() def _replot(self): PI = NumPy.pi t = NumPy.arange(0.0, 2.0, 0.01) s = NumPy.sin(2*PI*t) fig = self.plotPanel.get_figure() axes = fig.gca() # store the current zoom limits # NB: MPL 0.98.1 returns the underlying array objects of the limits xlim = tuple(axes.get_xlim()) ylim = tuple(axes.get_ylim()) # clear the axes and replot everything axes.cla() axes.plot(t, s, linewidth=1.0, label='sin') # plot the selected regions as rectangles for (xy, w, h) in self.selectionPoints: sel = matplotlib.patches.Rectangle(xy, w, h, edgecolor='k', facecolor='r', label='_nolegend_', alpha=0.25) axes.add_patch(sel) # plot the points if self.points: pts = NumPy.array(self.points) ptsY = NumPy.cos(2*PI*pts) axes.plot(pts, ptsY, 'go', markersize=5, label='pts') if 1 < len(self.points): rng = NumPy.arange(min(self.points), max(self.points), 0.01) rngY = NumPy.cos(2*PI*rng) axes.plot(rng, rngY, 'g-', linewidth=1, label='cos') axes.set_xlabel('time (s)') axes.set_ylabel('voltage (mV)') axes.set_title('Peter Plotter Picked a Peck of Picky Plotting') axes.legend() # restore the zoom limits (unless they're for an empty plot) if xlim != (0.0, 1.0) or ylim != (0.0, 1.0): axes.set_xlim(xlim) axes.set_ylim(ylim) # redraw the disply self.plotPanel.draw() def _on_regionButton(self, evt): if self.regionButton.GetValue(): self.plotPanel.set_zoom(False) else: self.plotPanel.set_zoom(True) def _on_selection(self, evt): self.plotPanel.set_zoom(True) self.regionButton.SetValue(False) x1, y1 = evt.x1data, evt.y1data x2, y2 = evt.x2data, evt.y2data self.selectionPoints.append(((x1, y1), x2-x1, y2-y1)) self._replot() def _on_point(self, evt): if self.pointButton.GetValue(): self.pointButton.SetValue(False) if evt.axes is not None: self.points.append(evt.xdata) self._replot() #app = wxmpl.PlotApp() #figure = app.get_figure() #plot_simple(figure) app = MyApp(False) app.MainLoop() wxmpl-2.0.0/demos/plotting.py0000755000175000017500000002160011150571521016435 0ustar segresegre00000000000000#!/usr/bin/env python # Purpose: Demonstrates different plots from the matplotlib examples collection # Author: Ken McIvor , deriving from the matplotlib examples # collection # # Copyright 2002-2004 John D. Hunter, 2005 Illinois Institute of Technology # # Distributed under the license agreement for matplotlib 0.72. # # For information on the usage and redistribution of this file, and for a # DISCLAIMER OF ALL WARRANTIES, see the file "LICENSE" that ships with the # matplotlib 0.72 or http://matplotlib.sourceforge.net/license.html __version__ = '1.0' import wx import wxmpl import matplotlib import matplotlib.cm as cm from pylab import array, arange, sin, cos, exp, pi, randn, normpdf, meshgrid, \ convolve def plot_simple(fig): t = arange(0.0, 2.0, 0.01) s = sin(2*pi*t) c = cos(2*pi*t) axes = fig.gca() axes.plot(t, s, linewidth=1.0) axes.plot(t, c, linewidth=1.0) axes.set_xlabel('time (s)') axes.set_ylabel('voltage (mV)') axes.set_title('About as simple as it gets, folks') axes.grid(True) def plot_subplot(fig): def f(t): return cos(2*pi*t) * exp(-t) t1 = arange(0.0, 5.0, 0.10) t2 = arange(0.0, 5.0, 0.02) a1 = fig.add_subplot(2, 1, 1) a1.plot(t1, f(t1), 'bo') a1.plot(t2, f(t2), 'k') a1.grid(True) a1.set_title('A Tale of 2 Subplots') a1.set_ylabel('Damped oscillation') a2 = fig.add_subplot(2, 1, 2) a2.plot(t2, cos(2*pi*t2), 'r>') a2.grid(True) a2.set_xlabel('time (s)') a2.set_ylabel('Undamped') def plot_subplot_sharex(fig): def f(t): return cos(2*pi*t) * exp(-t) t1 = arange(0.0, 5.0, 0.10) t2 = arange(0.0, 5.0, 0.02) a1 = fig.add_subplot(2, 1, 1) a1.plot(t1, f(t1), 'bo') a1.plot(t2, f(t2), 'k') a1.grid(True) a1.set_title('Two Subplots Sharing an Axis') a1.set_ylabel('Damped oscillation') for ticklabel in a1.get_xticklabels(): ticklabel.set_visible(False) a2 = fig.add_subplot(2, 1, 2, sharex=a1) a2.plot(t2, cos(2*pi*t2), 'r>') a2.grid(True) a2.set_xlabel('time (s)') a2.set_ylabel('Undamped') def plot_histogram(fig): mu, sigma = 100, 15 x = mu + sigma*randn(10000) axes = fig.gca() # the histogram of the data n, bins, patches = axes.hist(x, 100, normed=1) # add a 'best fit' line y = normpdf( bins, mu, sigma) l = axes.plot(bins, y, 'r--', linewidth=2) axes.set_xlim((40, 160)) axes.set_xlabel('Smarts') axes.set_ylabel('P') axes.set_title('IQ: mu=100, sigma=15') # axes.set_title(r'$\rm{IQ:}\/ \mu=100,\/ \sigma=15$') def plot_fill(fig): t = arange(0.0, 1.01, 0.01) s = sin(2*2*pi*t) axes = fig.gca() axes.fill(t, s*exp(-5*t), 'r') axes.grid(True) def plot_log(fig): dt = 0.01 t = arange(dt, 20.0, dt) a1 = fig.add_subplot(2, 1, 1) a1.semilogx(t, sin(2*pi*t)) a1.set_ylabel('semilogx') a1.grid(True) a2 = fig.add_subplot(2, 1, 2) a2.loglog(t, 20*exp(-t/10.0), basey=4) a2.xaxis.grid(True, which='minor') # minor grid on too a2.set_xlabel('time (s)') a2.set_ylabel('loglog') a2.grid(True) def plot_polar(fig): import pylab r = arange(0,1,0.001) theta = 2*2*pi*r # radar green, solid grid lines matplotlib.rc('grid', color='#316931', linewidth=1, linestyle='-') ax = fig.add_axes([0.1, 0.1, 0.8, 0.8], polar=True, axisbg='#d5de9c') ax.plot(theta, r, color='#ee8d18', lw=3) ax.set_title("And there was much rejoicing!", fontsize=14) matplotlib.rcdefaults() def plot_polar_subplot(fig): # # Polar demo # import pylab r = arange(0,1,0.001) theta = 2*2*pi*r # radar green, solid grid lines matplotlib.rc('grid', color='#316931', linewidth=1, linestyle='-') ax = fig.add_subplot(1, 2, 1, polar=True, axisbg='#d5de9c') ax.plot(theta, r, color='#ee8d18', lw=3) ax.set_title("And there was much rejoicing!", fontsize=14) matplotlib.rcdefaults() # # First part of the subplot demo # def f(t): return cos(2*pi*t) * exp(-t) t1 = arange(0.0, 5.0, 0.10) t2 = arange(0.0, 5.0, 0.02) A1 = fig.add_subplot(1, 2, 2) A1.plot(t1, f(t1), 'bo') A1.plot(t2, f(t2), 'k') A1.grid(True) A1.set_title('A tale of one subplot') A1.set_ylabel('Damped oscillation', fontsize=10) A1.set_xlabel('time (s)', fontsize=10) def plot_legend(fig): a = arange(0,3,.02) b = arange(0,3,.02) c = exp(a) d = c.tolist() d.reverse() d = array(d) axes = fig.gca() axes.plot(a,c,'k--',a,d,'k:',a,c+d,'k') axes.legend(('Model length', 'Data length', 'Total message length'), 'upper center', shadow=True) axes.set_ylim([-1,20]) axes.grid(False) axes.set_xlabel('Model complexity --->') axes.set_ylabel('Message length --->') axes.set_title('Minimum Message Length') axes.set_xticklabels([]) axes.set_yticklabels([]) def plot_image(fig): def func3(x,y): return (1- x/2 + x**5 + y**3)*exp(-x**2-y**2) dx, dy = 0.025, 0.025 x = arange(-3.0, 3.0, dx) y = arange(-3.0, 3.0, dy) X,Y = meshgrid(x, y) Z = func3(X, Y) axes = fig.gca() im = axes.imshow(Z, cmap=cm.jet, extent=(-3, 3, -3, 3)) def plot_layered_images(fig): def func3(x,y): return (1- x/2 + x**5 + y**3)*exp(-x**2-y**2) # make these smaller to increase the resolution dx, dy = 0.05, 0.05 x = arange(-3.0, 3.0, dx) y = arange(-3.0, 3.0, dy) X,Y = meshgrid(x, y) # when layering multiple images, the images need to have the same # extent. This does not mean they need to have the same shape, but # they both need to render to the same coordinate system determined by # xmin, xmax, ymin, ymax xmin, xmax, ymin, ymax = min(x), max(x), min(y), max(y) extent = xmin, xmax, ymin, ymax Z1 = array(([0,1]*4 + [1,0]*4)*4); Z1.shape = 8,8 # chessboard Z2 = func3(X, Y) axes = fig.gca() axes.imshow(Z1, cmap=cm.gray, interpolation='nearest', extent=extent) axes.hold(True) axes.imshow(Z2, cmap=cm.jet, alpha=.9, interpolation='bilinear', extent=extent) def plot_axes(fig): # create some data to use for the plot dt = 0.001 t = arange(0.0, 10.0, dt) r = exp(-t[:1000]/0.05) # impulse response x = randn(len(t)) s = convolve(x,r,mode=2)[:len(x)]*dt # colored noise # the main axes is subplot(111) by default axes = fig.gca() axes.plot(t, s) axes.set_xlim((0, 1)) axes.set_ylim((1.1*min(s), 2*max(s))) axes.set_xlabel('time (s)') axes.set_ylabel('current (nA)') axes.set_title('Gaussian colored noise') # this is an inset axes over the main axes a = fig.add_axes([.65, .6, .2, .2], axisbg='y') n, bins, patches = a.hist(s, 400, normed=1) a.set_title('Probability') a.set_xticks([]) a.set_yticks([]) # this is another inset axes over the main axes a = fig.add_axes([.2, .6, .2, .2], axisbg='y') a.plot(t[:len(r)], r) a.set_title('Impulse response') a.set_xlim((0, 0.2)) a.set_xticks([]) a.set_yticks([]) # # Demo Infrastructure # class Demo: def __init__(self, title, plotFunction, size=(6.0, 3.7), dpi=96): self.title = title self.plotFunction = plotFunction self.size = size self.dpi = dpi def run(self): frame = wxmpl.PlotFrame(None, -1, self.title, size=self.size, dpi=self.dpi) self.plotFunction(frame.get_figure()) frame.draw() frame.Show() def makeButton(self, parent): btn = wx.Button(parent, -1, self.title) wx.EVT_BUTTON(btn, btn.GetId(), self.OnButton) return btn def OnButton(self, evt): self.run() DEMONSTRATIONS = [ Demo('Simple Plot', plot_simple), Demo('Subplots', plot_subplot), Demo('Shared X Axes', plot_subplot_sharex), Demo('Histogram Plot', plot_histogram), Demo('Filled Polygons', plot_fill), Demo('Logarithmic Scaling', plot_log), Demo('Polar Plot', plot_polar, (6.0, 6.0)), Demo('Polar and Linear Subplots', plot_polar_subplot, (8.0,4.0)), Demo('Linear Plot with a Legend', plot_legend), Demo('Pseudocolor Image', plot_image), Demo('Layered Images', plot_layered_images), Demo('Overlapping Axes', plot_axes) ] class TestFrame(wx.Frame): def __init__(self, parent, id, title, **kwds): wx.Frame.__init__(self, parent, id, title, **kwds) buttons = [demo.makeButton(self) for demo in DEMONSTRATIONS] sizer = wx.BoxSizer(wx.VERTICAL) for btn in buttons: sizer.Add(btn, 0, wx.EXPAND|wx.ALL, 5) self.SetSizer(sizer) self.Fit() wx.EVT_WINDOW_DESTROY(self, self.OnWindowDestroy) def OnWindowDestroy(self, evt): wx.GetApp().ExitMainLoop() def main(): app = wx.PySimpleApp() frame = TestFrame(None, -1, 'WxMpl Demos') frame.Show(True) app.MainLoop() if __name__ == '__main__': main() wxmpl-2.0.0/demos/stripcharting.py0000755000175000017500000000525111647105364017473 0ustar segresegre00000000000000#!/usr/bin/env python # Purpose: Demonstrates stripcharting using wxmpl # Author: Ken McIvor # # Copyright 2005 Illinois Institute of Technology # # See the file "LICENSE" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. import wx import time import wxmpl from numpy import arange, cos, sin, pi, exp class StripchartApp(wx.App): def OnInit(self): self.timer = wx.PyTimer(self.OnTimer) self.numPoints = 0 self.frame = wxmpl.PlotFrame(None, -1, 'WxMpl Stripchart Demo') self.frame.Show(True) # The data to plot x = arange(0.0, 200, 0.1) y1 = 4*cos(2*pi*(x-1)/5.7)/(6+x) + 2*sin(2*pi*(x-1)/2.2)/(10) y2 = y1 + .5 y3 = y2 + .5 y4 = y3 + .5 # Fetch and setup the axes axes = self.frame.get_figure().gca() axes.set_title('Stripchart Test') axes.set_xlabel('t') axes.set_ylabel('f(t)') # Attach the StripCharter and define its channels self.charter = wxmpl.StripCharter(axes) self.charter.setChannels([ TestChannel('ch1', x, y1), TestChannel('ch2', x, y2), TestChannel('ch3', x, y3), TestChannel('ch4', x, y4) ]) # Prime the pump and start the timer self.charter.update() self.timer.Start(100) return True def OnTimer(self): # avoid wxPyDeadObject errors if not isinstance(self.frame, wxmpl.PlotFrame): self.timer.Stop() return if self.numPoints == self.charter.channels[0].x.shape[0]: self.timer.Stop() for channel in self.charter.channels: channel.tick() self.charter.update() class TestChannel(wxmpl.Channel): """ A data-provider that reveals another point every time its C{tick()} method is called. """ def __init__(self, name, x, y): """ Creates a new C{TestChannel} with the matplotlib label C{name} and X and Y vectors. """ wxmpl.Channel.__init__(self, name) self.x = x self.y = y self.idx = 0 def getX(self): """ Returns the current X vector. """ return self.x[0:self.idx] def getY(self): """ Returns the current Y vector. """ return self.y[0:self.idx] def tick(self): """ Reveals another point from the source X and Y vectors. """ if self.idx < self.x.shape[0]: self.setChanged(True) self.idx += 1 def main(): app = StripchartApp() app.MainLoop() if __name__ == '__main__': main() wxmpl-2.0.0/lib/0002755000175000017500000000000011647105502013665 5ustar segresegre00000000000000wxmpl-2.0.0/lib/wxmpl.py0000644000175000017500000017153511647105364015426 0ustar segresegre00000000000000# Purpose: painless matplotlib embedding for wxPython # Author: Ken McIvor # # Copyright 2005-2009 Illinois Institute of Technology # # See the file "LICENSE" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. """ Embedding matplotlib in wxPython applications is straightforward, but the default plotting widget lacks the capabilities necessary for interactive use. WxMpl (wxPython+matplotlib) is a library of components that provide these missing features in the form of a better matplolib FigureCanvas. """ import wx import sys import os.path import weakref import matplotlib matplotlib.use('WXAgg') import numpy as NumPy from matplotlib.axes import _process_plot_var_args from matplotlib.backend_bases import FigureCanvasBase from matplotlib.backends.backend_agg import FigureCanvasAgg, RendererAgg from matplotlib.backends.backend_wxagg import FigureCanvasWxAgg from matplotlib.figure import Figure from matplotlib.font_manager import FontProperties from matplotlib.projections.polar import PolarAxes from matplotlib.transforms import Bbox __version__ = '2.0dev' __all__ = ['PlotPanel', 'PlotFrame', 'PlotApp', 'StripCharter', 'Channel', 'FigurePrinter', 'PointEvent', 'EVT_POINT', 'SelectionEvent', 'EVT_SELECTION'] # If you are using wxGtk without libgnomeprint and want to use something other # than `lpr' to print you will have to specify that command here. POSTSCRIPT_PRINTING_COMMAND = 'lpr' # Between 0.98.1 and 0.98.3rc there were some significant API changes: # * FigureCanvasWx.draw(repaint=True) became draw(drawDC=None) # * The following events were added: # - figure_enter_event # - figure_leave_event # - axes_enter_event # - axes_leave_event MATPLOTLIB_0_98_3 = '0.98.3' <= matplotlib.__version__ # # Utility functions and classes # def invert_point(x, y, transform): """ Returns a coordinate inverted by the specificed C{Transform}. """ return transform.inverted().transform_point((x, y)) def find_axes(canvas, x, y): """ Finds the C{Axes} within a matplotlib C{FigureCanvas} contains the canvas coordinates C{(x, y)} and returns that axes and the corresponding data coordinates C{xdata, ydata} as a 3-tuple. If no axes contains the specified point a 3-tuple of C{None} is returned. """ evt = matplotlib.backend_bases.MouseEvent('', canvas, x, y) axes = None for a in canvas.get_figure().get_axes(): if a.in_axes(evt): if axes is None: axes = a else: return None, None, None if axes is None: return None, None, None xdata, ydata = invert_point(x, y, axes.transData) return axes, xdata, ydata def get_bbox_lims(bbox): """ Returns the boundaries of the X and Y intervals of a C{Bbox}. """ p0 = bbox.min p1 = bbox.max return (p0[0], p1[0]), (p0[1], p1[1]) def find_selected_axes(canvas, x1, y1, x2, y2): """ Finds the C{Axes} within a matplotlib C{FigureCanvas} that overlaps with a canvas area from C{(x1, y1)} to C{(x1, y1)}. That axes and the corresponding X and Y axes ranges are returned as a 3-tuple. If no axes overlaps with the specified area, or more than one axes overlaps, a 3-tuple of C{None}s is returned. """ axes = None bbox = Bbox.from_extents(x1, y1, x2, y2) for a in canvas.get_figure().get_axes(): if bbox.overlaps(a.bbox): if axes is None: axes = a else: return None, None, None if axes is None: return None, None, None x1, y1, x2, y2 = limit_selection(bbox, axes) xrange, yrange = get_bbox_lims( Bbox.from_extents(x1, y1, x2, y2).inverse_transformed(axes.transData)) return axes, xrange, yrange def limit_selection(bbox, axes): """ Finds the region of a selection C{bbox} which overlaps with the supplied C{axes} and returns it as the 4-tuple C{(xmin, ymin, xmax, ymax)}. """ bxr, byr = get_bbox_lims(bbox) axr, ayr = get_bbox_lims(axes.bbox) xmin = max(bxr[0], axr[0]) xmax = min(bxr[1], axr[1]) ymin = max(byr[0], ayr[0]) ymax = min(byr[1], ayr[1]) return xmin, ymin, xmax, ymax def format_coord(axes, xdata, ydata): """ A C{None}-safe version of {Axes.format_coord()}. """ if xdata is None or ydata is None: return '' return axes.format_coord(xdata, ydata) def toplevel_parent_of_window(window): """ Returns the first top-level parent of a wx.Window """ topwin = window while not isinstance(topwin, wx.TopLevelWindow): topwin = topwin.GetParent() return topwin class AxesLimits: """ Alters the X and Y limits of C{Axes} objects while maintaining a history of the changes. """ def __init__(self, autoscaleUnzoom): self.autoscaleUnzoom = autoscaleUnzoom self.history = weakref.WeakKeyDictionary() def setAutoscaleUnzoom(self, state): """ Enable or disable autoscaling the axes as a result of zooming all the way back out. """ self.limits.setAutoscaleUnzoom(state) def _get_history(self, axes): """ Returns the history list of X and Y limits associated with C{axes}. """ return self.history.setdefault(axes, []) def zoomed(self, axes): """ Returns a boolean indicating whether C{axes} has had its limits altered. """ return not (not self._get_history(axes)) def set(self, axes, xrange, yrange): """ Changes the X and Y limits of C{axes} to C{xrange} and {yrange} respectively. A boolean indicating whether or not the axes should be redraw is returned, because polar axes cannot have their limits changed sensibly. """ if not axes.can_zoom(): return False # The axes limits must be converted to tuples because MPL 0.98.1 # returns the underlying array objects oldRange = tuple(axes.get_xlim()), tuple(axes.get_ylim()) history = self._get_history(axes) history.append(oldRange) axes.set_xlim(xrange) axes.set_ylim(yrange) return True def restore(self, axes): """ Changes the X and Y limits of C{axes} to their previous values. A boolean indicating whether or not the axes should be redraw is returned. """ history = self._get_history(axes) if not history: return False xrange, yrange = history.pop() if self.autoscaleUnzoom and not len(history): axes.autoscale_view() else: axes.set_xlim(xrange) axes.set_ylim(yrange) return True # # Director of the matplotlib canvas # class PlotPanelDirector: """ Encapsulates all of the user-interaction logic required by the C{PlotPanel}, following the Humble Dialog Box pattern proposed by Michael Feathers: U{http://www.objectmentor.com/resources/articles/TheHumbleDialogBox.pdf} """ # TODO: add a programmatic interface to zooming and user interactions # TODO: full support for MPL events def __init__(self, view, zoom=True, selection=True, rightClickUnzoom=True, autoscaleUnzoom=True): """ Create a new director for the C{PlotPanel} C{view}. The keyword arguments C{zoom} and C{selection} have the same meanings as for C{PlotPanel}. """ self.view = view self.zoomEnabled = zoom self.selectionEnabled = selection self.rightClickUnzoom = rightClickUnzoom self.limits = AxesLimits(autoscaleUnzoom) self.leftButtonPoint = None def setSelection(self, state): """ Enable or disable left-click area selection. """ self.selectionEnabled = state def setZoomEnabled(self, state): """ Enable or disable zooming as a result of left-click area selection. """ self.zoomEnabled = state def setAutoscaleUnzoom(self, state): """ Enable or disable autoscaling the axes as a result of zooming all the way back out. """ self.limits.setAutoscaleUnzoom(state) def setRightClickUnzoom(self, state): """ Enable or disable unzooming as a result of right-clicking. """ self.rightClickUnzoom = state def canDraw(self): """ Indicates if plot may be not redrawn due to the presence of a selection box. """ return self.leftButtonPoint is None def zoomed(self, axes): """ Returns a boolean indicating whether or not the plot has been zoomed in as a result of a left-click area selection. """ return self.limits.zoomed(axes) def keyDown(self, evt): """ Handles wxPython key-press events. These events are currently skipped. """ evt.Skip() def keyUp(self, evt): """ Handles wxPython key-release events. These events are currently skipped. """ evt.Skip() def leftButtonDown(self, evt, x, y): """ Handles wxPython left-click events. """ self.leftButtonPoint = (x, y) view = self.view axes, xdata, ydata = find_axes(view, x, y) if axes is not None and self.selectionEnabled and axes.can_zoom(): view.cursor.setCross() view.crosshairs.clear() def leftButtonUp(self, evt, x, y): """ Handles wxPython left-click-release events. """ if self.leftButtonPoint is None: return view = self.view axes, xdata, ydata = find_axes(view, x, y) x0, y0 = self.leftButtonPoint self.leftButtonPoint = None view.rubberband.clear() if x0 == x: if y0 == y and axes is not None: view.notify_point(axes, x, y) view.crosshairs.set(x, y) return elif y0 == y: return xdata = ydata = None axes, xrange, yrange = find_selected_axes(view, x0, y0, x, y) if axes is not None: xdata, ydata = invert_point(x, y, axes.transData) if self.zoomEnabled: if self.limits.set(axes, xrange, yrange): self.view.draw() else: bbox = Bbox.from_extents(x0, y0, x, y) x1, y1, x2, y2 = limit_selection(bbox, axes) self.view.notify_selection(axes, x1, y1, x2, y2) if axes is None: view.cursor.setNormal() elif not axes.can_zoom(): view.cursor.setNormal() view.location.set(format_coord(axes, xdata, ydata)) else: view.crosshairs.set(x, y) view.location.set(format_coord(axes, xdata, ydata)) def rightButtonDown(self, evt, x, y): """ Handles wxPython right-click events. These events are currently skipped. """ evt.Skip() def rightButtonUp(self, evt, x, y): """ Handles wxPython right-click-release events. """ view = self.view axes, xdata, ydata = find_axes(view, x, y) if (axes is not None and self.zoomEnabled and self.rightClickUnzoom and self.limits.restore(axes)): view.crosshairs.clear() view.draw() view.crosshairs.set(x, y) def mouseMotion(self, evt, x, y): """ Handles wxPython mouse motion events, dispatching them based on whether or not a selection is in process and what the cursor is over. """ view = self.view axes, xdata, ydata = find_axes(view, x, y) if self.leftButtonPoint is not None: self.selectionMouseMotion(evt, x, y, axes, xdata, ydata) else: if axes is None: self.canvasMouseMotion(evt, x, y) elif not axes.can_zoom(): self.unzoomableAxesMouseMotion(evt, x, y, axes, xdata, ydata) else: self.axesMouseMotion(evt, x, y, axes, xdata, ydata) def selectionMouseMotion(self, evt, x, y, axes, xdata, ydata): """ Handles wxPython mouse motion events that occur during a left-click area selection. """ view = self.view x0, y0 = self.leftButtonPoint view.rubberband.set(x0, y0, x, y) if axes is None: view.location.clear() else: view.location.set(format_coord(axes, xdata, ydata)) def canvasMouseMotion(self, evt, x, y): """ Handles wxPython mouse motion events that occur over the canvas. """ view = self.view view.cursor.setNormal() view.crosshairs.clear() view.location.clear() def axesMouseMotion(self, evt, x, y, axes, xdata, ydata): """ Handles wxPython mouse motion events that occur over an axes. """ view = self.view view.cursor.setCross() view.crosshairs.set(x, y) view.location.set(format_coord(axes, xdata, ydata)) def unzoomableAxesMouseMotion(self, evt, x, y, axes, xdata, ydata): """ Handles wxPython mouse motion events that occur over an axes that does not support zooming. """ view = self.view view.cursor.setNormal() view.location.set(format_coord(axes, xdata, ydata)) # # Components used by the PlotPanel # class Painter: """ Painters encapsulate the mechanics of drawing some value in a wxPython window and erasing it. Subclasses override template methods to process values and draw them. @cvar PEN: C{wx.Pen} to use (defaults to C{wx.BLACK_PEN}) @cvar BRUSH: C{wx.Brush} to use (defaults to C{wx.TRANSPARENT_BRUSH}) @cvar FUNCTION: Logical function to use (defaults to C{wx.COPY}) @cvar FONT: C{wx.Font} to use (defaults to C{wx.NORMAL_FONT}) @cvar TEXT_FOREGROUND: C{wx.Colour} to use (defaults to C{wx.BLACK}) @cvar TEXT_BACKGROUND: C{wx.Colour} to use (defaults to C{wx.WHITE}) """ PEN = wx.BLACK_PEN BRUSH = wx.TRANSPARENT_BRUSH FUNCTION = wx.COPY FONT = wx.NORMAL_FONT TEXT_FOREGROUND = wx.BLACK TEXT_BACKGROUND = wx.WHITE def __init__(self, view, enabled=True): """ Create a new painter attached to the wxPython window C{view}. The keyword argument C{enabled} has the same meaning as the argument to the C{setEnabled()} method. """ self.view = view self.lastValue = None self.enabled = enabled def setEnabled(self, state): """ Enable or disable this painter. Disabled painters do not draw their values and calls to C{set()} have no effect on them. """ oldState, self.enabled = self.enabled, state if oldState and not self.enabled: self.clear() def set(self, *value): """ Update this painter's value and then draw it. Values may not be C{None}, which is used internally to represent the absence of a current value. """ if self.enabled: value = self.formatValue(value) self._paint(value, None) def redraw(self, dc=None): """ Redraw this painter's current value. """ value = self.lastValue self.lastValue = None self._paint(value, dc) def clear(self, dc=None): """ Clear the painter's current value from the screen and the painter itself. """ if self.lastValue is not None: self._paint(None, dc) def _paint(self, value, dc): """ Draws a previously processed C{value} on this painter's window. """ if dc is None: dc = wx.ClientDC(self.view) dc.SetPen(self.PEN) dc.SetBrush(self.BRUSH) dc.SetFont(self.FONT) dc.SetTextForeground(self.TEXT_FOREGROUND) dc.SetTextBackground(self.TEXT_BACKGROUND) dc.SetLogicalFunction(self.FUNCTION) dc.BeginDrawing() if self.lastValue is not None: self.clearValue(dc, self.lastValue) self.lastValue = None if value is not None: self.drawValue(dc, value) self.lastValue = value dc.EndDrawing() def formatValue(self, value): """ Template method that processes the C{value} tuple passed to the C{set()} method, returning the processed version. """ return value def drawValue(self, dc, value): """ Template method that draws a previously processed C{value} using the wxPython device context C{dc}. This DC has already been configured, so calls to C{BeginDrawing()} and C{EndDrawing()} may not be made. """ pass def clearValue(self, dc, value): """ Template method that clears a previously processed C{value} that was previously drawn, using the wxPython device context C{dc}. This DC has already been configured, so calls to C{BeginDrawing()} and C{EndDrawing()} may not be made. """ pass class LocationPainter(Painter): """ Draws a text message containing the current position of the mouse in the lower left corner of the plot. """ PADDING = 2 PEN = wx.WHITE_PEN BRUSH = wx.WHITE_BRUSH def formatValue(self, value): """ Extracts a string from the 1-tuple C{value}. """ return value[0] def get_XYWH(self, dc, value): """ Returns the upper-left coordinates C{(X, Y)} for the string C{value} its width and height C{(W, H)}. """ height = dc.GetSize()[1] w, h = dc.GetTextExtent(value) x = self.PADDING y = int(height - (h + self.PADDING)) return x, y, w, h def drawValue(self, dc, value): """ Draws the string C{value} in the lower left corner of the plot. """ x, y, w, h = self.get_XYWH(dc, value) dc.DrawText(value, x, y) def clearValue(self, dc, value): """ Clears the string C{value} from the lower left corner of the plot by painting a white rectangle over it. """ x, y, w, h = self.get_XYWH(dc, value) dc.DrawRectangle(x, y, w, h) class CrosshairPainter(Painter): """ Draws crosshairs through the current position of the mouse. """ PEN = wx.WHITE_PEN FUNCTION = wx.XOR def formatValue(self, value): """ Converts the C{(X, Y)} mouse coordinates from matplotlib to wxPython. """ x, y = value return int(x), int(self.view.get_figure().bbox.height - y) def drawValue(self, dc, value): """ Draws crosshairs through the C{(X, Y)} coordinates. """ dc.CrossHair(*value) def clearValue(self, dc, value): """ Clears the crosshairs drawn through the C{(X, Y)} coordinates. """ dc.CrossHair(*value) class RubberbandPainter(Painter): """ Draws a selection rubberband from one point to another. """ PEN = wx.WHITE_PEN FUNCTION = wx.XOR def formatValue(self, value): """ Converts the C{(x1, y1, x2, y2)} mouse coordinates from matplotlib to wxPython. """ x1, y1, x2, y2 = value height = self.view.get_figure().bbox.height y1 = height - y1 y2 = height - y2 if x2 < x1: x1, x2 = x2, x1 if y2 < y1: y1, y2 = y2, y1 return [int(z) for z in (x1, y1, x2-x1, y2-y1)] def drawValue(self, dc, value): """ Draws the selection rubberband around the rectangle C{(x1, y1, x2, y2)}. """ dc.DrawRectangle(*value) def clearValue(self, dc, value): """ Clears the selection rubberband around the rectangle C{(x1, y1, x2, y2)}. """ dc.DrawRectangle(*value) class CursorChanger: """ Manages the current cursor of a wxPython window, allowing it to be switched between a normal arrow and a square cross. """ def __init__(self, view, enabled=True): """ Create a CursorChanger attached to the wxPython window C{view}. The keyword argument C{enabled} has the same meaning as the argument to the C{setEnabled()} method. """ self.view = view self.cursor = wx.CURSOR_DEFAULT self.enabled = enabled def setEnabled(self, state): """ Enable or disable this cursor changer. When disabled, the cursor is reset to the normal arrow and calls to the C{set()} methods have no effect. """ oldState, self.enabled = self.enabled, state if oldState and not self.enabled and self.cursor != wx.CURSOR_DEFAULT: self.cursor = wx.CURSOR_DEFAULT self.view.SetCursor(wx.STANDARD_CURSOR) def setNormal(self): """ Change the cursor of the associated window to a normal arrow. """ if self.cursor != wx.CURSOR_DEFAULT and self.enabled: self.cursor = wx.CURSOR_DEFAULT self.view.SetCursor(wx.STANDARD_CURSOR) def setCross(self): """ Change the cursor of the associated window to a square cross. """ if self.cursor != wx.CURSOR_CROSS and self.enabled: self.cursor = wx.CURSOR_CROSS self.view.SetCursor(wx.CROSS_CURSOR) # # Printing Framework # # PostScript resolutions for the various WX print qualities PS_DPI_HIGH_QUALITY = 600 PS_DPI_MEDIUM_QUALITY = 300 PS_DPI_LOW_QUALITY = 150 PS_DPI_DRAFT_QUALITY = 72 def update_postscript_resolution(printData): """ Sets the default wx.PostScriptDC resolution from a wx.PrintData's quality setting. This is a workaround for WX ignoring the quality setting and defaulting to 72 DPI. Unfortunately wx.Printout.GetDC() returns a wx.DC object instead of the actual class, so it's impossible to set the resolution on the DC itself. Even more unforuntately, printing with libgnomeprint appears to always be stuck at 72 DPI. """ if not callable(getattr(wx, 'PostScriptDC_SetResolution', None)): return quality = printData.GetQuality() if quality > 0: dpi = quality elif quality == wx.PRINT_QUALITY_HIGH: dpi = PS_DPI_HIGH_QUALITY elif quality == wx.PRINT_QUALITY_MEDIUM: dpi = PS_DPI_MEDIUM_QUALITY elif quality == wx.PRINT_QUALITY_LOW: dpi = PS_DPI_LOW_QUALITY elif quality == wx.PRINT_QUALITY_DRAFT: dpi = PS_DPI_DRAFT_QUALITY else: dpi = PS_DPI_HIGH_QUALITY wx.PostScriptDC_SetResolution(dpi) class FigurePrinter: """ Provides a simplified interface to the wxPython printing framework that's designed for printing matplotlib figures. """ def __init__(self, view, printData=None): """ Create a new C{FigurePrinter} associated with the wxPython widget C{view}. The keyword argument C{printData} supplies a C{wx.PrintData} object containing the default printer settings. """ self.view = view if printData is None: printData = wx.PrintData() self.setPrintData(printData) def getPrintData(self): """ Return the current printer settings in their C{wx.PrintData} object. """ return self.pData def setPrintData(self, printData): """ Use the printer settings in C{printData}. """ self.pData = printData update_postscript_resolution(self.pData) def pageSetup(self): dlg = wx.PrintDialog(self.view) pdData = dlg.GetPrintDialogData() pdData.SetPrintData(self.pData) if dlg.ShowModal() == wx.ID_OK: self.setPrintData(pdData.GetPrintData()) dlg.Destroy() def previewFigure(self, figure, title=None): """ Open a "Print Preview" window for the matplotlib chart C{figure}. The keyword argument C{title} provides the printing framework with a title for the print job. """ topwin = toplevel_parent_of_window(self.view) fpo = FigurePrintout(figure, title) fpo4p = FigurePrintout(figure, title) preview = wx.PrintPreview(fpo, fpo4p, self.pData) frame = wx.PreviewFrame(preview, topwin, 'Print Preview') if self.pData.GetOrientation() == wx.PORTRAIT: frame.SetSize(wx.Size(450, 625)) else: frame.SetSize(wx.Size(600, 500)) frame.Initialize() frame.Show(True) def printFigure(self, figure, title=None): """ Open a "Print" dialog to print the matplotlib chart C{figure}. The keyword argument C{title} provides the printing framework with a title for the print job. """ pdData = wx.PrintDialogData() pdData.SetPrintData(self.pData) printer = wx.Printer(pdData) fpo = FigurePrintout(figure, title) if printer.Print(self.view, fpo, True): self.setPrintData(pdData.GetPrintData()) class FigurePrintout(wx.Printout): """ Render a matplotlib C{Figure} to a page or file using wxPython's printing framework. """ ASPECT_RECTANGULAR = 1 ASPECT_SQUARE = 2 def __init__(self, figure, title=None, size=None, aspectRatio=None): """ Create a printout for the matplotlib chart C{figure}. The keyword argument C{title} provides the printing framework with a title for the print job. The keyword argument C{size} specifies how to scale the figure, from 1 to 100 percent. The keyword argument C{aspectRatio} determines whether the printed figure will be rectangular or square. """ self.figure = figure figTitle = figure.gca().title.get_text() if not figTitle: figTitle = title or 'Matplotlib Figure' if size is None: size = 100 elif size < 1 or size > 100: raise ValueError('invalid figure size') self.size = size if aspectRatio is None: aspectRatio = self.ASPECT_RECTANGULAR elif (aspectRatio != self.ASPECT_RECTANGULAR and aspectRatio != self.ASPECT_SQUARE): raise ValueError('invalid aspect ratio') self.aspectRatio = aspectRatio wx.Printout.__init__(self, figTitle) def GetPageInfo(self): """ Overrides wx.Printout.GetPageInfo() to provide the printing framework with the number of pages in this print job. """ return (1, 1, 1, 1) def HasPage(self, pageNumber): """ Overrides wx.Printout.GetPageInfo() to tell the printing framework of the specified page exists. """ return pageNumber == 1 def OnPrintPage(self, pageNumber): """ Overrides wx.Printout.OnPrintPage() to render the matplotlib figure to a printing device context. """ # % of printable area to use imgPercent = max(1, min(100, self.size)) / 100.0 # ratio of the figure's width to its height if self.aspectRatio == self.ASPECT_RECTANGULAR: aspectRatio = 1.61803399 elif self.aspectRatio == self.ASPECT_SQUARE: aspectRatio = 1.0 else: raise ValueError('invalid aspect ratio') # Device context to draw the page dc = self.GetDC() # PPI_P: Pixels Per Inch of the Printer wPPI_P, hPPI_P = [float(x) for x in self.GetPPIPrinter()] PPI_P = (wPPI_P + hPPI_P)/2.0 # PPI: Pixels Per Inch of the DC if self.IsPreview(): wPPI, hPPI = [float(x) for x in self.GetPPIScreen()] else: wPPI, hPPI = wPPI_P, hPPI_P PPI = (wPPI + hPPI)/2.0 # Pg_Px: Size of the page (pixels) wPg_Px, hPg_Px = [float(x) for x in self.GetPageSizePixels()] # Dev_Px: Size of the DC (pixels) wDev_Px, hDev_Px = [float(x) for x in self.GetDC().GetSize()] # Pg: Size of the page (inches) wPg = wPg_Px / PPI_P hPg = hPg_Px / PPI_P # minimum margins (inches) wM = 0.75 hM = 0.75 # Area: printable area within the margins (inches) wArea = wPg - 2*wM hArea = hPg - 2*hM # Fig: printing size of the figure # hFig is at a maximum when wFig == wArea max_hFig = wArea / aspectRatio hFig = min(imgPercent * hArea, max_hFig) wFig = aspectRatio * hFig # scale factor = device size / page size (equals 1.0 for real printing) S = ((wDev_Px/PPI)/wPg + (hDev_Px/PPI)/hPg)/2.0 # Fig_S: scaled printing size of the figure (inches) # M_S: scaled minimum margins (inches) wFig_S = S * wFig hFig_S = S * hFig wM_S = S * wM hM_S = S * hM # Fig_Dx: scaled printing size of the figure (device pixels) # M_Dx: scaled minimum margins (device pixels) wFig_Dx = int(S * PPI * wFig) hFig_Dx = int(S * PPI * hFig) wM_Dx = int(S * PPI * wM) hM_Dx = int(S * PPI * hM) image = self.render_figure_as_image(wFig, hFig, PPI) if self.IsPreview(): image = image.Scale(wFig_Dx, hFig_Dx) self.GetDC().DrawBitmap(image.ConvertToBitmap(), wM_Dx, hM_Dx, False) return True def render_figure_as_image(self, wFig, hFig, dpi): """ Renders a matplotlib figure using the Agg backend and stores the result in a C{wx.Image}. The arguments C{wFig} and {hFig} are the width and height of the figure, and C{dpi} is the dots-per-inch to render at. """ figure = self.figure old_dpi = figure.dpi figure.dpi = dpi old_width = figure.get_figwidth() figure.set_figwidth(wFig) old_height = figure.get_figheight() figure.set_figheight(hFig) old_frameon = figure.frameon figure.frameon = False wFig_Px = int(figure.bbox.width) hFig_Px = int(figure.bbox.height) agg = RendererAgg(wFig_Px, hFig_Px, dpi) figure.draw(agg) figure.dpi = old_dpi figure.set_figwidth(old_width) figure.set_figheight(old_height) figure.frameon = old_frameon image = wx.EmptyImage(wFig_Px, hFig_Px) image.SetData(agg.tostring_rgb()) return image # # wxPython event interface for the PlotPanel and PlotFrame # EVT_POINT_ID = wx.NewId() def EVT_POINT(win, id, func): """ Register to receive wxPython C{PointEvent}s from a C{PlotPanel} or C{PlotFrame}. """ win.Connect(id, -1, EVT_POINT_ID, func) class PointEvent(wx.PyCommandEvent): """ wxPython event emitted when a left-click-release occurs in a matplotlib axes of a window without an area selection. @cvar axes: matplotlib C{Axes} which was left-clicked @cvar x: matplotlib X coordinate @cvar y: matplotlib Y coordinate @cvar xdata: axes X coordinate @cvar ydata: axes Y coordinate """ def __init__(self, id, axes, x, y): """ Create a new C{PointEvent} for the matplotlib coordinates C{(x, y)} of an C{axes}. """ wx.PyCommandEvent.__init__(self, EVT_POINT_ID, id) self.axes = axes self.x = x self.y = y self.xdata, self.ydata = invert_point(x, y, axes.transData) def Clone(self): return PointEvent(self.GetId(), self.axes, self.x, self.y) EVT_SELECTION_ID = wx.NewId() def EVT_SELECTION(win, id, func): """ Register to receive wxPython C{SelectionEvent}s from a C{PlotPanel} or C{PlotFrame}. """ win.Connect(id, -1, EVT_SELECTION_ID, func) class SelectionEvent(wx.PyCommandEvent): """ wxPython event emitted when an area selection occurs in a matplotlib axes of a window for which zooming has been disabled. The selection is described by a rectangle from C{(x1, y1)} to C{(x2, y2)}, of which only one point is required to be inside the axes. @cvar axes: matplotlib C{Axes} which was left-clicked @cvar x1: matplotlib x1 coordinate @cvar y1: matplotlib y1 coordinate @cvar x2: matplotlib x2 coordinate @cvar y2: matplotlib y2 coordinate @cvar x1data: axes x1 coordinate @cvar y1data: axes y1 coordinate @cvar x2data: axes x2 coordinate @cvar y2data: axes y2 coordinate """ def __init__(self, id, axes, x1, y1, x2, y2): """ Create a new C{SelectionEvent} for the area described by the rectangle from C{(x1, y1)} to C{(x2, y2)} in an C{axes}. """ wx.PyCommandEvent.__init__(self, EVT_SELECTION_ID, id) self.axes = axes self.x1 = x1 self.y1 = y1 self.x2 = x2 self.y2 = y2 self.x1data, self.y1data = invert_point(x1, y1, axes.transData) self.x2data, self.y2data = invert_point(x2, y2, axes.transData) def Clone(self): return SelectionEvent(self.GetId(), self.axes, self.x1, self.y1, self.x2, self.y2) # # Matplotlib canvas in a wxPython window # class PlotPanel(FigureCanvasWxAgg): """ A matplotlib canvas suitable for embedding in wxPython applications. """ def __init__(self, parent, id, size=(6.0, 3.70), dpi=96, cursor=True, location=True, crosshairs=True, selection=True, zoom=True, autoscaleUnzoom=True): """ Creates a new PlotPanel window that is the child of the wxPython window C{parent} with the wxPython identifier C{id}. The keyword arguments C{size} and {dpi} are used to create the matplotlib C{Figure} associated with this canvas. C{size} is the desired width and height of the figure, in inches, as the 2-tuple C{(width, height)}. C{dpi} is the dots-per-inch of the figure. The keyword arguments C{cursor}, C{location}, C{crosshairs}, C{selection}, C{zoom}, and C{autoscaleUnzoom} enable or disable various user interaction features that are descibed in their associated C{set()} methods. """ FigureCanvasWxAgg.__init__(self, parent, id, Figure(size, dpi)) self.insideOnPaint = False self.cursor = CursorChanger(self, cursor) self.location = LocationPainter(self, location) self.crosshairs = CrosshairPainter(self, crosshairs) self.rubberband = RubberbandPainter(self, selection) rightClickUnzoom = True # for now this is default behavior self.director = PlotPanelDirector(self, zoom, selection, rightClickUnzoom, autoscaleUnzoom) self.figure.set_edgecolor('black') self.figure.set_facecolor('white') self.SetBackgroundColour(wx.WHITE) # find the toplevel parent window and register an activation event # handler that is keyed to the id of this PlotPanel topwin = toplevel_parent_of_window(self) topwin.Connect(-1, self.GetId(), wx.wxEVT_ACTIVATE, self.OnActivate) wx.EVT_ERASE_BACKGROUND(self, self.OnEraseBackground) wx.EVT_WINDOW_DESTROY(self, self.OnDestroy) def OnActivate(self, evt): """ Handles the wxPython window activation event. """ if not evt.GetActive(): self.cursor.setNormal() self.location.clear() self.crosshairs.clear() self.rubberband.clear() evt.Skip() def OnEraseBackground(self, evt): """ Overrides the wxPython backround repainting event to reduce flicker. """ pass def OnDestroy(self, evt): """ Handles the wxPython window destruction event. """ if self.GetId() == evt.GetEventObject().GetId(): # unregister the activation event handler for this PlotPanel topwin = toplevel_parent_of_window(self) topwin.Disconnect(-1, self.GetId(), wx.wxEVT_ACTIVATE) def _onPaint(self, evt): """ Overrides the C{FigureCanvasWxAgg} paint event to redraw the crosshairs, etc. """ # avoid wxPyDeadObject errors if not isinstance(self, FigureCanvasWxAgg): return self.insideOnPaint = True FigureCanvasWxAgg._onPaint(self, evt) self.insideOnPaint = False dc = wx.PaintDC(self) self.location.redraw(dc) self.crosshairs.redraw(dc) self.rubberband.redraw(dc) def get_figure(self): """ Returns the figure associated with this canvas. """ return self.figure def set_cursor(self, state): """ Enable or disable the changing mouse cursor. When enabled, the cursor changes from the normal arrow to a square cross when the mouse enters a matplotlib axes on this canvas. """ self.cursor.setEnabled(state) def set_location(self, state): """ Enable or disable the display of the matplotlib axes coordinates of the mouse in the lower left corner of the canvas. """ self.location.setEnabled(state) def set_crosshairs(self, state): """ Enable or disable drawing crosshairs through the mouse cursor when it is inside a matplotlib axes. """ self.crosshairs.setEnabled(state) def set_selection(self, state): """ Enable or disable area selections, where user selects a rectangular area of the canvas by left-clicking and dragging the mouse. """ self.rubberband.setEnabled(state) self.director.setSelection(state) def set_zoom(self, state): """ Enable or disable zooming in when the user makes an area selection and zooming out again when the user right-clicks. """ self.director.setZoomEnabled(state) def set_autoscale_unzoom(self, state): """ Enable or disable automatic view rescaling when the user zooms out to the initial figure. """ self.director.setAutoscaleUnzoom(state) def zoomed(self, axes): """ Returns a boolean indicating whether or not the C{axes} is zoomed in. """ return self.director.zoomed(axes) def draw(self, **kwds): """ Draw the associated C{Figure} onto the screen. """ # don't redraw if the left mouse button is down and avoid # wxPyDeadObject errors if (not self.director.canDraw() or not isinstance(self, FigureCanvasWxAgg)): return if MATPLOTLIB_0_98_3: FigureCanvasWxAgg.draw(self, kwds.get('drawDC', None)) else: FigureCanvasWxAgg.draw(self, kwds.get('repaint', True)) # Don't redraw the decorations when called by _onPaint() if not self.insideOnPaint: self.location.redraw() self.crosshairs.redraw() self.rubberband.redraw() def notify_point(self, axes, x, y): """ Called by the associated C{PlotPanelDirector} to emit a C{PointEvent}. """ wx.PostEvent(self, PointEvent(self.GetId(), axes, x, y)) def notify_selection(self, axes, x1, y1, x2, y2): """ Called by the associated C{PlotPanelDirector} to emit a C{SelectionEvent}. """ wx.PostEvent(self, SelectionEvent(self.GetId(), axes, x1, y1, x2, y2)) def _get_canvas_xy(self, evt): """ Returns the X and Y coordinates of a wxPython event object converted to matplotlib canavas coordinates. """ return evt.GetX(), int(self.figure.bbox.height - evt.GetY()) def _onKeyDown(self, evt): """ Overrides the C{FigureCanvasWxAgg} key-press event handler, dispatching the event to the associated C{PlotPanelDirector}. """ self.director.keyDown(evt) def _onKeyUp(self, evt): """ Overrides the C{FigureCanvasWxAgg} key-release event handler, dispatching the event to the associated C{PlotPanelDirector}. """ self.director.keyUp(evt) def _onLeftButtonDown(self, evt): """ Overrides the C{FigureCanvasWxAgg} left-click event handler, dispatching the event to the associated C{PlotPanelDirector}. """ x, y = self._get_canvas_xy(evt) self.director.leftButtonDown(evt, x, y) def _onLeftButtonUp(self, evt): """ Overrides the C{FigureCanvasWxAgg} left-click-release event handler, dispatching the event to the associated C{PlotPanelDirector}. """ x, y = self._get_canvas_xy(evt) self.director.leftButtonUp(evt, x, y) def _onRightButtonDown(self, evt): """ Overrides the C{FigureCanvasWxAgg} right-click event handler, dispatching the event to the associated C{PlotPanelDirector}. """ x, y = self._get_canvas_xy(evt) self.director.rightButtonDown(evt, x, y) def _onRightButtonUp(self, evt): """ Overrides the C{FigureCanvasWxAgg} right-click-release event handler, dispatching the event to the associated C{PlotPanelDirector}. """ x, y = self._get_canvas_xy(evt) self.director.rightButtonUp(evt, x, y) def _onMotion(self, evt): """ Overrides the C{FigureCanvasWxAgg} mouse motion event handler, dispatching the event to the associated C{PlotPanelDirector}. """ x, y = self._get_canvas_xy(evt) self.director.mouseMotion(evt, x, y) # # Matplotlib canvas in a top-level wxPython window # class PlotFrame(wx.Frame): """ A matplotlib canvas embedded in a wxPython top-level window. @cvar ABOUT_TITLE: Title of the "About" dialog. @cvar ABOUT_MESSAGE: Contents of the "About" dialog. """ ABOUT_TITLE = 'About wxmpl.PlotFrame' ABOUT_MESSAGE = ('wxmpl.PlotFrame %s\n' % __version__ + 'Written by Ken McIvor \n' + 'Copyright 2005-2009 Illinois Institute of Technology') def __init__(self, parent, id, title, size=(6.0, 3.7), dpi=96, cursor=True, location=True, crosshairs=True, selection=True, zoom=True, autoscaleUnzoom=True, **kwds): """ Creates a new PlotFrame top-level window that is the child of the wxPython window C{parent} with the wxPython identifier C{id} and the title of C{title}. All of the named keyword arguments to this constructor have the same meaning as those arguments to the constructor of C{PlotPanel}. Any additional keyword arguments are passed to the constructor of C{wx.Frame}. """ wx.Frame.__init__(self, parent, id, title, **kwds) self.panel = PlotPanel(self, -1, size, dpi, cursor, location, crosshairs, selection, zoom) pData = wx.PrintData() pData.SetPaperId(wx.PAPER_LETTER) if callable(getattr(pData, 'SetPrinterCommand', None)): pData.SetPrinterCommand(POSTSCRIPT_PRINTING_COMMAND) self.printer = FigurePrinter(self, pData) self.create_menus() sizer = wx.BoxSizer(wx.VERTICAL) sizer.Add(self.panel, 1, wx.ALL|wx.EXPAND, 5) self.SetSizer(sizer) self.Fit() def create_menus(self): mainMenu = wx.MenuBar() menu = wx.Menu() id = wx.NewId() menu.Append(id, '&Save As...\tCtrl+S', 'Save a copy of the current plot') wx.EVT_MENU(self, id, self.OnMenuFileSave) menu.AppendSeparator() if wx.Platform != '__WXMAC__': id = wx.NewId() menu.Append(id, 'Page Set&up...', 'Set the size and margins of the printed figure') wx.EVT_MENU(self, id, self.OnMenuFilePageSetup) id = wx.NewId() menu.Append(id, 'Print Pre&view...', 'Preview the print version of the current plot') wx.EVT_MENU(self, id, self.OnMenuFilePrintPreview) id = wx.NewId() menu.Append(id, '&Print...\tCtrl+P', 'Print the current plot') wx.EVT_MENU(self, id, self.OnMenuFilePrint) menu.AppendSeparator() id = wx.NewId() menu.Append(id, '&Close Window\tCtrl+W', 'Close the current plot window') wx.EVT_MENU(self, id, self.OnMenuFileClose) mainMenu.Append(menu, '&File') menu = wx.Menu() id = wx.NewId() menu.Append(id, '&About...', 'Display version information') wx.EVT_MENU(self, id, self.OnMenuHelpAbout) mainMenu.Append(menu, '&Help') self.SetMenuBar(mainMenu) def OnMenuFileSave(self, evt): """ Handles File->Save menu events. """ fileName = wx.FileSelector('Save Plot', default_extension='png', wildcard=('Portable Network Graphics (*.png)|*.png|' + 'Encapsulated Postscript (*.eps)|*.eps|All files (*.*)|*.*'), parent=self, flags=wx.SAVE|wx.OVERWRITE_PROMPT) if not fileName: return path, ext = os.path.splitext(fileName) ext = ext[1:].lower() if ext != 'png' and ext != 'eps': error_message = ( 'Only the PNG and EPS image formats are supported.\n' 'A file extension of `png\' or `eps\' must be used.') wx.MessageBox(error_message, 'Error - plotit', parent=self, style=wx.OK|wx.ICON_ERROR) return try: self.panel.print_figure(fileName) except IOError, e: if e.strerror: err = e.strerror else: err = e wx.MessageBox('Could not save file: %s' % err, 'Error - plotit', parent=self, style=wx.OK|wx.ICON_ERROR) def OnMenuFilePageSetup(self, evt): """ Handles File->Page Setup menu events """ self.printer.pageSetup() def OnMenuFilePrintPreview(self, evt): """ Handles File->Print Preview menu events """ self.printer.previewFigure(self.get_figure()) def OnMenuFilePrint(self, evt): """ Handles File->Print menu events """ self.printer.printFigure(self.get_figure()) def OnMenuFileClose(self, evt): """ Handles File->Close menu events. """ self.Close() def OnMenuHelpAbout(self, evt): """ Handles Help->About menu events. """ wx.MessageBox(self.ABOUT_MESSAGE, self.ABOUT_TITLE, parent=self, style=wx.OK) def get_figure(self): """ Returns the figure associated with this canvas. """ return self.panel.figure def set_cursor(self, state): """ Enable or disable the changing mouse cursor. When enabled, the cursor changes from the normal arrow to a square cross when the mouse enters a matplotlib axes on this canvas. """ self.panel.set_cursor(state) def set_location(self, state): """ Enable or disable the display of the matplotlib axes coordinates of the mouse in the lower left corner of the canvas. """ self.panel.set_location(state) def set_crosshairs(self, state): """ Enable or disable drawing crosshairs through the mouse cursor when it is inside a matplotlib axes. """ self.panel.set_crosshairs(state) def set_selection(self, state): """ Enable or disable area selections, where user selects a rectangular area of the canvas by left-clicking and dragging the mouse. """ self.panel.set_selection(state) def set_zoom(self, state): """ Enable or disable zooming in when the user makes an area selection and zooming out again when the user right-clicks. """ self.panel.set_zoom(state) def set_autoscale_unzoom(self, state): """ Enable or disable automatic view rescaling when the user zooms out to the initial figure. """ self.panel.set_autoscale_unzoom(state) def draw(self): """ Draw the associated C{Figure} onto the screen. """ self.panel.draw() # # wxApp providing a matplotlib canvas in a top-level wxPython window # class PlotApp(wx.App): """ A wxApp that provides a matplotlib canvas embedded in a wxPython top-level window, encapsulating wxPython's nuts and bolts. @cvar ABOUT_TITLE: Title of the "About" dialog. @cvar ABOUT_MESSAGE: Contents of the "About" dialog. """ ABOUT_TITLE = None ABOUT_MESSAGE = None def __init__(self, title="WxMpl", size=(6.0, 3.7), dpi=96, cursor=True, location=True, crosshairs=True, selection=True, zoom=True, **kwds): """ Creates a new PlotApp, which creates a PlotFrame top-level window. The keyword argument C{title} specifies the title of this top-level window. All of other the named keyword arguments to this constructor have the same meaning as those arguments to the constructor of C{PlotPanel}. Any additional keyword arguments are passed to the constructor of C{wx.App}. """ self.title = title self.size = size self.dpi = dpi self.cursor = cursor self.location = location self.crosshairs = crosshairs self.selection = selection self.zoom = zoom wx.App.__init__(self, **kwds) def OnInit(self): self.frame = panel = PlotFrame(None, -1, self.title, self.size, self.dpi, self.cursor, self.location, self.crosshairs, self.selection, self.zoom) if self.ABOUT_TITLE is not None: panel.ABOUT_TITLE = self.ABOUT_TITLE if self.ABOUT_MESSAGE is not None: panel.ABOUT_MESSAGE = self.ABOUT_MESSAGE panel.Show(True) return True def get_figure(self): """ Returns the figure associated with this canvas. """ return self.frame.get_figure() def set_cursor(self, state): """ Enable or disable the changing mouse cursor. When enabled, the cursor changes from the normal arrow to a square cross when the mouse enters a matplotlib axes on this canvas. """ self.frame.set_cursor(state) def set_location(self, state): """ Enable or disable the display of the matplotlib axes coordinates of the mouse in the lower left corner of the canvas. """ self.frame.set_location(state) def set_crosshairs(self, state): """ Enable or disable drawing crosshairs through the mouse cursor when it is inside a matplotlib axes. """ self.frame.set_crosshairs(state) def set_selection(self, state): """ Enable or disable area selections, where user selects a rectangular area of the canvas by left-clicking and dragging the mouse. """ self.frame.set_selection(state) def set_zoom(self, state): """ Enable or disable zooming in when the user makes an area selection and zooming out again when the user right-clicks. """ self.frame.set_zoom(state) def draw(self): """ Draw the associated C{Figure} onto the screen. """ self.frame.draw() # # Automatically resizing vectors and matrices # class VectorBuffer: """ Manages a Numerical Python vector, automatically growing it as necessary to accomodate new entries. """ def __init__(self): self.data = NumPy.zeros((16,), dtype=float) self.nextRow = 0 def clear(self): """ Zero and reset this buffer without releasing the underlying array. """ self.data[:] = 0.0 self.nextRow = 0 def reset(self): """ Zero and reset this buffer, releasing the underlying array. """ self.data = NumPy.zeros((16,), dtype=float) self.nextRow = 0 def append(self, point): """ Append a new entry to the end of this buffer's vector. """ nextRow = self.nextRow data = self.data resize = False if nextRow == data.shape[0]: nR = int(NumPy.ceil(self.data.shape[0]*1.5)) resize = True if resize: self.data = NumPy.zeros((nR,), dtype=float) self.data[0:data.shape[0]] = data self.data[nextRow] = point self.nextRow += 1 def getData(self): """ Returns the current vector or C{None} if the buffer contains no data. """ if self.nextRow == 0: return None else: return self.data[0:self.nextRow] class MatrixBuffer: """ Manages a Numerical Python matrix, automatically growing it as necessary to accomodate new rows of entries. """ def __init__(self): self.data = NumPy.zeros((16, 1), dtype=float) self.nextRow = 0 def clear(self): """ Zero and reset this buffer without releasing the underlying array. """ self.data[:, :] = 0.0 self.nextRow = 0 def reset(self): """ Zero and reset this buffer, releasing the underlying array. """ self.data = NumPy.zeros((16, 1), dtype=float) self.nextRow = 0 def append(self, row): """ Append a new row of entries to the end of this buffer's matrix. """ row = NumPy.asarray(row, dtype=float) nextRow = self.nextRow data = self.data nPts = row.shape[0] if nPts == 0: return resize = True if nextRow == data.shape[0]: nC = data.shape[1] nR = int(NumPy.ceil(self.data.shape[0]*1.5)) if nC < nPts: nC = nPts elif data.shape[1] < nPts: nR = data.shape[0] nC = nPts else: resize = False if resize: self.data = NumPy.zeros((nR, nC), dtype=float) rowEnd, colEnd = data.shape self.data[0:rowEnd, 0:colEnd] = data self.data[nextRow, 0:nPts] = row self.nextRow += 1 def getData(self): """ Returns the current matrix or C{None} if the buffer contains no data. """ if self.nextRow == 0: return None else: return self.data[0:self.nextRow, :] # # Utility functions used by the StripCharter # def make_delta_bbox(X1, Y1, X2, Y2): """ Returns a C{Bbox} describing the range of difference between two sets of X and Y coordinates. """ return make_bbox(get_delta(X1, X2), get_delta(Y1, Y2)) def get_delta(X1, X2): """ Returns the vector of contiguous, different points between two vectors. """ n1 = X1.shape[0] n2 = X2.shape[0] if n1 < n2: return X2[n1:] elif n1 == n2: # shape is no longer a reliable indicator of change, so assume things # are different return X2 else: return X2 def make_bbox(X, Y): """ Returns a C{Bbox} that contains the supplied sets of X and Y coordinates. """ if X is None or X.shape[0] == 0: x1 = x2 = 0.0 else: x1 = min(X) x2 = max(X) if Y is None or Y.shape[0] == 0: y1 = y2 = 0.0 else: y1 = min(Y) y2 = max(Y) return Bbox.from_extents(x1, y1, x2, y2) # # Strip-charts lines using a matplotlib axes # class StripCharter: """ Plots and updates lines on a matplotlib C{Axes}. """ def __init__(self, axes): """ Create a new C{StripCharter} associated with a matplotlib C{axes}. """ self.axes = axes self.channels = [] self.lines = {} def setChannels(self, channels): """ Specify the data-providers of the lines to be plotted and updated. """ self.lines = None self.channels = channels[:] # minimal Axes.cla() self.axes.legend_ = None self.axes.lines = [] def update(self): """ Redraw the associated axes with updated lines if any of the channels' data has changed. """ axes = self.axes figureCanvas = axes.figure.canvas zoomed = figureCanvas.zoomed(axes) redraw = False if self.lines is None: self._create_plot() redraw = True else: for channel in self.channels: redraw = self._update_channel(channel, zoomed) or redraw if redraw: if not zoomed: axes.autoscale_view() figureCanvas.draw() def _create_plot(self): """ Initially plot the lines corresponding to the data-providers. """ self.lines = {} axes = self.axes styleGen = _process_plot_var_args(axes) for channel in self.channels: self._plot_channel(channel, styleGen) if self.channels: lines = [self.lines[x] for x in self.channels] labels = [x.get_label() for x in lines] self.axes.legend(lines, labels, numpoints=2, prop=FontProperties(size='x-small')) def _plot_channel(self, channel, styleGen): """ Initially plot a line corresponding to one of the data-providers. """ empty = False x = channel.getX() y = channel.getY() if x is None or y is None: x = y = [] empty = True line = styleGen(x, y).next() line._wxmpl_empty_line = empty if channel.getColor() is not None: line.set_color(channel.getColor()) if channel.getStyle() is not None: line.set_linestyle(channel.getStyle()) if channel.getMarker() is not None: line.set_marker(channel.getMarker()) line.set_markeredgecolor(line.get_color()) line.set_markerfacecolor(line.get_color()) line.set_label(channel.getLabel()) self.lines[channel] = line if not empty: self.axes.add_line(line) def _update_channel(self, channel, zoomed): """ Replot a line corresponding to one of the data-providers if the data has changed. """ if channel.hasChanged(): channel.setChanged(False) else: return False axes = self.axes line = self.lines[channel] newX = channel.getX() newY = channel.getY() if newX is None or newY is None: return False oldX = line._x oldY = line._y x, y = newX, newY line.set_data(x, y) if line._wxmpl_empty_line: axes.add_line(line) line._wxmpl_empty_line = False else: if line.get_transform() != axes.transData: xys = axes._get_verts_in_data_coords( line.get_transform(), zip(x, y)) else: xys = NumPy.zeros((x.shape[0], 2), dtype=float) xys[:,0] = x xys[:,1] = y axes.update_datalim(xys) if zoomed: return axes.viewLim.overlaps( make_delta_bbox(oldX, oldY, newX, newY)) else: return True # # Data-providing interface to the StripCharter # class Channel: """ Provides data for a C{StripCharter} to plot. Subclasses of C{Channel} override the template methods C{getX()} and C{getY()} to provide plot data and call C{setChanged(True)} when that data has changed. """ def __init__(self, name, color=None, style=None, marker=None): """ Creates a new C{Channel} with the matplotlib label C{name}. The keyword arguments specify the strings for the line color, style, and marker to use when the line is plotted. """ self.name = name self.color = color self.style = style self.marker = marker self.changed = False def getLabel(self): """ Returns the matplotlib label for this channel of data. """ return self.name def getColor(self): """ Returns the line color string to use when the line is plotted, or C{None} to use an automatically generated color. """ return self.color def getStyle(self): """ Returns the line style string to use when the line is plotted, or C{None} to use the default line style. """ return self.style def getMarker(self): """ Returns the line marker string to use when the line is plotted, or C{None} to use the default line marker. """ return self.marker def hasChanged(self): """ Returns a boolean indicating if the line data has changed. """ return self.changed def setChanged(self, changed): """ Sets the change indicator to the boolean value C{changed}. @note: C{StripCharter} instances call this method after detecting a change, so a C{Channel} cannot be shared among multiple charts. """ self.changed = changed def getX(self): """ Template method that returns the vector of X axis data or C{None} if there is no data available. """ return None def getY(self): """ Template method that returns the vector of Y axis data or C{None} if there is no data available. """ return None wxmpl-2.0.0/reference/0002755000175000017500000000000011647105502015055 5ustar segresegre00000000000000wxmpl-2.0.0/reference/api-objects.txt0000644000175000017500000001700411647105465020026 0ustar segresegre00000000000000wxmpl wxmpl-module.html wxmpl.update_postscript_resolution wxmpl-module.html#update_postscript_resolution wxmpl.toplevel_parent_of_window wxmpl-module.html#toplevel_parent_of_window wxmpl.limit_selection wxmpl-module.html#limit_selection wxmpl.MATPLOTLIB_0_98_3 wxmpl-module.html#MATPLOTLIB_0_98_3 wxmpl.find_selected_axes wxmpl-module.html#find_selected_axes wxmpl.get_delta wxmpl-module.html#get_delta wxmpl.make_delta_bbox wxmpl-module.html#make_delta_bbox wxmpl.EVT_POINT_ID wxmpl-module.html#EVT_POINT_ID wxmpl.get_bbox_lims wxmpl-module.html#get_bbox_lims wxmpl.PS_DPI_HIGH_QUALITY wxmpl-module.html#PS_DPI_HIGH_QUALITY wxmpl.EVT_SELECTION wxmpl-module.html#EVT_SELECTION wxmpl.find_axes wxmpl-module.html#find_axes wxmpl.POSTSCRIPT_PRINTING_COMMAND wxmpl-module.html#POSTSCRIPT_PRINTING_COMMAND wxmpl.format_coord wxmpl-module.html#format_coord wxmpl.make_bbox wxmpl-module.html#make_bbox wxmpl.PS_DPI_MEDIUM_QUALITY wxmpl-module.html#PS_DPI_MEDIUM_QUALITY wxmpl.EVT_POINT wxmpl-module.html#EVT_POINT wxmpl.PS_DPI_DRAFT_QUALITY wxmpl-module.html#PS_DPI_DRAFT_QUALITY wxmpl.PS_DPI_LOW_QUALITY wxmpl-module.html#PS_DPI_LOW_QUALITY wxmpl.EVT_SELECTION_ID wxmpl-module.html#EVT_SELECTION_ID wxmpl.invert_point wxmpl-module.html#invert_point wxmpl.Channel wxmpl.Channel-class.html wxmpl.Channel.setChanged wxmpl.Channel-class.html#setChanged wxmpl.Channel.getColor wxmpl.Channel-class.html#getColor wxmpl.Channel.getX wxmpl.Channel-class.html#getX wxmpl.Channel.getY wxmpl.Channel-class.html#getY wxmpl.Channel.getStyle wxmpl.Channel-class.html#getStyle wxmpl.Channel.__init__ wxmpl.Channel-class.html#__init__ wxmpl.Channel.getLabel wxmpl.Channel-class.html#getLabel wxmpl.Channel.getMarker wxmpl.Channel-class.html#getMarker wxmpl.Channel.hasChanged wxmpl.Channel-class.html#hasChanged wxmpl.FigurePrinter wxmpl.FigurePrinter-class.html wxmpl.FigurePrinter.previewFigure wxmpl.FigurePrinter-class.html#previewFigure wxmpl.FigurePrinter.printFigure wxmpl.FigurePrinter-class.html#printFigure wxmpl.FigurePrinter.getPrintData wxmpl.FigurePrinter-class.html#getPrintData wxmpl.FigurePrinter.setPrintData wxmpl.FigurePrinter-class.html#setPrintData wxmpl.FigurePrinter.pageSetup wxmpl.FigurePrinter-class.html#pageSetup wxmpl.FigurePrinter.__init__ wxmpl.FigurePrinter-class.html#__init__ wxmpl.PlotApp wxmpl.PlotApp-class.html wxmpl.PlotApp.draw wxmpl.PlotApp-class.html#draw wxmpl.PlotApp.set_zoom wxmpl.PlotApp-class.html#set_zoom wxmpl.PlotApp.set_location wxmpl.PlotApp-class.html#set_location wxmpl.PlotApp.set_selection wxmpl.PlotApp-class.html#set_selection wxmpl.PlotApp.ABOUT_MESSAGE wxmpl.PlotApp-class.html#ABOUT_MESSAGE wxmpl.PlotApp.ABOUT_TITLE wxmpl.PlotApp-class.html#ABOUT_TITLE wxmpl.PlotApp.get_figure wxmpl.PlotApp-class.html#get_figure wxmpl.PlotApp.set_crosshairs wxmpl.PlotApp-class.html#set_crosshairs wxmpl.PlotApp.set_cursor wxmpl.PlotApp-class.html#set_cursor wxmpl.PlotApp.OnInit wxmpl.PlotApp-class.html#OnInit wxmpl.PlotApp.__init__ wxmpl.PlotApp-class.html#__init__ wxmpl.PlotFrame wxmpl.PlotFrame-class.html wxmpl.PlotFrame.OnMenuHelpAbout wxmpl.PlotFrame-class.html#OnMenuHelpAbout wxmpl.PlotFrame.draw wxmpl.PlotFrame-class.html#draw wxmpl.PlotFrame.set_zoom wxmpl.PlotFrame-class.html#set_zoom wxmpl.PlotFrame.set_location wxmpl.PlotFrame-class.html#set_location wxmpl.PlotFrame.get_figure wxmpl.PlotFrame-class.html#get_figure wxmpl.PlotFrame.OnMenuFileSave wxmpl.PlotFrame-class.html#OnMenuFileSave wxmpl.PlotFrame.set_autoscale_unzoom wxmpl.PlotFrame-class.html#set_autoscale_unzoom wxmpl.PlotFrame.set_selection wxmpl.PlotFrame-class.html#set_selection wxmpl.PlotFrame.ABOUT_MESSAGE wxmpl.PlotFrame-class.html#ABOUT_MESSAGE wxmpl.PlotFrame.ABOUT_TITLE wxmpl.PlotFrame-class.html#ABOUT_TITLE wxmpl.PlotFrame.OnMenuFilePrintPreview wxmpl.PlotFrame-class.html#OnMenuFilePrintPreview wxmpl.PlotFrame.set_crosshairs wxmpl.PlotFrame-class.html#set_crosshairs wxmpl.PlotFrame.set_cursor wxmpl.PlotFrame-class.html#set_cursor wxmpl.PlotFrame.create_menus wxmpl.PlotFrame-class.html#create_menus wxmpl.PlotFrame.OnMenuFilePrint wxmpl.PlotFrame-class.html#OnMenuFilePrint wxmpl.PlotFrame.OnMenuFileClose wxmpl.PlotFrame-class.html#OnMenuFileClose wxmpl.PlotFrame.__init__ wxmpl.PlotFrame-class.html#__init__ wxmpl.PlotFrame.OnMenuFilePageSetup wxmpl.PlotFrame-class.html#OnMenuFilePageSetup wxmpl.PlotPanel wxmpl.PlotPanel-class.html wxmpl.PlotPanel._onRightButtonUp wxmpl.PlotPanel-class.html#_onRightButtonUp wxmpl.PlotPanel.set_crosshairs wxmpl.PlotPanel-class.html#set_crosshairs wxmpl.PlotPanel._onKeyUp wxmpl.PlotPanel-class.html#_onKeyUp wxmpl.PlotPanel.set_autoscale_unzoom wxmpl.PlotPanel-class.html#set_autoscale_unzoom wxmpl.PlotPanel.OnActivate wxmpl.PlotPanel-class.html#OnActivate wxmpl.PlotPanel.set_location wxmpl.PlotPanel-class.html#set_location wxmpl.PlotPanel.notify_point wxmpl.PlotPanel-class.html#notify_point wxmpl.PlotPanel.zoomed wxmpl.PlotPanel-class.html#zoomed wxmpl.PlotPanel.notify_selection wxmpl.PlotPanel-class.html#notify_selection wxmpl.PlotPanel._onLeftButtonUp wxmpl.PlotPanel-class.html#_onLeftButtonUp wxmpl.PlotPanel._onKeyDown wxmpl.PlotPanel-class.html#_onKeyDown wxmpl.PlotPanel.set_cursor wxmpl.PlotPanel-class.html#set_cursor wxmpl.PlotPanel.set_zoom wxmpl.PlotPanel-class.html#set_zoom wxmpl.PlotPanel._onMotion wxmpl.PlotPanel-class.html#_onMotion wxmpl.PlotPanel.OnDestroy wxmpl.PlotPanel-class.html#OnDestroy wxmpl.PlotPanel._onRightButtonDown wxmpl.PlotPanel-class.html#_onRightButtonDown wxmpl.PlotPanel.set_selection wxmpl.PlotPanel-class.html#set_selection wxmpl.PlotPanel.get_figure wxmpl.PlotPanel-class.html#get_figure wxmpl.PlotPanel.__init__ wxmpl.PlotPanel-class.html#__init__ wxmpl.PlotPanel._onLeftButtonDown wxmpl.PlotPanel-class.html#_onLeftButtonDown wxmpl.PlotPanel.draw wxmpl.PlotPanel-class.html#draw wxmpl.PlotPanel._onPaint wxmpl.PlotPanel-class.html#_onPaint wxmpl.PlotPanel.OnEraseBackground wxmpl.PlotPanel-class.html#OnEraseBackground wxmpl.PlotPanel._get_canvas_xy wxmpl.PlotPanel-class.html#_get_canvas_xy wxmpl.PointEvent wxmpl.PointEvent-class.html wxmpl.PointEvent.Clone wxmpl.PointEvent-class.html#Clone wxmpl.PointEvent.axes wxmpl.PointEvent-class.html#axes wxmpl.PointEvent.ydata wxmpl.PointEvent-class.html#ydata wxmpl.PointEvent.xdata wxmpl.PointEvent-class.html#xdata wxmpl.PointEvent.y wxmpl.PointEvent-class.html#y wxmpl.PointEvent.x wxmpl.PointEvent-class.html#x wxmpl.PointEvent.__init__ wxmpl.PointEvent-class.html#__init__ wxmpl.SelectionEvent wxmpl.SelectionEvent-class.html wxmpl.SelectionEvent.y2 wxmpl.SelectionEvent-class.html#y2 wxmpl.SelectionEvent.x2data wxmpl.SelectionEvent-class.html#x2data wxmpl.SelectionEvent.Clone wxmpl.SelectionEvent-class.html#Clone wxmpl.SelectionEvent.axes wxmpl.SelectionEvent-class.html#axes wxmpl.SelectionEvent.x2 wxmpl.SelectionEvent-class.html#x2 wxmpl.SelectionEvent.y2data wxmpl.SelectionEvent-class.html#y2data wxmpl.SelectionEvent.x1data wxmpl.SelectionEvent-class.html#x1data wxmpl.SelectionEvent.y1 wxmpl.SelectionEvent-class.html#y1 wxmpl.SelectionEvent.x1 wxmpl.SelectionEvent-class.html#x1 wxmpl.SelectionEvent.y1data wxmpl.SelectionEvent-class.html#y1data wxmpl.SelectionEvent.__init__ wxmpl.SelectionEvent-class.html#__init__ wxmpl.StripCharter wxmpl.StripCharter-class.html wxmpl.StripCharter._plot_channel wxmpl.StripCharter-class.html#_plot_channel wxmpl.StripCharter.update wxmpl.StripCharter-class.html#update wxmpl.StripCharter._update_channel wxmpl.StripCharter-class.html#_update_channel wxmpl.StripCharter.setChannels wxmpl.StripCharter-class.html#setChannels wxmpl.StripCharter._create_plot wxmpl.StripCharter-class.html#_create_plot wxmpl.StripCharter.__init__ wxmpl.StripCharter-class.html#__init__ wxmpl-2.0.0/reference/class-tree.html0000644000175000017500000001154611647105464020021 0ustar segresegre00000000000000 Class Hierarchy
 
[frames] | no frames]
[ Module Hierarchy | Class Hierarchy ]

Class Hierarchy

  • wx.App
  • wxmpl.Channel: Provides data for a StripCharter to plot.
  • wxmpl.FigurePrinter: Provides a simplified interface to the wxPython printing framework that's designed for printing matplotlib figures.
  • wx.Frame
  • wx.Panel
  • wx.PyCommandEvent
  • wx.PyCommandEvent
  • wxmpl.StripCharter: Plots and updates lines on a matplotlib Axes.
  • object: The most base type
    • matplotlib.backend_bases.FigureCanvasBase: The canvas the figure renders into.
wxmpl-2.0.0/reference/crarr.png0000644000175000017500000000052411647105464016702 0ustar segresegre00000000000000‰PNG  IHDR e¢E,tEXtCreation TimeTue 22 Aug 2006 00:43:10 -0500` XtIMEÖ)Ó}Ö pHYsÂÂnÐu>gAMA± üaEPLTEÿÿÿÍð×ÏÀ€f4sW áÛЊrD`@bCÜÕÈéäÜ–X{`,¯Ÿ€lN‡o@õóðª™xdEðí螊dÐÆ´”~TÖwÅvtRNS@æØfMIDATxÚc`@¼ì¼0&+š—Šˆ°»(’ˆ€ ;; /ðEXùØ‘?Ð n ƒª†— b;'ª+˜˜YÐ#œ(r<£"IEND®B`‚wxmpl-2.0.0/reference/epydoc.css0000644000175000017500000003722711647105464017072 0ustar segresegre00000000000000 /* Epydoc CSS Stylesheet * * This stylesheet can be used to customize the appearance of epydoc's * HTML output. * */ /* Default Colors & Styles * - Set the default foreground & background color with 'body'; and * link colors with 'a:link' and 'a:visited'. * - Use bold for decision list terms. * - The heading styles defined here are used for headings *within* * docstring descriptions. All headings used by epydoc itself use * either class='epydoc' or class='toc' (CSS styles for both * defined below). */ body { background: #ffffff; color: #000000; } p { margin-top: 0.5em; margin-bottom: 0.5em; } a:link { color: #0000ff; } a:visited { color: #204080; } dt { font-weight: bold; } h1 { font-size: +140%; font-style: italic; font-weight: bold; } h2 { font-size: +125%; font-style: italic; font-weight: bold; } h3 { font-size: +110%; font-style: italic; font-weight: normal; } code { font-size: 100%; } /* N.B.: class, not pseudoclass */ a.link { font-family: monospace; } /* Page Header & Footer * - The standard page header consists of a navigation bar (with * pointers to standard pages such as 'home' and 'trees'); a * breadcrumbs list, which can be used to navigate to containing * classes or modules; options links, to show/hide private * variables and to show/hide frames; and a page title (using *

). The page title may be followed by a link to the * corresponding source code (using 'span.codelink'). * - The footer consists of a navigation bar, a timestamp, and a * pointer to epydoc's homepage. */ h1.epydoc { margin: 0; font-size: +140%; font-weight: bold; } h2.epydoc { font-size: +130%; font-weight: bold; } h3.epydoc { font-size: +115%; font-weight: bold; margin-top: 0.2em; } td h3.epydoc { font-size: +115%; font-weight: bold; margin-bottom: 0; } table.navbar { background: #a0c0ff; color: #000000; border: 2px groove #c0d0d0; } table.navbar table { color: #000000; } th.navbar-select { background: #70b0ff; color: #000000; } table.navbar a { text-decoration: none; } table.navbar a:link { color: #0000ff; } table.navbar a:visited { color: #204080; } span.breadcrumbs { font-size: 85%; font-weight: bold; } span.options { font-size: 70%; } span.codelink { font-size: 85%; } td.footer { font-size: 85%; } /* Table Headers * - Each summary table and details section begins with a 'header' * row. This row contains a section title (marked by * 'span.table-header') as well as a show/hide private link * (marked by 'span.options', defined above). * - Summary tables that contain user-defined groups mark those * groups using 'group header' rows. */ td.table-header { background: #70b0ff; color: #000000; border: 1px solid #608090; } td.table-header table { color: #000000; } td.table-header table a:link { color: #0000ff; } td.table-header table a:visited { color: #204080; } span.table-header { font-size: 120%; font-weight: bold; } th.group-header { background: #c0e0f8; color: #000000; text-align: left; font-style: italic; font-size: 115%; border: 1px solid #608090; } /* Summary Tables (functions, variables, etc) * - Each object is described by a single row of the table with * two cells. The left cell gives the object's type, and is * marked with 'code.summary-type'. The right cell gives the * object's name and a summary description. * - CSS styles for the table's header and group headers are * defined above, under 'Table Headers' */ table.summary { border-collapse: collapse; background: #e8f0f8; color: #000000; border: 1px solid #608090; margin-bottom: 0.5em; } td.summary { border: 1px solid #608090; } code.summary-type { font-size: 85%; } table.summary a:link { color: #0000ff; } table.summary a:visited { color: #204080; } /* Details Tables (functions, variables, etc) * - Each object is described in its own div. * - A single-row summary table w/ table-header is used as * a header for each details section (CSS style for table-header * is defined above, under 'Table Headers'). */ table.details { border-collapse: collapse; background: #e8f0f8; color: #000000; border: 1px solid #608090; margin: .2em 0 0 0; } table.details table { color: #000000; } table.details a:link { color: #0000ff; } table.details a:visited { color: #204080; } /* Fields */ dl.fields { margin-left: 2em; margin-top: 1em; margin-bottom: 1em; } dl.fields dd ul { margin-left: 0em; padding-left: 0em; } dl.fields dd ul li ul { margin-left: 2em; padding-left: 0em; } div.fields { margin-left: 2em; } div.fields p { margin-bottom: 0.5em; } /* Index tables (identifier index, term index, etc) * - link-index is used for indices containing lists of links * (namely, the identifier index & term index). * - index-where is used in link indices for the text indicating * the container/source for each link. * - metadata-index is used for indices containing metadata * extracted from fields (namely, the bug index & todo index). */ table.link-index { border-collapse: collapse; background: #e8f0f8; color: #000000; border: 1px solid #608090; } td.link-index { border-width: 0px; } table.link-index a:link { color: #0000ff; } table.link-index a:visited { color: #204080; } span.index-where { font-size: 70%; } table.metadata-index { border-collapse: collapse; background: #e8f0f8; color: #000000; border: 1px solid #608090; margin: .2em 0 0 0; } td.metadata-index { border-width: 1px; border-style: solid; } table.metadata-index a:link { color: #0000ff; } table.metadata-index a:visited { color: #204080; } /* Function signatures * - sig* is used for the signature in the details section. * - .summary-sig* is used for the signature in the summary * table, and when listing property accessor functions. * */ .sig-name { color: #006080; } .sig-arg { color: #008060; } .sig-default { color: #602000; } .summary-sig { font-family: monospace; } .summary-sig-name { color: #006080; font-weight: bold; } table.summary a.summary-sig-name:link { color: #006080; font-weight: bold; } table.summary a.summary-sig-name:visited { color: #006080; font-weight: bold; } .summary-sig-arg { color: #006040; } .summary-sig-default { color: #501800; } /* Subclass list */ ul.subclass-list { display: inline; } ul.subclass-list li { display: inline; } /* To render variables, classes etc. like functions */ table.summary .summary-name { color: #006080; font-weight: bold; font-family: monospace; } table.summary a.summary-name:link { color: #006080; font-weight: bold; font-family: monospace; } table.summary a.summary-name:visited { color: #006080; font-weight: bold; font-family: monospace; } /* Variable values * - In the 'variable details' sections, each varaible's value is * listed in a 'pre.variable' box. The width of this box is * restricted to 80 chars; if the value's repr is longer than * this it will be wrapped, using a backslash marked with * class 'variable-linewrap'. If the value's repr is longer * than 3 lines, the rest will be ellided; and an ellipsis * marker ('...' marked with 'variable-ellipsis') will be used. * - If the value is a string, its quote marks will be marked * with 'variable-quote'. * - If the variable is a regexp, it is syntax-highlighted using * the re* CSS classes. */ pre.variable { padding: .5em; margin: 0; background: #dce4ec; color: #000000; border: 1px solid #708890; } .variable-linewrap { color: #604000; font-weight: bold; } .variable-ellipsis { color: #604000; font-weight: bold; } .variable-quote { color: #604000; font-weight: bold; } .variable-group { color: #008000; font-weight: bold; } .variable-op { color: #604000; font-weight: bold; } .variable-string { color: #006030; } .variable-unknown { color: #a00000; font-weight: bold; } .re { color: #000000; } .re-char { color: #006030; } .re-op { color: #600000; } .re-group { color: #003060; } .re-ref { color: #404040; } /* Base tree * - Used by class pages to display the base class hierarchy. */ pre.base-tree { font-size: 80%; margin: 0; } /* Frames-based table of contents headers * - Consists of two frames: one for selecting modules; and * the other listing the contents of the selected module. * - h1.toc is used for each frame's heading * - h2.toc is used for subheadings within each frame. */ h1.toc { text-align: center; font-size: 105%; margin: 0; font-weight: bold; padding: 0; } h2.toc { font-size: 100%; font-weight: bold; margin: 0.5em 0 0 -0.3em; } /* Syntax Highlighting for Source Code * - doctest examples are displayed in a 'pre.py-doctest' block. * If the example is in a details table entry, then it will use * the colors specified by the 'table pre.py-doctest' line. * - Source code listings are displayed in a 'pre.py-src' block. * Each line is marked with 'span.py-line' (used to draw a line * down the left margin, separating the code from the line * numbers). Line numbers are displayed with 'span.py-lineno'. * The expand/collapse block toggle button is displayed with * 'a.py-toggle' (Note: the CSS style for 'a.py-toggle' should not * modify the font size of the text.) * - If a source code page is opened with an anchor, then the * corresponding code block will be highlighted. The code * block's header is highlighted with 'py-highlight-hdr'; and * the code block's body is highlighted with 'py-highlight'. * - The remaining py-* classes are used to perform syntax * highlighting (py-string for string literals, py-name for names, * etc.) */ pre.py-doctest { padding: .5em; margin: 1em; background: #e8f0f8; color: #000000; border: 1px solid #708890; } table pre.py-doctest { background: #dce4ec; color: #000000; } pre.py-src { border: 2px solid #000000; background: #f0f0f0; color: #000000; } .py-line { border-left: 2px solid #000000; margin-left: .2em; padding-left: .4em; } .py-lineno { font-style: italic; font-size: 90%; padding-left: .5em; } a.py-toggle { text-decoration: none; } div.py-highlight-hdr { border-top: 2px solid #000000; border-bottom: 2px solid #000000; background: #d8e8e8; } div.py-highlight { border-bottom: 2px solid #000000; background: #d0e0e0; } .py-prompt { color: #005050; font-weight: bold;} .py-more { color: #005050; font-weight: bold;} .py-string { color: #006030; } .py-comment { color: #003060; } .py-keyword { color: #600000; } .py-output { color: #404040; } .py-name { color: #000050; } .py-name:link { color: #000050 !important; } .py-name:visited { color: #000050 !important; } .py-number { color: #005000; } .py-defname { color: #000060; font-weight: bold; } .py-def-name { color: #000060; font-weight: bold; } .py-base-class { color: #000060; } .py-param { color: #000060; } .py-docstring { color: #006030; } .py-decorator { color: #804020; } /* Use this if you don't want links to names underlined: */ /*a.py-name { text-decoration: none; }*/ /* Graphs & Diagrams * - These CSS styles are used for graphs & diagrams generated using * Graphviz dot. 'img.graph-without-title' is used for bare * diagrams (to remove the border created by making the image * clickable). */ img.graph-without-title { border: none; } img.graph-with-title { border: 1px solid #000000; } span.graph-title { font-weight: bold; } span.graph-caption { } /* General-purpose classes * - 'p.indent-wrapped-lines' defines a paragraph whose first line * is not indented, but whose subsequent lines are. * - The 'nomargin-top' class is used to remove the top margin (e.g. * from lists). The 'nomargin' class is used to remove both the * top and bottom margin (but not the left or right margin -- * for lists, that would cause the bullets to disappear.) */ p.indent-wrapped-lines { padding: 0 0 0 7em; text-indent: -7em; margin: 0; } .nomargin-top { margin-top: 0; } .nomargin { margin-top: 0; margin-bottom: 0; } /* HTML Log */ div.log-block { padding: 0; margin: .5em 0 .5em 0; background: #e8f0f8; color: #000000; border: 1px solid #000000; } div.log-error { padding: .1em .3em .1em .3em; margin: 4px; background: #ffb0b0; color: #000000; border: 1px solid #000000; } div.log-warning { padding: .1em .3em .1em .3em; margin: 4px; background: #ffffb0; color: #000000; border: 1px solid #000000; } div.log-info { padding: .1em .3em .1em .3em; margin: 4px; background: #b0ffb0; color: #000000; border: 1px solid #000000; } h2.log-hdr { background: #70b0ff; color: #000000; margin: 0; padding: 0em 0.5em 0em 0.5em; border-bottom: 1px solid #000000; font-size: 110%; } p.log { font-weight: bold; margin: .5em 0 .5em 0; } tr.opt-changed { color: #000000; font-weight: bold; } tr.opt-default { color: #606060; } pre.log { margin: 0; padding: 0; padding-left: 1em; } wxmpl-2.0.0/reference/epydoc.js0000644000175000017500000002452511647105464016713 0ustar segresegre00000000000000function toggle_private() { // Search for any private/public links on this page. Store // their old text in "cmd," so we will know what action to // take; and change their text to the opposite action. var cmd = "?"; var elts = document.getElementsByTagName("a"); for(var i=0; i...
"; elt.innerHTML = s; } } function toggle(id) { elt = document.getElementById(id+"-toggle"); if (elt.innerHTML == "-") collapse(id); else expand(id); return false; } function highlight(id) { var elt = document.getElementById(id+"-def"); if (elt) elt.className = "py-highlight-hdr"; var elt = document.getElementById(id+"-expanded"); if (elt) elt.className = "py-highlight"; var elt = document.getElementById(id+"-collapsed"); if (elt) elt.className = "py-highlight"; } function num_lines(s) { var n = 1; var pos = s.indexOf("\n"); while ( pos > 0) { n += 1; pos = s.indexOf("\n", pos+1); } return n; } // Collapse all blocks that mave more than `min_lines` lines. function collapse_all(min_lines) { var elts = document.getElementsByTagName("div"); for (var i=0; i 0) if (elt.id.substring(split, elt.id.length) == "-expanded") if (num_lines(elt.innerHTML) > min_lines) collapse(elt.id.substring(0, split)); } } function expandto(href) { var start = href.indexOf("#")+1; if (start != 0 && start != href.length) { if (href.substring(start, href.length) != "-") { collapse_all(4); pos = href.indexOf(".", start); while (pos != -1) { var id = href.substring(start, pos); expand(id); pos = href.indexOf(".", pos+1); } var id = href.substring(start, href.length); expand(id); highlight(id); } } } function kill_doclink(id) { var parent = document.getElementById(id); parent.removeChild(parent.childNodes.item(0)); } function auto_kill_doclink(ev) { if (!ev) var ev = window.event; if (!this.contains(ev.toElement)) { var parent = document.getElementById(this.parentID); parent.removeChild(parent.childNodes.item(0)); } } function doclink(id, name, targets_id) { var elt = document.getElementById(id); // If we already opened the box, then destroy it. // (This case should never occur, but leave it in just in case.) if (elt.childNodes.length > 1) { elt.removeChild(elt.childNodes.item(0)); } else { // The outer box: relative + inline positioning. var box1 = document.createElement("div"); box1.style.position = "relative"; box1.style.display = "inline"; box1.style.top = 0; box1.style.left = 0; // A shadow for fun var shadow = document.createElement("div"); shadow.style.position = "absolute"; shadow.style.left = "-1.3em"; shadow.style.top = "-1.3em"; shadow.style.background = "#404040"; // The inner box: absolute positioning. var box2 = document.createElement("div"); box2.style.position = "relative"; box2.style.border = "1px solid #a0a0a0"; box2.style.left = "-.2em"; box2.style.top = "-.2em"; box2.style.background = "white"; box2.style.padding = ".3em .4em .3em .4em"; box2.style.fontStyle = "normal"; box2.onmouseout=auto_kill_doclink; box2.parentID = id; // Get the targets var targets_elt = document.getElementById(targets_id); var targets = targets_elt.getAttribute("targets"); var links = ""; target_list = targets.split(","); for (var i=0; i" + target[0] + ""; } // Put it all together. elt.insertBefore(box1, elt.childNodes.item(0)); //box1.appendChild(box2); box1.appendChild(shadow); shadow.appendChild(box2); box2.innerHTML = "Which "+name+" do you want to see documentation for?" + ""; } return false; } function get_anchor() { var href = location.href; var start = href.indexOf("#")+1; if ((start != 0) && (start != href.length)) return href.substring(start, href.length); } function redirect_url(dottedName) { // Scan through each element of the "pages" list, and check // if "name" matches with any of them. for (var i=0; i-m" or "-c"; // extract the portion & compare it to dottedName. var pagename = pages[i].substring(0, pages[i].length-2); if (pagename == dottedName.substring(0,pagename.length)) { // We've found a page that matches `dottedName`; // construct its URL, using leftover `dottedName` // content to form an anchor. var pagetype = pages[i].charAt(pages[i].length-1); var url = pagename + ((pagetype=="m")?"-module.html": "-class.html"); if (dottedName.length > pagename.length) url += "#" + dottedName.substring(pagename.length+1, dottedName.length); return url; } } } wxmpl-2.0.0/reference/frames.html0000644000175000017500000000107711647105464017232 0ustar segresegre00000000000000 WxMpl wxmpl-2.0.0/reference/help.html0000644000175000017500000002525111647105464016705 0ustar segresegre00000000000000 Help
 
[frames] | no frames]

API Documentation

This document contains the API (Application Programming Interface) documentation for WxMpl. Documentation for the Python objects defined by the project is divided into separate pages for each package, module, and class. The API documentation also includes two pages containing information about the project as a whole: a trees page, and an index page.

Object Documentation

Each Package Documentation page contains:

  • A description of the package.
  • A list of the modules and sub-packages contained by the package.
  • A summary of the classes defined by the package.
  • A summary of the functions defined by the package.
  • A summary of the variables defined by the package.
  • A detailed description of each function defined by the package.
  • A detailed description of each variable defined by the package.

Each Module Documentation page contains:

  • A description of the module.
  • A summary of the classes defined by the module.
  • A summary of the functions defined by the module.
  • A summary of the variables defined by the module.
  • A detailed description of each function defined by the module.
  • A detailed description of each variable defined by the module.

Each Class Documentation page contains:

  • A class inheritance diagram.
  • A list of known subclasses.
  • A description of the class.
  • A summary of the methods defined by the class.
  • A summary of the instance variables defined by the class.
  • A summary of the class (static) variables defined by the class.
  • A detailed description of each method defined by the class.
  • A detailed description of each instance variable defined by the class.
  • A detailed description of each class (static) variable defined by the class.

Project Documentation

The Trees page contains the module and class hierarchies:

  • The module hierarchy lists every package and module, with modules grouped into packages. At the top level, and within each package, modules and sub-packages are listed alphabetically.
  • The class hierarchy lists every class, grouped by base class. If a class has more than one base class, then it will be listed under each base class. At the top level, and under each base class, classes are listed alphabetically.

The Index page contains indices of terms and identifiers:

  • The term index lists every term indexed by any object's documentation. For each term, the index provides links to each place where the term is indexed.
  • The identifier index lists the (short) name of every package, module, class, method, function, variable, and parameter. For each identifier, the index provides a short description, and a link to its documentation.

The Table of Contents

The table of contents occupies the two frames on the left side of the window. The upper-left frame displays the project contents, and the lower-left frame displays the module contents:

Project
Contents
...
API
Documentation
Frame


Module
Contents
 
...
 

The project contents frame contains a list of all packages and modules that are defined by the project. Clicking on an entry will display its contents in the module contents frame. Clicking on a special entry, labeled "Everything," will display the contents of the entire project.

The module contents frame contains a list of every submodule, class, type, exception, function, and variable defined by a module or package. Clicking on an entry will display its documentation in the API documentation frame. Clicking on the name of the module, at the top of the frame, will display the documentation for the module itself.

The "frames" and "no frames" buttons below the top navigation bar can be used to control whether the table of contents is displayed or not.

The Navigation Bar

A navigation bar is located at the top and bottom of every page. It indicates what type of page you are currently viewing, and allows you to go to related pages. The following table describes the labels on the navigation bar. Note that not some labels (such as [Parent]) are not displayed on all pages.

Label Highlighted when... Links to...
[Parent] (never highlighted) the parent of the current package
[Package] viewing a package the package containing the current object
[Module] viewing a module the module containing the current object
[Class] viewing a class the class containing the current object
[Trees] viewing the trees page the trees page
[Index] viewing the index page the index page
[Help] viewing the help page the help page

The "show private" and "hide private" buttons below the top navigation bar can be used to control whether documentation for private objects is displayed. Private objects are usually defined as objects whose (short) names begin with a single underscore, but do not end with an underscore. For example, "_x", "__pprint", and "epydoc.epytext._tokenize" are private objects; but "re.sub", "__init__", and "type_" are not. However, if a module defines the "__all__" variable, then its contents are used to decide which objects are private.

A timestamp below the bottom navigation bar indicates when each page was last updated.

wxmpl-2.0.0/reference/identifier-index.html0000644000175000017500000006364011647105464021210 0ustar segresegre00000000000000 Identifier Index
 
[frames] | no frames]

Identifier Index

[ A B C D E F G H I J K L M N O P Q R S T U V W X Y Z _ ]

A

C

D

E

F

G

H

M

N

O

P

S

U

W

Z

_



wxmpl-2.0.0/reference/index.html0000644000175000017500000000107711647105465017065 0ustar segresegre00000000000000 WxMpl wxmpl-2.0.0/reference/module-tree.html0000644000175000017500000000760211647105464020177 0ustar segresegre00000000000000 Module Hierarchy
 
[frames] | no frames]
[ Module Hierarchy | Class Hierarchy ]

Module Hierarchy

  • wxmpl: Embedding matplotlib in wxPython applications is straightforward, but the default plotting widget lacks the capabilities necessary for interactive use.
wxmpl-2.0.0/reference/redirect.html0000644000175000017500000000222611647105465017554 0ustar segresegre00000000000000Epydoc Redirect Page

Epydoc Auto-redirect page

When javascript is enabled, this page will redirect URLs of the form redirect.html#dotted.name to the documentation for the object with the given fully-qualified dotted name.

 

wxmpl-2.0.0/reference/toc-everything.html0000644000175000017500000000346111647105464020723 0ustar segresegre00000000000000 Everything

Everything


All Classes

wxmpl.Channel
wxmpl.FigurePrinter
wxmpl.PlotApp
wxmpl.PlotFrame
wxmpl.PlotPanel
wxmpl.PointEvent
wxmpl.SelectionEvent
wxmpl.StripCharter

All Functions

wxmpl.EVT_POINT
wxmpl.EVT_SELECTION

wxmpl-2.0.0/reference/toc-wxmpl-module.html0000644000175000017500000000335211647105464021170 0ustar segresegre00000000000000 wxmpl

Module wxmpl


Classes

Channel
FigurePrinter
PlotApp
PlotFrame
PlotPanel
PointEvent
SelectionEvent
StripCharter

Functions

EVT_POINT
EVT_SELECTION

wxmpl-2.0.0/reference/toc.html0000644000175000017500000000212611647105464016536 0ustar segresegre00000000000000 Table of Contents

Table of Contents


Everything

Modules

wxmpl

wxmpl-2.0.0/reference/wxmpl-module.html0000644000175000017500000002230011647105464020377 0ustar segresegre00000000000000 wxmpl
Module wxmpl
[frames] | no frames]

Module wxmpl

source code

Embedding matplotlib in wxPython applications is straightforward, but the default plotting widget lacks the capabilities necessary for interactive use. WxMpl (wxPython+matplotlib) is a library of components that provide these missing features in the form of a better matplolib FigureCanvas.


Version: 2.0dev

Classes
  FigurePrinter
Provides a simplified interface to the wxPython printing framework that's designed for printing matplotlib figures.
  PointEvent
wxPython event emitted when a left-click-release occurs in a matplotlib axes of a window without an area selection.
  SelectionEvent
wxPython event emitted when an area selection occurs in a matplotlib axes of a window for which zooming has been disabled.
  PlotPanel
A matplotlib canvas suitable for embedding in wxPython applications.
  PlotFrame
A matplotlib canvas embedded in a wxPython top-level window.
  PlotApp
A wxApp that provides a matplotlib canvas embedded in a wxPython top-level window, encapsulating wxPython's nuts and bolts.
  StripCharter
Plots and updates lines on a matplotlib Axes.
  Channel
Provides data for a StripCharter to plot.
Functions
 
EVT_POINT(win, id, func)
Register to receive wxPython PointEvents from a PlotPanel or PlotFrame.
source code
 
EVT_SELECTION(win, id, func)
Register to receive wxPython SelectionEvents from a PlotPanel or PlotFrame.
source code
wxmpl-2.0.0/reference/wxmpl-pysrc.html0000644000175000017500000175730711647105465020302 0ustar segresegre00000000000000 wxmpl
Module wxmpl
[frames] | no frames]

Source Code for Module wxmpl

   1  # Purpose: painless matplotlib embedding for wxPython 
   2  # Author: Ken McIvor <mcivor@iit.edu> 
   3  # 
   4  # Copyright 2005-2009 Illinois Institute of Technology 
   5  # 
   6  # See the file "LICENSE" for information on usage and redistribution 
   7  # of this file, and for a DISCLAIMER OF ALL WARRANTIES. 
   8   
   9  """ 
  10  Embedding matplotlib in wxPython applications is straightforward, but the 
  11  default plotting widget lacks the capabilities necessary for interactive use. 
  12  WxMpl (wxPython+matplotlib) is a library of components that provide these 
  13  missing features in the form of a better matplolib FigureCanvas. 
  14  """ 
  15   
  16   
  17  import wx 
  18  import sys 
  19  import os.path 
  20  import weakref 
  21   
  22  import matplotlib 
  23  matplotlib.use('WXAgg') 
  24  import numpy as NumPy 
  25  from matplotlib.axes import _process_plot_var_args 
  26  from matplotlib.backend_bases import FigureCanvasBase 
  27  from matplotlib.backends.backend_agg import FigureCanvasAgg, RendererAgg 
  28  from matplotlib.backends.backend_wxagg import FigureCanvasWxAgg 
  29  from matplotlib.figure import Figure 
  30  from matplotlib.font_manager import FontProperties 
  31  from matplotlib.projections.polar import PolarAxes 
  32  from matplotlib.transforms import Bbox 
  33   
  34  __version__ = '2.0dev' 
  35   
  36  __all__ = ['PlotPanel', 'PlotFrame', 'PlotApp', 'StripCharter', 'Channel', 
  37      'FigurePrinter', 'PointEvent', 'EVT_POINT', 'SelectionEvent', 
  38      'EVT_SELECTION'] 
  39   
  40  # If you are using wxGtk without libgnomeprint and want to use something other 
  41  # than `lpr' to print you will have to specify that command here. 
  42  POSTSCRIPT_PRINTING_COMMAND = 'lpr' 
  43   
  44  # Between 0.98.1 and 0.98.3rc there were some significant API changes: 
  45  #   * FigureCanvasWx.draw(repaint=True) became draw(drawDC=None) 
  46  #   * The following events were added: 
  47  #       - figure_enter_event 
  48  #       - figure_leave_event 
  49  #       - axes_enter_event 
  50  #       - axes_leave_event 
  51  MATPLOTLIB_0_98_3 = '0.98.3' <= matplotlib.__version__ 
  52   
  53   
  54  # 
  55  # Utility functions and classes 
  56  # 
  57   
58 -def invert_point(x, y, transform):
59 """ 60 Returns a coordinate inverted by the specificed C{Transform}. 61 """ 62 return transform.inverted().transform_point((x, y))
63 64
65 -def find_axes(canvas, x, y):
66 """ 67 Finds the C{Axes} within a matplotlib C{FigureCanvas} contains the canvas 68 coordinates C{(x, y)} and returns that axes and the corresponding data 69 coordinates C{xdata, ydata} as a 3-tuple. 70 71 If no axes contains the specified point a 3-tuple of C{None} is returned. 72 """ 73 evt = matplotlib.backend_bases.MouseEvent('', canvas, x, y) 74 75 axes = None 76 for a in canvas.get_figure().get_axes(): 77 if a.in_axes(evt): 78 if axes is None: 79 axes = a 80 else: 81 return None, None, None 82 83 if axes is None: 84 return None, None, None 85 86 xdata, ydata = invert_point(x, y, axes.transData) 87 return axes, xdata, ydata
88 89
90 -def get_bbox_lims(bbox):
91 """ 92 Returns the boundaries of the X and Y intervals of a C{Bbox}. 93 """ 94 p0 = bbox.min 95 p1 = bbox.max 96 return (p0[0], p1[0]), (p0[1], p1[1])
97 98
99 -def find_selected_axes(canvas, x1, y1, x2, y2):
100 """ 101 Finds the C{Axes} within a matplotlib C{FigureCanvas} that overlaps with a 102 canvas area from C{(x1, y1)} to C{(x1, y1)}. That axes and the 103 corresponding X and Y axes ranges are returned as a 3-tuple. 104 105 If no axes overlaps with the specified area, or more than one axes 106 overlaps, a 3-tuple of C{None}s is returned. 107 """ 108 axes = None 109 bbox = Bbox.from_extents(x1, y1, x2, y2) 110 111 for a in canvas.get_figure().get_axes(): 112 if bbox.overlaps(a.bbox): 113 if axes is None: 114 axes = a 115 else: 116 return None, None, None 117 118 if axes is None: 119 return None, None, None 120 121 x1, y1, x2, y2 = limit_selection(bbox, axes) 122 xrange, yrange = get_bbox_lims( 123 Bbox.from_extents(x1, y1, x2, y2).inverse_transformed(axes.transData)) 124 return axes, xrange, yrange
125 126
127 -def limit_selection(bbox, axes):
128 """ 129 Finds the region of a selection C{bbox} which overlaps with the supplied 130 C{axes} and returns it as the 4-tuple C{(xmin, ymin, xmax, ymax)}. 131 """ 132 bxr, byr = get_bbox_lims(bbox) 133 axr, ayr = get_bbox_lims(axes.bbox) 134 135 xmin = max(bxr[0], axr[0]) 136 xmax = min(bxr[1], axr[1]) 137 ymin = max(byr[0], ayr[0]) 138 ymax = min(byr[1], ayr[1]) 139 return xmin, ymin, xmax, ymax
140 141
142 -def format_coord(axes, xdata, ydata):
143 """ 144 A C{None}-safe version of {Axes.format_coord()}. 145 """ 146 if xdata is None or ydata is None: 147 return '' 148 return axes.format_coord(xdata, ydata)
149 150
151 -def toplevel_parent_of_window(window):
152 """ 153 Returns the first top-level parent of a wx.Window 154 """ 155 topwin = window 156 while not isinstance(topwin, wx.TopLevelWindow): 157 topwin = topwin.GetParent() 158 return topwin
159 160
161 -class AxesLimits:
162 """ 163 Alters the X and Y limits of C{Axes} objects while maintaining a history of 164 the changes. 165 """
166 - def __init__(self, autoscaleUnzoom):
167 self.autoscaleUnzoom = autoscaleUnzoom 168 self.history = weakref.WeakKeyDictionary()
169
170 - def setAutoscaleUnzoom(self, state):
171 """ 172 Enable or disable autoscaling the axes as a result of zooming all the 173 way back out. 174 """ 175 self.limits.setAutoscaleUnzoom(state)
176
177 - def _get_history(self, axes):
178 """ 179 Returns the history list of X and Y limits associated with C{axes}. 180 """ 181 return self.history.setdefault(axes, [])
182
183 - def zoomed(self, axes):
184 """ 185 Returns a boolean indicating whether C{axes} has had its limits 186 altered. 187 """ 188 return not (not self._get_history(axes))
189
190 - def set(self, axes, xrange, yrange):
191 """ 192 Changes the X and Y limits of C{axes} to C{xrange} and {yrange} 193 respectively. A boolean indicating whether or not the 194 axes should be redraw is returned, because polar axes cannot have 195 their limits changed sensibly. 196 """ 197 if not axes.can_zoom(): 198 return False 199 200 # The axes limits must be converted to tuples because MPL 0.98.1 201 # returns the underlying array objects 202 oldRange = tuple(axes.get_xlim()), tuple(axes.get_ylim()) 203 204 history = self._get_history(axes) 205 history.append(oldRange) 206 axes.set_xlim(xrange) 207 axes.set_ylim(yrange) 208 return True
209
210 - def restore(self, axes):
211 """ 212 Changes the X and Y limits of C{axes} to their previous values. A 213 boolean indicating whether or not the axes should be redraw is 214 returned. 215 """ 216 history = self._get_history(axes) 217 if not history: 218 return False 219 220 xrange, yrange = history.pop() 221 if self.autoscaleUnzoom and not len(history): 222 axes.autoscale_view() 223 else: 224 axes.set_xlim(xrange) 225 axes.set_ylim(yrange) 226 return True
227 228 229 # 230 # Director of the matplotlib canvas 231 # 232
233 -class PlotPanelDirector:
234 """ 235 Encapsulates all of the user-interaction logic required by the 236 C{PlotPanel}, following the Humble Dialog Box pattern proposed by Michael 237 Feathers: 238 U{http://www.objectmentor.com/resources/articles/TheHumbleDialogBox.pdf} 239 """ 240 241 # TODO: add a programmatic interface to zooming and user interactions 242 # TODO: full support for MPL events 243
244 - def __init__(self, view, zoom=True, selection=True, rightClickUnzoom=True, 245 autoscaleUnzoom=True):
246 """ 247 Create a new director for the C{PlotPanel} C{view}. The keyword 248 arguments C{zoom} and C{selection} have the same meanings as for 249 C{PlotPanel}. 250 """ 251 self.view = view 252 self.zoomEnabled = zoom 253 self.selectionEnabled = selection 254 self.rightClickUnzoom = rightClickUnzoom 255 self.limits = AxesLimits(autoscaleUnzoom) 256 self.leftButtonPoint = None
257
258 - def setSelection(self, state):
259 """ 260 Enable or disable left-click area selection. 261 """ 262 self.selectionEnabled = state
263
264 - def setZoomEnabled(self, state):
265 """ 266 Enable or disable zooming as a result of left-click area selection. 267 """ 268 self.zoomEnabled = state
269
270 - def setAutoscaleUnzoom(self, state):
271 """ 272 Enable or disable autoscaling the axes as a result of zooming all the 273 way back out. 274 """ 275 self.limits.setAutoscaleUnzoom(state)
276
277 - def setRightClickUnzoom(self, state):
278 """ 279 Enable or disable unzooming as a result of right-clicking. 280 """ 281 self.rightClickUnzoom = state
282
283 - def canDraw(self):
284 """ 285 Indicates if plot may be not redrawn due to the presence of a selection 286 box. 287 """ 288 return self.leftButtonPoint is None
289
290 - def zoomed(self, axes):
291 """ 292 Returns a boolean indicating whether or not the plot has been zoomed in 293 as a result of a left-click area selection. 294 """ 295 return self.limits.zoomed(axes)
296
297 - def keyDown(self, evt):
298 """ 299 Handles wxPython key-press events. These events are currently skipped. 300 """ 301 evt.Skip()
302
303 - def keyUp(self, evt):
304 """ 305 Handles wxPython key-release events. These events are currently 306 skipped. 307 """ 308 evt.Skip()
309
310 - def leftButtonDown(self, evt, x, y):
311 """ 312 Handles wxPython left-click events. 313 """ 314 self.leftButtonPoint = (x, y) 315 316 view = self.view 317 axes, xdata, ydata = find_axes(view, x, y) 318 319 if axes is not None and self.selectionEnabled and axes.can_zoom(): 320 view.cursor.setCross() 321 view.crosshairs.clear()
322
323 - def leftButtonUp(self, evt, x, y):
324 """ 325 Handles wxPython left-click-release events. 326 """ 327 if self.leftButtonPoint is None: 328 return 329 330 view = self.view 331 axes, xdata, ydata = find_axes(view, x, y) 332 333 x0, y0 = self.leftButtonPoint 334 self.leftButtonPoint = None 335 view.rubberband.clear() 336 337 if x0 == x: 338 if y0 == y and axes is not None: 339 view.notify_point(axes, x, y) 340 view.crosshairs.set(x, y) 341 return 342 elif y0 == y: 343 return 344 345 xdata = ydata = None 346 axes, xrange, yrange = find_selected_axes(view, x0, y0, x, y) 347 348 if axes is not None: 349 xdata, ydata = invert_point(x, y, axes.transData) 350 if self.zoomEnabled: 351 if self.limits.set(axes, xrange, yrange): 352 self.view.draw() 353 else: 354 bbox = Bbox.from_extents(x0, y0, x, y) 355 x1, y1, x2, y2 = limit_selection(bbox, axes) 356 self.view.notify_selection(axes, x1, y1, x2, y2) 357 358 if axes is None: 359 view.cursor.setNormal() 360 elif not axes.can_zoom(): 361 view.cursor.setNormal() 362 view.location.set(format_coord(axes, xdata, ydata)) 363 else: 364 view.crosshairs.set(x, y) 365 view.location.set(format_coord(axes, xdata, ydata))
366
367 - def rightButtonDown(self, evt, x, y):
368 """ 369 Handles wxPython right-click events. These events are currently 370 skipped. 371 """ 372 evt.Skip()
373
374 - def rightButtonUp(self, evt, x, y):
375 """ 376 Handles wxPython right-click-release events. 377 """ 378 view = self.view 379 axes, xdata, ydata = find_axes(view, x, y) 380 if (axes is not None and self.zoomEnabled and self.rightClickUnzoom 381 and self.limits.restore(axes)): 382 view.crosshairs.clear() 383 view.draw() 384 view.crosshairs.set(x, y)
385
386 - def mouseMotion(self, evt, x, y):
387 """ 388 Handles wxPython mouse motion events, dispatching them based on whether 389 or not a selection is in process and what the cursor is over. 390 """ 391 view = self.view 392 axes, xdata, ydata = find_axes(view, x, y) 393 394 if self.leftButtonPoint is not None: 395 self.selectionMouseMotion(evt, x, y, axes, xdata, ydata) 396 else: 397 if axes is None: 398 self.canvasMouseMotion(evt, x, y) 399 elif not axes.can_zoom(): 400 self.unzoomableAxesMouseMotion(evt, x, y, axes, xdata, ydata) 401 else: 402 self.axesMouseMotion(evt, x, y, axes, xdata, ydata)
403
404 - def selectionMouseMotion(self, evt, x, y, axes, xdata, ydata):
405 """ 406 Handles wxPython mouse motion events that occur during a left-click 407 area selection. 408 """ 409 view = self.view 410 x0, y0 = self.leftButtonPoint 411 view.rubberband.set(x0, y0, x, y) 412 if axes is None: 413 view.location.clear() 414 else: 415 view.location.set(format_coord(axes, xdata, ydata))
416
417 - def canvasMouseMotion(self, evt, x, y):
418 """ 419 Handles wxPython mouse motion events that occur over the canvas. 420 """ 421 view = self.view 422 view.cursor.setNormal() 423 view.crosshairs.clear() 424 view.location.clear()
425
426 - def axesMouseMotion(self, evt, x, y, axes, xdata, ydata):
427 """ 428 Handles wxPython mouse motion events that occur over an axes. 429 """ 430 view = self.view 431 view.cursor.setCross() 432 view.crosshairs.set(x, y) 433 view.location.set(format_coord(axes, xdata, ydata))
434
435 - def unzoomableAxesMouseMotion(self, evt, x, y, axes, xdata, ydata):
436 """ 437 Handles wxPython mouse motion events that occur over an axes that does 438 not support zooming. 439 """ 440 view = self.view 441 view.cursor.setNormal() 442 view.location.set(format_coord(axes, xdata, ydata))
443 444 445 # 446 # Components used by the PlotPanel 447 # 448
449 -class Painter:
450 """ 451 Painters encapsulate the mechanics of drawing some value in a wxPython 452 window and erasing it. Subclasses override template methods to process 453 values and draw them. 454 455 @cvar PEN: C{wx.Pen} to use (defaults to C{wx.BLACK_PEN}) 456 @cvar BRUSH: C{wx.Brush} to use (defaults to C{wx.TRANSPARENT_BRUSH}) 457 @cvar FUNCTION: Logical function to use (defaults to C{wx.COPY}) 458 @cvar FONT: C{wx.Font} to use (defaults to C{wx.NORMAL_FONT}) 459 @cvar TEXT_FOREGROUND: C{wx.Colour} to use (defaults to C{wx.BLACK}) 460 @cvar TEXT_BACKGROUND: C{wx.Colour} to use (defaults to C{wx.WHITE}) 461 """ 462 463 PEN = wx.BLACK_PEN 464 BRUSH = wx.TRANSPARENT_BRUSH 465 FUNCTION = wx.COPY 466 FONT = wx.NORMAL_FONT 467 TEXT_FOREGROUND = wx.BLACK 468 TEXT_BACKGROUND = wx.WHITE 469
470 - def __init__(self, view, enabled=True):
471 """ 472 Create a new painter attached to the wxPython window C{view}. The 473 keyword argument C{enabled} has the same meaning as the argument to the 474 C{setEnabled()} method. 475 """ 476 self.view = view 477 self.lastValue = None 478 self.enabled = enabled
479
480 - def setEnabled(self, state):
481 """ 482 Enable or disable this painter. Disabled painters do not draw their 483 values and calls to C{set()} have no effect on them. 484 """ 485 oldState, self.enabled = self.enabled, state 486 if oldState and not self.enabled: 487 self.clear()
488
489 - def set(self, *value):
490 """ 491 Update this painter's value and then draw it. Values may not be 492 C{None}, which is used internally to represent the absence of a current 493 value. 494 """ 495 if self.enabled: 496 value = self.formatValue(value) 497 self._paint(value, None)
498
499 - def redraw(self, dc=None):
500 """ 501 Redraw this painter's current value. 502 """ 503 value = self.lastValue 504 self.lastValue = None 505 self._paint(value, dc)
506
507 - def clear(self, dc=None):
508 """ 509 Clear the painter's current value from the screen and the painter 510 itself. 511 """ 512 if self.lastValue is not None: 513 self._paint(None, dc)
514
515 - def _paint(self, value, dc):
516 """ 517 Draws a previously processed C{value} on this painter's window. 518 """ 519 if dc is None: 520 dc = wx.ClientDC(self.view) 521 522 dc.SetPen(self.PEN) 523 dc.SetBrush(self.BRUSH) 524 dc.SetFont(self.FONT) 525 dc.SetTextForeground(self.TEXT_FOREGROUND) 526 dc.SetTextBackground(self.TEXT_BACKGROUND) 527 dc.SetLogicalFunction(self.FUNCTION) 528 dc.BeginDrawing() 529 530 if self.lastValue is not None: 531 self.clearValue(dc, self.lastValue) 532 self.lastValue = None 533 534 if value is not None: 535 self.drawValue(dc, value) 536 self.lastValue = value 537 538 dc.EndDrawing()
539
540 - def formatValue(self, value):
541 """ 542 Template method that processes the C{value} tuple passed to the 543 C{set()} method, returning the processed version. 544 """ 545 return value
546
547 - def drawValue(self, dc, value):
548 """ 549 Template method that draws a previously processed C{value} using the 550 wxPython device context C{dc}. This DC has already been configured, so 551 calls to C{BeginDrawing()} and C{EndDrawing()} may not be made. 552 """ 553 pass
554
555 - def clearValue(self, dc, value):
556 """ 557 Template method that clears a previously processed C{value} that was 558 previously drawn, using the wxPython device context C{dc}. This DC has 559 already been configured, so calls to C{BeginDrawing()} and 560 C{EndDrawing()} may not be made. 561 """ 562 pass
563 564
565 -class LocationPainter(Painter):
566 """ 567 Draws a text message containing the current position of the mouse in the 568 lower left corner of the plot. 569 """ 570 571 PADDING = 2 572 PEN = wx.WHITE_PEN 573 BRUSH = wx.WHITE_BRUSH 574
575 - def formatValue(self, value):
576 """ 577 Extracts a string from the 1-tuple C{value}. 578 """ 579 return value[0]
580
581 - def get_XYWH(self, dc, value):
582 """ 583 Returns the upper-left coordinates C{(X, Y)} for the string C{value} 584 its width and height C{(W, H)}. 585 """ 586 height = dc.GetSize()[1] 587 w, h = dc.GetTextExtent(value) 588 x = self.PADDING 589 y = int(height - (h + self.PADDING)) 590 return x, y, w, h
591
592 - def drawValue(self, dc, value):
593 """ 594 Draws the string C{value} in the lower left corner of the plot. 595 """ 596 x, y, w, h = self.get_XYWH(dc, value) 597 dc.DrawText(value, x, y)
598
599 - def clearValue(self, dc, value):
600 """ 601 Clears the string C{value} from the lower left corner of the plot by 602 painting a white rectangle over it. 603 """ 604 x, y, w, h = self.get_XYWH(dc, value) 605 dc.DrawRectangle(x, y, w, h)
606 607
608 -class CrosshairPainter(Painter):
609 """ 610 Draws crosshairs through the current position of the mouse. 611 """ 612 613 PEN = wx.WHITE_PEN 614 FUNCTION = wx.XOR 615
616 - def formatValue(self, value):
617 """ 618 Converts the C{(X, Y)} mouse coordinates from matplotlib to wxPython. 619 """ 620 x, y = value 621 return int(x), int(self.view.get_figure().bbox.height - y)
622
623 - def drawValue(self, dc, value):
624 """ 625 Draws crosshairs through the C{(X, Y)} coordinates. 626 """ 627 dc.CrossHair(*value)
628
629 - def clearValue(self, dc, value):
630 """ 631 Clears the crosshairs drawn through the C{(X, Y)} coordinates. 632 """ 633 dc.CrossHair(*value)
634 635
636 -class RubberbandPainter(Painter):
637 """ 638 Draws a selection rubberband from one point to another. 639 """ 640 641 PEN = wx.WHITE_PEN 642 FUNCTION = wx.XOR 643
644 - def formatValue(self, value):
645 """ 646 Converts the C{(x1, y1, x2, y2)} mouse coordinates from matplotlib to 647 wxPython. 648 """ 649 x1, y1, x2, y2 = value 650 height = self.view.get_figure().bbox.height 651 y1 = height - y1 652 y2 = height - y2 653 if x2 < x1: x1, x2 = x2, x1 654 if y2 < y1: y1, y2 = y2, y1 655 return [int(z) for z in (x1, y1, x2-x1, y2-y1)]
656
657 - def drawValue(self, dc, value):
658 """ 659 Draws the selection rubberband around the rectangle 660 C{(x1, y1, x2, y2)}. 661 """ 662 dc.DrawRectangle(*value)
663
664 - def clearValue(self, dc, value):
665 """ 666 Clears the selection rubberband around the rectangle 667 C{(x1, y1, x2, y2)}. 668 """ 669 dc.DrawRectangle(*value)
670 671
672 -class CursorChanger:
673 """ 674 Manages the current cursor of a wxPython window, allowing it to be switched 675 between a normal arrow and a square cross. 676 """
677 - def __init__(self, view, enabled=True):
678 """ 679 Create a CursorChanger attached to the wxPython window C{view}. The 680 keyword argument C{enabled} has the same meaning as the argument to the 681 C{setEnabled()} method. 682 """ 683 self.view = view 684 self.cursor = wx.CURSOR_DEFAULT 685 self.enabled = enabled
686
687 - def setEnabled(self, state):
688 """ 689 Enable or disable this cursor changer. When disabled, the cursor is 690 reset to the normal arrow and calls to the C{set()} methods have no 691 effect. 692 """ 693 oldState, self.enabled = self.enabled, state 694 if oldState and not self.enabled and self.cursor != wx.CURSOR_DEFAULT: 695 self.cursor = wx.CURSOR_DEFAULT 696 self.view.SetCursor(wx.STANDARD_CURSOR)
697
698 - def setNormal(self):
699 """ 700 Change the cursor of the associated window to a normal arrow. 701 """ 702 if self.cursor != wx.CURSOR_DEFAULT and self.enabled: 703 self.cursor = wx.CURSOR_DEFAULT 704 self.view.SetCursor(wx.STANDARD_CURSOR)
705
706 - def setCross(self):
707 """ 708 Change the cursor of the associated window to a square cross. 709 """ 710 if self.cursor != wx.CURSOR_CROSS and self.enabled: 711 self.cursor = wx.CURSOR_CROSS 712 self.view.SetCursor(wx.CROSS_CURSOR)
713 714 715 # 716 # Printing Framework 717 # 718 719 # PostScript resolutions for the various WX print qualities 720 PS_DPI_HIGH_QUALITY = 600 721 PS_DPI_MEDIUM_QUALITY = 300 722 PS_DPI_LOW_QUALITY = 150 723 PS_DPI_DRAFT_QUALITY = 72 724 725
726 -def update_postscript_resolution(printData):
727 """ 728 Sets the default wx.PostScriptDC resolution from a wx.PrintData's quality 729 setting. 730 731 This is a workaround for WX ignoring the quality setting and defaulting to 732 72 DPI. Unfortunately wx.Printout.GetDC() returns a wx.DC object instead 733 of the actual class, so it's impossible to set the resolution on the DC 734 itself. 735 736 Even more unforuntately, printing with libgnomeprint appears to always be 737 stuck at 72 DPI. 738 """ 739 if not callable(getattr(wx, 'PostScriptDC_SetResolution', None)): 740 return 741 742 quality = printData.GetQuality() 743 if quality > 0: 744 dpi = quality 745 elif quality == wx.PRINT_QUALITY_HIGH: 746 dpi = PS_DPI_HIGH_QUALITY 747 elif quality == wx.PRINT_QUALITY_MEDIUM: 748 dpi = PS_DPI_MEDIUM_QUALITY 749 elif quality == wx.PRINT_QUALITY_LOW: 750 dpi = PS_DPI_LOW_QUALITY 751 elif quality == wx.PRINT_QUALITY_DRAFT: 752 dpi = PS_DPI_DRAFT_QUALITY 753 else: 754 dpi = PS_DPI_HIGH_QUALITY 755 756 wx.PostScriptDC_SetResolution(dpi)
757 758
759 -class FigurePrinter:
760 """ 761 Provides a simplified interface to the wxPython printing framework that's 762 designed for printing matplotlib figures. 763 """ 764
765 - def __init__(self, view, printData=None):
766 """ 767 Create a new C{FigurePrinter} associated with the wxPython widget 768 C{view}. The keyword argument C{printData} supplies a C{wx.PrintData} 769 object containing the default printer settings. 770 """ 771 self.view = view 772 773 if printData is None: 774 printData = wx.PrintData() 775 776 self.setPrintData(printData)
777
778 - def getPrintData(self):
779 """ 780 Return the current printer settings in their C{wx.PrintData} object. 781 """ 782 return self.pData
783
784 - def setPrintData(self, printData):
785 """ 786 Use the printer settings in C{printData}. 787 """ 788 self.pData = printData 789 update_postscript_resolution(self.pData)
790
791 - def pageSetup(self):
792 dlg = wx.PrintDialog(self.view) 793 pdData = dlg.GetPrintDialogData() 794 pdData.SetPrintData(self.pData) 795 796 if dlg.ShowModal() == wx.ID_OK: 797 self.setPrintData(pdData.GetPrintData()) 798 dlg.Destroy()
799
800 - def previewFigure(self, figure, title=None):
801 """ 802 Open a "Print Preview" window for the matplotlib chart C{figure}. The 803 keyword argument C{title} provides the printing framework with a title 804 for the print job. 805 """ 806 topwin = toplevel_parent_of_window(self.view) 807 fpo = FigurePrintout(figure, title) 808 fpo4p = FigurePrintout(figure, title) 809 preview = wx.PrintPreview(fpo, fpo4p, self.pData) 810 frame = wx.PreviewFrame(preview, topwin, 'Print Preview') 811 if self.pData.GetOrientation() == wx.PORTRAIT: 812 frame.SetSize(wx.Size(450, 625)) 813 else: 814 frame.SetSize(wx.Size(600, 500)) 815 frame.Initialize() 816 frame.Show(True)
817
818 - def printFigure(self, figure, title=None):
819 """ 820 Open a "Print" dialog to print the matplotlib chart C{figure}. The 821 keyword argument C{title} provides the printing framework with a title 822 for the print job. 823 """ 824 pdData = wx.PrintDialogData() 825 pdData.SetPrintData(self.pData) 826 printer = wx.Printer(pdData) 827 fpo = FigurePrintout(figure, title) 828 if printer.Print(self.view, fpo, True): 829 self.setPrintData(pdData.GetPrintData())
830 831
832 -class FigurePrintout(wx.Printout):
833 """ 834 Render a matplotlib C{Figure} to a page or file using wxPython's printing 835 framework. 836 """ 837 838 ASPECT_RECTANGULAR = 1 839 ASPECT_SQUARE = 2 840
841 - def __init__(self, figure, title=None, size=None, aspectRatio=None):
842 """ 843 Create a printout for the matplotlib chart C{figure}. The 844 keyword argument C{title} provides the printing framework with a title 845 for the print job. The keyword argument C{size} specifies how to scale 846 the figure, from 1 to 100 percent. The keyword argument C{aspectRatio} 847 determines whether the printed figure will be rectangular or square. 848 """ 849 self.figure = figure 850 851 figTitle = figure.gca().title.get_text() 852 if not figTitle: 853 figTitle = title or 'Matplotlib Figure' 854 855 if size is None: 856 size = 100 857 elif size < 1 or size > 100: 858 raise ValueError('invalid figure size') 859 self.size = size 860 861 if aspectRatio is None: 862 aspectRatio = self.ASPECT_RECTANGULAR 863 elif (aspectRatio != self.ASPECT_RECTANGULAR 864 and aspectRatio != self.ASPECT_SQUARE): 865 raise ValueError('invalid aspect ratio') 866 self.aspectRatio = aspectRatio 867 868 wx.Printout.__init__(self, figTitle)
869
870 - def GetPageInfo(self):
871 """ 872 Overrides wx.Printout.GetPageInfo() to provide the printing framework 873 with the number of pages in this print job. 874 """ 875 return (1, 1, 1, 1)
876
877 - def HasPage(self, pageNumber):
878 """ 879 Overrides wx.Printout.GetPageInfo() to tell the printing framework 880 of the specified page exists. 881 """ 882 return pageNumber == 1
883
884 - def OnPrintPage(self, pageNumber):
885 """ 886 Overrides wx.Printout.OnPrintPage() to render the matplotlib figure to 887 a printing device context. 888 """ 889 # % of printable area to use 890 imgPercent = max(1, min(100, self.size)) / 100.0 891 892 # ratio of the figure's width to its height 893 if self.aspectRatio == self.ASPECT_RECTANGULAR: 894 aspectRatio = 1.61803399 895 elif self.aspectRatio == self.ASPECT_SQUARE: 896 aspectRatio = 1.0 897 else: 898 raise ValueError('invalid aspect ratio') 899 900 # Device context to draw the page 901 dc = self.GetDC() 902 903 # PPI_P: Pixels Per Inch of the Printer 904 wPPI_P, hPPI_P = [float(x) for x in self.GetPPIPrinter()] 905 PPI_P = (wPPI_P + hPPI_P)/2.0 906 907 # PPI: Pixels Per Inch of the DC 908 if self.IsPreview(): 909 wPPI, hPPI = [float(x) for x in self.GetPPIScreen()] 910 else: 911 wPPI, hPPI = wPPI_P, hPPI_P 912 PPI = (wPPI + hPPI)/2.0 913 914 # Pg_Px: Size of the page (pixels) 915 wPg_Px, hPg_Px = [float(x) for x in self.GetPageSizePixels()] 916 917 # Dev_Px: Size of the DC (pixels) 918 wDev_Px, hDev_Px = [float(x) for x in self.GetDC().GetSize()] 919 920 # Pg: Size of the page (inches) 921 wPg = wPg_Px / PPI_P 922 hPg = hPg_Px / PPI_P 923 924 # minimum margins (inches) 925 wM = 0.75 926 hM = 0.75 927 928 # Area: printable area within the margins (inches) 929 wArea = wPg - 2*wM 930 hArea = hPg - 2*hM 931 932 # Fig: printing size of the figure 933 # hFig is at a maximum when wFig == wArea 934 max_hFig = wArea / aspectRatio 935 hFig = min(imgPercent * hArea, max_hFig) 936 wFig = aspectRatio * hFig 937 938 # scale factor = device size / page size (equals 1.0 for real printing) 939 S = ((wDev_Px/PPI)/wPg + (hDev_Px/PPI)/hPg)/2.0 940 941 # Fig_S: scaled printing size of the figure (inches) 942 # M_S: scaled minimum margins (inches) 943 wFig_S = S * wFig 944 hFig_S = S * hFig 945 wM_S = S * wM 946 hM_S = S * hM 947 948 # Fig_Dx: scaled printing size of the figure (device pixels) 949 # M_Dx: scaled minimum margins (device pixels) 950 wFig_Dx = int(S * PPI * wFig) 951 hFig_Dx = int(S * PPI * hFig) 952 wM_Dx = int(S * PPI * wM) 953 hM_Dx = int(S * PPI * hM) 954 955 image = self.render_figure_as_image(wFig, hFig, PPI) 956 957 if self.IsPreview(): 958 image = image.Scale(wFig_Dx, hFig_Dx) 959 self.GetDC().DrawBitmap(image.ConvertToBitmap(), wM_Dx, hM_Dx, False) 960 961 return True
962
963 - def render_figure_as_image(self, wFig, hFig, dpi):
964 """ 965 Renders a matplotlib figure using the Agg backend and stores the result 966 in a C{wx.Image}. The arguments C{wFig} and {hFig} are the width and 967 height of the figure, and C{dpi} is the dots-per-inch to render at. 968 """ 969 figure = self.figure 970 971 old_dpi = figure.dpi 972 figure.dpi = dpi 973 old_width = figure.get_figwidth() 974 figure.set_figwidth(wFig) 975 old_height = figure.get_figheight() 976 figure.set_figheight(hFig) 977 old_frameon = figure.frameon 978 figure.frameon = False 979 980 wFig_Px = int(figure.bbox.width) 981 hFig_Px = int(figure.bbox.height) 982 983 agg = RendererAgg(wFig_Px, hFig_Px, dpi) 984 figure.draw(agg) 985 986 figure.dpi = old_dpi 987 figure.set_figwidth(old_width) 988 figure.set_figheight(old_height) 989 figure.frameon = old_frameon 990 991 image = wx.EmptyImage(wFig_Px, hFig_Px) 992 image.SetData(agg.tostring_rgb()) 993 return image
994 995 996 # 997 # wxPython event interface for the PlotPanel and PlotFrame 998 # 999 1000 EVT_POINT_ID = wx.NewId() 1001 1002
1003 -def EVT_POINT(win, id, func):
1004 """ 1005 Register to receive wxPython C{PointEvent}s from a C{PlotPanel} or 1006 C{PlotFrame}. 1007 """ 1008 win.Connect(id, -1, EVT_POINT_ID, func)
1009 1010
1011 -class PointEvent(wx.PyCommandEvent):
1012 """ 1013 wxPython event emitted when a left-click-release occurs in a matplotlib 1014 axes of a window without an area selection. 1015 1016 @cvar axes: matplotlib C{Axes} which was left-clicked 1017 @cvar x: matplotlib X coordinate 1018 @cvar y: matplotlib Y coordinate 1019 @cvar xdata: axes X coordinate 1020 @cvar ydata: axes Y coordinate 1021 """
1022 - def __init__(self, id, axes, x, y):
1023 """ 1024 Create a new C{PointEvent} for the matplotlib coordinates C{(x, y)} of 1025 an C{axes}. 1026 """ 1027 wx.PyCommandEvent.__init__(self, EVT_POINT_ID, id) 1028 self.axes = axes 1029 self.x = x 1030 self.y = y 1031 self.xdata, self.ydata = invert_point(x, y, axes.transData)
1032
1033 - def Clone(self):
1034 return PointEvent(self.GetId(), self.axes, self.x, self.y)
1035 1036 1037 EVT_SELECTION_ID = wx.NewId() 1038 1039
1040 -def EVT_SELECTION(win, id, func):
1041 """ 1042 Register to receive wxPython C{SelectionEvent}s from a C{PlotPanel} or 1043 C{PlotFrame}. 1044 """ 1045 win.Connect(id, -1, EVT_SELECTION_ID, func)
1046 1047
1048 -class SelectionEvent(wx.PyCommandEvent):
1049 """ 1050 wxPython event emitted when an area selection occurs in a matplotlib axes 1051 of a window for which zooming has been disabled. The selection is 1052 described by a rectangle from C{(x1, y1)} to C{(x2, y2)}, of which only 1053 one point is required to be inside the axes. 1054 1055 @cvar axes: matplotlib C{Axes} which was left-clicked 1056 @cvar x1: matplotlib x1 coordinate 1057 @cvar y1: matplotlib y1 coordinate 1058 @cvar x2: matplotlib x2 coordinate 1059 @cvar y2: matplotlib y2 coordinate 1060 @cvar x1data: axes x1 coordinate 1061 @cvar y1data: axes y1 coordinate 1062 @cvar x2data: axes x2 coordinate 1063 @cvar y2data: axes y2 coordinate 1064 """
1065 - def __init__(self, id, axes, x1, y1, x2, y2):
1066 """ 1067 Create a new C{SelectionEvent} for the area described by the rectangle 1068 from C{(x1, y1)} to C{(x2, y2)} in an C{axes}. 1069 """ 1070 wx.PyCommandEvent.__init__(self, EVT_SELECTION_ID, id) 1071 self.axes = axes 1072 self.x1 = x1 1073 self.y1 = y1 1074 self.x2 = x2 1075 self.y2 = y2 1076 self.x1data, self.y1data = invert_point(x1, y1, axes.transData) 1077 self.x2data, self.y2data = invert_point(x2, y2, axes.transData)
1078
1079 - def Clone(self):
1080 return SelectionEvent(self.GetId(), self.axes, self.x1, self.y1, 1081 self.x2, self.y2)
1082 1083 1084 # 1085 # Matplotlib canvas in a wxPython window 1086 # 1087
1088 -class PlotPanel(FigureCanvasWxAgg):
1089 """ 1090 A matplotlib canvas suitable for embedding in wxPython applications. 1091 """
1092 - def __init__(self, parent, id, size=(6.0, 3.70), dpi=96, cursor=True, 1093 location=True, crosshairs=True, selection=True, zoom=True, 1094 autoscaleUnzoom=True):
1095 """ 1096 Creates a new PlotPanel window that is the child of the wxPython window 1097 C{parent} with the wxPython identifier C{id}. 1098 1099 The keyword arguments C{size} and {dpi} are used to create the 1100 matplotlib C{Figure} associated with this canvas. C{size} is the 1101 desired width and height of the figure, in inches, as the 2-tuple 1102 C{(width, height)}. C{dpi} is the dots-per-inch of the figure. 1103 1104 The keyword arguments C{cursor}, C{location}, C{crosshairs}, 1105 C{selection}, C{zoom}, and C{autoscaleUnzoom} enable or disable various 1106 user interaction features that are descibed in their associated 1107 C{set()} methods. 1108 """ 1109 FigureCanvasWxAgg.__init__(self, parent, id, Figure(size, dpi)) 1110 1111 self.insideOnPaint = False 1112 self.cursor = CursorChanger(self, cursor) 1113 self.location = LocationPainter(self, location) 1114 self.crosshairs = CrosshairPainter(self, crosshairs) 1115 self.rubberband = RubberbandPainter(self, selection) 1116 rightClickUnzoom = True # for now this is default behavior 1117 self.director = PlotPanelDirector(self, zoom, selection, 1118 rightClickUnzoom, autoscaleUnzoom) 1119 1120 self.figure.set_edgecolor('black') 1121 self.figure.set_facecolor('white') 1122 self.SetBackgroundColour(wx.WHITE) 1123 1124 # find the toplevel parent window and register an activation event 1125 # handler that is keyed to the id of this PlotPanel 1126 topwin = toplevel_parent_of_window(self) 1127 topwin.Connect(-1, self.GetId(), wx.wxEVT_ACTIVATE, self.OnActivate) 1128 1129 wx.EVT_ERASE_BACKGROUND(self, self.OnEraseBackground) 1130 wx.EVT_WINDOW_DESTROY(self, self.OnDestroy)
1131
1132 - def OnActivate(self, evt):
1133 """ 1134 Handles the wxPython window activation event. 1135 """ 1136 if not evt.GetActive(): 1137 self.cursor.setNormal() 1138 self.location.clear() 1139 self.crosshairs.clear() 1140 self.rubberband.clear() 1141 evt.Skip()
1142
1143 - def OnEraseBackground(self, evt):
1144 """ 1145 Overrides the wxPython backround repainting event to reduce flicker. 1146 """ 1147 pass
1148
1149 - def OnDestroy(self, evt):
1150 """ 1151 Handles the wxPython window destruction event. 1152 """ 1153 if self.GetId() == evt.GetEventObject().GetId(): 1154 # unregister the activation event handler for this PlotPanel 1155 topwin = toplevel_parent_of_window(self) 1156 topwin.Disconnect(-1, self.GetId(), wx.wxEVT_ACTIVATE)
1157
1158 - def _onPaint(self, evt):
1159 """ 1160 Overrides the C{FigureCanvasWxAgg} paint event to redraw the 1161 crosshairs, etc. 1162 """ 1163 # avoid wxPyDeadObject errors 1164 if not isinstance(self, FigureCanvasWxAgg): 1165 return 1166 1167 self.insideOnPaint = True 1168 FigureCanvasWxAgg._onPaint(self, evt) 1169 self.insideOnPaint = False 1170 1171 dc = wx.PaintDC(self) 1172 self.location.redraw(dc) 1173 self.crosshairs.redraw(dc) 1174 self.rubberband.redraw(dc)
1175
1176 - def get_figure(self):
1177 """ 1178 Returns the figure associated with this canvas. 1179 """ 1180 return self.figure
1181
1182 - def set_cursor(self, state):
1183 """ 1184 Enable or disable the changing mouse cursor. When enabled, the cursor 1185 changes from the normal arrow to a square cross when the mouse enters a 1186 matplotlib axes on this canvas. 1187 """ 1188 self.cursor.setEnabled(state)
1189
1190 - def set_location(self, state):
1191 """ 1192 Enable or disable the display of the matplotlib axes coordinates of the 1193 mouse in the lower left corner of the canvas. 1194 """ 1195 self.location.setEnabled(state)
1196
1197 - def set_crosshairs(self, state):
1198 """ 1199 Enable or disable drawing crosshairs through the mouse cursor when it 1200 is inside a matplotlib axes. 1201 """ 1202 self.crosshairs.setEnabled(state)
1203
1204 - def set_selection(self, state):
1205 """ 1206 Enable or disable area selections, where user selects a rectangular 1207 area of the canvas by left-clicking and dragging the mouse. 1208 """ 1209 self.rubberband.setEnabled(state) 1210 self.director.setSelection(state)
1211
1212 - def set_zoom(self, state):
1213 """ 1214 Enable or disable zooming in when the user makes an area selection and 1215 zooming out again when the user right-clicks. 1216 """ 1217 self.director.setZoomEnabled(state)
1218
1219 - def set_autoscale_unzoom(self, state):
1220 """ 1221 Enable or disable automatic view rescaling when the user zooms out to 1222 the initial figure. 1223 """ 1224 self.director.setAutoscaleUnzoom(state)
1225
1226 - def zoomed(self, axes):
1227 """ 1228 Returns a boolean indicating whether or not the C{axes} is zoomed in. 1229 """ 1230 return self.director.zoomed(axes)
1231
1232 - def draw(self, **kwds):
1233 """ 1234 Draw the associated C{Figure} onto the screen. 1235 """ 1236 # don't redraw if the left mouse button is down and avoid 1237 # wxPyDeadObject errors 1238 if (not self.director.canDraw() 1239 or not isinstance(self, FigureCanvasWxAgg)): 1240 return 1241 1242 if MATPLOTLIB_0_98_3: 1243 FigureCanvasWxAgg.draw(self, kwds.get('drawDC', None)) 1244 else: 1245 FigureCanvasWxAgg.draw(self, kwds.get('repaint', True)) 1246 1247 # Don't redraw the decorations when called by _onPaint() 1248 if not self.insideOnPaint: 1249 self.location.redraw() 1250 self.crosshairs.redraw() 1251 self.rubberband.redraw()
1252
1253 - def notify_point(self, axes, x, y):
1254 """ 1255 Called by the associated C{PlotPanelDirector} to emit a C{PointEvent}. 1256 """ 1257 wx.PostEvent(self, PointEvent(self.GetId(), axes, x, y))
1258
1259 - def notify_selection(self, axes, x1, y1, x2, y2):
1260 """ 1261 Called by the associated C{PlotPanelDirector} to emit a 1262 C{SelectionEvent}. 1263 """ 1264 wx.PostEvent(self, SelectionEvent(self.GetId(), axes, x1, y1, x2, y2))
1265
1266 - def _get_canvas_xy(self, evt):
1267 """ 1268 Returns the X and Y coordinates of a wxPython event object converted to 1269 matplotlib canavas coordinates. 1270 """ 1271 return evt.GetX(), int(self.figure.bbox.height - evt.GetY())
1272
1273 - def _onKeyDown(self, evt):
1274 """ 1275 Overrides the C{FigureCanvasWxAgg} key-press event handler, dispatching 1276 the event to the associated C{PlotPanelDirector}. 1277 """ 1278 self.director.keyDown(evt)
1279
1280 - def _onKeyUp(self, evt):
1281 """ 1282 Overrides the C{FigureCanvasWxAgg} key-release event handler, 1283 dispatching the event to the associated C{PlotPanelDirector}. 1284 """ 1285 self.director.keyUp(evt)
1286
1287 - def _onLeftButtonDown(self, evt):
1288 """ 1289 Overrides the C{FigureCanvasWxAgg} left-click event handler, 1290 dispatching the event to the associated C{PlotPanelDirector}. 1291 """ 1292 x, y = self._get_canvas_xy(evt) 1293 self.director.leftButtonDown(evt, x, y)
1294
1295 - def _onLeftButtonUp(self, evt):
1296 """ 1297 Overrides the C{FigureCanvasWxAgg} left-click-release event handler, 1298 dispatching the event to the associated C{PlotPanelDirector}. 1299 """ 1300 x, y = self._get_canvas_xy(evt) 1301 self.director.leftButtonUp(evt, x, y)
1302
1303 - def _onRightButtonDown(self, evt):
1304 """ 1305 Overrides the C{FigureCanvasWxAgg} right-click event handler, 1306 dispatching the event to the associated C{PlotPanelDirector}. 1307 """ 1308 x, y = self._get_canvas_xy(evt) 1309 self.director.rightButtonDown(evt, x, y)
1310
1311 - def _onRightButtonUp(self, evt):
1312 """ 1313 Overrides the C{FigureCanvasWxAgg} right-click-release event handler, 1314 dispatching the event to the associated C{PlotPanelDirector}. 1315 """ 1316 x, y = self._get_canvas_xy(evt) 1317 self.director.rightButtonUp(evt, x, y)
1318
1319 - def _onMotion(self, evt):
1320 """ 1321 Overrides the C{FigureCanvasWxAgg} mouse motion event handler, 1322 dispatching the event to the associated C{PlotPanelDirector}. 1323 """ 1324 x, y = self._get_canvas_xy(evt) 1325 self.director.mouseMotion(evt, x, y)
1326 1327 1328 # 1329 # Matplotlib canvas in a top-level wxPython window 1330 # 1331
1332 -class PlotFrame(wx.Frame):
1333 """ 1334 A matplotlib canvas embedded in a wxPython top-level window. 1335 1336 @cvar ABOUT_TITLE: Title of the "About" dialog. 1337 @cvar ABOUT_MESSAGE: Contents of the "About" dialog. 1338 """ 1339 1340 ABOUT_TITLE = 'About wxmpl.PlotFrame' 1341 ABOUT_MESSAGE = ('wxmpl.PlotFrame %s\n' % __version__ 1342 + 'Written by Ken McIvor <mcivor@iit.edu>\n' 1343 + 'Copyright 2005-2009 Illinois Institute of Technology') 1344
1345 - def __init__(self, parent, id, title, size=(6.0, 3.7), dpi=96, cursor=True, 1346 location=True, crosshairs=True, selection=True, zoom=True, 1347 autoscaleUnzoom=True, **kwds):
1348 """ 1349 Creates a new PlotFrame top-level window that is the child of the 1350 wxPython window C{parent} with the wxPython identifier C{id} and the 1351 title of C{title}. 1352 1353 All of the named keyword arguments to this constructor have the same 1354 meaning as those arguments to the constructor of C{PlotPanel}. 1355 1356 Any additional keyword arguments are passed to the constructor of 1357 C{wx.Frame}. 1358 """ 1359 wx.Frame.__init__(self, parent, id, title, **kwds) 1360 self.panel = PlotPanel(self, -1, size, dpi, cursor, location, 1361 crosshairs, selection, zoom) 1362 1363 pData = wx.PrintData() 1364 pData.SetPaperId(wx.PAPER_LETTER) 1365 if callable(getattr(pData, 'SetPrinterCommand', None)): 1366 pData.SetPrinterCommand(POSTSCRIPT_PRINTING_COMMAND) 1367 self.printer = FigurePrinter(self, pData) 1368 1369 self.create_menus() 1370 sizer = wx.BoxSizer(wx.VERTICAL) 1371 sizer.Add(self.panel, 1, wx.ALL|wx.EXPAND, 5) 1372 self.SetSizer(sizer) 1373 self.Fit()
1374
1375 - def create_menus(self):
1376 mainMenu = wx.MenuBar() 1377 menu = wx.Menu() 1378 1379 id = wx.NewId() 1380 menu.Append(id, '&Save As...\tCtrl+S', 1381 'Save a copy of the current plot') 1382 wx.EVT_MENU(self, id, self.OnMenuFileSave) 1383 1384 menu.AppendSeparator() 1385 1386 if wx.Platform != '__WXMAC__': 1387 id = wx.NewId() 1388 menu.Append(id, 'Page Set&up...', 1389 'Set the size and margins of the printed figure') 1390 wx.EVT_MENU(self, id, self.OnMenuFilePageSetup) 1391 1392 id = wx.NewId() 1393 menu.Append(id, 'Print Pre&view...', 1394 'Preview the print version of the current plot') 1395 wx.EVT_MENU(self, id, self.OnMenuFilePrintPreview) 1396 1397 id = wx.NewId() 1398 menu.Append(id, '&Print...\tCtrl+P', 'Print the current plot') 1399 wx.EVT_MENU(self, id, self.OnMenuFilePrint) 1400 1401 menu.AppendSeparator() 1402 1403 id = wx.NewId() 1404 menu.Append(id, '&Close Window\tCtrl+W', 1405 'Close the current plot window') 1406 wx.EVT_MENU(self, id, self.OnMenuFileClose) 1407 1408 mainMenu.Append(menu, '&File') 1409 menu = wx.Menu() 1410 1411 id = wx.NewId() 1412 menu.Append(id, '&About...', 'Display version information') 1413 wx.EVT_MENU(self, id, self.OnMenuHelpAbout) 1414 1415 mainMenu.Append(menu, '&Help') 1416 self.SetMenuBar(mainMenu)
1417
1418 - def OnMenuFileSave(self, evt):
1419 """ 1420 Handles File->Save menu events. 1421 """ 1422 fileName = wx.FileSelector('Save Plot', default_extension='png', 1423 wildcard=('Portable Network Graphics (*.png)|*.png|' 1424 + 'Encapsulated Postscript (*.eps)|*.eps|All files (*.*)|*.*'), 1425 parent=self, flags=wx.SAVE|wx.OVERWRITE_PROMPT) 1426 1427 if not fileName: 1428 return 1429 1430 path, ext = os.path.splitext(fileName) 1431 ext = ext[1:].lower() 1432 1433 if ext != 'png' and ext != 'eps': 1434 error_message = ( 1435 'Only the PNG and EPS image formats are supported.\n' 1436 'A file extension of `png\' or `eps\' must be used.') 1437 wx.MessageBox(error_message, 'Error - plotit', 1438 parent=self, style=wx.OK|wx.ICON_ERROR) 1439 return 1440 1441 try: 1442 self.panel.print_figure(fileName) 1443 except IOError, e: 1444 if e.strerror: 1445 err = e.strerror 1446 else: 1447 err = e 1448 1449 wx.MessageBox('Could not save file: %s' % err, 'Error - plotit', 1450 parent=self, style=wx.OK|wx.ICON_ERROR)
1451
1452 - def OnMenuFilePageSetup(self, evt):
1453 """ 1454 Handles File->Page Setup menu events 1455 """ 1456 self.printer.pageSetup()
1457
1458 - def OnMenuFilePrintPreview(self, evt):
1459 """ 1460 Handles File->Print Preview menu events 1461 """ 1462 self.printer.previewFigure(self.get_figure())
1463
1464 - def OnMenuFilePrint(self, evt):
1465 """ 1466 Handles File->Print menu events 1467 """ 1468 self.printer.printFigure(self.get_figure())
1469
1470 - def OnMenuFileClose(self, evt):
1471 """ 1472 Handles File->Close menu events. 1473 """ 1474 self.Close()
1475
1476 - def OnMenuHelpAbout(self, evt):
1477 """ 1478 Handles Help->About menu events. 1479 """ 1480 wx.MessageBox(self.ABOUT_MESSAGE, self.ABOUT_TITLE, parent=self, 1481 style=wx.OK)
1482
1483 - def get_figure(self):
1484 """ 1485 Returns the figure associated with this canvas. 1486 """ 1487 return self.panel.figure
1488
1489 - def set_cursor(self, state):
1490 """ 1491 Enable or disable the changing mouse cursor. When enabled, the cursor 1492 changes from the normal arrow to a square cross when the mouse enters a 1493 matplotlib axes on this canvas. 1494 """ 1495 self.panel.set_cursor(state)
1496
1497 - def set_location(self, state):
1498 """ 1499 Enable or disable the display of the matplotlib axes coordinates of the 1500 mouse in the lower left corner of the canvas. 1501 """ 1502 self.panel.set_location(state)
1503
1504 - def set_crosshairs(self, state):
1505 """ 1506 Enable or disable drawing crosshairs through the mouse cursor when it 1507 is inside a matplotlib axes. 1508 """ 1509 self.panel.set_crosshairs(state)
1510
1511 - def set_selection(self, state):
1512 """ 1513 Enable or disable area selections, where user selects a rectangular 1514 area of the canvas by left-clicking and dragging the mouse. 1515 """ 1516 self.panel.set_selection(state)
1517
1518 - def set_zoom(self, state):
1519 """ 1520 Enable or disable zooming in when the user makes an area selection and 1521 zooming out again when the user right-clicks. 1522 """ 1523 self.panel.set_zoom(state)
1524
1525 - def set_autoscale_unzoom(self, state):
1526 """ 1527 Enable or disable automatic view rescaling when the user zooms out to 1528 the initial figure. 1529 """ 1530 self.panel.set_autoscale_unzoom(state)
1531
1532 - def draw(self):
1533 """ 1534 Draw the associated C{Figure} onto the screen. 1535 """ 1536 self.panel.draw()
1537 1538 1539 # 1540 # wxApp providing a matplotlib canvas in a top-level wxPython window 1541 # 1542
1543 -class PlotApp(wx.App):
1544 """ 1545 A wxApp that provides a matplotlib canvas embedded in a wxPython top-level 1546 window, encapsulating wxPython's nuts and bolts. 1547 1548 @cvar ABOUT_TITLE: Title of the "About" dialog. 1549 @cvar ABOUT_MESSAGE: Contents of the "About" dialog. 1550 """ 1551 1552 ABOUT_TITLE = None 1553 ABOUT_MESSAGE = None 1554
1555 - def __init__(self, title="WxMpl", size=(6.0, 3.7), dpi=96, cursor=True, 1556 location=True, crosshairs=True, selection=True, zoom=True, **kwds):
1557 """ 1558 Creates a new PlotApp, which creates a PlotFrame top-level window. 1559 1560 The keyword argument C{title} specifies the title of this top-level 1561 window. 1562 1563 All of other the named keyword arguments to this constructor have the 1564 same meaning as those arguments to the constructor of C{PlotPanel}. 1565 1566 Any additional keyword arguments are passed to the constructor of 1567 C{wx.App}. 1568 """ 1569 self.title = title 1570 self.size = size 1571 self.dpi = dpi 1572 self.cursor = cursor 1573 self.location = location 1574 self.crosshairs = crosshairs 1575 self.selection = selection 1576 self.zoom = zoom 1577 wx.App.__init__(self, **kwds)
1578
1579 - def OnInit(self):
1580 self.frame = panel = PlotFrame(None, -1, self.title, self.size, 1581 self.dpi, self.cursor, self.location, self.crosshairs, 1582 self.selection, self.zoom) 1583 1584 if self.ABOUT_TITLE is not None: 1585 panel.ABOUT_TITLE = self.ABOUT_TITLE 1586 1587 if self.ABOUT_MESSAGE is not None: 1588 panel.ABOUT_MESSAGE = self.ABOUT_MESSAGE 1589 1590 panel.Show(True) 1591 return True
1592
1593 - def get_figure(self):
1594 """ 1595 Returns the figure associated with this canvas. 1596 """ 1597 return self.frame.get_figure()
1598
1599 - def set_cursor(self, state):
1600 """ 1601 Enable or disable the changing mouse cursor. When enabled, the cursor 1602 changes from the normal arrow to a square cross when the mouse enters a 1603 matplotlib axes on this canvas. 1604 """ 1605 self.frame.set_cursor(state)
1606
1607 - def set_location(self, state):
1608 """ 1609 Enable or disable the display of the matplotlib axes coordinates of the 1610 mouse in the lower left corner of the canvas. 1611 """ 1612 self.frame.set_location(state)
1613
1614 - def set_crosshairs(self, state):
1615 """ 1616 Enable or disable drawing crosshairs through the mouse cursor when it 1617 is inside a matplotlib axes. 1618 """ 1619 self.frame.set_crosshairs(state)
1620
1621 - def set_selection(self, state):
1622 """ 1623 Enable or disable area selections, where user selects a rectangular 1624 area of the canvas by left-clicking and dragging the mouse. 1625 """ 1626 self.frame.set_selection(state)
1627
1628 - def set_zoom(self, state):
1629 """ 1630 Enable or disable zooming in when the user makes an area selection and 1631 zooming out again when the user right-clicks. 1632 """ 1633 self.frame.set_zoom(state)
1634
1635 - def draw(self):
1636 """ 1637 Draw the associated C{Figure} onto the screen. 1638 """ 1639 self.frame.draw()
1640 1641 1642 # 1643 # Automatically resizing vectors and matrices 1644 # 1645
1646 -class VectorBuffer:
1647 """ 1648 Manages a Numerical Python vector, automatically growing it as necessary to 1649 accomodate new entries. 1650 """
1651 - def __init__(self):
1652 self.data = NumPy.zeros((16,), NumPy.Float) 1653 self.nextRow = 0
1654
1655 - def clear(self):
1656 """ 1657 Zero and reset this buffer without releasing the underlying array. 1658 """ 1659 self.data[:] = 0.0 1660 self.nextRow = 0
1661
1662 - def reset(self):
1663 """ 1664 Zero and reset this buffer, releasing the underlying array. 1665 """ 1666 self.data = NumPy.zeros((16,), NumPy.Float) 1667 self.nextRow = 0
1668
1669 - def append(self, point):
1670 """ 1671 Append a new entry to the end of this buffer's vector. 1672 """ 1673 nextRow = self.nextRow 1674 data = self.data 1675 1676 resize = False 1677 if nextRow == data.shape[0]: 1678 nR = int(NumPy.ceil(self.data.shape[0]*1.5)) 1679 resize = True 1680 1681 if resize: 1682 self.data = NumPy.zeros((nR,), NumPy.Float) 1683 self.data[0:data.shape[0]] = data 1684 1685 self.data[nextRow] = point 1686 self.nextRow += 1
1687
1688 - def getData(self):
1689 """ 1690 Returns the current vector or C{None} if the buffer contains no data. 1691 """ 1692 if self.nextRow == 0: 1693 return None 1694 else: 1695 return self.data[0:self.nextRow]
1696 1697
1698 -class MatrixBuffer:
1699 """ 1700 Manages a Numerical Python matrix, automatically growing it as necessary to 1701 accomodate new rows of entries. 1702 """
1703 - def __init__(self):
1704 self.data = NumPy.zeros((16, 1), NumPy.Float) 1705 self.nextRow = 0
1706
1707 - def clear(self):
1708 """ 1709 Zero and reset this buffer without releasing the underlying array. 1710 """ 1711 self.data[:, :] = 0.0 1712 self.nextRow = 0
1713
1714 - def reset(self):
1715 """ 1716 Zero and reset this buffer, releasing the underlying array. 1717 """ 1718 self.data = NumPy.zeros((16, 1), NumPy.Float) 1719 self.nextRow = 0
1720
1721 - def append(self, row):
1722 """ 1723 Append a new row of entries to the end of this buffer's matrix. 1724 """ 1725 row = NumPy.asarray(row, NumPy.Float) 1726 nextRow = self.nextRow 1727 data = self.data 1728 nPts = row.shape[0] 1729 1730 if nPts == 0: 1731 return 1732 1733 resize = True 1734 if nextRow == data.shape[0]: 1735 nC = data.shape[1] 1736 nR = int(NumPy.ceil(self.data.shape[0]*1.5)) 1737 if nC < nPts: 1738 nC = nPts 1739 elif data.shape[1] < nPts: 1740 nR = data.shape[0] 1741 nC = nPts 1742 else: 1743 resize = False 1744 1745 if resize: 1746 self.data = NumPy.zeros((nR, nC), NumPy.Float) 1747 rowEnd, colEnd = data.shape 1748 self.data[0:rowEnd, 0:colEnd] = data 1749 1750 self.data[nextRow, 0:nPts] = row 1751 self.nextRow += 1
1752
1753 - def getData(self):
1754 """ 1755 Returns the current matrix or C{None} if the buffer contains no data. 1756 """ 1757 if self.nextRow == 0: 1758 return None 1759 else: 1760 return self.data[0:self.nextRow, :]
1761 1762 1763 # 1764 # Utility functions used by the StripCharter 1765 # 1766
1767 -def make_delta_bbox(X1, Y1, X2, Y2):
1768 """ 1769 Returns a C{Bbox} describing the range of difference between two sets of X 1770 and Y coordinates. 1771 """ 1772 return make_bbox(get_delta(X1, X2), get_delta(Y1, Y2))
1773 1774
1775 -def get_delta(X1, X2):
1776 """ 1777 Returns the vector of contiguous, different points between two vectors. 1778 """ 1779 n1 = X1.shape[0] 1780 n2 = X2.shape[0] 1781 1782 if n1 < n2: 1783 return X2[n1:] 1784 elif n1 == n2: 1785 # shape is no longer a reliable indicator of change, so assume things 1786 # are different 1787 return X2 1788 else: 1789 return X2
1790 1791
1792 -def make_bbox(X, Y):
1793 """ 1794 Returns a C{Bbox} that contains the supplied sets of X and Y coordinates. 1795 """ 1796 if X is None or X.shape[0] == 0: 1797 x1 = x2 = 0.0 1798 else: 1799 x1 = min(X) 1800 x2 = max(X) 1801 1802 if Y is None or Y.shape[0] == 0: 1803 y1 = y2 = 0.0 1804 else: 1805 y1 = min(Y) 1806 y2 = max(Y) 1807 1808 return Bbox.from_extents(x1, y1, x2, y2)
1809 1810 1811 # 1812 # Strip-charts lines using a matplotlib axes 1813 # 1814
1815 -class StripCharter:
1816 """ 1817 Plots and updates lines on a matplotlib C{Axes}. 1818 """
1819 - def __init__(self, axes):
1820 """ 1821 Create a new C{StripCharter} associated with a matplotlib C{axes}. 1822 """ 1823 self.axes = axes 1824 self.channels = [] 1825 self.lines = {}
1826
1827 - def setChannels(self, channels):
1828 """ 1829 Specify the data-providers of the lines to be plotted and updated. 1830 """ 1831 self.lines = None 1832 self.channels = channels[:] 1833 1834 # minimal Axes.cla() 1835 self.axes.legend_ = None 1836 self.axes.lines = []
1837
1838 - def update(self):
1839 """ 1840 Redraw the associated axes with updated lines if any of the channels' 1841 data has changed. 1842 """ 1843 axes = self.axes 1844 figureCanvas = axes.figure.canvas 1845 1846 zoomed = figureCanvas.zoomed(axes) 1847 1848 redraw = False 1849 if self.lines is None: 1850 self._create_plot() 1851 redraw = True 1852 else: 1853 for channel in self.channels: 1854 redraw = self._update_channel(channel, zoomed) or redraw 1855 1856 if redraw: 1857 if not zoomed: 1858 axes.autoscale_view() 1859 figureCanvas.draw()
1860
1861 - def _create_plot(self):
1862 """ 1863 Initially plot the lines corresponding to the data-providers. 1864 """ 1865 self.lines = {} 1866 axes = self.axes 1867 styleGen = _process_plot_var_args(axes) 1868 1869 for channel in self.channels: 1870 self._plot_channel(channel, styleGen) 1871 1872 if self.channels: 1873 lines = [self.lines[x] for x in self.channels] 1874 labels = [x.get_label() for x in lines] 1875 self.axes.legend(lines, labels, numpoints=2, 1876 prop=FontProperties(size='x-small'))
1877
1878 - def _plot_channel(self, channel, styleGen):
1879 """ 1880 Initially plot a line corresponding to one of the data-providers. 1881 """ 1882 empty = False 1883 x = channel.getX() 1884 y = channel.getY() 1885 if x is None or y is None: 1886 x = y = [] 1887 empty = True 1888 1889 line = styleGen(x, y).next() 1890 line._wxmpl_empty_line = empty 1891 1892 if channel.getColor() is not None: 1893 line.set_color(channel.getColor()) 1894 if channel.getStyle() is not None: 1895 line.set_linestyle(channel.getStyle()) 1896 if channel.getMarker() is not None: 1897 line.set_marker(channel.getMarker()) 1898 line.set_markeredgecolor(line.get_color()) 1899 line.set_markerfacecolor(line.get_color()) 1900 1901 line.set_label(channel.getLabel()) 1902 self.lines[channel] = line 1903 if not empty: 1904 self.axes.add_line(line)
1905
1906 - def _update_channel(self, channel, zoomed):
1907 """ 1908 Replot a line corresponding to one of the data-providers if the data 1909 has changed. 1910 """ 1911 if channel.hasChanged(): 1912 channel.setChanged(False) 1913 else: 1914 return False 1915 1916 axes = self.axes 1917 line = self.lines[channel] 1918 newX = channel.getX() 1919 newY = channel.getY() 1920 1921 if newX is None or newY is None: 1922 return False 1923 1924 oldX = line._x 1925 oldY = line._y 1926 1927 x, y = newX, newY 1928 line.set_data(x, y) 1929 1930 if line._wxmpl_empty_line: 1931 axes.add_line(line) 1932 line._wxmpl_empty_line = False 1933 else: 1934 if line.get_transform() != axes.transData: 1935 xys = axes._get_verts_in_data_coords( 1936 line.get_transform(), zip(x, y)) 1937 else: 1938 xys = NumPy.zeros((x.shape[0], 2), NumPy.Float) 1939 xys[:,0] = x 1940 xys[:,1] = y 1941 axes.update_datalim(xys) 1942 1943 if zoomed: 1944 return axes.viewLim.overlaps( 1945 make_delta_bbox(oldX, oldY, newX, newY)) 1946 else: 1947 return True
1948 1949 1950 # 1951 # Data-providing interface to the StripCharter 1952 # 1953
1954 -class Channel:
1955 """ 1956 Provides data for a C{StripCharter} to plot. Subclasses of C{Channel} 1957 override the template methods C{getX()} and C{getY()} to provide plot data 1958 and call C{setChanged(True)} when that data has changed. 1959 """
1960 - def __init__(self, name, color=None, style=None, marker=None):
1961 """ 1962 Creates a new C{Channel} with the matplotlib label C{name}. The 1963 keyword arguments specify the strings for the line color, style, and 1964 marker to use when the line is plotted. 1965 """ 1966 self.name = name 1967 self.color = color 1968 self.style = style 1969 self.marker = marker 1970 self.changed = False
1971
1972 - def getLabel(self):
1973 """ 1974 Returns the matplotlib label for this channel of data. 1975 """ 1976 return self.name
1977
1978 - def getColor(self):
1979 """ 1980 Returns the line color string to use when the line is plotted, or 1981 C{None} to use an automatically generated color. 1982 """ 1983 return self.color
1984
1985 - def getStyle(self):
1986 """ 1987 Returns the line style string to use when the line is plotted, or 1988 C{None} to use the default line style. 1989 """ 1990 return self.style
1991
1992 - def getMarker(self):
1993 """ 1994 Returns the line marker string to use when the line is plotted, or 1995 C{None} to use the default line marker. 1996 """ 1997 return self.marker
1998
1999 - def hasChanged(self):
2000 """ 2001 Returns a boolean indicating if the line data has changed. 2002 """ 2003 return self.changed
2004
2005 - def setChanged(self, changed):
2006 """ 2007 Sets the change indicator to the boolean value C{changed}. 2008 2009 @note: C{StripCharter} instances call this method after detecting a 2010 change, so a C{Channel} cannot be shared among multiple charts. 2011 """ 2012 self.changed = changed
2013
2014 - def getX(self):
2015 """ 2016 Template method that returns the vector of X axis data or C{None} if 2017 there is no data available. 2018 """ 2019 return None
2020
2021 - def getY(self):
2022 """ 2023 Template method that returns the vector of Y axis data or C{None} if 2024 there is no data available. 2025 """ 2026 return None
2027

wxmpl-2.0.0/reference/wxmpl.Channel-class.html0000644000175000017500000003323211647105464021574 0ustar segresegre00000000000000 wxmpl.Channel
Module wxmpl :: Class Channel
[frames] | no frames]

Class Channel

source code

Provides data for a StripCharter to plot. Subclasses of Channel override the template methods getX() and getY() to provide plot data and call setChanged(True) when that data has changed.

Instance Methods
 
__init__(self, name, color=None, style=None, marker=None)
Creates a new Channel with the matplotlib label name.
source code
 
getLabel(self)
Returns the matplotlib label for this channel of data.
source code
 
getColor(self)
Returns the line color string to use when the line is plotted, or None to use an automatically generated color.
source code
 
getStyle(self)
Returns the line style string to use when the line is plotted, or None to use the default line style.
source code
 
getMarker(self)
Returns the line marker string to use when the line is plotted, or None to use the default line marker.
source code
 
hasChanged(self)
Returns a boolean indicating if the line data has changed.
source code
 
setChanged(self, changed)
Sets the change indicator to the boolean value changed.
source code
 
getX(self)
Template method that returns the vector of X axis data or None if there is no data available.
source code
 
getY(self)
Template method that returns the vector of Y axis data or None if there is no data available.
source code
Method Details

__init__(self, name, color=None, style=None, marker=None)
(Constructor)

source code 

Creates a new Channel with the matplotlib label name. The keyword arguments specify the strings for the line color, style, and marker to use when the line is plotted.

setChanged(self, changed)

source code 

Sets the change indicator to the boolean value changed.

Note: StripCharter instances call this method after detecting a change, so a Channel cannot be shared among multiple charts.


wxmpl-2.0.0/reference/wxmpl.FigurePrinter-class.html0000644000175000017500000003034511647105464023013 0ustar segresegre00000000000000 wxmpl.FigurePrinter
Module wxmpl :: Class FigurePrinter
[frames] | no frames]

Class FigurePrinter

source code

Provides a simplified interface to the wxPython printing framework that's designed for printing matplotlib figures.

Instance Methods
 
__init__(self, view, printData=None)
Create a new FigurePrinter associated with the wxPython widget view.
source code
 
getPrintData(self)
Return the current printer settings in their wx.PrintData object.
source code
 
setPrintData(self, printData)
Use the printer settings in printData.
source code
 
pageSetup(self) source code
 
previewFigure(self, figure, title=None)
Open a "Print Preview" window for the matplotlib chart figure.
source code
 
printFigure(self, figure, title=None)
Open a "Print" dialog to print the matplotlib chart figure.
source code
Method Details

__init__(self, view, printData=None)
(Constructor)

source code 

Create a new FigurePrinter associated with the wxPython widget view. The keyword argument printData supplies a wx.PrintData object containing the default printer settings.

previewFigure(self, figure, title=None)

source code 

Open a "Print Preview" window for the matplotlib chart figure. The keyword argument title provides the printing framework with a title for the print job.

printFigure(self, figure, title=None)

source code 

Open a "Print" dialog to print the matplotlib chart figure. The keyword argument title provides the printing framework with a title for the print job.


wxmpl-2.0.0/reference/wxmpl.PlotApp-class.html0000644000175000017500000003736111647105464021612 0ustar segresegre00000000000000 wxmpl.PlotApp
Module wxmpl :: Class PlotApp
[frames] | no frames]

Class PlotApp

source code

wx.App --+
         |
        PlotApp

A wxApp that provides a matplotlib canvas embedded in a wxPython top-level window, encapsulating wxPython's nuts and bolts.

Instance Methods
 
__init__(self, title="WxMpl", size=(6.0,3.7), dpi=96, cursor=True, location=True, crosshairs=True, selection=True, zoom=True, **kwds)
Creates a new PlotApp, which creates a PlotFrame top-level window.
source code
 
OnInit(self) source code
 
get_figure(self)
Returns the figure associated with this canvas.
source code
 
set_cursor(self, state)
Enable or disable the changing mouse cursor.
source code
 
set_location(self, state)
Enable or disable the display of the matplotlib axes coordinates of the mouse in the lower left corner of the canvas.
source code
 
set_crosshairs(self, state)
Enable or disable drawing crosshairs through the mouse cursor when it is inside a matplotlib axes.
source code
 
set_selection(self, state)
Enable or disable area selections, where user selects a rectangular area of the canvas by left-clicking and dragging the mouse.
source code
 
set_zoom(self, state)
Enable or disable zooming in when the user makes an area selection and zooming out again when the user right-clicks.
source code
 
draw(self)
Draw the associated Figure onto the screen.
source code
Class Variables
  ABOUT_TITLE = None
Title of the "About" dialog.
  ABOUT_MESSAGE = None
Contents of the "About" dialog.
Method Details

__init__(self, title="WxMpl", size=(6.0,3.7), dpi=96, cursor=True, location=True, crosshairs=True, selection=True, zoom=True, **kwds)
(Constructor)

source code 

Creates a new PlotApp, which creates a PlotFrame top-level window.

The keyword argument title specifies the title of this top-level window.

All of other the named keyword arguments to this constructor have the same meaning as those arguments to the constructor of PlotPanel.

Any additional keyword arguments are passed to the constructor of wx.App.

set_cursor(self, state)

source code 

Enable or disable the changing mouse cursor. When enabled, the cursor changes from the normal arrow to a square cross when the mouse enters a matplotlib axes on this canvas.


wxmpl-2.0.0/reference/wxmpl.PlotFrame-class.html0000644000175000017500000005523411647105464022123 0ustar segresegre00000000000000 wxmpl.PlotFrame
Module wxmpl :: Class PlotFrame
[frames] | no frames]

Class PlotFrame

source code

wx.Frame --+
           |
          PlotFrame

A matplotlib canvas embedded in a wxPython top-level window.

Instance Methods
 
__init__(self, parent, id, title, size=(6.0,3.7), dpi=96, cursor=True, location=True, crosshairs=True, selection=True, zoom=True, autoscaleUnzoom=True, **kwds)
Creates a new PlotFrame top-level window that is the child of the wxPython window parent with the wxPython identifier id and the title of title.
source code
 
create_menus(self) source code
 
OnMenuFileSave(self, evt)
Handles File->Save menu events.
source code
 
OnMenuFilePageSetup(self, evt)
Handles File->Page Setup menu events
source code
 
OnMenuFilePrintPreview(self, evt)
Handles File->Print Preview menu events
source code
 
OnMenuFilePrint(self, evt)
Handles File->Print menu events
source code
 
OnMenuFileClose(self, evt)
Handles File->Close menu events.
source code
 
OnMenuHelpAbout(self, evt)
Handles Help->About menu events.
source code
 
get_figure(self)
Returns the figure associated with this canvas.
source code
 
set_cursor(self, state)
Enable or disable the changing mouse cursor.
source code
 
set_location(self, state)
Enable or disable the display of the matplotlib axes coordinates of the mouse in the lower left corner of the canvas.
source code
 
set_crosshairs(self, state)
Enable or disable drawing crosshairs through the mouse cursor when it is inside a matplotlib axes.
source code
 
set_selection(self, state)
Enable or disable area selections, where user selects a rectangular area of the canvas by left-clicking and dragging the mouse.
source code
 
set_zoom(self, state)
Enable or disable zooming in when the user makes an area selection and zooming out again when the user right-clicks.
source code
 
set_autoscale_unzoom(self, state)
Enable or disable automatic view rescaling when the user zooms out to the initial figure.
source code
 
draw(self)
Draw the associated Figure onto the screen.
source code
Class Variables
  ABOUT_TITLE = 'About wxmpl.PlotFrame'
Title of the "About" dialog.
  ABOUT_MESSAGE = 'wxmpl.PlotFrame %s\n' % __version__+ 'Written...
Contents of the "About" dialog.
Method Details

__init__(self, parent, id, title, size=(6.0,3.7), dpi=96, cursor=True, location=True, crosshairs=True, selection=True, zoom=True, autoscaleUnzoom=True, **kwds)
(Constructor)

source code 

Creates a new PlotFrame top-level window that is the child of the wxPython window parent with the wxPython identifier id and the title of title.

All of the named keyword arguments to this constructor have the same meaning as those arguments to the constructor of PlotPanel.

Any additional keyword arguments are passed to the constructor of wx.Frame.

set_cursor(self, state)

source code 

Enable or disable the changing mouse cursor. When enabled, the cursor changes from the normal arrow to a square cross when the mouse enters a matplotlib axes on this canvas.


Class Variable Details

ABOUT_MESSAGE

Contents of the "About" dialog.
Value:
'wxmpl.PlotFrame %s\n' % __version__+ 'Written by Ken McIvor <mcivor@i\
it.edu>\n'+ 'Copyright 2005-2009 Illinois Institute of Technology'

wxmpl-2.0.0/reference/wxmpl.PlotPanel-class.html0000644000175000017500000006545011647105464022131 0ustar segresegre00000000000000 wxmpl.PlotPanel
Module wxmpl :: Class PlotPanel
[frames] | no frames]

Class PlotPanel

source code

                                 object --+            
                                          |            
  matplotlib.backend_bases.FigureCanvasBase --+        
                                              |        
matplotlib.backends.backend_agg.FigureCanvasAgg --+    
                                                  |    
                                 object --+       |    
                                          |       |    
  matplotlib.backend_bases.FigureCanvasBase --+   |    
                                              |   |    
                                   wx.Panel --+   |    
                                              |   |    
  matplotlib.backends.backend_wx.FigureCanvasWx --+    
                                                  |    
matplotlib.backends.backend_wxagg.FigureCanvasWxAgg --+
                                                      |
                                                     PlotPanel

A matplotlib canvas suitable for embedding in wxPython applications.

Instance Methods
 
__init__(self, parent, id, size=(6.0,3.70), dpi=96, cursor=True, location=True, crosshairs=True, selection=True, zoom=True, autoscaleUnzoom=True)
Creates a new PlotPanel window that is the child of the wxPython window parent with the wxPython identifier id.
source code
 
OnActivate(self, evt)
Handles the wxPython window activation event.
source code
 
OnEraseBackground(self, evt)
Overrides the wxPython backround repainting event to reduce flicker.
source code
 
OnDestroy(self, evt)
Handles the wxPython window destruction event.
source code
 
get_figure(self)
Returns the figure associated with this canvas.
source code
 
set_cursor(self, state)
Enable or disable the changing mouse cursor.
source code
 
set_location(self, state)
Enable or disable the display of the matplotlib axes coordinates of the mouse in the lower left corner of the canvas.
source code
 
set_crosshairs(self, state)
Enable or disable drawing crosshairs through the mouse cursor when it is inside a matplotlib axes.
source code
 
set_selection(self, state)
Enable or disable area selections, where user selects a rectangular area of the canvas by left-clicking and dragging the mouse.
source code
 
set_zoom(self, state)
Enable or disable zooming in when the user makes an area selection and zooming out again when the user right-clicks.
source code
 
set_autoscale_unzoom(self, state)
Enable or disable automatic view rescaling when the user zooms out to the initial figure.
source code
 
zoomed(self, axes)
Returns a boolean indicating whether or not the axes is zoomed in.
source code
 
draw(self, **kwds)
Draw the associated Figure onto the screen.
source code
 
notify_point(self, axes, x, y)
Called by the associated PlotPanelDirector to emit a PointEvent.
source code
 
notify_selection(self, axes, x1, y1, x2, y2)
Called by the associated PlotPanelDirector to emit a SelectionEvent.
source code

Inherited from matplotlib.backends.backend_wxagg.FigureCanvasWxAgg: blit, print_figure

Inherited from matplotlib.backends.backend_agg.FigureCanvasAgg: buffer_rgba, copy_from_bbox, get_default_filetype, get_renderer, print_png, print_raw, print_rgba, print_to_buffer, restore_region, tostring_argb, tostring_rgb

Inherited from matplotlib.backends.backend_wx.FigureCanvasWx: Copy_to_Clipboard, Destroy, Printer_Init, Printer_Preview, Printer_Print, Printer_Setup, Printer_Setup2, draw_idle, flush_events, gui_repaint, new_timer, print_bmp, print_jpeg, print_jpg, print_pcx, print_tif, print_tiff, print_xpm, printerData, printerPageData, start_event_loop, stop_event_loop

Inherited from matplotlib.backend_bases.FigureCanvasBase: button_press_event, button_release_event, close_event, draw_cursor, draw_event, enter_notify_event, get_supported_filetypes, get_supported_filetypes_grouped, get_width_height, grab_mouse, idle_event, key_press_event, key_release_event, leave_notify_event, motion_notify_event, mpl_connect, mpl_disconnect, onHilite, onRemove, pick, pick_event, print_emf, print_eps, print_pdf, print_ps, print_rgb, print_svg, print_svgz, release_mouse, resize, resize_event, scroll_event, set_window_title, start_event_loop_default, stop_event_loop_default, switch_backends

Inherited from object: __delattr__, __format__, __getattribute__, __hash__, __new__, __reduce__, __reduce_ex__, __repr__, __setattr__, __sizeof__, __str__, __subclasshook__

Class Variables

Inherited from matplotlib.backends.backend_wxagg.FigureCanvasWxAgg: filetypes

Inherited from matplotlib.backends.backend_wx.FigureCanvasWx: keyvald

Inherited from matplotlib.backend_bases.FigureCanvasBase: events

Properties

Inherited from object: __class__

Method Details

__init__(self, parent, id, size=(6.0,3.70), dpi=96, cursor=True, location=True, crosshairs=True, selection=True, zoom=True, autoscaleUnzoom=True)
(Constructor)

source code 

Creates a new PlotPanel window that is the child of the wxPython window parent with the wxPython identifier id.

The keyword arguments size and {dpi} are used to create the matplotlib Figure associated with this canvas. size is the desired width and height of the figure, in inches, as the 2-tuple (width, height). dpi is the dots-per-inch of the figure.

The keyword arguments cursor, location, crosshairs, selection, zoom, and autoscaleUnzoom enable or disable various user interaction features that are descibed in their associated set() methods.

Overrides: object.__init__

set_cursor(self, state)

source code 

Enable or disable the changing mouse cursor. When enabled, the cursor changes from the normal arrow to a square cross when the mouse enters a matplotlib axes on this canvas.

draw(self, **kwds)

source code 

Draw the associated Figure onto the screen.

Overrides: matplotlib.backend_bases.FigureCanvasBase.draw

wxmpl-2.0.0/reference/wxmpl.PointEvent-class.html0000644000175000017500000001714211647105464022321 0ustar segresegre00000000000000 wxmpl.PointEvent
Module wxmpl :: Class PointEvent
[frames] | no frames]

Class PointEvent

source code

wx.PyCommandEvent --+
                    |
                   PointEvent

wxPython event emitted when a left-click-release occurs in a matplotlib axes of a window without an area selection.

Instance Methods
 
__init__(self, id, axes, x, y)
Create a new PointEvent for the matplotlib coordinates (x, y) of an axes.
source code
 
Clone(self) source code
Class Variables
  axes
matplotlib Axes which was left-clicked
  x
matplotlib X coordinate
  xdata
axes X coordinate
  y
matplotlib Y coordinate
  ydata
axes Y coordinate
wxmpl-2.0.0/reference/wxmpl.SelectionEvent-class.html0000644000175000017500000002176111647105464023157 0ustar segresegre00000000000000 wxmpl.SelectionEvent
Module wxmpl :: Class SelectionEvent
[frames] | no frames]

Class SelectionEvent

source code

wx.PyCommandEvent --+
                    |
                   SelectionEvent

wxPython event emitted when an area selection occurs in a matplotlib axes of a window for which zooming has been disabled. The selection is described by a rectangle from (x1, y1) to (x2, y2), of which only one point is required to be inside the axes.

Instance Methods
 
__init__(self, id, axes, x1, y1, x2, y2)
Create a new SelectionEvent for the area described by the rectangle from (x1, y1) to (x2, y2) in an axes.
source code
 
Clone(self) source code
Class Variables
  axes
matplotlib Axes which was left-clicked
  x1
matplotlib x1 coordinate
  x1data
axes x1 coordinate
  x2
matplotlib x2 coordinate
  x2data
axes x2 coordinate
  y1
matplotlib y1 coordinate
  y1data
axes y1 coordinate
  y2
matplotlib y2 coordinate
  y2data
axes y2 coordinate
wxmpl-2.0.0/reference/wxmpl.StripCharter-class.html0000644000175000017500000001466411647105464022646 0ustar segresegre00000000000000 wxmpl.StripCharter
Module wxmpl :: Class StripCharter
[frames] | no frames]

Class StripCharter

source code

Plots and updates lines on a matplotlib Axes.

Instance Methods
 
__init__(self, axes)
Create a new StripCharter associated with a matplotlib axes.
source code
 
setChannels(self, channels)
Specify the data-providers of the lines to be plotted and updated.
source code
 
update(self)
Redraw the associated axes with updated lines if any of the channels' data has changed.
source code
wxmpl-2.0.0/ChangeLog0000644000175000017500000001245511647105364014704 0ustar segresegre0000000000000010-17-2011 Carlo Segre * Release 2.0.0 * Replaced all references to numerix with numpy functions 02-22-2009 Ken McIvor * Fixed a serious bug in the way top-level parent windows were determined. 02-21-2009 Ken McIvor * Fixed a bug that was breaking plotit's quickplot mode ('-q') 02-20-2009 Ken McIvor * Release: 1.3.0 * Compatability fixes for Matplotlib >= 0.98.1 * Improved support for wxMAC and PostScript printing * PlotPanel and PlotFrame have a new keyword argument, autoscaleUnzoom, which controls whether an Axes is autoscaled when the user unzooms all the way out. * The DestructableViewMixin class has been removed (Python does circular references just fine, nowadays) 11-08-2007 Ken McIvor * Release: 1.2.9 * Fixed a bug in printing support (wx.PrintData.SetPrinterCommand() is undefined on some platforms). * Compatability fixes for Matplotlib >= 0.90 08-28-2006 Ken McIvor * Release: 1.2.8 * Updated metasetup.py to version 1.1. 06-20-2006 Ken McIvor * Fixed a bug in PlotPanel's EVT_ACTIVATE registration that was reported by Andrew Jones. PlotPanel would register with the last toplevel parent window instead of the first one, resulting in PyDeadObjectErrors. * PlotPanels now unregister their EVT_ACTIVATE handlers in OnDestroy, making it possible to dynamically create and destroy them. 04-14-2006 Ken McIvor * Fixed a bug in the anti-crosshair-junk logic (the decorations were being redrawn from within _onPaint()). 04-13-2006 Ken McIvor * Release: 1.2.7 * `plotit' would occasionally hang while exiting during quickscans at APS 10ID. This should be fixed now. 04-05-2006 Ken McIvor * Release: 1.2.6 * Fixed the crosshair junk that was sometimes left behind after a repaint. 02-23-2006 Ken McIvor * Release: 1.2.5 * Fixed an increadibly daft bug that was reported by Philippe Dalet. * Corrected a grammerical error in plotit's help message. * AxesLimits.restore() now autoscales the axes when unzooming all the way out, allowing you to add lines outside the initial plot limits while zoomed in. 12-13-2005 Ken McIvor * Fixed FigurePrinter.pageSetup() so it now honors the paper size and other parameters correctly. 11-30-2005 Ken McIvor * Release: 1.2.4 * Point and selection events now work properly. * Added a new demo to cover using the point and selection API. 11-14-2005 Ken McIvor * Release: 1.2.3 * Renamed `python/' to `lib/' * Fixed an incompatability with FigureCanvasWx.draw() introduced in matplotlib 0.84. * Included the `plotit' script in the distribution. * Updated setup.py to use metasetup.py 07-10-2005 Ken McIvor * Release: 1.2.2 * Fixed a bug in the way channels without data were being handled that resulted in axes autoscaling starting at x=0 when the data finally arrived. 05-26-2005 Ken McIvor * Release: 1.2.1 05-23-2005 Ken McIvor * Disabled printing under OSX. The DPI of the printer is always being reported as 72, resulting in ugly plots. 5-19-2005 Ken McIvor * Release: 1.2 * Added support for the wxPython printing framework via FigurePrinter and FigurePrintout. * Added printing entries to the "File" menu of PlotFrame. 05-16-2005 Ken McIvor * Crosshairs now redraw correctly after a point selection. 05-15-2005 Ken McIvor * Changed the way axes.legend() is invoked so that only the Channel lines will be included in the resulting legend. * Added getColor(), getStyle(), and getMarker() to the Channel class to provide finer-grained control over the line styles. 05-12-2005 Ken McIvor * Fixed a bug in StripCharter where axes.legend() was being called when there were no lines plotted. 05-05-2005 Ken McIvor * release: 1.1 * Added extra keyword arguments to PlotApp * The Buffer classes now work properly and use matplotlib.numerix. * Changed the directory layout of the distribution to make building Debian packages easier. 05-04-2005 Ken McIvor * release: 1.0 * Support for stripcharting (updating a plot with new data as it arrives) has been added and an example is provided in `wxmpl-stripchart-demo.py'. * The PlotApp class has been added to ease creating a single plot window. * New wxPython-based interface for point and area selection events. * The user-interaction features (e.g. zooming) may be selectively disabled. * The PlotFrame now has File and Help menus and accelerator keys for saving the plot and and closing the window. * A demonstration of shared X axes has been added to `wxmpl-demos.py'. * A port of the XDP `plotit' application to WxMpl, `wxmpl-plotit.py', has beed added to the distribution. * Documentation generated from the docstrings of `wxmpl.py' is now included in the `doc/' subdirectory of the distribution. * A brief tutorial, "Getting Started with WxMpl and Matplotlib", is now included in the `tutorial/' subdirectory of the distribution. 03-09-2005 Ken McIvor * release: 0.9 (intial public release) wxmpl-2.0.0/LICENSE.txt0000644000175000017500000000255011147705702014745 0ustar segresegre00000000000000 Copyright 2005-2009 Illinois Institute of Technology Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ILLINOIS INSTITUTE OF TECHNOLOGY BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. Except as contained in this notice, the name of Illinois Institute of Technology shall not be used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from Illinois Institute of Technology. wxmpl-2.0.0/MANIFEST0000644000175000017500000000161011647105502014244 0ustar segresegre00000000000000# file GENERATED by distutils, do NOT edit ChangeLog LICENSE.txt MANIFEST MANIFEST.in README.txt metasetup.py plotit setup.py demos/picking_points.py demos/plotting.py demos/stripcharting.py lib/wxmpl.py reference/api-objects.txt reference/class-tree.html reference/crarr.png reference/epydoc.css reference/epydoc.js reference/frames.html reference/help.html reference/identifier-index.html reference/index.html reference/module-tree.html reference/redirect.html reference/toc-everything.html reference/toc-wxmpl-module.html reference/toc.html reference/wxmpl-module.html reference/wxmpl-pysrc.html reference/wxmpl.Channel-class.html reference/wxmpl.FigurePrinter-class.html reference/wxmpl.PlotApp-class.html reference/wxmpl.PlotFrame-class.html reference/wxmpl.PlotPanel-class.html reference/wxmpl.PointEvent-class.html reference/wxmpl.SelectionEvent-class.html reference/wxmpl.StripCharter-class.html wxmpl-2.0.0/MANIFEST.in0000644000175000017500000000026111150570723014652 0ustar segresegre00000000000000include README.txt LICENSE.txt ChangeLog MANIFEST.in MANIFEST metasetup.py include plotit recursive-include demos *.py recursive-include reference *.html *.txt *.css *.js *.png wxmpl-2.0.0/README.txt0000644000175000017500000000603611147705152014622 0ustar segresegre00000000000000WxMpl - Painless matplolib embedding for wxPython ------------------------------------------------- The `wxmpl' module provides an matplotlib `FigureCanvas' with user-interaction features like point-under-cursor and zooming in on a selected area. Support for creating stripcharts, plots that update as their data changes, is also included. Documentation of the module itself is available in the`reference/' subdirectory. An introduction to using matplotlib with WxMpl is available in the `tutorial/' subdirectory. Scripts demonstrating some of matplotlib's examples with WxMpl and plotting stripcharts data are in the `demos/' subdirectory. REQUIREMENTS ------------ * Python 2.5 or later http://www.python.org * wxPython 2.6.3.2 or later http://www.wxpython.org * matplotlib 0.98.1 or later http://matplotlib.sourceforge.net PLATFORMS --------- WxMpl has been tested under Debian GNU/Linux 5.0 "Lenny" [wxPython 2.6.3.2] and Mac OS 10.5.6 [wxPython 2.8.9.1]. INSTALLATION ------------ The Python Distutils system provides packaging, compilation, and installation for wxmpl. To install, execute the following command as superuser: # python setup.py install [OPTIONS] For more information about installation options, execute the following command: > python setup.py install --help For information about other Distutils commands, execute the following command: > python setup.py install --help-commands AVAILABILITY ------------ There is no website for WxMpl yet, so your best bet is to bug Ken. WxMpl's subversion repository is http://svn.csrri.iit.edu/mr-software/wxmpl/ AUTHOR ------ WxMpl was written by Ken McIvor COPYRIGHT & LICENSE ------------------- Copyright 2005-2009 Illinois Institute of Technology Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ILLINOIS INSTITUTE OF TECHNOLOGY BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. Except as contained in this notice, the name of Illinois Institute of Technology shall not be used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from Illinois Institute of Technology. wxmpl-2.0.0/metasetup.py0000644000175000017500000003454611647105364015520 0ustar segresegre00000000000000################################################################################ # Name: metasetup.py # Purpose: A scriptlet to simplify writing `setup.py' scripts # Author: Ken McIvor # # # Metasetup does several things that make writing setup scripts easier: # 1. Automagically translates uppercased global variables into their # corresponding keyword arguments # 2. Manages keyword argument compatability for you (e.g. keyword arguments # for distutils extensions like py2exe are omitted when using distutils) # 3. Adds support for "package_data" when using distutils with Python < 2.4 # # # Automatic Translation # Any global variable that is the uppercased version of a keyword argument # will be used as that keyword arguments value. # # In other words, # # AUTHOR = 'Ken McIvor' # AUTHOR_EMAIL = 'mcivor@iit.edu' # # will be turned into # # setup(..., author='Ken McIvor', author_email='mcivor@iit.edu', ...) # # # Keyword Compatability # Metasetup omits keyword arguments that are incompatible with your current # build environment: # * Python < 2.2.3: classifiers, download_url # # Arguments for setuptools, py2app, and py2exe are omitted unless you # imported them before running metasetup: # * setuptools: zip_safe, install_requires, entry_points, extras_require, # setup_requires, namespace_packages, test_suite, # eager_resources # * py2app: app # * py2exe: console, windows, service, com_server, zipfile # # # Using distutils Extensions # Metasetup can automatically load distutils extensions without requiring you # to edit `setup.py'. Extensions are loaded based on the environment # variables USE_SETUPTOOLS, USE_PY2EXE, and USE_PY2APP. To use an extension, # set the corresponding environment variable USE_XYZ to "1", "y", or "yes". # # # Using metasetup # Use execfile() to run metasetup at the end of `setup.py': # # Example setup.py that uses metasetup # NAME = 'example' # VERSION = '1.0' # PY_MODULES = ['example.py'] # execfile('metasetup.py') # ################################################################################ # # LICENSING AND COPYRIGHT # # The class `_package_data_build_py' is derived from Python 2.4's distutils # package. This portion of the software is licensed under the terms of the PSF # License Agreement for Python 2.4. # # # Copyright 2005-2006 Illinois Institute of Technology # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the # "Software"), to deal in the Software without restriction, including # without limitation the rights to use, copy, modify, merge, publish, # distribute, sublicense, and/or sell copies of the Software, and to # permit persons to whom the Software is furnished to do so, subject to # the following conditions: # # The above copyright notice and this permission notice shall be # included in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. # IN NO EVENT SHALL ILLINOIS INSTITUTE OF TECHNOLOGY BE LIABLE FOR ANY # CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, # TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE # SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # # Except as contained in this notice, the name of Illinois Institute # of Technology shall not be used in advertising or otherwise to promote # the sale, use or other dealings in this Software without prior written # authorization from Illinois Institute of Technology. # ################################################################################ # # ChangeLog # # 08-24-2006 Ken McIvor # * Release: 1.1 # * Setuptools is no longer used by default, as it is no longer a drop-in # replacement for distuils (it now attempts to check whether installation # directories appear in `sys.path'). # * Distutils extensions can now be loaded via environment variables. # * A bug in the handling of the Python 2.2.3 metadata has been fixed. # # 11-11-2005 Ken McIvor # * Release: 1.0 ################################################################################ import sys import glob import os import os.path import distutils.command.build_py import distutils.dist import distutils.log import distutils.util __metasetup_version__ = '1.1' # # Functions and classes to setup the build environment appropriately # def _use_distutils_extension(modname): """ Checks to see if `setup.py' imported the distutils extension "modname". If not, and the USE_MODNAME environment variable is set, the extension will be automatically imported. """ if sys.modules.has_key(modname): return True try: var = os.getenv('USE_'+modname.upper(), '0').lower() except: return False if var in ('1', 'y', 'yes'): try: __import__(modname) except ImportError, e: sys.stderr.write( '%s: could not import the "%s" distutils extension\n' % (os.path.basename(sys.argv[0]), modname)) sys.exit(1) else: return True else: return False def _use_setuptools(): """ Checks if `setup.py' imported setuptools and loads it automatically if the USE_SETUPTOOLS environment variable is set. """ return _use_distutils_extension('setuptools') def _use_py2app(): """ Checks if `setup.py' imported py2app and loads it automatically if the USE_PY2APP environment variable is set. """ return _use_distutils_extension('py2app') def _use_py2exe(): """ Checks if `setup.py' imported py2exe and loads it automatically if the USE_PY2EXE environment variable is set. """ return _use_distutils_extension('py2exe') def _get_setup_function(): """ Retrieve the appropriate setup() function. Setuptools is favored over distutils if it is installed. """ if _use_setuptools(): from setuptools import setup else: from distutils.core import setup return setup class _package_data_build_py(distutils.command.build_py.build_py): """ Adds support for package data files to distutils for Python < 2.4. The contents of this class are derived from Python 2.4's build_py class, located in the distutils.command.build_py module (revision $Id: install_lib.py,v 1.45 2004/12/02 20:14:16 lemburg Exp $). Subsequently, this portion of the software is licensed under the terms of the PSF License Agreement for Python 2.4. NOTE: When using metasetup.py to invoke setup(), this command class must be installed by _install_package_data_support(), rather than using the CMDCLASS variable. """ def initialize_options (self): distutils.command.build_py.build_py.initialize_options(self) self.package_data = None def finalize_options (self): distutils.command.build_py.build_py.finalize_options(self) self.package_data = self.distribution.package_data self.data_files = self.get_data_files() def run(self): if self.py_modules: self.build_modules() if self.packages: self.build_packages() self.build_package_data() self.byte_compile(self.get_outputs(include_bytecode=0)) def get_data_files (self): """Generate list of '(package,src_dir,build_dir,filenames)' tuples""" data = [] if not self.packages or self.package_data is None: return data for package in self.packages: # Locate package source directory src_dir = self.get_package_dir(package) # Compute package build directory build_dir = os.path.join(*([self.build_lib] + package.split('.'))) # Length of path to strip from found files plen = len(src_dir)+1 # Strip directory from globbed filenames filenames = [ file[plen:] for file in self.find_data_files(package, src_dir) ] data.append((package, src_dir, build_dir, filenames)) return data def find_data_files (self, package, src_dir): """Return filenames for package's data files in 'src_dir'""" globs = (self.package_data.get('', []) + self.package_data.get(package, [])) files = [] for pattern in globs: platform_path = distutils.util.convert_path(pattern) # Each pattern has to be converted to a platform-specific path filelist = glob.glob(os.path.join(src_dir, platform_path)) # Files that match more than one pattern are only added once files.extend([fn for fn in filelist if fn not in files]) return files def build_package_data (self): """Copy data files into build directory""" for package, src_dir, build_dir, filenames in self.data_files: for filename in filenames: target = os.path.join(build_dir, filename) self.mkpath(os.path.dirname(target)) self.copy_file(os.path.join(src_dir, filename), target, preserve_mode=False) def _install_package_data_support(): """ Installs support for the package_data argument if necessary. """ global CMDCLASS try: CMDCLASS except NameError: CMDCLASS = None # check for setuptools or Python >= 2.4 if _use_setuptools() or sys.version_info[0:2] >= (2,4): return # prevent distutils from complaining about the package_data keyword argument distutils.dist.Distribution.package_data = None # override the default build_py command if CMDCLASS is None: CMDCLASS = {} if not CMDCLASS.has_key('build_py'): CMDCLASS['build_py'] = _package_data_build_py def _fixup_extensions_for_setuptools(extensions): """ This function replaces instances of the original distutils.Extension class in the "extensions" list with instances of setuptools version. Setuptools monkeypatches distutils.Extension to add support for extensions written in Pyrex (.pyx), which leads to extreme badness in distutils.build_ext if you call setup() with distutils.Extension instances. """ import setuptools for i in range(0, len(extensions)): ext = extensions[i] if isinstance(ext, setuptools.Extension): continue else: extensions[i] = setuptools.Extension( name=ext.name, sources=ext.sources, include_dirs=ext.include_dirs, define_macros=ext.define_macros, undef_macros=ext.undef_macros, library_dirs=ext.library_dirs, libraries=ext.libraries, runtime_library_dirs=ext.runtime_library_dirs, extra_objects=ext.extra_objects, extra_compile_args=ext.extra_compile_args, extra_link_args=ext.extra_link_args, export_symbols=ext.export_symbols, depends=ext.depends, language=ext.language) # # Create the lists of variables that correspond to keyword arguments of setup() # # package metadata _distutils_base_metadata_variables = [ 'NAME', 'VERSION', 'AUTHOR', 'AUTHOR_EMAIL', 'MAINTAINER', 'MAINTAINER_EMAIL', 'URL', 'LICENSE', 'DESCRIPTION', 'LONG_DESCRIPTION', 'KEYWORDS', 'PLATFORMS'] # package metadata added in Python 2.2.3 _distutils_py223_metadata_variables = ['CLASSIFIERS', 'DOWNLOAD_URL'] # packages, modules, and extensions _distutils_python_variables = [ 'PACKAGES', 'PACKAGE_DIR', 'PY_MODULES', 'EXT_MODULES'] # build options _distutils_extension_variables = [ 'LIBRARIES', 'HEADERS', 'INCLUDE_DIRS', 'EXTRA_PATH', 'OPTIONS'] # additional files to distribute _distutils_resource_variables = ['SCRIPTS', 'PACKAGE_DATA', 'DATA_FILES'] # hooks to override the behavior of distutils _distutils_command_variables = [ 'CMDCLASS', 'DISTCLASS', 'SCRIPT_NAME', 'SCRIPT_ARGS'] # setuptools options _setuptools_variables = [ 'ZIP_SAFE', 'INSTALL_REQUIRES', 'ENTRY_POINTS', 'EXTRAS_REQUIRE', 'SETUP_REQUIRES', 'NAMESPACE_PACKAGES', 'TEST_SUITE', 'EAGER_RESOURCES'] # py2app options _py2app_variables = ['APP'] # py2exe options _py2exe_variables = ['CONSOLE', 'WINDOWS', 'SERVICE', 'COM_SERVER', 'ZIPFILE'] # # Setup the build envrionment and invoke setup() # if __name__ == '__main__': # Prevent people from running this script directly if os.path.basename(sys.argv[0]).startswith('metasetup'): sys.stderr.write('%s: please run `setup.py\' instead\n' % os.path.basename(sys.argv[0])) sys.exit(1) # if necessary, install support for the 'package_data' keyword argument _install_package_data_support() # omit the new metadata keyword arguments for Python < 2.2.3 if sys.version < '2.2.3': _distutils_metadata_variables = _distutils_base_metadata_variables else: _distutils_metadata_variables = (_distutils_base_metadata_variables + _distutils_py223_metadata_variables) # start building the list of supported keyword arguments _kwd_variables = (_distutils_metadata_variables + _distutils_python_variables + _distutils_extension_variables + _distutils_resource_variables + _distutils_command_variables) # include the setuptools keyword arguments if _use_setuptools(): _kwd_variables += _setuptools_variables # include the py2app keyword arguments if _use_py2app(): _kwd_variables += _py2app_variables # include the py2exe keyword arguments if _use_py2exe: _kwd_variables += _py2exe_variables # build the arguments dictionary _kwd_arguments = {} for _kwd_name in _kwd_variables: _kwd_value = globals().get(_kwd_name) if _kwd_value is not None: _kwd_arguments[_kwd_name.lower()] = _kwd_value # convert distutils.Extension instances to setuptools.Extension instances if _use_setuptools() and _kwd_arguments.has_key('ext_modules'): _fixup_extensions_for_setuptools(_kwd_arguments['ext_modules']) # fetch and invoke setup() _setup_function = _get_setup_function() _setup_function(**_kwd_arguments) wxmpl-2.0.0/plotit0000755000175000017500000010734311647105364014374 0ustar segresegre00000000000000#!/usr/bin/env python # Name: plotit # Purpose: Experiment data visualization # Author: Ken McIvor # # Copyright 2004-2009 Illinois Institute of Technology # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the # "Software"), to deal in the Software without restriction, including # without limitation the rights to use, copy, modify, merge, publish, # distribute, sublicense, and/or sell copies of the Software, and to # permit persons to whom the Software is furnished to do so, subject to # the following conditions: # # The above copyright notice and this permission notice shall be # included in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. # IN NO EVENT SHALL ILLINOIS INSTITUTE OF TECHNOLOGY BE LIABLE FOR ANY # CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, # TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE # SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # # Except as contained in this notice, the name of Illinois Institute # of Technology shall not be used in advertising or otherwise to promote # the sale, use or other dealings in this Software without prior written # authorization from Illinois Institute of Technology. # ChangeLog # # 10-17-2011 Carlo Segre # * Release 3.0 # * Replace all references to Numerix with Numpy # 02-21-2009 Ken McIvor # * Release 2.3.4 # * Fixed a bug that was breaking the quickplot ('-q') mode # 02-20-2009 Ken McIvor # * Release 2.3.3 # * Stopped using the deprecated 'sre' module # * Updated legend formatting for matplotlib 0.98.x # * Dollar signs in axes labels are now properly escaped # 04-06-2006 Ken McIvor # * Release 2.3.2 # * Had another go at shutting down cleanly after the "exit" command while in # stripchart mode. # * Fixed a bug in cmd_START_PLOT()'s error handling. # 04-04-2006 Ken McIvor # * Release 2.3.1 # * Attemped to fix a subtle race condition that caused the plot window to # survive the "exit" command, hanging around at the end of MX quick scans. # * Switched to using LinearLocator(5) for X and Y axis tick locations to # yield nicer looking plots for the occasional corner cases (e.g. when # AutoLocator gives you 9 ticks with overlapping labels). # 11-14-2005 Ken McIvor # * Release: 2.3 # * Column names may be used in expressions if they are present in the files # * Empty data files no longer cause the entire plot to fail # * Column expressions are now masked arrays, clamping +/- INF # 11-11-2005 Ken McIvor # * Merged the ScalarFormatter fix from August back into the main trunk. This # fix undoes some of the confusing axis labeling caused by changes # introduced in matplotlib 0.81. # 10-21-2005 Ken McIvor # * Release: 2.2 # * Added full support for plotgngu.pl's start_plot command. The two integer # arguments that were previously ignored are now required and specify the # number of columns of independently varying data and the column index that # contains the abscissa (starting from zero). # 08-08-2005 Ken McIvor # * Release: 2.1.1 # * Worked around a problem in matplotlib so that PlotIt no longer chokes on # expressions that evaluate to inf or NaN. # 07-10-2005 Ken McIvor # * Release: 2.1 # * Quickplot mode now correctly handles single-column data files. # * You can now plot only the Y expressions of files from the command line. # * PlotIt now tries to remeber its last window position, which should improve # the user experience when it's being used by MX to display scan data. # 05-26-2005 Ken McIvor # * Release: 2.0 # 05-23-2005 Ken McIvor # * Fixed a bug in the `set linestyles' command. # * Made the linestyles, ticksize, and ticks `set' commands more robust # against invalid arguments. # * The PlotItApp no longer redirects stderr. # 05-19-2005 Ken McIvor # * Release: 2.0rc4 # * The command-line invocation has been changed so `$ plotit' won't appear to # hang as it reads commands from standard input. # * Added a quick-plotting mode that graphs the first two columns of files. # * Expression evaluation only does one row at a time if an error occurs. # * Error handling in expression evaluation is much more robust. # 05-15-2005 Ken McIvor # * Release: 2.0rc3 (`plot' is now `plotit') # * Refactored the static vs. stripcharting logic out of PlotApp # * Cleaned up the MX kludges, especially the workaround for wx.PostEvent() # hanging after MainLoop() has exited (a queue is now used in place of the # CommandEvent). # * The plot window is now unclosable while stripcharting stdin. # * Fixed up bug where cmd_START_PLOT() relied entirely on parse_command() to # split up the equations. # * Added several new `set' commands: ticks, ticksize, linestyles. # * Added the `marker' command to draw vertical lines. # * Plot expressions now recognize `@N' for column names in addition to `$N'. # * Added the ability to do quick plots of multiple data files from the # command line. # 05-12-2005 Ken McIvor # * Added some missing calls to sys.exit() to the ImportError handlers. # * Added the `start_plot' command and special case handling for MX's # inconsistent syntax (e.g. "start_plot;0;1;$f[0]/$f[1]"). # * The `plot' command is now a no-op, since MX sends it after every `data' # command. # * Fixed a bug where `convert_plotgnu_expression()' was omitting the rest of # the expression after the last channel number (e.g. "log($0/$1)" was # becoming "log($2/$3") # * Added an `exit' command. # * Fixed the way the PlotApp and FileReaderThread interact because # `wx.PostEvent()' blocks after the PlotApp has exited. # 05-10-2005 Ken McIvor # * release: 2.0rc2 # * Default behavior is now to watch stdin, but not watch files. The `-w' # argument has been changed to reflect this. # * Plot window now has a correct title, rather than just "WxMpl". # 05-05-2005 Ken McIvor # * release: 2.0rc1 # * WxMpl is now used for the plotting, rather than including wxPyPlot # * The `plot' command has been changed to be compatible with `plotgnu' # * A new command, `line', has been added to support the new equation syntax # * Replotting is now driven by a timer, rather than the arrival of new data # * The Python 2.1 compatability fixes have been removed, since matplotlib # requires Python 2.3 or later. # 10-04-2004 Ken McIvor # * release: 1.1 # * Debian Stable fixes: # - removed `typecode' keyword from Numerix.zeros() # - forcibly placed wxPython.wx.wxNewId() into wx as NewId() # 10-03-2004 Ken McIvor # * release: 1.0 __version__ = '2.3.2' import ConfigParser import os.path import re import sys import threading try: import wx except ImportError: if __name__ == '__main__': sys.stderr.write('''\ This program requires wxPython, the Python bindings for the wxWidgets GUI framework. wxPython can be downloaded from http://www.wxpython.org ''') sys.exit(1) try: import matplotlib except ImportError: if __name__ == '__main__': sys.stderr.write('''\ This program requires matplotlib, Python's 2D plotting library. matplotlib can be downloaded from http://matplotlib.sourceforge.net ''') sys.exit(1) try: import wxmpl except ImportError: if __name__ == '__main__': sys.stderr.write('''\ This program requires WxMpl, a library for embedding matplotlib in wxPython applications. WxMpl can be downloaded from http://agni.phys.iit.edu/~kmcivor/wxmp/ ''') sys.exit(1) try: import xdp.io # if it's available, use XDP to load data except ImportError: xdp = None import numpy as NumPy from matplotlib.font_manager import FontProperties class Queue: def __init__(self): self.mutex = threading.Lock() self.queue = [] def put(self, item): self.mutex.acquire() self.queue.append(item) self.mutex.release() def getAll(self): self.mutex.acquire() items = self.queue[:] del self.queue[:] self.mutex.release() return items # # Functions to load and store the plot window's position. # # FIXME: this is rather POSIX-specific PLOTIT_POSITION_FILE = '~/.plotitrc' def load_window_position(): fnam = os.path.expanduser(PLOTIT_POSITION_FILE) cp = ConfigParser.ConfigParser() try: cp.read([fnam]) x = cp.getint('position', 'x') y = cp.getint('position', 'y') except Exception: return wx.DefaultPosition return wx.Point(x, y) def store_window_position(pos): fnam = os.path.expanduser(PLOTIT_POSITION_FILE) cp = ConfigParser.ConfigParser() cp.add_section('position') cp.set('position', 'x', str(pos.x)) cp.set('position', 'y', str(pos.y)) try: output = file(fnam, 'w') cp.write(output) output.close() except Exception: pass # # wxPython Application class # class PlotItApp(wx.App): def __init__(self, options, arguments, **kwds): self.options = options self.director = None self.arguments = arguments wx.App.__init__(self, **kwds) def OnInit(self): self.frame = PlotFrame(pos=load_window_position()) if len(self.arguments) < 2 and not options.quick: self.init_plotgnu() else: self.init_quickplot() self.frame.Show(True) return True def init_plotgnu(self): args = self.arguments if args[0] == '-': inputFile = sys.stdin options.watch = not options.watch else: try: inputFile = file(args[0], 'r') except IOError, e: fatalIOError(e) if self.options.watch: self.director = StripChartDirector(self.frame, inputFile) else: self.director = PlotCommandDirector(self.frame, inputFile) def init_quickplot(self): args = self.arguments style = 'lp' if options.lines and options.points: pass # let people type `-lp' like in GNUPLOT elif options.lines: style = 'l' elif options.points: style = 'p' if options.quick: self.director = QuickPlotDirector(self.frame, args, style) else: if len(args) == 2 or not is_plot_expression(args[1]): xExpr = None yExpr, fileNames = args[0], args[1:] else: xExpr, yExpr, fileNames = args[0], args[1], args[2:] self.director = ExpressionPlotDirector(self.frame, xExpr, yExpr, fileNames, style) def cleanup(self): self.director.cleanup() class PlotFrame(wxmpl.PlotFrame): ABOUT_TITLE = 'About plotit' ABOUT_MESSAGE = ('plotit %s\n' % __version__ + 'Written by Ken McIvor \n' + 'Copyright 2004-2005 Illinois Institute of Technology') def __init__(self, **kwds): wxmpl.PlotFrame.__init__(self, None, -1, 'plotit', **kwds) # # Classes to perform the various kinds of plotting # class PlotDirector: def __init__(self, frame): self.frame = frame wx.EVT_CLOSE(self.frame, self.OnClose) def OnClose(self, evt): store_window_position(self.frame.GetPosition()) evt.Skip() def setup_axes(self, axes): if matplotlib.__version__ >= '0.81': axes.yaxis.set_major_formatter( matplotlib.ticker.OldScalarFormatter()) axes.yaxis.set_major_locator( matplotlib.ticker.LinearLocator(5)) axes.xaxis.set_major_formatter( matplotlib.ticker.OldScalarFormatter()) axes.xaxis.set_major_locator( matplotlib.ticker.LinearLocator(5)) def cleanup(self): pass class PlotCommandDirector(PlotDirector): def __init__(self, frame, inputFile): PlotDirector.__init__(self, frame) frame.SetTitle(get_frame_title(inputFile)) interpreter = CommandInterpreter(frame.get_figure().gca(), inputFile, ignoreExit=True) line = inputFile.readline() while line: line = line.strip() interpreter.doCommand(line) line = inputFile.readline() interpreter.replot() class StripChartDirector(PlotDirector): def __init__(self, frame, inputFile): PlotDirector.__init__(self, frame) axes = frame.get_figure().gca() self.setup_axes(axes) frame.SetTitle(get_frame_title(inputFile)) self.inputFile = inputFile self.canClose = inputFile is not sys.stdin self.interpreter = CommandInterpreter(axes, inputFile) self.queue = Queue() self.fileReader = FileReaderThread(inputFile, self.queue) self.timer = wx.PyTimer(self.OnTimer) self.timer.Start(250) self.fileReader.start() def OnClose(self, evt): if not self.canClose and evt.CanVeto() and self.fileReader.isAlive(): wx.Bell() evt.Veto() else: self.timer.Stop() PlotDirector.OnClose(self, evt) def OnTimer(self): interpreter = self.interpreter for cmd in self.queue.getAll(): interpreter.doCommand(cmd) if interpreter.hasExited: self.timer.Stop() try: self.inputFile.close() except: pass if self.fileReader.isAlive(): interpreter.replot() else: self.timer.Stop() interpreter.replot() def cleanup(self): if self.fileReader.isAlive(): self.fileReader.join() class QuickPlotDirector(PlotDirector): def __init__(self, frame, inputFiles, style): PlotDirector.__init__(self, frame) frame.SetTitle('PlotIt') axes = frame.get_figure().gca() self.setup_axes(axes) # FIXME: refactor this chunk into a function shared by # QuickPlotDirector and ExpressionPlotDirector lines = [] for inputFile in inputFiles[:]: x, y = quickplot_evaluate_file(inputFile) if x is None or y is None: inputFiles.remove(inputFile) else: lines.append((x, y)) inputs = [split_path(x) for x in inputFiles] if len(inputs) == 1: idx = 0 else: idx = len(os.path.commonprefix([x[0] for x in inputs])) matplotlib.rc('lines', markersize=2) for i, (x, y) in enumerate(lines): if x is None or y is None: continue path, name = inputs[i] fullName = os.path.join(path[idx:], name) line = axes.plot(x, y, label=fullName)[0] if style == 'l': pass elif style == 'p': line.set_linestyle('None') line.set_marker('o') else: line.set_marker('o') line.set_markeredgecolor(line.get_color()) line.set_markerfacecolor(line.get_color()) if not axes.get_lines(): sys.stderr.write('%s: no data to plot\n' % os.path.basename(sys.argv[0])) sys.exit(1) axes.legend(numpoints=2, prop=FontProperties(size='x-small')) class ExpressionPlotDirector(PlotDirector): def __init__(self, frame, xExpr, yExpr, inputFiles, style): PlotDirector.__init__(self, frame) frame.SetTitle('PlotIt') axes = frame.get_figure().gca() self.setup_axes(axes) axes.set_ylabel(yExpr.replace('@', '$').replace('$', '\$')) if xExpr is None: axes.set_xlabel('0...N') else: axes.set_xlabel(xExpr.replace('@', '$').replace('$', '\$')) lines = [] for inputFile in inputFiles[:]: x, y = evaluate_file(inputFile, xExpr, yExpr) if x is None or y is None: inputFiles.remove(inputFile) else: lines.append((x, y)) inputs = [split_path(x) for x in inputFiles] if len(inputs) == 1: idx = 0 else: idx = len(os.path.commonprefix([x[0] for x in inputs])) matplotlib.rc('lines', markersize=2) for i, (x, y) in enumerate(lines): if x is None or y is None: continue path, name = inputs[i] fullName = os.path.join(path[idx:], name) line = axes.plot(x, y, label=fullName)[0] if style == 'l': pass elif style == 'p': line.set_linestyle('None') line.set_marker('o') else: line.set_marker('o') line.set_markeredgecolor(line.get_color()) line.set_markerfacecolor(line.get_color()) if not axes.get_lines(): sys.stderr.write('%s: no data to plot\n' % os.path.basename(sys.argv[0])) sys.exit(1) axes.legend(numpoints=2, prop=FontProperties(size='x-small')) def cleanup(self): pass # # Thread that pushes lines from a file into a Queue # class FileReaderThread(threading.Thread): def __init__(self, inputFile, queue): threading.Thread.__init__(self, name='FileReader') self.queue = queue self.inputFile = inputFile def run(self): queue = self.queue inputFile = self.inputFile line = inputFile.readline() while line: line = line.strip() queue.put(line) line = inputFile.readline() # # Class that executes plotting commands # class CommandInterpreter: def __init__(self, axes, inputFile, ignoreExit=False): self.axes = axes self.ignoreExit = ignoreExit if inputFile is sys.stdin: self.fileDesc = 'standard input' else: self.fileDesc = 'file `%s\'' % inputFile.name self.buffer = wxmpl.MatrixBuffer() self.charter = wxmpl.StripCharter(axes) self.channels = [] self.hasExited = False self.need_replot = False matplotlib.rc('lines', markersize=2) def replot(self): if self.need_replot and not self.hasExited: self.need_replot = False self.charter.update() def doCommand(self, command): tokens = self.parse_command(command) if not len(tokens): return cmd, args = tokens[0].upper(), tokens[1:] method = getattr(self, 'cmd_%s'%cmd, None) if callable(method) and method(args): self.need_replot = True def parse_command(self, command): if command.startswith('start_plot;'): return ['start_plot'] + command.split(';')[1:] try: return tokenize(command) except Exception: return [] def cmd_START_PLOT(self, args): if len(args) < 3: return False try: independent_variable_count = int(args[0]) innermost_loop_motor_index = int(args[1]) except (ValueError, OverflowError), e: print >> sys.stderr, ( 'Error in "start_plot" statement for file %s: %s' % (self.fileDesc, e)) return False if independent_variable_count < 1: independent_variable_count = 0 if innermost_loop_motor_index < 0: innermost_loop_motor_index = 0 xExpr = '$%d' % (innermost_loop_motor_index + 1) for eqn in args[2:]: yExpr = convert_plotgnu_expression(eqn, independent_variable_count) channel = ExpressionChannel(self.buffer, xExpr, yExpr, self.fileDesc) channel.marker = 'o' self.channels.append(channel) self.charter.setChannels(self.channels) return True def cmd_PLOT(self, args): return False def cmd_REPLOT(self, args): self.replot() return False def cmd_SET(self, args): if len(args): var, args = args[0].upper(), args[1:] if len(args) and args[0] == '=': args = args[1:] method = getattr(self, 'set_%s'%var, None) if callable(method): return method(args) return False def cmd_DATA(self, args): if not len(args): return False data = [0.0] * len(args) for i, point in enumerate(args): try: data[i] = float(point) except Exception, e: pass self.buffer.append(data) for channel in self.channels: channel.recalculate() return True def cmd_MARKER(self, args): if len(args) != 1: return False try: x = float(args[0]) except: return False self.axes.axvline(x, color='k', linestyle='--') return True def set_TITLE(self, args): if len(args) == 1: self.axes.set_title(args[0]) return True else: return False def set_XLABEL(self, args): if len(args) == 1: self.axes.set_xlabel(args[0]) return True else: return False def set_YLABEL(self, args): if len(args) == 1: self.axes.set_ylabel(args[0]) return True else: return False def set_TIC(self, args): return self.set_TICKS(args) def set_TICS(self, args): return self.set_TICKS(args) def set_TICSIZE(self, args): return self.set_TICKSIZE(args) def set_TICKS(self, args): if len(args): ticks = [] for tick in args: if matplotlib.lines.Line2D._markers.has_key(tick): ticks.append(tick) else: ticks.append(None) for i, marker in enumerate(ticks[:len(self.channels)]): self.channels[i].marker = marker else: for channel in self.channels: channel.marker = None self.charter.setChannels(self.channels) return True def set_TICKSIZE(self, args): if len(args) == 0: matplotlib.rc('lines', markersize=2) return elif len(args) != 1: return True try: size = float(args[0]) except: return False if markersize <= 0: return False matplotlib.rc('lines', markersize=size) return True def set_LINESTYLES(self, args): if len(args): styles = [] for style in args: if matplotlib.lines.Line2D._lineStyles.has_key(style): styles.append(style) else: styles.append(None) for i, style in enumerate(styles[:len(self.channels)]): self.channels[i].style = style else: for channel in self.channels: channel.style = None self.charter.setChannels(self.channels) return True def set_LEGEND(self, args): if len(args): for i, label in enumerate(args[:len(self.channels)]): self.channels[i].name = label self.charter.setChannels(self.channels) else: self.axes.legend_ = None return True def cmd_EXIT(self, args): if self.ignoreExit: return False app = wx.GetApp() if app is not None: app.ExitMainLoop() self.hasExited = True return False # # Channels that calculate their X and Y data from expressions # class ExpressionChannel(wxmpl.Channel): def __init__(self, buffer, xExpr, yExpr, fileDesc): if xExpr is None: label = yExpr else: label = xExpr + ', ' + yExpr wxmpl.Channel.__init__(self, label) self.buffer = buffer self.x = None self.y = None self.xExpr = xExpr self.yExpr = yExpr self.fileDesc = fileDesc def getX(self): def failure(msg, *args): print >> sys.stderr, (msg % args) ; self.x = None ; return None if self.x is not None: return self.x if self.xExpr is None: data = self.buffer.getData() if data is not None: self.x = data[:, 0] return self.x try: self.x = evaluate_expression(self.xExpr, self.buffer.getData()) except Exception, e: return failure('Error evaluating X expression `%s\' for %s: %s', self.xExpr, self.fileDesc, e) if (self.x is not None and not isinstance(self.x, (NumPy.ArrayType, NumPy.ma.MaskedArray))): return failure('Error evaluating X expression `%s\' for %s: ' 'result is not a vector', self.xExpr, self.fileDesc) return self.x def getY(self): def failure(msg, *args): print >> sys.stderr, (msg % args) ; self.y = None ; return None if self.y is not None: return self.y try: self.y = evaluate_expression(self.yExpr, self.buffer.getData()) except Exception, e: return failure('Error evaluating Y expression `%s\' for %s: %s', self.yExpr, self.fileDesc, e) if (self.y is not None and not isinstance(self.y, (NumPy.ArrayType, NumPy.ma.MaskedArray))): return failure('Error evaluating Y expression `%s\' for %s: ' 'result is not a vector', self.yExpr, self.fileDesc) return self.y def recalculate(self): self.x = self.y = None self.setChanged(True) # # Evaluate X and Y expressions using a file of data # def quickplot_evaluate_file(fileName): def failure(msg, *args): print >> sys.stderr, (msg % args) return None, None data, columnNames = load_data(fileName) if data is None: return None, None if data.shape[1] == 1: return NumPy.arange(0, data.shape[0], 1, dtype=float), data[:, 0] else: return data[:, 0], data[:, 1] def evaluate_file(fileName, xExpr, yExpr): def failure(msg, *args): print >> sys.stderr, (msg % args) return None, None data, columnNames = load_data(fileName) if data is None: return None, None try: x = evaluate_expression(xExpr, data, columnNames) except Exception, e: return failure('Error evaluating X for file `%s\': %s', fileName, e) try: y = evaluate_expression(yExpr, data, columnNames) except Exception, e: return failure('Error evaluating Y for file `%s\': %s', fileName, e) if not isinstance(x, (NumPy.ArrayType, NumPy.ma.MaskedArray)): return failure('Error evaluating X for file `%s\': result is not a ' 'vector', fileName) elif not isinstance(y, (NumPy.ArrayType, NumPy.ma.MaskedArray)): return failure('Error evaluating Y for file `%s\': result is not a ' 'vector', fileName) if x.shape != y.shape: return failure('BUG? x.shape != y.shape for file `%s\'', fileName) return x, y def load_data(fileName): if xdp is not None: try: header, dataset = xdp.io.readFile(fileName) except IOError: pass else: return dataset.getMatrix(), dataset.getColumnNames() try: input = file(fileName, 'r') except IOError, e: fatalIOError(e) buffer = wxmpl.MatrixBuffer() line = input.readline() while line: line = line.strip() if line: _parse_data(buffer, line) line = input.readline() input.close() return buffer.getData(), () def _parse_data(buffer, line): failures = 0 values = line.split() data = [0.0] * len(values) for i, point in enumerate(values): try: data[i] = float(point) except Exception, e: if i == 0 and point == 'data': failures += 1 else: return if failures: buffer.append(data[failures:]) else: buffer.append(data) # # Evaluating equations against a matrix # def is_plot_expression(string): return (COLNUMS.search(string) is not None or COLNAMES.search(string) is not None or PG_COLNUMS.search(string) is not None) def convert_plotgnu_expression(pgExpr, offset): i = 0 expr = '' while 1: m = PG_COLNUMS.search(pgExpr[i:]) if m is None: break expr += pgExpr[i:i+m.start()] expr += '$' + str(int(m.group('number'))+offset+1) i += m.end() expr += pgExpr[i:] return expr def evaluate_expression(expr, data, columnNames=()): if data is None: return None elif expr is None: return NumPy.arange(0, data.shape[0], 1, dtype=float) columnCount = data.shape[1] namespace = EVAL_NAMESPACE.copy() for column, _, number in COLNUMS.findall(expr): number = int(number) if number < 1 or number > columnCount: raise ValueError('invalid column "%s"' % number) for column, _, name in COLNAMES.findall(expr): if not columnNames: raise ValueError('column names are unavailable') elif name not in columnNames: raise ValueError('invalid column "%s"' % name) expr = COLNUMS.sub('__C_\g', expr) expr = COLNAMES.sub('__C_\g', expr) try: code = compile(expr, '', 'eval') except SyntaxError, e: raise ValueError('incorrect syntax: %s' % e) for i in range(0, columnCount): namespace['__C_%d' % (i+1)] = None for i in range(0, min(columnCount, len(columnNames))): namespace['__C_%s' % columnNames[i]] = None for var in code.co_names: if not namespace.has_key(var): raise ValueError('invalid variable "%s"' % var) # try to evaluate things the fast way # XXX: causes problems with Matplotlib, which chokes on `inf' and `NaN'. for i in range(0, columnCount): namespace['__C_%d' % (i+1)] = data[:, i] for i in range(0, min(columnCount, len(columnNames))): namespace['__C_%s' % columnNames[i]] = data[:, i] try: result = eval(code, namespace) return NumPy.ma.masked_outside(result, -1e308, 1e308) except Exception, e: pass # evaluate one point at a time if necessary res = NumPy.zeros((data.shape[0],), dtype=float) for i in range(0, data.shape[0]): for j in range(0, columnCount): namespace['__C_%d' % (j+1)] = data[i, j] for j in range(0, min(columnCount, len(columnNames))): namespace['__C_%s' % columnNames[j]] =data[i, j] try: res[i] = eval(code, namespace) except Exception, e: pass return res COLNUMS = re.compile(r'(?P(\$|\@)(?P\d+))') COLNAMES = re.compile(r'(?P(\$|\@)(?P[a-zA-Z_][a-zA-Z0-9_]*))') PG_COLNUMS = re.compile(r'(?P\$f\[(?P\d+)\])') EVAL_NAMESPACE = { 'int': int, 'float': float, 'complex': complex, 'pi': NumPy.pi, 'e': NumPy.e, 'abs': NumPy.absolute, 'arccos': NumPy.arccos, 'arccosh': NumPy.arccosh, 'arcsin': NumPy.arcsin, 'arcsinh': NumPy.arcsinh, 'arctan': NumPy.arctan, 'arctanh': NumPy.arctanh, 'cos': NumPy.cos, 'cosh': NumPy.cosh, 'exp': NumPy.exp, 'log': NumPy.log, 'log10': NumPy.log10, 'power': NumPy.power, 'sin': NumPy.sin, 'sinh': NumPy.sinh, 'sqrt': NumPy.sqrt, 'tan': NumPy.tan, 'tanh': NumPy.tanh } # # Potpourri utility functions # WORD = r'(\\.)|[^"\'\s]' DWORD = r'(\\.)|[^"\s]' SWORD = r'(\\.)|[^\'\s]' DQUOTE = r'%s| |\t' % SWORD SQUOTE = r'%s| |\t' % SWORD RE_SKIP = re.compile(r'\s+') RE_TOKEN = re.compile(r'(%s)+|("(%s|(\\.))*")|(\'(%s|(\\.))*\')' % (WORD, DQUOTE, SQUOTE)) def tokenize(string, limit=None): tokens = [] while string: m = RE_SKIP.match(string) if m is not None: string = string[m.end():] if not string: break if limit is not None and len(tokens) == limit: tokens.append(string) break m = RE_TOKEN.match(string) if m is None: return None tok = string[:m.end()] if tok.startswith('"') or tok.startswith('\''): tok = tok[1:-1] tokens.append(tok) string = string[m.end():] return tokens def enumerate(seq): return [(i,seq[i]) for i in range(0, len(seq))] def split_path(fileName): name = os.path.basename(fileName) path = os.path.dirname(os.path.abspath(fileName)) user = os.path.expanduser('~') if user != '~': path = path.replace(user, '~') return path, name def cleanup_path(fileName): return os.path.join(*split_path(fileName)) def get_frame_title(inputFile): if inputFile is sys.stdin: return 'stdin - PlotIt' else: path, name = split_path(inputFile.name) return (name + ' (' + path + ') - PlotIt') # # Command-Line Interface # def fatalError(msg): sys.stderr.write('Error: ') sys.stderr.write(str(msg)) sys.stderr.write('\n') sys.exit(1) def fatalIOError(err): if isinstance(err, IOError) and err.strerror and err.filename: err = '%s: %s' % (err.strerror, err.filename) fatalError(err) def ParseArguments(args): from optparse import OptionParser USAGE = '''\ %prog [-w] FILE: execute the commands read from FILE (use `-' for stdin) %prog [-lp] -q FILE [FILE...]: plot the 1st and 2nd columns of files %prog [-lp] Y FILE [FILE...]: plot the Y expressions for files %prog [-lp] X Y FILE [FILE...]: plot the X and Y expressions for files `%prog' is a simple plotting program which can draw line plots and stripcharts using a subset of GNUPLOT's command language. You can also do quick plots of multiple data files from the command-line.''' VERSION = '%prog ' + __version__ + ', by Ken McIvor ' parser = OptionParser(usage=USAGE, version=VERSION) # # Command-line options # parser.add_option('-w', action='store_const', dest='watch', const=True, default=False, help=('watch the input file for commands to stripchart, or wait to ' + ' read all of of stdin before plotting')) parser.add_option('-q', action='store_const', dest='quick', const=True, default=False, help='plot the first and second columns of multiple files') parser.add_option('-l', action='store_const', dest='lines', const=True, default=False, help='plot X and Y with lines') parser.add_option('-p', action='store_const', dest='points', const=True, default=False, help='plot X and Y with points') opts, args = parser.parse_args(args) if (not len(args) or (len(args) == 2 and is_plot_expression(args[0]) and is_plot_expression(args[1]))): parser.print_usage() sys.exit(1) return opts, args # # Application entry-point # def main(options, arguments): app = PlotItApp(options, arguments, redirect=0) app.MainLoop() app.cleanup() # # Magic incantation to call main() when run as a script # if __name__ == '__main__': try: options, arguments = ParseArguments(sys.argv[1:]) main(options, arguments) except KeyboardInterrupt: pass wxmpl-2.0.0/setup.py0000644000175000017500000000117511647105364014641 0ustar segresegre00000000000000#!/usr/bin/env python # Name: setup.py # Purpose: wxmpl distutils install program # Author: Ken McIvor # Carlo Segre # # Copyright 2005-2011 Illinois Institute of Technology # # See the file "LICENSE" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. NAME = 'wxmpl' VERSION = '2.0.0' AUTHOR = 'Carlo Segre' AUTHOR_EMAIL = 'segre@iit.edu' LICENSE = 'MIT' DESCRPTION = 'A library for painlessly embedding matplotlib in wxPython' PACKAGE_DIR = {'': 'lib'} PY_MODULES = ['wxmpl'] SCRIPTS = ['plotit'] execfile('metasetup.py') wxmpl-2.0.0/PKG-INFO0000644000175000017500000000027111647105502014212 0ustar segresegre00000000000000Metadata-Version: 1.0 Name: wxmpl Version: 2.0.0 Summary: UNKNOWN Home-page: UNKNOWN Author: Carlo Segre Author-email: segre@iit.edu License: MIT Description: UNKNOWN Platform: UNKNOWN