def get_graphviz(self, triple_hook=graphviz_triple_hook, node_hook=graphviz_node_hook, theme_options=VIS_THEME_OPTIONS, **hook_options): """ Create a pygraphviz graph from the tree @param triple_hook: a function that returns an attribute dict (or None) given a triple and the kargs @param node_hook: a function that returns a label given a node and the kargs @param theme_options: a dict-of-dicts containing global graph/node/edge attributes @param hook_options: additional arguments to pass to the hook functions """ def _id(node): return node.uri.split("/")[-1] g = AGraph(directed=True, strict=False) triples = list(self.get_triples()) # create nodes nodeset = set(chain.from_iterable((t.subject, t.object) for t in triples)) for n in sorted(nodeset, key=lambda n:n.id): g.add_node(_id(n), **node_hook(n, **hook_options)) connected = set() # create edges for triple in sorted(triples, key=lambda t:t.predicate): kargs = triple_hook(triple, **hook_options) if kargs: if kargs.get('reverse'): g.add_edge(_id(triple.object), _id(triple.subject), **kargs) else: g.add_edge(_id(triple.subject), _id(triple.object), **kargs) connected |= {_id(triple.subject), _id(triple.object)} connected = chain.from_iterable(g.edges()) for isolate in set(g.nodes()) - set(connected): g.remove_node(isolate) # some theme options for obj, attrs in theme_options.iteritems(): for k, v in attrs.iteritems(): getattr(g, "%s_attr" % obj)[k] = v return g
class UiGraphio(QMainWindow): """ Main window for application """ def __init__(self): """ Constructor """ QMainWindow.__init__(self) self.ui = graphio.Ui_MainWindow() self.ui.setupUi(self) self.scene_graph = QGraphicsScene() self.ui.graphicsView.setScene(self.scene_graph) self.ui.graphicsView.update() self.graph = AGraph(strict=True, directed=True) self.graph.layout(prog='dot') ##################################################### # View update ##################################################### def update_adj_matrix(self): count = self.graph.number_of_nodes() self.ui.tw_adjmatrix.setRowCount(count) self.ui.tw_adjmatrix.setColumnCount(count) self.ui.tw_adjmatrix.setHorizontalHeaderLabels(self.graph.nodes()) self.ui.tw_adjmatrix.setVerticalHeaderLabels(self.graph.nodes()) for (i, u) in enumerate(self.graph.nodes()): for (j, v) in enumerate(self.graph.nodes_iter()): if self.graph.has_edge(u, v): self.ui.tw_adjmatrix.setItem( i, j, QTableWidgetItem( self.graph.get_edge(u, v).attr['label'])) else: self.ui.tw_adjmatrix.setItem(i, j, QTableWidgetItem(str(0))) def update_matrix_incidence(self): nodes = self.graph.nodes() edges = self.graph.edges() self.ui.tw_incmatrix.setRowCount(len(nodes)) self.ui.tw_incmatrix.setColumnCount(len(edges)) self.ui.tw_incmatrix.setHorizontalHeaderLabels( [str(node) for node in self.graph.edges()]) self.ui.tw_incmatrix.setVerticalHeaderLabels(self.graph.nodes()) for (i, u) in enumerate(nodes): for (j, edg) in enumerate(edges): value = 0 if (u == edg[0]): value = 1 elif (u == edg[1]): value = -1 self.ui.tw_incmatrix.setItem(i, j, QTableWidgetItem(str(value))) def update_list_edges(self): edges = self.graph.edges() self.ui.tw_edges.setRowCount(len(edges)) for (i, edge) in enumerate(edges): self.ui.tw_edges.setItem(i, 0, QTableWidgetItem(edge[0])) self.ui.tw_edges.setItem(i, 1, QTableWidgetItem(edge[1])) def update_adj_list(self): nodes = self.graph.nodes() self.ui.tw_adjlist.setRowCount(self.graph.number_of_nodes()) self.ui.tw_adjlist.setVerticalHeaderLabels(nodes) for (i, node) in enumerate(nodes): value = '' for adj in self.graph.out_edges(node): value += adj[1] + ', ' self.ui.tw_adjlist.setItem(i, 0, QTableWidgetItem(value[:-2])) ##################################################### # Reset editors ##################################################### def add_cb_item(self, label): n = self.ui.cb_nodes.count() i = 0 while i < n: itext = self.ui.cb_nodes.itemText(i) if label == itext: return elif label < itext: break i += 1 # insert item to lists self.ui.cb_nodes.insertItem(i, label) self.ui.cb_starting_node.insertItem(i, label) self.ui.cb_ending_node.insertItem(i, label) @pyqtSlot(bool, name='on_bt_add_node_clicked') @pyqtSlot(bool, name='on_bt_del_node_clicked') @pyqtSlot(bool, name='on_bt_add_edge_clicked') @pyqtSlot(bool, name='on_bt_del_edge_clicked') def reset_editors(self): self.ui.cb_nodes.clearEditText() self.ui.cb_starting_node.clearEditText() self.ui.cb_ending_node.clearEditText() self.ui.sb_weight_edge.setMinimum() def redraw(self): self.graph.draw('graph', 'png', 'dot') self.scene_graph.clear() self.scene_graph.addItem(QGraphicsPixmapItem(QPixmap('graph'))) self.ui.graphicsView.update() ##################################################### # Buttons actions ##################################################### @pyqtSlot() def on_bt_add_node_clicked(self): """ Slot when click on Add node button """ label = self.ui.cb_nodes.currentText() if not self.graph.has_node(label): self.add_cb_item(label) self.graph.add_node(label) self.redraw() @pyqtSlot() def on_bt_del_node_clicked(self): """ Slot when click on Delete node button """ index = self.ui.cb_nodes.currentIndex() label = self.ui.cb_nodes.currentText() if index > -1 and self.graph.has_node(label): self.graph.remove_node(label) self.redraw() self.ui.cb_nodes.removeItem(index) self.ui.cb_starting_node.removeItem(index) self.ui.cb_ending_node.removeItem(index) @pyqtSlot() def on_bt_add_edge_clicked(self): """ Slot when click on Add branch button """ start = self.ui.cb_starting_node.currentText() end = self.ui.cb_ending_node.currentText() weight = self.ui.sb_weight_edge.value() if start and end: self.add_cb_item(start) self.add_cb_item(end) self.graph.add_edge(start, end, label=weight) self.redraw() @pyqtSlot() def on_bt_del_edge_clicked(self): """ Slot when click on Delete branch button """ start = self.ui.cb_starting_node.currentText() end = self.ui.cb_ending_node.currentText() weight = self.ui.sb_weight_edge.value() if start and end and self.graph.has_edge(start, end): self.graph.remove_edge(start, end) self.redraw() @pyqtSlot(int) @pyqtSlot(bool, name='on_bt_add_node_clicked') @pyqtSlot(bool, name='on_bt_del_node_clicked') @pyqtSlot(bool, name='on_bt_add_edge_clicked') @pyqtSlot(bool, name='on_bt_del_edge_clicked') def on_toolbox_view_currentChanged(self, index): index = self.ui.toolbox_view.currentIndex() if index == 0: self.update_adj_matrix() elif index == 1: self.update_matrix_incidence() elif index == 2: self.update_list_edges() elif index == 3: self.update_adj_list()