Ejemplo n.º 1
0
    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))
Ejemplo n.º 2
0
Archivo: tree.py Proyecto: mindis/larch
    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())