def _dot(self, engine='fdp'): '''Generate dot representation (as object, not source). Requires graphviz module. Returns: string (SVG) ''' try: from graphviz import Graph as gvGraph, Digraph as gvDigraph except: raise Exception('Missing module: graphviz') g = gvDigraph(engine=engine) if self.directed else gvGraph( engine=engine) for src in range(self.order): for dst in self.adjlists[src]: if self.directed or src <= dst: g.edge(str(src), str(dst)) return g
def _gvgraph_(self): def _gv_args(node): is_dict = isinstance(node, dict) return { 'shape': 'none' if is_dict else 'box', 'margin': '0' if is_dict else '.05' } def _tostr(node): if isinstance(node, dict): return ''.join( ['<<FONT POINT-SIZE="12"><TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0">'] + ['<TR><TD>{}</TD><TD>{}</TD></TR>'.format(k, _escape(v)) for k, v in node.items() if not k.startswith('_thread_')] + ['</TABLE></FONT>>']) return str(node) def walk(T): curr = self.node(G, _tostr(T.root), id(T), gv_args = _gv_args(T.root)) if T.children: for child in T.children: self.node(G, _tostr(child.root), id(child), gv_args = _gv_args(child.root)) self.edge(G, curr, id(child )) with G.subgraph(edge_attr = {'style': 'invis'}, graph_attr = {'rank': 'same'}) as S: for f, t in zip(T.children, T.children[1:]): self.edge(S, id(f), id(t)) for child in T.children: walk(child) G = gvDigraph( graph_attr = { 'nodesep': '.25', 'ranksep': '.25' }, node_attr = { 'width': '0', 'height': '0', 'style': 'rounded, setlinewidth(.25)' }, edge_attr = { 'dir': 'none' } ) self._nodes = set() walk(self) return G
def _gvgraph_(self): if self.G: return self.G sep = '\n' if self.large_labels else None G = gvDigraph( graph_attr = { 'rankdir': 'LR', 'size': '32' }, node_attr = {'margin': '.05'} if self.large_labels else {}, engine = 'dot' ) if self.S is not None: self.edge(G, self.node(G, '', id(self.S), gv_args = {'shape': 'none'}), self.node(G, self.S, sep = sep, gv_args = {'peripheries': '2' if self.S in self.F else '1'}) ) for X, x, Y in self.transitions: self.edge(G, self.node(G, X, sep = sep, gv_args = {'peripheries': '2' if X in self.F else '1'}), self.node(G, Y, sep = sep, gv_args = {'peripheries': '2' if Y in self.F else '1'}), x, self.large_labels ) self.G = G return G
def displaySVG(ref, filename='temp'): """Render a graph to SVG format. *Warning:* Made for use within IPython/Jupyter only. Args: ref (Graph). filename (str): Temporary filename to store SVG output. Returns: SVG: IPython SVG wrapper object for graph. """ # Ensure all modules are available try: from graphviz import Graph as gvGraph, Digraph as gvDigraph from IPython.display import SVG except: raise Exception("Missing module: graphviz and/or IPython.") # Traverse graph and generate temporary Digraph/Graph object output_format = 'svg' if ref.directed: graph = gvDigraph(filename, format=output_format) else: graph = gvGraph(filename, format=output_format) if ref is not None: for src in range(ref.order): src_id = 'node_' + str(src) graph.node(src_id, label=str(src)) for dst in ref.adjlists[src]: if ref.directed or src >= dst: graph.edge(src_id, 'node_' + str(dst)) # Render to temporary file and SVG object graph.render(filename=filename, cleanup=True) return SVG(filename + '.' + output_format)
def _gvgraph_(self): if self.G is not None: return self.G derivation = self.derivation G = gvDigraph( graph_attr = { 'nodesep': '.25', 'ranksep': '.25' }, node_attr = { 'shape': 'box', 'margin': '.05', 'width': '0', 'height': '0', 'style': 'rounded, setlinewidth(.25)' }, edge_attr = { 'dir': 'none', 'penwidth': '.5', 'arrowsize': '.5' } ) def remove_ε(sentence): return tuple(_ for _ in sentence if _[0] != ε) sentence = ((derivation.start, 0, 0), ) for step, (rule, pos) in enumerate(derivation.steps(), 1): lhs, rhs = derivation.G.P[rule].as_type0() rhsn = tuple((X, step, p) for p, X in enumerate(rhs)) sentence = remove_ε(sentence[:pos] + rhsn + sentence[pos + len(lhs):]) last_sentence = set(sentence) use_levels = not self.compact sentence = ((derivation.start, 0, 0), ) with G.subgraph(graph_attr = {'rank': 'same'}) as S: if use_levels: prev_level = self.node(S, ('LevelNode', 0), gv_args = {'style': 'invis'}) self.node(S, sentence[0][0], hash(sentence[0])) for step, (rule, pos) in enumerate(derivation.steps(), 1): lhs, rhs = derivation.G.P[rule].as_type0() rhsn = tuple((X, step, p) for p, X in enumerate(rhs)) with G.subgraph(graph_attr = {'rank': 'same'}) as S: if use_levels: new_level = self.node(S, ('LevelNode', step), gv_args = {'style': 'invis'}) for node in rhsn: self.node(S, node[0], hash(node), gv_args = {'style': 'rounded, setlinewidth(1.25)' if node in last_sentence else 'rounded, setlinewidth(.25)'}) if use_levels: self.edge(G, prev_level, new_level, gv_args = {'style': 'invis'}) prev_level = new_level if len(lhs) == 1: frm = sentence[pos] for to in rhsn: self.edge(G, hash(frm), hash(to)) else: id_dot = self.node(G, (step, rule), gv_args = {'shape': 'point', 'width': '.07', 'height': '.07'}) for frm in sentence[pos:pos + len(lhs)]: self.edge(G, hash(frm), id_dot) for to in rhsn: self.edge(G, id_dot, hash(to)) if len(rhs) > 1: with G.subgraph(edge_attr = {'style': 'invis'}, graph_attr = {'rank': 'same'}) as S: for f, t in zip(rhsn, rhsn[1:]): self.edge(S, hash(f), hash(t)) sentence = remove_ε(sentence[:pos] + rhsn + sentence[pos + len(lhs):]) self.G = G return G
def __init__(self, arcs, sep = None): self.G = gvDigraph(graph_attr = {'size': '8', 'rankdir': 'LR'}) for src, dst in arcs: self.G.edge(letstr(src, sep = sep), letstr(dst, sep = sep))