37 from python_qt_binding
import QT_BINDING
38 from python_qt_binding.QtCore
import Qt, qVersion, qWarning, Signal
39 from python_qt_binding.QtGui
import QColor
40 from python_qt_binding.QtWidgets
import QWidget, QHBoxLayout
44 from .pyqtgraph_data_plot
import PyQtGraphDataPlot
45 except ImportError
as e:
46 PyQtGraphDataPlot =
None 49 from .mat_data_plot
import MatDataPlot
50 except ImportError
as e:
54 from .qwt_data_plot
import QwtDataPlot
55 except ImportError
as e:
69 """A widget for displaying a plot of data 71 The DataPlot widget displays a plot, on one of several plotting backends, 72 depending on which backend(s) are available at runtime. It currently 73 supports PyQtGraph, MatPlot and QwtPlot backends. 75 The DataPlot widget manages the plot backend internally, and can save 76 and restore the internal state using `save_settings` and `restore_settings` 79 Currently, the user MUST call `restore_settings` before using the widget, 80 to cause the creation of the enclosed plotting widget. 86 'widget_class': PyQtGraphDataPlot,
88 'Based on PyQtGraph\n- installer: http://luke.campagnola.me/code/pyqtgraph\n',
89 'enabled': PyQtGraphDataPlot
is not None,
93 'widget_class': MatDataPlot,
95 'Based on MatPlotLib\n- needs most CPU\n- needs matplotlib >= 1.1.0\n- if using ' 96 'PySide: PySide > 1.1.0\n',
97 'enabled': MatDataPlot
is not None,
101 'widget_class': QwtDataPlot,
103 'Based on QwtPlot\n- does not use timestamps\n- uses least CPU\n- needs Python ' 105 'enabled': QwtDataPlot
is not None,
118 _colors = [Qt.blue, Qt.red, Qt.cyan, Qt.magenta, Qt.green,
119 Qt.darkYellow, Qt.black, Qt.darkCyan, Qt.darkRed, Qt.gray]
121 limits_changed = Signal()
123 _add_curve = Signal(str, str,
'QColor', bool)
126 """Create a new, empty DataPlot 128 This will raise a RuntimeError if none of the supported plotting 129 backends can be found 131 super(DataPlot, self).
__init__(parent)
149 enabled_plot_types = [pt
for pt
in self.
plot_types if pt[
'enabled']]
150 if not enabled_plot_types:
151 if qVersion().startswith(
'4.'):
152 version_info =
'1.1.0' 155 version_info =
'1.4.0' 156 if QT_BINDING ==
'pyside':
157 version_info +=
' and PySide %s' % \
158 (
'> 1.1.0' if qVersion().startswith(
'4.')
else '>= 2.0.0')
160 'No usable plot type found. Install at least one of: PyQtGraph, MatPlotLib ' 161 '(at least %s) or Python-Qwt5.' % version_info)
168 """Internal method for activating a plotting backend by index""" 170 if not self.
plot_types[plot_index][
'enabled']:
172 for index, plot_type
in enumerate(self.
plot_types):
173 if plot_type[
'enabled']:
186 self._data_plot_widget.close()
189 x_limits = [0.0, 10.0]
190 y_limits = [-0.001, 0.001]
193 self._data_plot_widget.limits_changed.connect(self.
limits_changed)
194 self._add_curve.connect(self._data_plot_widget.add_curve)
200 self._data_plot_widget.add_curve(curve_id, curve[
'name'], curve[
'color'], markers_on)
211 self._data_plot_widget._color_index = 0
214 self._data_plot_widget.remove_curve(curve_id)
216 self._data_plot_widget.add_curve(curve_id, curve[
'name'], curve[
'color'], markers_on)
223 """get the title of the current plotting backend""" 227 """Save the settings associated with this widget 229 Currently, this is just the plot type, but may include more useful 230 data in the future""" 231 instance_settings.set_value(
'plot_type', self.
_plot_index)
236 xlim = [float(x)
for x
in xlim]
237 ylim = [float(y)
for y
in ylim]
238 instance_settings.set_value(
'x_limits', pack(xlim))
239 instance_settings.set_value(
'y_limits', pack(ylim))
242 """Restore the settings for this widget 244 Currently, this just restores the plot type.""" 246 xlim = unpack(instance_settings.value(
'x_limits', []))
247 ylim = unpack(instance_settings.value(
'y_limits', []))
252 xlim = [float(x)
for x
in xlim]
255 qWarning(
"Failed to restore X limits")
258 ylim = [float(y)
for y
in ylim]
261 qWarning(
"Failed to restore Y limits")
264 """Present the user with a dialog for choosing the plot backend 266 This displays a SimpleSettingsDialog asking the user to choose a 267 plot type, gets the result, and updates the plot type as necessary 269 This method is blocking""" 273 'title':
'Show Plot Markers',
275 'Warning: Displaying markers in rqt_plot may cause\n \t high cpu load, ' 276 'especially using PyQtGraph\n',
280 selected_checkboxes = [0]
282 selected_checkboxes = []
285 dialog.add_exclusive_option_group(
287 dialog.add_checkbox_group(
288 title=
'Plot Markers', options=marker_settings, selected_indexes=selected_checkboxes)
289 [plot_type, checkboxes] = dialog.get_settings()
290 if plot_type
is not None and \
291 plot_type[
'selected_index']
is not None and \
294 plot_type[
'selected_index'], 0
in checkboxes[
'selected_indexes'])
296 if checkboxes
is not None and self.
_markers_on != (0
in checkboxes[
'selected_indexes']):
302 """Enable or disable autoscrolling of the plot""" 309 """Redraw the underlying plot 311 This causes the underlying plot to be redrawn. This is usually used 312 after adding or updating the plot data""" 317 self._data_plot_widget.set_values(curve_id, curve[
'x'], curve[
'y'])
318 self._data_plot_widget.redraw()
327 def add_curve(self, curve_id, curve_name, data_x, data_y):
328 """Add a new, named curve to this plot 330 Add a curve named `curve_name` to the plot, with initial data series 331 `data_x` and `data_y`. 333 Future references to this curve should use the provided `curve_id` 335 Note that the plot is not redraw automatically; call `redraw()` to make 336 any changes visible to the user. 341 self.
_curves[curve_id] = {
'x': numpy.array(data_x),
342 'y': numpy.array(data_y),
344 'color': curve_color}
346 self._add_curve.emit(curve_id, curve_name, curve_color, self.
_markers_on)
349 """Remove the specified curve from this plot""" 354 self._data_plot_widget.remove_curve(curve_id)
357 """Append new data to an existing curve 359 `values_x` and `values_y` will be appended to the existing data for 362 Note that the plot is not redraw automatically; call `redraw()` to make 363 any changes visible to the user. 365 If `sort_data` is set to False, values won't be sorted by `values_x` 369 curve[
'x'] = numpy.append(curve[
'x'], values_x)
370 curve[
'y'] = numpy.append(curve[
'y'], values_y)
374 sort_order = curve[
'x'].argsort()
375 curve[
'x'] = curve[
'x'][sort_order]
376 curve[
'y'] = curve[
'y'][sort_order]
379 """Clear the values for the specified curve, or all curves 381 This will erase the data series associaed with `curve_id`, or all 382 curves if `curve_id` is not present or is None 384 Note that the plot is not redraw automatically; call `redraw()` to make 385 any changes visible to the user. 390 curve[
'x'] = numpy.array([])
391 curve[
'y'] = numpy.array([])
394 self.
_curves[curve_id][
'x'] = numpy.array([])
395 self.
_curves[curve_id][
'y'] = numpy.array([])
398 """Draw a vertical line on the plot 400 Draw a line a position X, with the given color 402 @param x: position of the vertical line to draw 403 @param color: optional parameter specifying the color, as tuple of 404 RGB values from 0 to 255 408 self._data_plot_widget.vline(x, color)
412 """Change autoscaling of plot axes 414 if a parameter is not passed, the autoscaling setting for that axis is 417 @param x: enable or disable autoscaling for X 418 @param y: set autoscaling mode for Y 442 x_limit = [numpy.inf, -numpy.inf]
446 if len(curve[
'x']) > 0:
447 x_limit[0] = min(x_limit[0], curve[
'x'].min())
448 x_limit[1] = max(x_limit[1], curve[
'x'].max())
452 x_width = x_limit[1] - x_limit[0]
455 x_limit[1] = -numpy.inf
460 if len(curve[
'x']) > 0:
461 x_limit[1] = max(x_limit[1], curve[
'x'].max())
464 x_limit[0] = x_limit[1] - x_width
470 if numpy.isinf(x_limit[0]):
472 if numpy.isinf(x_limit[1]):
475 y_limit = [numpy.inf, -numpy.inf]
484 end_index = len(curve[
'x'])
490 start_index = curve[
'x'].searchsorted(x_limit[0])
492 end_index = curve[
'x'].searchsorted(x_limit[1])
496 region = curve[
'y'][start_index:end_index]
498 y_limit[0] = min(y_limit[0], region.min())
499 y_limit[1] = max(y_limit[1], region.max())
517 if numpy.isinf(y_limit[0]):
519 if numpy.isinf(y_limit[1]):
528 return self._data_plot_widget.get_xlim()
530 qWarning(
"No plot widget; returning default X limits")
536 self._data_plot_widget.set_xlim(limits)
538 qWarning(
"No plot widget; can't set X limits")
543 return self._data_plot_widget.get_ylim()
545 qWarning(
"No plot widget; returning default Y limits")
551 self._data_plot_widget.set_ylim(limits)
553 qWarning(
"No plot widget; can't set Y limits")
def save_settings(self, plugin_settings, instance_settings)
def __init__(self, parent=None)
def set_autoscale(self, x=None, y=None)
def restore_settings(self, plugin_settings, instance_settings)
def set_xlim(self, limits)
def doSettingsDialog(self)
def vline(self, x, color=RED)
def add_curve(self, curve_id, curve_name, data_x, data_y)
def _merged_autoscale(self)
def _switch_plot_markers(self, markers_on)
def _get_curve(self, curve_id)
def remove_curve(self, curve_id)
def set_ylim(self, limits)
def clear_values(self, curve_id=None)
def update_values(self, curve_id, values_x, values_y, sort_data=True)
def _switch_data_plot_widget(self, plot_index, markers_on=False)
def autoscroll(self, enabled=True)