Go to the documentation of this file.00001 
00002 
00003 
00004 
00005 
00006 
00007 
00008 
00009 
00010 
00011 
00012 
00013 
00014 
00015 
00016 
00017 
00018 
00019 
00020 
00021 
00022 
00023 
00024 
00025 
00026 
00027 
00028 
00029 
00030 
00031 
00032 
00033 import roslib
00034 roslib.load_manifest('rqt_plot')
00035 
00036 from python_qt_binding import QT_BINDING
00037 from python_qt_binding.QtCore import qDebug
00038 from qt_gui_py_common.simple_settings_dialog import SimpleSettingsDialog
00039 from rqt_gui_py.plugin import Plugin
00040 
00041 from .plot_widget import PlotWidget
00042 
00043 try:
00044     qDebug('rqt_plot.plot: importing PyQtGraphDataPlot')
00045     from pyqtgraph_data_plot import PyQtGraphDataPlot
00046 except ImportError:
00047     qDebug('rqt_plot.plot: import of PyQtGraphDataPlot failed')
00048     PyQtGraphDataPlot = None
00049 
00050 try:
00051     qDebug('rqt_plot.plot: importing MatDataPlot')
00052     from mat_data_plot import MatDataPlot
00053 except ImportError:
00054     qDebug('rqt_plot.plot: import of MatDataPlot failed')
00055     MatDataPlot = None
00056 
00057 try:
00058     qDebug('rqt_plot.plot: importing QwtDataPlot')
00059     from qwt_data_plot import QwtDataPlot
00060 except ImportError:
00061     qDebug('rqt_plot.plot: import of QwtDataPlot failed')
00062     QwtDataPlot = None
00063 
00064 
00065 class Plot(Plugin):
00066     
00067     plot_types = [
00068         {
00069             'title': 'PyQtGraph',
00070             'widget_class': PyQtGraphDataPlot,
00071             'description': 'Based on PyQtGraph\n- installer: http://luke.campagnola.me/code/pyqtgraph',
00072             'enabled': PyQtGraphDataPlot is not None,
00073         },
00074         {
00075             'title': 'MatPlot',
00076             'widget_class': MatDataPlot,
00077             'description': 'Based on MatPlotLib\n- needs most CPU\n- needs matplotlib >= 1.1.0\n- if using PySide: PySide > 1.1.0',
00078             'enabled': MatDataPlot is not None,
00079         },
00080         {
00081             'title': 'QwtPlot',
00082             'widget_class': QwtDataPlot,
00083             'description': 'Based on QwtPlot\n- does not use timestamps\n- uses least CPU\n- needs Python Qwt bindings',
00084             'enabled': QwtDataPlot is not None,
00085         },
00086     ]
00087 
00088     def __init__(self, context):
00089         super(Plot, self).__init__(context)
00090         self.setObjectName('Plot')
00091 
00092         enabled_plot_types = [pt for pt in self.plot_types if pt['enabled']]
00093         if not enabled_plot_types:
00094             version_info = ' and PySide > 1.1.0' if QT_BINDING == 'pyside' else ''
00095             raise RuntimeError('No usable plot type found. Install at least one of: PyQtGraph, MatPlotLib (at least 1.1.0%s) or Python-Qwt5.' % version_info)
00096 
00097         self._plot_type_index = 0
00098         self._context = context
00099 
00100         args, topics = self._process_arguments(context.argv())
00101         self._widget = PlotWidget(args, topics)
00102         if context.serial_number() > 1:
00103             self._widget.setWindowTitle(self._widget.windowTitle() + (' (%d)' % context.serial_number()))
00104         context.add_widget(self._widget)
00105 
00106     def _process_arguments(self, argv):
00107         from argparse import ArgumentParser
00108         parser = ArgumentParser()
00109 
00110         
00111         parser.add_argument("-P", "--pause", action="store_true",
00112                       dest="start_paused",
00113                       help="start in paused state")
00114 
00115         args, topics = parser.parse_known_args(argv)
00116 
00117         
00118         topic_list = []
00119         for t in topics:
00120             
00121             c_topics = []
00122             
00123             for sub_t in [x for x in t.split(',') if x]:
00124                 
00125                 if ':' in sub_t:
00126                     base = sub_t[:sub_t.find(':')]
00127                     
00128                     c_topics.append(base)
00129                     if not '/' in base:
00130                         parser.error("%s must contain a topic and field name" % sub_t)
00131                     base = base[:base.rfind('/')]
00132 
00133                     
00134                     fields = sub_t.split(':')[1:]
00135                     c_topics.extend(["%s/%s" % (base, f) for f in fields if f])
00136                 else:
00137                     c_topics.append(sub_t)
00138             
00139             import rosgraph
00140             c_topics = [rosgraph.names.script_resolve_name('rqt_plot', n) for n in c_topics]
00141             if type(c_topics) == list:
00142                 topic_list.extend(c_topics)
00143             else:
00144                 topic_list.append(c_topics)
00145 
00146         
00147         print_topic_list = []
00148         for l in topic_list:
00149             if type(l) == list:
00150                 print_topic_list.extend(l)
00151             else:
00152                 print_topic_list.append(l)
00153 
00154         print "plotting topics", ', '.join(print_topic_list)
00155 
00156         return (args, topic_list)
00157 
00158     def _switch_data_plot_widget(self, plot_type_index):
00159         
00160         if not self.plot_types[plot_type_index]['enabled']:
00161             
00162             for index, plot_type in enumerate(self.plot_types):
00163                 if plot_type['enabled']:
00164                     plot_type_index = index
00165                     break
00166 
00167         self._plot_type_index = plot_type_index
00168         selected_plot = self.plot_types[plot_type_index]
00169 
00170         self._widget.switch_data_plot_widget(selected_plot['widget_class'](self._widget))
00171         self._widget.setWindowTitle(selected_plot['title'])
00172         if self._context.serial_number() > 1:
00173             self._widget.setWindowTitle(self._widget.windowTitle() + (' (%d)' % self._context.serial_number()))
00174 
00175     def save_settings(self, plugin_settings, instance_settings):
00176         instance_settings.set_value('plot_type', self._plot_type_index)
00177 
00178     def restore_settings(self, plugin_settings, instance_settings):
00179         self._switch_data_plot_widget(int(instance_settings.value('plot_type', 0)))
00180 
00181     def trigger_configuration(self):
00182         dialog = SimpleSettingsDialog(title='Plot Options')
00183         dialog.add_exclusive_option_group(title='Plot Type', options=self.plot_types, selected_index=self._plot_type_index)
00184         plot_type = dialog.get_settings()[0]
00185         if plot_type is not None and plot_type['selected_index'] is not None and self._plot_type_index != plot_type['selected_index']:
00186             self._switch_data_plot_widget(plot_type['selected_index'])
00187 
00188     def shutdown_plugin(self):
00189         self._widget.clean_up_subscribers()