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 
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 
00043 if QT_BINDING == 'pyside':
00044     qt_binding_version = QT_BINDING_VERSION.replace('~', '-')
00045     if parse_version(qt_binding_version) <= parse_version('1.1.2'):
00046         raise ImportError('A PySide version newer than 1.1.0 is required.')
00047 
00048 from python_qt_binding.QtCore import Slot, Qt, qVersion, qWarning, Signal
00049 from python_qt_binding.QtGui import QColor
00050 from python_qt_binding.QtWidgets import QWidget, QVBoxLayout, QSizePolicy
00051 
00052 import operator
00053 import matplotlib
00054 if qVersion().startswith('5.'):
00055     if QT_BINDING == 'pyside':
00056         if parse_version(matplotlib.__version__) < parse_version('2.1.0'):
00057             raise ImportError('A newer matplotlib is required (at least 2.1.0 for PySide 2)')
00058     if parse_version(matplotlib.__version__) < parse_version('1.4.0'):
00059         raise ImportError('A newer matplotlib is required (at least 1.4.0 for Qt 5)')
00060     try:
00061         matplotlib.use('Qt5Agg')
00062         from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
00063     except ImportError:
00064         # work around bug in dateutil
00065         import sys
00066         import thread
00067         sys.modules['_thread'] = thread
00068         from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
00069     from matplotlib.backends.backend_qt5agg import NavigationToolbar2QT as NavigationToolbar
00070 elif qVersion().startswith('4.'):
00071     if parse_version(matplotlib.__version__) < parse_version('1.1.0'):
00072         raise ImportError('A newer matplotlib is required (at least 1.1.0 for Qt 4)')
00073     try:
00074         matplotlib.use('Qt4Agg')
00075         from matplotlib.backends.backend_qt4agg import FigureCanvasQTAgg as FigureCanvas
00076     except ImportError:
00077         # work around bug in dateutil
00078         import sys
00079         import thread
00080         sys.modules['_thread'] = thread
00081         from matplotlib.backends.backend_qt4agg import FigureCanvasQTAgg as FigureCanvas
00082     try:
00083         from matplotlib.backends.backend_qt4agg import NavigationToolbar2QTAgg as NavigationToolbar
00084     except ImportError:
00085         from matplotlib.backends.backend_qt4agg import NavigationToolbar2QT as NavigationToolbar
00086 else:
00087     raise NotImplementedError('Unsupport Qt version: %s' % qVersion())
00088 
00089 from matplotlib.figure import Figure
00090 
00091 import numpy
00092 
00093 
00094 class MatDataPlot(QWidget):
00095 
00096     class Canvas(FigureCanvas):
00097 
00098         """Ultimately, this is a QWidget (as well as a FigureCanvasAgg, etc.)."""
00099 
00100         def __init__(self, parent=None):
00101             super(MatDataPlot.Canvas, self).__init__(Figure())
00102             self.axes = self.figure.add_subplot(111)
00103             self.axes.grid(True, color='gray')
00104             self.figure.tight_layout()
00105             self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
00106             self.updateGeometry()
00107 
00108         def resizeEvent(self, event):
00109             super(MatDataPlot.Canvas, self).resizeEvent(event)
00110             self.figure.tight_layout()
00111 
00112     limits_changed = Signal()
00113 
00114     def __init__(self, parent=None):
00115         super(MatDataPlot, self).__init__(parent)
00116         self._canvas = MatDataPlot.Canvas()
00117         self._toolbar = NavigationToolbar(self._canvas, self._canvas)
00118         vbox = QVBoxLayout()
00119         vbox.addWidget(self._toolbar)
00120         vbox.addWidget(self._canvas)
00121         self.setLayout(vbox)
00122 
00123         self._curves = {}
00124         self._current_vline = None
00125         self._canvas.mpl_connect('button_release_event', self._limits_changed)
00126 
00127     def _limits_changed(self, event):
00128         self.limits_changed.emit()
00129 
00130     def add_curve(self, curve_id, curve_name, curve_color=QColor(Qt.blue), markers_on=False):
00131 
00132         # adding an empty curve and change the limits, so save and restore them
00133         x_limits = self.get_xlim()
00134         y_limits = self.get_ylim()
00135         if markers_on:
00136             marker_size = 3
00137         else:
00138             marker_size = 0
00139         line = self._canvas.axes.plot([], [], 'o-', markersize=marker_size, label=curve_name,
00140                                       linewidth=1, picker=5, color=curve_color.name())[0]
00141         self._curves[curve_id] = line
00142         self._update_legend()
00143         self.set_xlim(x_limits)
00144         self.set_ylim(y_limits)
00145 
00146     def remove_curve(self, curve_id):
00147         curve_id = str(curve_id)
00148         if curve_id in self._curves:
00149             self._curves[curve_id].remove()
00150             del self._curves[curve_id]
00151             self._update_legend()
00152 
00153     def _update_legend(self):
00154         handles, labels = self._canvas.axes.get_legend_handles_labels()
00155         if handles:
00156             hl = sorted(zip(handles, labels), key=operator.itemgetter(1))
00157             handles, labels = zip(*hl)
00158         self._canvas.axes.legend(handles, labels, loc='upper left')
00159 
00160     def set_values(self, curve, data_x, data_y):
00161         line = self._curves[curve]
00162         line.set_data(data_x, data_y)
00163 
00164     def redraw(self):
00165         self._canvas.axes.grid(True, color='gray')
00166         self._canvas.draw()
00167 
00168     def vline(self, x, color):
00169         # convert color range from (0,255) to (0,1.0)
00170         matcolor = (color[0] / 255.0, color[1] / 255.0, color[2] / 255.0)
00171         if self._current_vline:
00172             self._current_vline.remove()
00173         self._current_vline = self._canvas.axes.axvline(x=x, color=matcolor)
00174 
00175     def set_xlim(self, limits):
00176         self._canvas.axes.set_xbound(lower=limits[0], upper=limits[1])
00177 
00178     def set_ylim(self, limits):
00179         self._canvas.axes.set_ybound(lower=limits[0], upper=limits[1])
00180 
00181     def get_xlim(self):
00182         return list(self._canvas.axes.get_xbound())
00183 
00184     def get_ylim(self):
00185         return list(self._canvas.axes.get_ybound())


rqt_plot
Author(s): Dorian Scholz
autogenerated on Sun Mar 17 2019 02:29:34