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']:
189 x_limits = [0.0, 10.0]
190 y_limits = [-0.001, 0.001]
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"""
331 def add_curve(self, curve_id, curve_name, data_x, data_y):
332 """Add a new, named curve to this plot
334 Add a curve named `curve_name` to the plot, with initial data series
335 `data_x` and `data_y`.
337 Future references to this curve should use the provided `curve_id`
339 Note that the plot is not redraw automatically; call `redraw()` to make
340 any changes visible to the user.
345 self.
_curves[curve_id] = {
'x': numpy.array(data_x),
346 'y': numpy.array(data_y),
348 'color': curve_color}
353 """Remove the specified curve from this plot"""
361 """Append new data to an existing curve
363 `values_x` and `values_y` will be appended to the existing data for
366 Note that the plot is not redraw automatically; call `redraw()` to make
367 any changes visible to the user.
369 If `sort_data` is set to False, values won't be sorted by `values_x`
373 curve[
'x'] = numpy.append(curve[
'x'], values_x)
374 curve[
'y'] = numpy.append(curve[
'y'], values_y)
378 sort_order = curve[
'x'].argsort()
379 curve[
'x'] = curve[
'x'][sort_order]
380 curve[
'y'] = curve[
'y'][sort_order]
383 """Clear the values for the specified curve, or all curves
385 This will erase the data series associaed with `curve_id`, or all
386 curves if `curve_id` is not present or is None
388 Note that the plot is not redraw automatically; call `redraw()` to make
389 any changes visible to the user.
394 curve[
'x'] = numpy.array([])
395 curve[
'y'] = numpy.array([])
398 self.
_curves[curve_id][
'x'] = numpy.array([])
399 self.
_curves[curve_id][
'y'] = numpy.array([])
402 """Draw a vertical line on the plot
404 Draw a line a position X, with the given color
406 @param x: position of the vertical line to draw
407 @param color: optional parameter specifying the color, as tuple of
408 RGB values from 0 to 255
416 """Change autoscaling of plot axes
418 if a parameter is not passed, the autoscaling setting for that axis is
421 @param x: enable or disable autoscaling for X
422 @param y: set autoscaling mode for Y
446 x_limit = [numpy.inf, -numpy.inf]
450 if len(curve[
'x']) > 0:
451 x_limit[0] = min(x_limit[0], curve[
'x'].min())
452 x_limit[1] = max(x_limit[1], curve[
'x'].max())
456 x_width = x_limit[1] - x_limit[0]
459 x_limit[1] = -numpy.inf
464 if len(curve[
'x']) > 0:
465 x_limit[1] = max(x_limit[1], curve[
'x'].max())
468 x_limit[0] = x_limit[1] - x_width
474 if numpy.isinf(x_limit[0]):
476 if numpy.isinf(x_limit[1]):
479 y_limit = [numpy.inf, -numpy.inf]
488 end_index = len(curve[
'x'])
494 start_index = curve[
'x'].searchsorted(x_limit[0])
496 end_index = curve[
'x'].searchsorted(x_limit[1])
500 region = curve[
'y'][start_index:end_index]
502 y_limit[0] = min(y_limit[0], region.min())
503 y_limit[1] = max(y_limit[1], region.max())
521 if numpy.isinf(y_limit[0]):
523 if numpy.isinf(y_limit[1]):
534 qWarning(
"No plot widget; returning default X limits")
542 qWarning(
"No plot widget; can't set X limits")
549 qWarning(
"No plot widget; returning default Y limits")
557 qWarning(
"No plot widget; can't set Y limits")