Advertisement
rzzzwilson

Dynamic of errorbar plot in matplotlib

Jul 18th, 2011
419
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 7.07 KB | None | 0 0
  1. #!/usr/bin/env python
  2.  
  3. """A wxPython widget to dislay a simple matplotlib graph.
  4.  
  5. This could be made *much* more complicated.
  6.  
  7. TODO:
  8.    Allow series colour change
  9.    Allow line, points, etc, series
  10.    Allow changing of number of points in series (how?)
  11.    Allow more than one series (how?)
  12.    Allow setting of axis ticks/subticks
  13.    etc, etc
  14.  
  15.    The basic idea is to minimise the number of args passed to the constructor
  16.    and add methods to control the graph look&feel.
  17. """
  18.  
  19.  
  20. import wx
  21. import numpy as np
  22. from matplotlib.figure import Figure
  23. from matplotlib.backends.backend_wxagg import FigureCanvasWxAgg as FigureCanvas
  24. from matplotlib.backends.backend_wx import NavigationToolbar2Wx
  25. from matplotlib.path import Path
  26. import matplotlib.patches as patches
  27. import pylab
  28.  
  29.  
  30. class MplWidget(wx.Panel):
  31.     """Class to display a matplotlib graph on a wxPython panel.
  32.  
  33.    Note that the dataset length must be set initially AND NOT CHANGED
  34.    THEREAFTER.  Whether this is fixed in stone or merely due to my
  35.    imperfect understanding of wxPython ...
  36.    """
  37.  
  38.     def __init__(self, parent, toolbar=False, num_points=100,
  39.                  x_range=(-1,1), y_range=(-1,1), **kwargs):
  40.         """Create an MplWidget instance.
  41.  
  42.        parent      the owning object reference
  43.        toolbar     if True attach the matplotlib toolbar to graph
  44.        num_points  number of points in the dataset
  45.        x_range     tuple (min, max) of graph X values
  46.        y_range     tuple (min, max) of graph Y values
  47.        kwargs      panel-specific keyword params
  48.  
  49.        We set the data ranges once instead of letting each update automatically
  50.        set them - this can lead to strangeness in axis labelling.  Consider
  51.        adding a self.setRanges() function if you need to change the X/Y ranges
  52.        for an update.
  53.        """
  54.  
  55.         wx.Panel.__init__(self, parent, **kwargs)
  56.  
  57.         # create a static vertical boxsizer, a nice enclosing line
  58.         self.sbsizer = wx.StaticBoxSizer(wx.StaticBox(self, wx.ID_ANY, ''),
  59.                                          orient=wx.VERTICAL)
  60.  
  61.         # usual Matplotlib functions
  62.         self.figure = Figure(figsize=(2,2))
  63.         self.axes = self.figure.add_subplot(111)
  64.         self.patch = None
  65.  
  66.         # define the 2D dataset for number of points and containing None
  67.         # it appears we can't change a dataset *size* dynamically!?
  68.         self.x_data = [None] * num_points
  69.         self.y_data = [None] * num_points
  70.         self.y_error = [None] * num_points
  71.         self.plot_data = self.axes.plot(self.x_data, self.y_data,
  72.                                         color='red', lw=3)[0]
  73.  
  74.         # graph title and labels - set to nondescript values
  75.         # user can change these
  76.         pylab.setp(self.axes, title='')
  77.         pylab.setp(self.axes, xlabel='')
  78.         pylab.setp(self.axes, ylabel='')
  79.  
  80.         # set X and Y limits
  81.         # these could be changed, but we don't allow it in this version
  82.         (x_min, x_max) = x_range
  83.         self.axes.set_xbound(lower=x_min, upper=x_max)
  84.         (y_min, y_max) = y_range
  85.         self.axes.set_ybound(lower=y_min, upper=y_max)
  86.  
  87.         # initialize the FigureCanvas, mapping the figure to the WxAgg backend
  88.         self.canvas = FigureCanvas(self, wx.ID_ANY, self.figure)
  89.  
  90.         # add the figure canvas
  91.         self.sbsizer.Add(self.canvas, 1, wx.LEFT | wx.TOP | wx.EXPAND)
  92.  
  93.         # if the user wants a toolbar
  94.         if toolbar:
  95.             # instantiate the Navigation Toolbar
  96.             self.toolbar = NavigationToolbar2Wx(self.canvas)
  97.             # needed to support Windows systems
  98.             self.toolbar.Realize()
  99.  
  100.             # add it to the sub-box sizer
  101.             self.sbsizer.Add(self.toolbar, 0, wx.LEFT)
  102.             # explicitly show the toolbar
  103.             self.toolbar.Show()
  104.  
  105.         self.SetSizer(self.sbsizer)
  106.  
  107.  
  108.     def setData(self, x_data, y_data, e_data):
  109.         """Update the widget X, Y and errorbar data."""
  110.  
  111.         # change graph data
  112.         self.x_data = x_data
  113.         self.y_data = y_data
  114.         self.plot_data.set_data(np.array(x_data), np.array(y_data))
  115.  
  116.         # remove any previous errorbar patch
  117.         if self.patch:
  118.             self.axes.patches.remove(self.patch)
  119.  
  120.         # calculate new errorbar info, patch it in
  121.         verts = []
  122.         codes = []
  123.         for (x, y, e) in zip(x_data, y_data, e_data):
  124.             verts.append((x, y+e))
  125.             codes.append(Path.MOVETO)
  126.  
  127.             verts.append((x, y-e))
  128.             codes.append(Path.LINETO)
  129.         barpath = Path(verts, codes)
  130.         self.patch = patches.PathPatch(barpath, facecolor='grey', alpha=0.5)
  131.         self.axes.add_patch(self.patch)
  132.  
  133.  
  134.     def setTitle(self, title):
  135.         """Set a new graph title."""
  136.  
  137.         pylab.setp(self.axes, title=title)
  138.  
  139.  
  140.     def setAxisLabels(self, x_label, y_label=None):
  141.         """Set new graph axis labels."""
  142.  
  143.         pylab.setp(self.axes, xlabel=x_label, ylabel=y_label)
  144.  
  145.  
  146.     def setGrid(self, state):
  147.         """Fiddle with the graph grid.
  148.  
  149.        state   if True show the grid
  150.        """
  151.  
  152.         self.axes.grid(state)
  153.  
  154.  
  155.     def setLinewidth(self, linewidth=1):
  156.         """Set line series linewidth."""
  157.  
  158.         pylab.setp(self.plot_data, linewidth=linewidth)
  159.  
  160.  
  161.     def Refresh(self):
  162.         """Draw the series plot data specified.
  163.  
  164.        We don't do a refresh automatically after each set*() change.
  165.        That could lead to many unnecessary redraws and flashing.
  166.        Let the user control do:
  167.            possibly many updates, then
  168.            one refresh
  169.        """
  170.  
  171.         self.canvas.draw()
  172.  
  173.  
  174. if __name__ == '__main__':
  175.     class MyForm(wx.Frame):
  176.         def __init__(self):
  177.             wx.Frame.__init__(self, None, wx.ID_ANY, title='Errorbar Test')
  178.             self.SetMinSize((550,450))
  179.  
  180.             self.panel = wx.Panel(self, wx.ID_ANY)
  181.  
  182.             topSizer = wx.BoxSizer(wx.VERTICAL)
  183.             self.mpl = MplWidget(self.panel, num_points=5,
  184.                                  x_range=(0,4), y_range=(0,1))
  185.             self.mpl.setTitle('Test graph')
  186.             self.mpl.setAxisLabels('X-axis', 'Y-axis')
  187.             self.mpl.setGrid(True)
  188.             topSizer.Add(self.mpl, 1, wx.ALL|wx.EXPAND)
  189.  
  190.             self.btn = wx.Button(self.panel, -1, 'Another')
  191.             topSizer.Add(self.btn, 0, wx.ALIGN_RIGHT)
  192.  
  193.             self.panel.SetSizer(topSizer)
  194.             topSizer.Fit(self)
  195.  
  196.             self.linewidth = 0
  197.  
  198.             self.btn.Bind(wx.EVT_BUTTON, self.onAnother)
  199.  
  200.         def onAnother(self, event=None):
  201.             x = np.arange(0.0, 5, 1.0)
  202.             y = np.exp(-x) + np.random.random(x.size) / 5
  203.             e = np.random.random(x.size) / 5
  204.             self.mpl.setData(x, y, e)
  205.             self.linewidth += 1
  206.             if self.linewidth > 5:
  207.                 self.linewidth = 1
  208.             self.mpl.setTitle('Test graph - linewidth %d' % self.linewidth)
  209.             self.mpl.setLinewidth(self.linewidth)
  210.             self.mpl.Refresh()
  211.  
  212.     app = wx.PySimpleApp()
  213.     frame = MyForm().Show()
  214.     app.MainLoop()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement