def __xml__(self, use_viz=True, use_dot=True, output='svg', figsize=None, **format): viz = None dot = None if use_viz: try: import pygraphviz as viz except ImportError: if use_dot: try: import pydot as dot except ImportError: pass elif use_dot: try: import pydot as dot except ImportError: pass if viz is None and dot is None: import warnings if use_viz and use_dot: msg = "neither pydot nor pygraphviz modules are installed, unable to draw nesting tree" elif use_viz: msg = "pygraphviz module not installed, unable to draw nesting tree" elif use_dot: msg = "pydot module not installed, unable to draw nesting tree" else: msg = "no drawing module used, unable to draw nesting tree" warnings.warn(msg) raise NotImplementedError(msg) if viz is not None: existing_format_keys = list(format.keys()) for key in existing_format_keys: if key.upper() != key: format[key.upper()] = format[key] if 'SUPPRESSGRAPHSIZE' not in format: if 'GRAPHWIDTH' not in format: format['GRAPHWIDTH'] = 6.5 if 'GRAPHHEIGHT' not in format: format['GRAPHHEIGHT'] = 4 if 'UNAVAILABLE' not in format: format['UNAVAILABLE'] = True # x = XML_Builder("div", {'class':"nesting_graph larch_art"}) # x.h2("Nesting Structure", anchor=1, attrib={'class':'larch_art_xhtml'}) from io import BytesIO if 'SUPPRESSGRAPHSIZE' not in format: G = viz.AGraph( name='Tree', directed=True, size="{GRAPHWIDTH},{GRAPHHEIGHT}".format(**format)) else: G = viz.AGraph(name='Tree', directed=True) for n in self.nodes: nname = self.nodes[n].get('name', n) if nname == n: G.add_node(n, label='<{1}>'.format(n, nname), style='rounded,solid', shape='box') else: G.add_node( n, label='<{1} <FONT COLOR="#999999">({0})</FONT>>'. format(n, nname), style='rounded,solid', shape='box') eG = G.add_subgraph(name='cluster_elemental', nbunch=self.elementals, color='#cccccc', bgcolor='#eeeeee', label='Elemental Alternatives', labelloc='b', style='rounded,solid') unavailable_nodes = set() # if format['UNAVAILABLE']: # if self.is_provisioned(): # try: # for n, ncode in enumerate(self.alternative_codes()): # if numpy.sum(self.Data('Avail'),axis=0)[n,0]==0: unavailable_nodes.add(ncode) # except: raise # try: # legible_avail = not isinstance(self.df.queries.avail, str) # except: # legible_avail = False # if legible_avail: # for ncode,navail in self.df.queries.avail.items(): # try: # if navail=='0': unavailable_nodes.add(ncode) # except: raise # eG.add_subgraph(name='cluster_elemental_unavailable', nbunch=unavailable_nodes, color='#bbbbbb', bgcolor='#dddddd', # label='Unavailable Alternatives', labelloc='b', style='rounded,solid') G.add_node(self.root_id, label="Root") up_nodes = set() down_nodes = set() for i, j in self.edges: G.add_edge(i, j) down_nodes.add(j) up_nodes.add(i) pyg_imgdata = BytesIO() try: G.draw( pyg_imgdata, format=output, prog='dot') # write postscript in k5.ps with neato layout except ValueError as err: if 'in path' in str(err): import warnings warnings.warn( str(err) + "; unable to draw nesting tree in report") raise NotImplementedError() if output == 'svg': import xml.etree.ElementTree as ET ET.register_namespace("", "http://www.w3.org/2000/svg") ET.register_namespace("xlink", "http://www.w3.org/1999/xlink") return ET.fromstring(pyg_imgdata.getvalue().decode()) else: raise NotImplementedError(f"output {output} with use_viz") else: pydot = dot # set Graphviz graph type if self.is_directed(): graph_type = 'digraph' else: graph_type = 'graph' strict = nx.number_of_selfloops( self) == 0 and not self.is_multigraph() name = self.name graph_defaults = self.graph.get('graph', {}) if name == '': P = pydot.Dot('', graph_type=graph_type, strict=strict, **graph_defaults) else: P = pydot.Dot('"%s"' % name, graph_type=graph_type, strict=strict, **graph_defaults) try: P.set_node_defaults(**self.graph['node']) except KeyError: pass try: P.set_edge_defaults(**self.graph['edge']) except KeyError: pass cluster_elemental = pydot.Cluster( 'elemental', style='rounded', bgcolor='lightgrey', color='white', rank='same', rankdir="LR", ) for n, nodedata in self.nodes(data=True): str_nodedata = dict( (k if k != 'name' else 'name_', '"' + str(v) + '"') for k, v in nodedata.items()) if 'parameter' in nodedata: param_label = '<BR ALIGN="CENTER" /><FONT COLOR="#999999" POINT-SIZE="9"><I>{0}</I></FONT>'.format( nodedata['parameter']) else: param_label = '' if 'name' in nodedata and n != self.root_id: name = nodedata['name'] str_nodedata['label'] = '<' \ '<FONT COLOR="#999999" POINT-SIZE="9">({1}) </FONT>' \ '{0}' \ '{2}>'.format(name,n,param_label) # Default styling for nodes can have been overridden if n in self.elementals: str_nodedata['style'] = str_nodedata.get('style', 'filled') str_nodedata['fillcolor'] = str_nodedata.get( 'fillcolor', 'white') elif n == self.root_id: str_nodedata['shape'] = str_nodedata.get( 'shape', 'invhouse') else: str_nodedata['style'] = str_nodedata.get( 'style', 'rounded') str_nodedata['shape'] = str_nodedata.get( 'shape', 'rectangle') p = pydot.Node(str(n), **str_nodedata) P.add_node(p) if n in self.elementals: cluster_elemental.add_node(p) P.add_subgraph(cluster_elemental) if self.is_multigraph(): for u, v, key, edgedata in self.edges(data=True, keys=True): str_edgedata = dict((k, str(v_)) for k, v_ in edgedata.items() if k != 'key') if v in self.elementals: str_edgedata['constraint'] = 'false' edge = pydot.Edge(str(u), str(v), key=str(key), **str_edgedata) P.add_edge(edge) else: for u, v, edgedata in self.edges(data=True): str_edgedata = dict( (k, '"' + str(v) + '"') for k, v in edgedata.items()) edge = pydot.Edge(str(u), str(v), **str_edgedata) P.add_edge(edge) ### from xmle import Elem prog = None if output == 'svg': import xml.etree.ElementTree as ET ET.register_namespace("", "http://www.w3.org/2000/svg") ET.register_namespace("xlink", "http://www.w3.org/1999/xlink") elif output == 'png': prog = [P.prog, '-Gdpi=300'] if figsize is not None: prog.append(f"-Gsize={figsize[0]},{figsize[1]}\!") e = Elem.from_any(P.create(prog=prog, format=output, **format)) e.attrib['dpi'] = (300, 300) return e return Elem.from_any(P.create(prog=prog, format=output, **format))
def __xml__(self, **format): viz = None dot = None try: import pygraphviz as viz except ImportError: try: import pydot as dot except ImportError: pass if viz is None and dot is None: import warnings warnings.warn( "pygraphviz module not installed, unable to draw nesting tree") raise NotImplementedError( "pygraphviz module not installed, unable to draw nesting tree") if viz is not None: existing_format_keys = list(format.keys()) for key in existing_format_keys: if key.upper() != key: format[key.upper()] = format[key] if 'SUPPRESSGRAPHSIZE' not in format: if 'GRAPHWIDTH' not in format: format['GRAPHWIDTH'] = 6.5 if 'GRAPHHEIGHT' not in format: format['GRAPHHEIGHT'] = 4 if 'UNAVAILABLE' not in format: format['UNAVAILABLE'] = True # x = XML_Builder("div", {'class':"nesting_graph larch_art"}) # x.h2("Nesting Structure", anchor=1, attrib={'class':'larch_art_xhtml'}) from io import BytesIO if 'SUPPRESSGRAPHSIZE' not in format: G = viz.AGraph( name='Tree', directed=True, size="{GRAPHWIDTH},{GRAPHHEIGHT}".format(**format)) else: G = viz.AGraph(name='Tree', directed=True) for n in self.nodes: nname = self.nodes[n].get('name', n) if nname == n: G.add_node(n, label='<{1}>'.format(n, nname), style='rounded,solid', shape='box') else: G.add_node( n, label='<{1} <FONT COLOR="#999999">({0})</FONT>>'. format(n, nname), style='rounded,solid', shape='box') eG = G.add_subgraph(name='cluster_elemental', nbunch=self.elementals, color='#cccccc', bgcolor='#eeeeee', label='Elemental Alternatives', labelloc='b', style='rounded,solid') unavailable_nodes = set() # if format['UNAVAILABLE']: # if self.is_provisioned(): # try: # for n, ncode in enumerate(self.alternative_codes()): # if numpy.sum(self.Data('Avail'),axis=0)[n,0]==0: unavailable_nodes.add(ncode) # except: raise # try: # legible_avail = not isinstance(self.df.queries.avail, str) # except: # legible_avail = False # if legible_avail: # for ncode,navail in self.df.queries.avail.items(): # try: # if navail=='0': unavailable_nodes.add(ncode) # except: raise # eG.add_subgraph(name='cluster_elemental_unavailable', nbunch=unavailable_nodes, color='#bbbbbb', bgcolor='#dddddd', # label='Unavailable Alternatives', labelloc='b', style='rounded,solid') G.add_node(self.root_id, label="Root") up_nodes = set() down_nodes = set() for i, j in self.edges: G.add_edge(i, j) down_nodes.add(j) up_nodes.add(i) pyg_imgdata = BytesIO() try: G.draw( pyg_imgdata, format='svg', prog='dot') # write postscript in k5.ps with neato layout except ValueError as err: if 'in path' in str(err): import warnings warnings.warn( str(err) + "; unable to draw nesting tree in report") raise NotImplementedError() import xml.etree.ElementTree as ET ET.register_namespace("", "http://www.w3.org/2000/svg") ET.register_namespace("xlink", "http://www.w3.org/1999/xlink") return ET.fromstring(pyg_imgdata.getvalue().decode()) else: N = self pydot = dot # set Graphviz graph type if N.is_directed(): graph_type = 'digraph' else: graph_type = 'graph' strict = nx.number_of_selfloops(N) == 0 and not N.is_multigraph() name = N.name graph_defaults = N.graph.get('graph', {}) if name is '': P = pydot.Dot('', graph_type=graph_type, strict=strict, **graph_defaults) else: P = pydot.Dot('"%s"' % name, graph_type=graph_type, strict=strict, **graph_defaults) try: P.set_node_defaults(**N.graph['node']) except KeyError: pass try: P.set_edge_defaults(**N.graph['edge']) except KeyError: pass for n, nodedata in N.nodes(data=True): str_nodedata = dict((k if k != 'name' else 'name_', str(v)) for k, v in nodedata.items()) p = pydot.Node(str(n), **str_nodedata) P.add_node(p) if N.is_multigraph(): for u, v, key, edgedata in N.edges(data=True, keys=True): str_edgedata = dict( (k, str(v)) for k, v in edgedata.items() if k != 'key') edge = pydot.Edge(str(u), str(v), key=str(key), **str_edgedata) P.add_edge(edge) else: for u, v, edgedata in N.edges(data=True): str_edgedata = dict( (k, str(v)) for k, v in edgedata.items()) edge = pydot.Edge(str(u), str(v), **str_edgedata) P.add_edge(edge) ### from xmle import Elem return Elem.from_any(P.create_svg())