예제 #1
0
    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)
예제 #2
0
    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()
예제 #3
0
 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)
예제 #4
0
    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()
예제 #5
0
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()
예제 #6
0
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)
예제 #7
0
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_())
예제 #8
0
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()
예제 #9
0
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()