def __init__(self): QWidget.__init__(self) self.layout = QVBoxLayout(self) self.graphwidget = GraphWidget(self) self.graph = None self.refresh = False self.p = 1 self.layout.addWidget(self.graphwidget) self.infobar = QHBoxLayout() self.info_nodes = QLabel(self) self.info_nodes.setMinimumHeight(30) self.info_nodes.setMaximumHeight(30) self.info_edges = QLabel(self) self.info_edges.setMinimumHeight(30) self.info_edges.setMaximumHeight(30) self.info_p = QLabel(self) self.info_p.setMinimumHeight(30) self.info_p.setMaximumHeight(30) self.info_clustersize = QLabel(self) self.info_clustersize.setMinimumHeight(30) self.info_clustersize.setMaximumHeight(30) self.infobar.addSpacerItem( QSpacerItem(10, 10, QSizePolicy.Expanding, QSizePolicy.Minimum)) self.infobar.addWidget(self.info_p) self.infobar.addWidget(self.info_nodes) self.infobar.addWidget(self.info_edges) self.infobar.addWidget(self.info_clustersize) self.infobar.addSpacerItem( QSpacerItem(10, 10, QSizePolicy.Expanding, QSizePolicy.Minimum)) self.layout.addLayout(self.infobar) info = QLabel(self) info.setMinimumHeight(30) info.setMaximumHeight(30) info.setText( "Press +/- to zoom, WASD for panning or Q/E for rotating.") infolayout = QHBoxLayout() infolayout.addSpacerItem( QSpacerItem(10, 10, QSizePolicy.Expanding, QSizePolicy.Minimum)) infolayout.addWidget(info) infolayout.addSpacerItem( QSpacerItem(10, 10, QSizePolicy.Expanding, QSizePolicy.Minimum)) self.layout.addLayout(infolayout) self.setMinimumSize(300, 300)
def __init__(self, arguments=None, initial_topics=None): super(RosplotWidget, self).__init__() ui_file = os.path.join(os.path.dirname(os.path.realpath(__file__)), '../../resource/plot_widget.ui') loadUi(ui_file, self) self.subscribe_topic_button.setIcon(QIcon.fromTheme('add')) self.remove_topic_button.setIcon(QIcon.fromTheme('remove')) self.clear_button.setText('Remove all Topics') self.subscribe_topic_button.setEnabled(False) self.zoom_button.setText('Zoom: On ') # Topic Tree and Topic Completer self.ros_topic_tree = RosTopicTree(self) self._topic_completer = TopicCompleter(self) self._topic_completer.setModel(self.ros_topic_tree) self.topic_edit.setCompleter(self._topic_completer) self.connect(self.topic_edit, SIGNAL("tabPressed"), self.on_topic_edit_tabPressed) # the rosstuff self._start_time = rospy.get_time() self._rosdata = {} self._remove_topic_menu = QMenu() # init and start update timer for plot self._update_plot_timer = QTimer(self) self._update_plot_timer.timeout.connect(self.update_plot) self._update_plot_timer.start(self._redraw_interval) # graph window self.graph_widget = GraphWidget(self) self.graph_widget_layout.addWidget(self.graph_widget) QObject.connect(self.graph_widget, SIGNAL("legendChecked(QwtPlotItem *,bool)"), self.legend_clicked) self.subscribed_topics_changed() self.show()
def display_graph(self, g, layout=None): """Load GraphWidget and display graph g using layout (if available) Arguments: g -- a graph_tool.Graph Keyword arguments: layout -- a graph_tool.PropertyMap to be applied to the widget (default: None) If True, loads a custom PropertyMap from layout file """ if layout == None: # Generate a SFDP layout self.graphWidget = GraphWidget(self, g, layout=sfdp_layout(g)) elif layout != True: # Load given PropertyMap self.graphWidget = GraphWidget(self, g, layout=layout) else: # Custom layout, load it try: self.graphWidget = GraphWidget(self, g, pos=g.vp["layout"]) except KeyError: # just in case custom layout is invalid self.graphWidget = GraphWidget(self, g, layout=sfdp_layout(g)) self.graphWidget.show_all() self.graphFrame.add(self.graphWidget)
def __init__(self, arguments = None, initial_topics = None): super(RosplotWidget, self).__init__() ui_file = os.path.join(os.path.dirname(os.path.realpath(__file__)), '../../resource/plot_widget.ui') loadUi(ui_file, self) self.subscribe_topic_button.setIcon(QIcon.fromTheme('add')) self.remove_topic_button.setIcon(QIcon.fromTheme('remove')) self.clear_button.setText('Remove all Topics') self.subscribe_topic_button.setEnabled(False) self.zoom_button.setText('Zoom: On ') # Topic Tree and Topic Completer self.ros_topic_tree = RosTopicTree(self) self._topic_completer = TopicCompleter(self) self._topic_completer.setModel(self.ros_topic_tree) self.topic_edit.setCompleter(self._topic_completer) self.connect(self.topic_edit, SIGNAL("tabPressed"), self.on_topic_edit_tabPressed) # the rosstuff self._start_time = rospy.get_time() self._rosdata = {} self._remove_topic_menu = QMenu() # init and start update timer for plot self._update_plot_timer = QTimer(self) self._update_plot_timer.timeout.connect(self.update_plot) self._update_plot_timer.start(self._redraw_interval) # graph window self.graph_widget = GraphWidget(self) self.graph_widget_layout.addWidget(self.graph_widget) QObject.connect(self.graph_widget, SIGNAL("legendChecked(QwtPlotItem *,bool)"), self.legend_clicked) self.subscribed_topics_changed() self.show()
class RosplotWidget(QWidget): _redraw_interval = 40 def __init__(self, arguments=None, initial_topics=None): super(RosplotWidget, self).__init__() ui_file = os.path.join(os.path.dirname(os.path.realpath(__file__)), '../../resource/plot_widget.ui') loadUi(ui_file, self) self.subscribe_topic_button.setIcon(QIcon.fromTheme('add')) self.remove_topic_button.setIcon(QIcon.fromTheme('remove')) self.clear_button.setText('Remove all Topics') self.subscribe_topic_button.setEnabled(False) self.zoom_button.setText('Zoom: On ') # Topic Tree and Topic Completer self.ros_topic_tree = RosTopicTree(self) self._topic_completer = TopicCompleter(self) self._topic_completer.setModel(self.ros_topic_tree) self.topic_edit.setCompleter(self._topic_completer) self.connect(self.topic_edit, SIGNAL("tabPressed"), self.on_topic_edit_tabPressed) # the rosstuff self._start_time = rospy.get_time() self._rosdata = {} self._remove_topic_menu = QMenu() # init and start update timer for plot self._update_plot_timer = QTimer(self) self._update_plot_timer.timeout.connect(self.update_plot) self._update_plot_timer.start(self._redraw_interval) # graph window self.graph_widget = GraphWidget(self) self.graph_widget_layout.addWidget(self.graph_widget) QObject.connect(self.graph_widget, SIGNAL("legendChecked(QwtPlotItem *,bool)"), self.legend_clicked) self.subscribed_topics_changed() self.show() def legend_clicked(self, item, val): topic_path = item.title().text() topic_path = str(topic_path) self.remove_topic(topic_path) @pyqtSlot(str) def on_topic_edit_textChanged(self, slot_name): if slot_name == "": print 'Updating topics' self.ros_topic_tree.update() return is_num = self.ros_topic_tree.isNummeric(slot_name) all_children_num = self.ros_topic_tree.allChildrenNummeric(slot_name) self.subscribe_topic_button.setEnabled(is_num or all_children_num) # Perform autocompletion when tab is pressed topic_edit text box def on_topic_edit_tabPressed(self): if self._topic_completer.completionCount( ) == 1: # If there is a single autocompletion, use that updated_text = self._topic_completer.currentCompletion() self.topic_edit.setText(updated_text) self.topic_edit.insert("/") elif self._topic_completer.completionCount( ) > 1: # If there is more than one autocompletion, complete upto the last common letter match = str(self._topic_completer.currentCompletion()) for i in range(1, self._topic_completer.completionCount()): self._topic_completer.setCurrentRow(i) word = str(self._topic_completer.currentCompletion()) match = string_intersect(word, match) self._topic_completer.setCurrentRow( 0 ) # Set the current row back to zero in case tab is pressed again self.topic_edit.setText(match) @pyqtSlot() def on_topic_edit_returnPressed(self): self.attempt_to_add_topics() @pyqtSlot() def on_subscribe_topic_button_clicked(self): self.attempt_to_add_topics() @pyqtSlot() def on_clear_button_clicked(self): self.clean_up_subscribers() @pyqtSlot() def on_zoom_button_clicked(self): if self.graph_widget.zoom_enabled: self.graph_widget.zoom_enabled = False self.zoom_button.setText('Zoom: Off') else: self.graph_widget.zoom_enabled = True self.zoom_button.setText('Zoom: On ') def update_plot(self): if self.graph_widget is not None: for topic_name, rosdata in self._rosdata.items(): try: data_x, data_y = rosdata.next() self.graph_widget.update_values(topic_name, data_x, data_y) except RosPlotException as e: qWarning('PlotWidget.update_plot(): error in rosplot: %s' % e) self.graph_widget.redraw() def subscribed_topics_changed(self): self.update_remove_topic_menu() self.graph_widget.redraw() def update_remove_topic_menu(self): def make_remove_topic_function(x): return lambda: self.remove_topic(x) self._remove_topic_menu.clear() for topic_name in sorted(self._rosdata.keys()): action = QAction(topic_name, self._remove_topic_menu) action.triggered.connect(make_remove_topic_function(topic_name)) self._remove_topic_menu.addAction(action) self.remove_topic_button.setMenu(self._remove_topic_menu) def attempt_to_add_topics(self): slot_name = str(self.topic_edit.text()) if self.ros_topic_tree.isNummeric(slot_name): self.add_topic(slot_name) if self.ros_topic_tree.allChildrenNummeric(slot_name): if not slot_name[-1] == '/': slot_name += '/' for slot in self.ros_topic_tree.pathFromAllChildren(slot_name): self.add_topic(slot) def add_topic(self, topic_name): if topic_name in self._rosdata: qWarning('PlotWidget.add_topic(): topic already subscribed: %s' % topic_name) return self._rosdata[topic_name] = ROSData(topic_name, self._start_time) data_x, data_y = self._rosdata[topic_name].next() self.graph_widget.add_curve(topic_name, topic_name, data_x, data_y) self.subscribed_topics_changed() def remove_topic(self, topic_name): self._rosdata[topic_name].close() del self._rosdata[topic_name] self.graph_widget.remove_curve(topic_name) self.subscribed_topics_changed() def clean_up_subscribers(self): for topic_name, rosdata in self._rosdata.items(): rosdata.close() self.graph_widget.remove_curve(topic_name) self._rosdata = {} self.subscribed_topics_changed()
class PyCubic: """Main window""" def __init__(self): """Create a PyCubic window instance""" self.builder = Gtk.Builder() self.builder.add_from_file("PyCubic.glade") self.graphFrame = self.builder.get_object("graph_frame") self.treeView = self.builder.get_object("graph_treeview") self.statusBar = self.builder.get_object("statusbar") self.update_statusbar("Welcome to PyCubic!") self.treeView_menu = self.build_treeView_menu() def display_graph(self, g, layout=None): """Load GraphWidget and display graph g using layout (if available) Arguments: g -- a graph_tool.Graph Keyword arguments: layout -- a graph_tool.PropertyMap to be applied to the widget (default: None) If True, loads a custom PropertyMap from layout file """ if layout == None: # Generate a SFDP layout self.graphWidget = GraphWidget(self, g, layout=sfdp_layout(g)) elif layout != True: # Load given PropertyMap self.graphWidget = GraphWidget(self, g, layout=layout) else: # Custom layout, load it try: self.graphWidget = GraphWidget(self, g, pos=g.vp["layout"]) except KeyError: # just in case custom layout is invalid self.graphWidget = GraphWidget(self, g, layout=sfdp_layout(g)) self.graphWidget.show_all() self.graphFrame.add(self.graphWidget) def clear_graph(self) : """Clear the GraphWidget and its graph""" self.graphWidget.destroy() self.graphWidget = None def build_treeView_menu(self): """Return the treeview right-click menu""" treeView_menu = Gtk.Menu() for icon, label, handler in [(Gtk.STOCK_EXECUTE, "Load", self.on_treeView_menu_load_button_handler), (Gtk.STOCK_DELETE, "Delete", self.on_treeView_menu_delete_button_handler)]: menu_item = Gtk.ImageMenuItem(icon) menu_item.set_label(label) treeView_menu.append(menu_item) menu_item.connect("activate", handler) menu_item.show() return treeView_menu def build_treeStore(self) : """Prepare and fill the TreeStore""" filename = os.path.splitext(os.path.basename(self.filename))[0] self.treeStore = Gtk.TreeStore(str) # Fill the Tree Store self.layoutList = dict() self.layouts = self.treeStore.append(None, ["Saved layouts"]) for root, dirs, files in os.walk(os.path.join(os.getcwd(), "saved_layouts", filename)): for file in files : (name, ext) = os.path.splitext(file) if ext == ".graphml": self.layoutList[name] = os.path.join(root, file) self.treeStore.append(self.layouts, [name]) pmatchings = self.treeStore.append(None, ["Perfect matchings"]) self.treeStore.append(pmatchings, ["Unknown"]) # TODO # Generate the layout for this model treeviewcolumn = Gtk.TreeViewColumn(filename) self.treeView.append_column(treeviewcolumn) cellrenderertext = Gtk.CellRendererText() treeviewcolumn.pack_start(cellrenderertext, False) treeviewcolumn.add_attribute(cellrenderertext, "text", 0) self.treeView.set_model(self.treeStore) self.treeView.expand_all() # Connect button-press-event to its handler self.treeView.connect("button-press-event", self.on_treeview_button_press_event) def on_treeview_button_press_event(self, treeview, event): """Handle TreeView interactions""" layout_clicked = False x = int(event.x) y = int(event.y) time = event.time pthinfo = treeview.get_path_at_pos(x, y) if pthinfo is not None: path, col, cellx, celly = pthinfo treeview.grab_focus() treeview.set_cursor(path, col, 0) # Get label, but only if it's a layout treeiter = self.treeStore.get_iter(path) if self.treeStore.is_ancestor(self.layouts, treeiter): layout_clicked = True self.layout_name = self.treeStore.get_value(treeiter, 0) self.treeiter = treeiter # If left clicking, load graph if layout_clicked and event.button == 1: self.load_layout(self.layout_name) # If right clicking elif layout_clicked and event.button == 3: self.treeView_menu.popup(None, None, None, None, event.button, event.time) return True def on_treeView_menu_load_button_handler(self, menu_item): """Right-click menu "Load" button handler""" self.load_layout(self.layout_name) def on_treeView_menu_delete_button_handler(self, menu_item): """Right-click menu "Delete" button handler""" self.delete_layout(self.layout_name) def clear_treeStore(self) : """Clear TreeStore and TreeViewColumns""" self.treeStore = Gtk.TreeStore(str) for column in self.treeView.get_columns(): self.treeView.remove_column(column) def activate_widget(self, widgetName): """Set widgetName to sensitive""" self.builder.get_object(widgetName).set_sensitive(True) def deactivate_widget(self, widgetName): """Set widgetName to insensitive""" self.builder.get_object(widgetName).set_sensitive(False) def reset_buttons(self): """Reset all buttons to default state""" self.graphWidget.re_init() self.activate_widget("save_layout_button") self.activate_widget("save_menu") self.activate_widget("exportPDF_menu") self.activate_widget("exportTikZ_menu") self.activate_widget("layoutMenu") def update_statusbar(self, message): """Update statusbar with message""" self.statusBar.pop(0) self.statusBar.push(0, message) def load_layout(self, layout_name): """Load graph layout from layout_name corresponding .graphml file""" filename = os.path.join(os.getcwd(), 'saved_layouts', os.path.basename(os.path.splitext(self.filename)[0]), layout_name + '.graphml') try: g = load_graph(filename, fmt="xml") self.clear_graph() self.display_graph(g, layout=True) self.update_statusbar("Layout " + layout_name + " loaded successfully.") self.layout_name = layout_name self.reset_buttons() except Exception as e: logging.exception(e) def delete_layout(self, layout_name): """Delete layout_name corresponding .graphml file""" filename = os.path.join(os.getcwd(), 'saved_layouts', os.path.basename(os.path.splitext(self.filename)[0]), layout_name + '.graphml') try: os.remove(filename) try: os.rmdir(os.path.split(filename)[0]) except OSError: pass # Directory not empty, pass self.update_statusbar("Layout " + layout_name + " deleted successfully.") self.treeStore.remove(self.treeiter) del self.layoutList[layout_name] except Exception as e: logging.exception(e)
from PyQt5.QtCore import (qsrand, QTime) from PyQt5.QtWidgets import QApplication from graph_widget import GraphWidget if __name__ == '__main__': import sys app = QApplication(sys.argv) app.setApplicationName('Endue') qsrand(QTime(0, 0, 0).secsTo(QTime.currentTime())) widget = GraphWidget() widget.show() sys.exit(app.exec_())
class PercolationWidget(QWidget): graphUpdated = pyqtSignal(float, float) def __init__(self): QWidget.__init__(self) self.layout = QVBoxLayout(self) self.graphwidget = GraphWidget(self) self.graph = None self.refresh = False self.p = 1 self.layout.addWidget(self.graphwidget) self.infobar = QHBoxLayout() self.info_nodes = QLabel(self) self.info_nodes.setMinimumHeight(30) self.info_nodes.setMaximumHeight(30) self.info_edges = QLabel(self) self.info_edges.setMinimumHeight(30) self.info_edges.setMaximumHeight(30) self.info_p = QLabel(self) self.info_p.setMinimumHeight(30) self.info_p.setMaximumHeight(30) self.info_clustersize = QLabel(self) self.info_clustersize.setMinimumHeight(30) self.info_clustersize.setMaximumHeight(30) self.infobar.addSpacerItem( QSpacerItem(10, 10, QSizePolicy.Expanding, QSizePolicy.Minimum)) self.infobar.addWidget(self.info_p) self.infobar.addWidget(self.info_nodes) self.infobar.addWidget(self.info_edges) self.infobar.addWidget(self.info_clustersize) self.infobar.addSpacerItem( QSpacerItem(10, 10, QSizePolicy.Expanding, QSizePolicy.Minimum)) self.layout.addLayout(self.infobar) info = QLabel(self) info.setMinimumHeight(30) info.setMaximumHeight(30) info.setText( "Press +/- to zoom, WASD for panning or Q/E for rotating.") infolayout = QHBoxLayout() infolayout.addSpacerItem( QSpacerItem(10, 10, QSizePolicy.Expanding, QSizePolicy.Minimum)) infolayout.addWidget(info) infolayout.addSpacerItem( QSpacerItem(10, 10, QSizePolicy.Expanding, QSizePolicy.Minimum)) self.layout.addLayout(infolayout) self.setMinimumSize(300, 300) def setGraph(self, graph): self.graph = graph self.updateGraph() def setRefresh(self, refresh): self.refresh = refresh def updateGraph(self): if (self.graph == None): return self.graph.setFractionOfEdges(self.p, self.refresh) clusters, largest_cluster, largest_cluster_size = self.graph.findClusters( ) region = (clusters == largest_cluster) # get the masks indicating which node belongs to top- or bottomboundary # as defined by the grid type bottomboundary = self.graph.getBottomBoundary() topboundary = self.graph.getTopBoundary() bottomrow = clusters[bottomboundary] toprow = clusters[topboundary] # find the indices in top- and bottomrow belonging belonging to the same cluster same, b, c = np.intersect1d(toprow, bottomrow, return_indices=True) if (len(b) > 0): # use np.nonzero to get the indices from the masks bottomindex_graph = np.nonzero(bottomboundary)[0][c][0] topindex_graph = np.nonzero(topboundary)[0][b][0] path = self.graph.findPath(bottomindex_graph, topindex_graph) self.graphwidget.setGraph(self.graph, [region], [path]) else: self.graphwidget.setGraph(self.graph, [region], []) self.info_nodes.setText("\tNodes: " + str(len(self.graph.nodes))) self.info_edges.setText("\tEdges: " + str(len(self.graph.edges)) + ", " + str(self.graph.active_edge_count) + " active") self.info_clustersize.setText("\tLargest cluster: " + "{:.2f}".format( 100 * largest_cluster_size / len(self.graph.nodes)) + " %") self.graphUpdated.emit(self.p, largest_cluster_size / len(self.graph.nodes)) def setPValue(self, value): self.p = value / 100 self.info_p.setText("p = " + str(self.p)) self.updateGraph()
class RosplotWidget(QWidget): _redraw_interval = 40 def __init__(self, arguments = None, initial_topics = None): super(RosplotWidget, self).__init__() ui_file = os.path.join(os.path.dirname(os.path.realpath(__file__)), '../../resource/plot_widget.ui') loadUi(ui_file, self) self.subscribe_topic_button.setIcon(QIcon.fromTheme('add')) self.remove_topic_button.setIcon(QIcon.fromTheme('remove')) self.clear_button.setText('Remove all Topics') self.subscribe_topic_button.setEnabled(False) self.zoom_button.setText('Zoom: On ') # Topic Tree and Topic Completer self.ros_topic_tree = RosTopicTree(self) self._topic_completer = TopicCompleter(self) self._topic_completer.setModel(self.ros_topic_tree) self.topic_edit.setCompleter(self._topic_completer) self.connect(self.topic_edit, SIGNAL("tabPressed"), self.on_topic_edit_tabPressed) # the rosstuff self._start_time = rospy.get_time() self._rosdata = {} self._remove_topic_menu = QMenu() # init and start update timer for plot self._update_plot_timer = QTimer(self) self._update_plot_timer.timeout.connect(self.update_plot) self._update_plot_timer.start(self._redraw_interval) # graph window self.graph_widget = GraphWidget(self) self.graph_widget_layout.addWidget(self.graph_widget) QObject.connect(self.graph_widget, SIGNAL("legendChecked(QwtPlotItem *,bool)"), self.legend_clicked) self.subscribed_topics_changed() self.show() def legend_clicked(self,item,val): topic_path = item.title().text() topic_path = str(topic_path) self.remove_topic( topic_path ) @pyqtSlot(str) def on_topic_edit_textChanged(self, slot_name): if slot_name =="": print 'Updating topics' self.ros_topic_tree.update() return is_num = self.ros_topic_tree.isNummeric(slot_name) all_children_num = self.ros_topic_tree.allChildrenNummeric(slot_name) self.subscribe_topic_button.setEnabled(is_num or all_children_num) # Perform autocompletion when tab is pressed topic_edit text box def on_topic_edit_tabPressed(self): if self._topic_completer.completionCount() == 1: # If there is a single autocompletion, use that updated_text = self._topic_completer.currentCompletion() self.topic_edit.setText(updated_text) self.topic_edit.insert("/") elif self._topic_completer.completionCount() > 1: # If there is more than one autocompletion, complete upto the last common letter match = str(self._topic_completer.currentCompletion()) for i in range(1, self._topic_completer.completionCount()): self._topic_completer.setCurrentRow(i) word = str(self._topic_completer.currentCompletion()) match = string_intersect(word, match) self._topic_completer.setCurrentRow(0) # Set the current row back to zero in case tab is pressed again self.topic_edit.setText(match) @pyqtSlot() def on_topic_edit_returnPressed(self): self.attempt_to_add_topics() @pyqtSlot() def on_subscribe_topic_button_clicked(self): self.attempt_to_add_topics() @pyqtSlot() def on_clear_button_clicked(self): self.clean_up_subscribers() @pyqtSlot() def on_zoom_button_clicked(self): if self.graph_widget.zoom_enabled: self.graph_widget.zoom_enabled = False self.zoom_button.setText('Zoom: Off') else: self.graph_widget.zoom_enabled = True self.zoom_button.setText('Zoom: On ') def update_plot(self): if self.graph_widget is not None: for topic_name, rosdata in self._rosdata.items(): try: data_x, data_y = rosdata.next() self.graph_widget.update_values(topic_name, data_x, data_y) except RosPlotException as e: qWarning('PlotWidget.update_plot(): error in rosplot: %s' % e) self.graph_widget.redraw() def subscribed_topics_changed(self): self.update_remove_topic_menu() self.graph_widget.redraw() def update_remove_topic_menu(self): def make_remove_topic_function(x): return lambda: self.remove_topic(x) self._remove_topic_menu.clear() for topic_name in sorted(self._rosdata.keys()): action = QAction(topic_name, self._remove_topic_menu) action.triggered.connect(make_remove_topic_function(topic_name)) self._remove_topic_menu.addAction(action) self.remove_topic_button.setMenu(self._remove_topic_menu) def attempt_to_add_topics(self): slot_name = str(self.topic_edit.text()) if self.ros_topic_tree.isNummeric(slot_name): self.add_topic(slot_name) if self.ros_topic_tree.allChildrenNummeric(slot_name): if not slot_name[-1] == '/': slot_name += '/' for slot in self.ros_topic_tree.pathFromAllChildren(slot_name): self.add_topic(slot) def add_topic(self, topic_name): if topic_name in self._rosdata: qWarning('PlotWidget.add_topic(): topic already subscribed: %s' % topic_name) return self._rosdata[topic_name] = ROSData(topic_name, self._start_time) data_x, data_y = self._rosdata[topic_name].next() self.graph_widget.add_curve(topic_name, topic_name, data_x, data_y) self.subscribed_topics_changed() def remove_topic(self, topic_name): self._rosdata[topic_name].close() del self._rosdata[topic_name] self.graph_widget.remove_curve(topic_name) self.subscribed_topics_changed() def clean_up_subscribers(self): for topic_name, rosdata in self._rosdata.items(): rosdata.close() self.graph_widget.remove_curve(topic_name) self._rosdata = {} self.subscribed_topics_changed()