def _draw_subgraph(diagram: pydot.Dot, label_last_seen: DefaultDict[str, str], subgraph_name: str, subgraph_ops: List[Union[Op, Trace, Any]]) -> None: """Draw a subgraph of ops into an existing `diagram`. Args: diagram: The diagram to be appended to. label_last_seen: A mapping of {data_dict_key: node_id} indicating the last node which generated the key. subgraph_name: The name to be associated with this subgraph. subgraph_ops: The ops to be wrapped in this subgraph. """ subgraph = pydot.Cluster(style='dashed', graph_name=subgraph_name) subgraph.set('label', subgraph_name) subgraph.set('labeljust', 'l') for idx, op in enumerate(subgraph_ops): node_id = str(id(op)) Traceability._add_node(subgraph, op, node_id) if isinstance(op, (Op, Trace)): # Need the instance check since subgraph_ops might contain a tf dataset or torch dataloader edge_srcs = defaultdict(lambda: []) for inp in op.inputs: if inp == '*': continue edge_srcs[label_last_seen[inp]].append(inp) for src, labels in edge_srcs.items(): diagram.add_edge(pydot.Edge(src=src, dst=node_id, label=f" {', '.join(labels)} ")) for out in op.outputs: label_last_seen[out] = node_id if isinstance(op, Trace) and idx > 0: # Invisibly connect traces in order so that they aren't all just squashed horizontally into the image diagram.add_edge(pydot.Edge(src=str(id(subgraph_ops[idx - 1])), dst=node_id, style='invis')) diagram.add_subgraph(subgraph)
def _draw_subgraph(diagram: pydot.Dot, label_last_seen: DefaultDict[str, str], subgraph_name: str, subgraph_ops: List[Union[Op, Trace]]) -> None: """Draw a subgraph of ops into an existing `diagram`. Args: diagram: The diagram to be appended to. label_last_seen: A mapping of {data_dict_key: node_id} indicating the last node which generated the key. subgraph_name: The name to be associated with this subgraph. subgraph_ops: The ops to be wrapped in this subgraph. """ subgraph = pydot.Cluster(style='dashed', graph_name=subgraph_name) subgraph.set('label', subgraph_name) subgraph.set('labeljust', 'l') for idx, op in enumerate(subgraph_ops): node_id = str(id(op)) if isinstance(op, ModelOp): label = f"{op.__class__.__name__} ({FEID(id(op))}): {op.model.model_name}" model_ref = Hyperref(Marker(name=str(op.model.model_name), prefix='subsec'), text=NoEscape(r'\textcolor{blue}{') + bold(op.model.model_name) + NoEscape('}')).dumps() texlbl = f"{HrefFEID(FEID(id(op)), name=op.__class__.__name__).dumps()}: {model_ref}" else: label = f"{op.__class__.__name__} ({FEID(id(op))})" texlbl = HrefFEID(FEID(id(op)), name=op.__class__.__name__).dumps() subgraph.add_node(pydot.Node(node_id, label=label, texlbl=texlbl)) edge_srcs = defaultdict(lambda: []) for inp in op.inputs: if inp == '*': continue edge_srcs[label_last_seen[inp]].append(inp) for src, labels in edge_srcs.items(): diagram.add_edge( pydot.Edge(src=src, dst=node_id, label=f" {', '.join(labels)} ")) for out in op.outputs: label_last_seen[out] = node_id if isinstance(op, Trace) and idx > 0: # Invisibly connect traces in order so that they aren't all just squashed horizontally into the image diagram.add_edge( pydot.Edge(src=str(id(subgraph_ops[idx - 1])), dst=node_id, style='invis')) diagram.add_subgraph(subgraph)
def draw(self, path: str, format: str = "raw") -> None: node_aggr = {} for node in self._nodes: level = node.get_level() label = node.get_label() identifier = node.get_id() if node_aggr.get(level) is None: node_aggr[level] = {} if level != 0: gv_cluster = GVCluster(identifier) gv_cluster.set("label", label) node_aggr[level][identifier] = gv_cluster else: gv_node = GVNode(identifier) gv_node.set("label", label) node_aggr[level][identifier] = gv_node gv_dot = GVDot() gv_dot.set("ranksep", "1.0 equally") if self._lable is not None: gv_dot.set("label", self._lable) for node in self._nodes: level = node.get_level() parent = node.get_parent() parent_level = node.get_parent_level() identifier = node.get_id() if level != 0: if parent is not None: node_aggr[parent_level][parent].add_subgraph(node_aggr[level][identifier]) else: gv_dot.add_subgraph(node_aggr[level][identifier]) else: if parent is not None: node_aggr[parent_level][parent].add_node(node_aggr[level][identifier]) else: gv_dot.add_node(node_aggr[level][identifier]) for edge in self._edges: label = edge.get_label() gv_edge = GVEdge(edge.get_src(), edge.get_dst()) if label is not None: gv_edge.set("label", edge.get_label()) gv_dot.add_edge(gv_edge) gv_dot.write(path, format=format)
graph.set_node_defaults(shape = "record") teacher = Node("Teacher", label = "{Nastavnik|+ime:String \n+prezime:String|\n}") course = Node("Course", label = "{Kurs|\n|\n}") student = Node("Student", label = "{Student|\n|\n}") lesson = Node("Lesson", label = "{Predavanja|\n|\n}") tutorial = Node("Tutorial", label = "{Konsultacije|\n |\n}") assessment = Node("Assessment", label = "{Ocenjivanje|\n|\n}") coursework = Node("Coursework", label = "{Predispitne obaveze|\n|\n}") exam = Node("Exam", label = "{Ispit|\n|\n }") S = Subgraph(rank='same') S.add_node(teacher) S.add_node(student) S.add_node(course) graph.add_subgraph(S) graph.add_node(lesson) graph.add_node(tutorial) graph.add_node(assessment) graph.add_node(coursework) graph.add_node(exam) graph.write_png("objektni_primer.png"); edge1 = Edge(teacher, course, label = "Predaje", arrowhead = "none", arrowtail = "normal", headlabel = "1", taillabel = "1") edge2 = Edge(student, course, label = "Pohađa", arrowhead="none", arrowtail="normal",headlabel="1",taillabel="1") edge3 = Edge(lesson, course, arrowhead="diamond",arrowtail="normal") edge4 = Edge(tutorial, course, arrowhead="diamond",arrowtail="normal") edge5 = Edge(assessment, course, arrowhead="diamond",arrowtail="normal")
class SysCDiagramPlugin(): def initPlugin(self, signalproxy): """Initialise the systemc block diagram plugin""" self.signalproxy = signalproxy self.do = signalproxy.distributedObjects # systemc stuff and and pointer type strings needed for casting in gdb # because systemc objects can be systemc modules, systemc ports, etc. self.ctx = None self.ctx_pointer = None self.ctx_func = "sc_get_curr_simcontext()" self.ctx_found = False self.ctx_type = "(sc_core::sc_simcontext*)" self.port_type = "(sc_core::sc_port_base*)" self.module_type = "(sc_core::sc_module*)" self.object_type = "(sc_core::sc_object*)" self.prim_channel_type = "(sc_core::sc_prim_channel*)" # dict with a string that represents the pointer as key and # a nested dict with parent, children, etc as key-values # dst_dict[ptr] = {"wrapper": vw, # "name": None, # "parent_ptr": None, # "children": {}} self.sysc_modules = {} self.sysc_objects = {} self.sysc_ports = {} self.sysc_prim_channels = {} # because of how we built the interface for the tracepoints on the # datagraph we first need to create an file obj. We choose StringIO # because it uses a string as buffer and does not acces the filesystem self._file_obj = StringIO() self.image = SVGImage("SystemC Block Diagram", self._file_obj) self.image_wrapper = SVGDataGraphVW(self.image, self.do) self.signalproxy.inferiorStoppedNormally.connect(self.update) # hook Datagraph variable wrapper into the datagraph controller # after self.action.commit is called the image will be displayed at the # datagraph self.action = self.do.actions.\ getAddSVGToDatagraphAction(self.image_wrapper, self.do. datagraphController.addVar) # pydot graph visualization library self.block_diagram = Dot(graph_type='digraph') self.block_diagram.set_graph_defaults(compound='true', splines='ortho', rankdir='LR') self.block_diagram.set_node_defaults(shape='box') # Needed for creating the right variables and variable wrappers from # the systemc pointers self.vwFactory = VarWrapperFactory() self.variableList = VariableList(self.vwFactory, self.do) def deInitPlugin(self): pass def evaluateExp(self, exp): return self.signalproxy.gdbEvaluateExpression(exp) def showDiagram(self): self.action.commit() def update(self): if not self.ctx_found and self.ctx is None: self.__findSimContext() if self.ctx is None: return else: # don't try to analyze if elaboration is not done if not cpp2py(self.ctx["m_elaboration_done"].value): return # prepare for easy information collection object_vec = self.ctx["m_child_objects"] # find all relevant information self.__findSysCObjects(object_vec, self.object_type, self.sysc_objects) # if there are no objects to draw than skip the drawing part # this might happen if you set the breakpoint before any objects are # created. This is actually catched above, but there might also be a # design with no objects. if len(self.sysc_objects.keys()) == 0: return clusters = {} nodes = {} # build pydot hierachy and add all subgraphs and nodes to the main # graph self.__buildHierachy(self.sysc_objects, clusters, nodes) for sptr in clusters: self.block_diagram.add_subgraph(clusters[sptr]) for sptr in nodes: self.block_diagram.add_node(nodes[sptr]) self._file_obj.write(self.block_diagram.create_svg()) self.signalproxy.inferiorStoppedNormally.disconnect(self.update) self.showDiagram() def __buildHierachy(self, obj_dict, clusters, nodes): """ Build Cluster and Node hierachy for pydot """ for ptr in obj_dict: obj = obj_dict[ptr] if ptr in (self.sysc_ports.keys()+self.sysc_prim_channels.keys()): continue if len(obj["children"].keys()) == 0: node = Node(obj["name"]) nodes[ptr] = node else: clust = Cluster(obj["name"].replace(".", "_"), color='red', label=obj["name"]) c_clusters = {} c_nodes = {} self.__buildHierachy(obj["children"], c_clusters, c_nodes) for sptr in c_clusters: clust.add_subgraph(c_clusters[sptr]) for sptr in c_nodes: clust.add_node(c_nodes[sptr]) clusters[ptr] = clust def __findSysCObjects(self, obj_vec, obj_type, dst_dict): """ Find sc_object from module, port and prim channel registry """ for i in obj_vec.childs: ptr = i.value var = "(*{}{})".format(obj_type, ptr) vw = self.variableList.addVarByName(var) dst_dict[ptr] = {"wrapper": vw, "name": None, "parent_ptr": None, "children": {}} for member in vw.childs: if member.exp == "m_name": dst_dict[ptr]["name"] = member.value.strip('"') elif member.exp == "m_child_objects": children = {} self.__findSysCObjects(vw["m_child_objects"], obj_type, children) dst_dict[ptr]["children"] = children elif member.exp == "m_parent": dst_dict[ptr]["parent_ptr"] = member.value def __findSimContext(self): """ Find systemc simulation context """ self.ctx_pointer = self.evaluateExp(self.ctx_func) if self.ctx is None: frame = 0 depth = self.signalproxy.gdbGetStackDepth() while (self.ctx_pointer is None) and frame <= depth: frame += 1 self.signalproxy.gdbSelectStackFrame(frame) self.ctx_pointer = self.evaluateExp(self.ctx_func) else: if self.ctx_pointer is None: self.ctx_found = False return else: self.ctx_found = True self.ctx = self.do.variablePool.getVar(self.ctx_func)["*"] else: self.ctx_found = True self.ctx = self.do.variablePool.getVar(self.ctx_func)["*"]
def graph(self, context=None, **kwargs): """ Returns a graph object Keyword Arguments: context {bool|None} -- controls the animations (default: {None}) Returns: [pydot.Dot] -- graph object """ graph = Dot(graph_type="digraph", rankdir=("LR" if context is None else "TB")) machine_graph = Subgraph(graph_name="cluster_machine", graph_type="digraph", label="MACHINE") for current_state in sorted(self._states): node_args = {} shape = "circle" shape = ("double" if current_state in self._end_states else "") + shape node_args["shape"] = shape if context is not None and current_state == self._current_state: node_args["fillcolor"] = "cyan" node_args["style"] = "filled" machine_graph.add_node(Node(current_state, **node_args)) machine_graph.add_node(Node("0", shape="point")) machine_graph.add_edge(Edge("0", self._start_state)) for current_state in self._states: transitions = self._transitions.get(current_state) if transitions: for current_symbol in transitions: next_symbol, direction, next_state = transitions.get( current_symbol) label = f"'{current_symbol}' '{next_symbol}' {'R' if direction else 'L'}" edge_args = {} if (context and current_state == self._current_state and current_symbol == self._tape[self._head]): edge_args["color"] = "cyan" machine_graph.add_edge( Edge(current_state, next_state, label=label, **edge_args)) graph.add_subgraph(machine_graph) if context is not None: tape_graph = Subgraph(graph_name="cluster_tape", graph_type="digraph", label="TAPE") tape = [] for index in range(-4 + self._head, 5 + self._head): tape.append( f"<t{index}> {self._tape[index] if 0 <= index < len(self._tape) else self._blank_symbol}" ) tape_graph.add_node( Node("tape", label="|".join(tape), shape="record")) tape_graph.add_node(Node("t0", shape="point")) tape_graph.add_edge(Edge("t0", f"tape:t{self._head}")) graph.add_subgraph(tape_graph) if kwargs.get("filename"): graph.write(kwargs.get("filename"), format="png") return f"Graph saved to {kwargs.get('filename')}" return graph
def diskusage(db, userName, withIndexes=False, percent=True): """Extracts the physical storage of the current user as a picture based on Oracle statistics The generation of the picture is powered by Graphviz (http://www.graphviz.org) through the PyDot API (http://www.dkbza.org/pydot.html) """ # Tries to import pydot module try: from pydot import find_graphviz, Dot, Subgraph, Cluster, Edge, Node except ImportError: message = _("Function not available because pydot module is not installed.\n\t") message += _("Go to http://dkbza.org/pydot.html to get it.") raise PysqlException(message) # Reads conf conf = PysqlConf.getConfig() unit = conf.get("unit") # Unit used to format data format = conf.get("graph_format") # Output format of the picture fontname = conf.get("graph_fontname") # Font used for table names fontsize = conf.get("graph_fontsize") # Font size for table names fontcolor = conf.get("graph_fontcolor") # Color of table and column names tablecolor = conf.get("graph_tablecolor") # Color of tables indexcolor = conf.get("graph_indexcolor") # Color of indexes bordercolor = conf.get("graph_bordercolor") # Color of borders # Gets picture generator prog = getProg(find_graphviz(), conf.get("graph_program"), "fdp") # First step: objects library building # Tablespaces if userName == db.getUsername().upper(): tablespaces = db.executeAll(diskusageSql["Tablespaces"]) else: tablespaces = db.executeAll(diskusageSql["TablespacesFromOwner"], [userName]) tbsBytes = 0 tbsList = [] for tablespace in tablespaces: tablespaceName = unicode(tablespace[0]) # Tables from current tablespace if userName == db.getUsername().upper(): tables = db.executeAll(diskusageSql["TablesFromTbs"], [tablespaceName]) else: tables = db.executeAll(diskusageSql["TablesFromOwnerAndTbs"], [userName, tablespaceName]) tabList = [] print CYAN + _("Extracting %3d tables from tablespace %s") % (len(tables), tablespaceName) + RESET for table in tables: tableName = table[0] if table[1] is None: print RED + _("""Warning: table "%s" removed because no statistics have been found""") \ % (tablespaceName + "/" + tableName) + RESET continue if table[1] == 0: print RED + _("""Warning: table "%s" removed because it is empty""") \ % (tablespaceName + "/" + tableName) + RESET continue numRows = int(table[1]) avgRowLen = float(table[2]) bytes = int(table[3]) tbsBytes += bytes tabList += [[tableName, bytes, numRows, avgRowLen]] if withIndexes: # Indexes from current tablespace if userName == db.getUsername().upper(): indexes = db.executeAll(diskusageSql["IndexesFromTbs"], [tablespaceName]) else: indexes = db.executeAll(diskusageSql["IndexesFromOwnerAndTbs"], [userName, tablespaceName]) idxList = [] print CYAN + _("Extracting %3d indexes from tablespace %s") % (len(indexes), tablespaceName) + RESET for index in indexes: indexName = index[0] if index[1] is None: print RED + _("""Warning: index "%s" removed because no statistics have been found""") \ % (tablespaceName + "/" + indexName) + RESET continue if index[1] == 0: print RED + _("""Warning: index "%s" removed because it is empty""") \ % (tablespaceName + "/" + indexName) + RESET continue numRows = int(index[1]) distinctKeys = int(index[2]) bytes = int(index[3]) tabName = str(index[4]) tbsBytes += bytes idxList += [[indexName, bytes, numRows, distinctKeys, tabName]] else: print CYAN + _("Not extracting indexes from tablespace %s (ignored)") % (tablespaceName) + RESET idxList = [] tbsList += [[tablespaceName, tbsBytes, tabList, idxList]] # Second step: objects drawing graph = Dot(label=userName, overlap="false", splines="true") for tbs in tbsList: tbsName = tbs[0] tbsBytes = tbs[1] tabList = tbs[2] idxList = tbs[3] subGraph = Subgraph("cluster_" + tbsName, bgcolor="palegreen", \ fontname=fontname, fontsize=str(fontsize - 1), \ label="%s\\n(%d %s)" % (tbsName, convert(tbsBytes, unit), unit.upper())) graph.add_subgraph(subGraph) print CYAN + _("Displaying %3d tables for tablespace %s") % (len(tabList), tbsName) + RESET for tab in tabList: name = tab[0] bytes = tab[1] numRows = tab[2] # unused avgRowLen = tab[3] # unused # Mathematics at work width = 0.2 height = 0.2 if percent: height += 10 * round(float(bytes) / tbsBytes, 4) label = "%s\\n(%.2f %s)" % (name, round(100 * float(bytes) / tbsBytes, 2), "%") else: height += round(sqrt(bytes) / 8192, 3) width += round(sqrt(bytes) / 8192, 3) label = "%s\\n(%3d %s)" % (name, convert(bytes, unit), unit.upper()) subGraph.add_node(Node(name, label=label, shape="box", style="filled", \ color="none", fillcolor=tablecolor, \ fontname=fontname, fontcolor=fontcolor, fixedsize="false", \ fontsize=str(fontsize - 2 - floor((len(label) - 7) / 15)), \ nodesep="0.01", height=str(height), width=str(max(width, 1)))) print CYAN + _("Displaying %3d indexes for tablespace %s") % (len(idxList), tbsName) + RESET for idx in idxList: name = idx[0] bytes = idx[1] numRows = idx[2] # unused distinctKeys = idx[3] # unused tabName = idx[4] # unused # Mathematics at work again) width = 0.2 height = 0.2 if percent: height += 10 * round(float(bytes) / tbsBytes, 4) label = "%s\\n(%.2f %s)" % (name, round(100 * float(bytes) / tbsBytes, 2), "%") else: height += round(sqrt(bytes) / 8192, 3) width += round(sqrt(bytes) / 8192, 3) label = "%s\\n(%3d %s)" % (name, convert(bytes, unit), unit.upper()) subGraph.add_node(Node(name, label=label, shape="box", style="filled", \ color="none", fillcolor=indexcolor, \ fontname=fontname, fontcolor=fontcolor, fixedsize="false", \ fontsize=str(fontsize - 2 - floor((len(label) - 7) / 15)), \ nodesep="0.01", height=str(height), width=str(max(width, 1)))) #Moving index near by its table (unused because it widens the graph) #subGraph.add_edge(Edge(src=name, dst=tabName, constraint="false", style="invis")) filename = "du_" + userName + "." + format generateImage(graph, filename, prog, format) viewImage(filename)