mat_data_plot.py
Go to the documentation of this file.
00001 #!/usr/bin/env python
00002 
00003 # Copyright (c) 2011, Ye Cheng, Dorian Scholz
00004 # All rights reserved.
00005 #
00006 # Redistribution and use in source and binary forms, with or without
00007 # modification, are permitted provided that the following conditions
00008 # are met:
00009 #
00010 #   * Redistributions of source code must retain the above copyright
00011 #     notice, this list of conditions and the following disclaimer.
00012 #   * Redistributions in binary form must reproduce the above
00013 #     copyright notice, this list of conditions and the following
00014 #     disclaimer in the documentation and/or other materials provided
00015 #     with the distribution.
00016 #   * Neither the name of the TU Darmstadt nor the names of its
00017 #     contributors may be used to endorse or promote products derived
00018 #     from this software without specific prior written permission.
00019 #
00020 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
00021 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
00022 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
00023 # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
00024 # COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
00025 # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
00026 # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
00027 # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
00028 # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00029 # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
00030 # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00031 # POSSIBILITY OF SUCH DAMAGE.
00032 
00033 from python_qt_binding import QT_BINDING, QT_BINDING_VERSION
00034 if QT_BINDING == 'pyside':
00035     try:
00036         from pkg_resources import parse_version
00037     except:
00038         import re
00039 
00040         def parse_version(s):
00041             return [int(x) for x in re.sub(r'(\.0+)*$', '', s).split('.')]
00042     if parse_version(QT_BINDING_VERSION) <= parse_version('1.1.2'):
00043         raise ImportError('A PySide version newer than 1.1.0 is required.')
00044 
00045 from python_qt_binding.QtCore import Slot, Qt
00046 from python_qt_binding.QtGui import QWidget, QVBoxLayout, QSizePolicy, QColor
00047 
00048 import collections
00049 import operator
00050 import matplotlib
00051 if matplotlib.__version__ < '1.1.0':
00052     raise ImportError('A newer matplotlib is required (at least 1.1.0)')
00053 
00054 try:
00055     from matplotlib.backends.backend_qt4agg import FigureCanvasQTAgg as FigureCanvas
00056 except ImportError:
00057     # work around bug in dateutil
00058     import sys
00059     import thread
00060     sys.modules['_thread'] = thread
00061     from matplotlib.backends.backend_qt4agg import FigureCanvasQTAgg as FigureCanvas
00062 from matplotlib.backends.backend_qt4agg import NavigationToolbar2QTAgg as NavigationToolbar
00063 from matplotlib.figure import Figure
00064 
00065 import numpy
00066 
00067 
00068 class MatDataPlot(QWidget):
00069     class Canvas(FigureCanvas):
00070         """Ultimately, this is a QWidget (as well as a FigureCanvasAgg, etc.)."""
00071         def __init__(self, parent=None):
00072             fig = Figure()
00073             self.axes = fig.add_subplot(111)
00074             self.axes.grid(True, color='gray')
00075             super(MatDataPlot.Canvas, self).__init__(fig)
00076             self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
00077             self.updateGeometry()
00078 
00079     _colors = [Qt.red, Qt.blue, Qt.magenta, Qt.cyan, Qt.green, Qt.darkYellow, Qt.black, Qt.darkRed, Qt.gray, Qt.darkCyan]
00080 
00081     def __init__(self, parent=None):
00082         super(MatDataPlot, self).__init__(parent)
00083         self._canvas = MatDataPlot.Canvas()
00084         self._toolbar = NavigationToolbar(self._canvas, self._canvas)
00085         vbox = QVBoxLayout()
00086         vbox.addWidget(self._toolbar)
00087         vbox.addWidget(self._canvas)
00088         self.setLayout(vbox)
00089 
00090         self._color_index = 0
00091         self._curves = {}
00092 
00093     def add_curve(self, curve_id, curve_name, data_x, data_y):
00094         data_x = collections.deque(data_x)
00095         data_y = collections.deque(data_y)
00096         color = QColor(self._colors[self._color_index % len(self._colors)])
00097         self._color_index += 1
00098         plot = self._canvas.axes.plot(data_x, data_y, label=curve_name, linewidth=1, picker=5, color=color.name())[0]
00099         self._curves[curve_id] = (data_x, data_y, plot)
00100         self._update_legend()
00101 
00102     def remove_curve(self, curve_id):
00103         curve_id = str(curve_id)
00104         if curve_id in self._curves:
00105             self._curves[curve_id][2].remove()
00106             del self._curves[curve_id]
00107             self._update_legend()
00108 
00109     def _update_legend(self):
00110         handles, labels = self._canvas.axes.get_legend_handles_labels()
00111         if handles:
00112             hl = sorted(zip(handles, labels), key=operator.itemgetter(1))
00113             handles, labels = zip(*hl)
00114         self._canvas.axes.legend(handles, labels, loc='upper left')
00115 
00116     @Slot(str, list, list)
00117     def update_values(self, curve_id, x, y):
00118         data_x, data_y, _ = self._curves[curve_id]
00119         data_x.extend(x)
00120         data_y.extend(y)
00121 
00122     def redraw(self):
00123         self._canvas.axes.grid(True, color='gray')
00124         # Set axis bounds
00125         ymin = ymax = None
00126         xmax = 0
00127         for curve in self._curves.values():
00128             data_x, data_y, plot = curve
00129             if len(data_x) == 0:
00130                 continue
00131 
00132             xmax = max(xmax, data_x[-1])
00133             self._canvas.axes.set_xbound(lower=xmax - 5, upper=xmax)
00134 
00135             if ymin is None:
00136                 ymin = min(data_y)
00137                 ymax = max(data_y)
00138             else:
00139                 ymin = min(min(data_y), ymin)
00140                 ymax = max(max(data_y), ymax)
00141 
00142             # pad the min/max
00143             delta = max(ymax - ymin, 0.1)
00144             ymin -= .05 * delta
00145             ymax += .05 * delta
00146 
00147             self._canvas.axes.set_ybound(lower=ymin, upper=ymax)
00148 
00149         # Set plot data on current axes
00150         for curve in self._curves.values():
00151             data_x, data_y, plot = curve
00152             plot.set_data(numpy.array(data_x), numpy.array(data_y))
00153 
00154         self._canvas.draw()


rqt_plot
Author(s): Dorian Scholz
autogenerated on Fri Jan 3 2014 11:55:13