def get_graphviz(self, engine="automatic", graph_attr=None, node_attr=None, edge_attr=None):
        """
        Generate task graph in the DOT language (only parents and children of this task).

        Args:
            engine: ['dot', 'neato', 'twopi', 'circo', 'fdp', 'sfdp', 'patchwork', 'osage']
            graph_attr: Mapping of (attribute, value) pairs for the graph.
            node_attr: Mapping of (attribute, value) pairs set for all nodes.
            edge_attr: Mapping of (attribute, value) pairs set for all edges.

        Returns: graphviz.Digraph <https://graphviz.readthedocs.io/en/stable/api.html#digraph>
        """
        # https://www.graphviz.org/doc/info/
        from graphviz import Digraph
        fg = Digraph("task", # filename="task_%s.gv" % os.path.basename(self.workdir),
            engine="dot" if engine == "automatic" else engine)

        # Set graph attributes.
        #fg.attr(label="%s@%s" % (self.__class__.__name__, self.relworkdir))
        fg.attr(label=repr(self))
        #fg.attr(fontcolor="white", bgcolor='purple:pink')
        #fg.attr(rankdir="LR", pagedir="BL")
        #fg.attr(constraint="false", pack="true", packMode="clust")
        fg.node_attr.update(color='lightblue2', style='filled')

        # Add input attributes.
        if graph_attr is not None:
            fg.graph_attr.update(**graph_attr)
        if node_attr is not None:
            fg.node_attr.update(**node_attr)
        if edge_attr is not None:
            fg.edge_attr.update(**edge_attr)

        def node_kwargs(node):
            return dict(
                #shape="circle",
                color=node.color_hex,
                label=(str(node) if not hasattr(node, "pos_str") else
                    node.pos_str + "\n" + node.__class__.__name__),
            )

        edge_kwargs = dict(arrowType="vee", style="solid")
        cluster_kwargs = dict(rankdir="LR", pagedir="BL", style="rounded", bgcolor="azure2")

        # Build cluster with tasks.
        cluster_name = "cluster%s" % self.work.name
        with fg.subgraph(name=cluster_name) as wg:
            wg.attr(**cluster_kwargs)
            wg.attr(label="%s (%s)" % (self.__class__.__name__, self.name))
            wg.node(self.name, **node_kwargs(self))

            # Connect task to children.
            for child in self.get_children():
                # Test if child is in the same work.
                myg = wg if child in self.work else fg
                myg.node(child.name, **node_kwargs(child))
                # Find file extensions required by this task
                i = [dep.node for dep in child.deps].index(self)
                edge_label = "+".join(child.deps[i].exts)
                myg.edge(self.name, child.name, label=edge_label, color=self.color_hex,
                         **edge_kwargs)

            # Connect task to parents
            for parent in self.get_parents():
                # Test if parent is in the same work.
                myg = wg if parent in self.work else fg
                myg.node(parent.name, **node_kwargs(parent))
                # Find file extensions required by self (task)
                i = [dep.node for dep in self.deps].index(parent)
                edge_label = "+".join(self.deps[i].exts)
                myg.edge(parent.name, self.name, label=edge_label, color=parent.color_hex,
                         **edge_kwargs)

        # Treat the case in which we have a work producing output for other tasks.
        #for work in self:
        #    children = work.get_children()
        #    if not children: continue
        #    cluster_name = "cluster%s" % work.name
        #    seen = set()
        #    for child in children:
        #        # This is not needed, too much confusing
        #        #fg.edge(cluster_name, child.name, color=work.color_hex, **edge_kwargs)
        #        # Find file extensions required by work
        #        i = [dep.node for dep in child.deps].index(work)
        #        for ext in child.deps[i].exts:
        #            out = "%s (%s)" % (ext, work.name)
        #            fg.node(out)
        #            fg.edge(out, child.name, **edge_kwargs)
        #            key = (cluster_name, out)
        #            if key not in seen:
        #                fg.edge(cluster_name, out, color=work.color_hex, **edge_kwargs)
        #                seen.add(key)

        return fg
def get_graphviz ( self , engine = "automatic" , graph_attr = None , node_attr = None , edge_attr = None ) : from graphviz import Digraph fg = Digraph ( "task" , engine = "dot" if engine == "automatic" else engine ) fg . attr ( label = repr ( self ) ) fg . node_attr . update ( color = 'lightblue2' , style = 'filled' ) if graph_attr is not None : fg . graph_attr . update ( ** graph_attr ) if node_attr is not None : fg . node_attr . update ( ** node_attr ) if edge_attr is not None : fg . edge_attr . update ( ** edge_attr ) def node_kwargs ( node ) : return dict ( color = node . color_hex , label = ( str ( node ) if not hasattr ( node , "pos_str" ) else node . pos_str + "\n" + node . __class__ . __name__ ) , ) edge_kwargs = dict ( arrowType = "vee" , style = "solid" ) cluster_kwargs = dict ( rankdir = "LR" , pagedir = "BL" , style = "rounded" , bgcolor = "azure2" ) cluster_name = "cluster%s" % self . work . name with fg . subgraph ( name = cluster_name ) as wg : wg . attr ( ** cluster_kwargs ) wg . attr ( label = "%s (%s)" % ( self . __class__ . __name__ , self . name ) ) wg . node ( self . name , ** node_kwargs ( self ) ) for child in self . get_children ( ) : myg = wg if child in self . work else fg myg . node ( child . name , ** node_kwargs ( child ) ) i = [ dep . node for dep in child . deps ] . index ( self ) edge_label = "+" . join ( child . deps [ i ] . exts ) myg . edge ( self . name , child . name , label = edge_label , color = self . color_hex , ** edge_kwargs ) for parent in self . get_parents ( ) : myg = wg if parent in self . work else fg myg . node ( parent . name , ** node_kwargs ( parent ) ) i = [ dep . node for dep in self . deps ] . index ( parent ) edge_label = "+" . join ( self . deps [ i ] . exts ) myg . edge ( parent . name , self . name , label = edge_label , color = parent . color_hex , ** edge_kwargs ) return fg
Generate task graph in the DOT language (only parents and children of this task).

        Args:
            engine: ['dot', 'neato', 'twopi', 'circo', 'fdp', 'sfdp', 'patchwork', 'osage']
            graph_attr: Mapping of (attribute, value) pairs for the graph.
            node_attr: Mapping of (attribute, value) pairs set for all nodes.
            edge_attr: Mapping of (attribute, value) pairs set for all edges.

        Returns: graphviz.Digraph <https://graphviz.readthedocs.io/en/stable/api.html#digraph>