docs: def get_cluster_graph(self, engine="fdp", graph_attr=None, node_attr=None, edge_attr=None):
          """
          Generate directory graph in the DOT language. Directories are shown as clusters
  
          .. warning::
  
              This function scans the entire directory tree starting from top so the resulting
              graph can be really big.
  
          Args:
              engine: Layout command used. ['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
          g = Digraph("directory", #filename="flow_%s.gv" % os.path.basename(self.relworkdir),
              engine=engine) # if engine == "automatic" else engine)
  
          # Set graph attributes.
          #g.attr(label="%s@%s" % (self.__class__.__name__, self.relworkdir))
          g.attr(label=self.top)
          #g.attr(fontcolor="white", bgcolor='purple:pink')
          #g.attr(rankdir="LR", pagedir="BL")
          #g.attr(constraint="false", pack="true", packMode="clust")
          g.node_attr.update(color='lightblue2', style='filled')
          #g.node_attr.update(ranksep='equally')
  
          # 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(path):
              return dict(
                  #shape="circle",
                  #shape="none",
                  #shape="plaintext",
                  #shape="point",
                  shape="record",
                  #color=node.color_hex,
                  fontsize="8.0",
                  label=os.path.basename(path),
              )
  
          edge_kwargs = dict(arrowType="vee", style="solid", minlen="1")
          cluster_kwargs = dict(rankdir="LR", pagedir="BL", style="rounded", bgcolor="azure2")
  
          # TODO: Write other method without clusters if not walk.
          exclude_top_node = False
          for root, dirs, files in os.walk(self.top):
              if exclude_top_node and root == self.top: continue
              cluster_name = "cluster_%s" % root
              #print("root", root, cluster_name, "dirs", dirs, "files", files, sep="\n")
  
              with g.subgraph(name=cluster_name) as d:
                  d.attr(**cluster_kwargs)
                  d.attr(rank="source" if (files or dirs) else "sink")
                  d.attr(label=os.path.basename(root))
                  for f in files:
                      filepath = os.path.join(root, f)
                      d.node(filepath, **node_kwargs(filepath))
                      if os.path.islink(filepath):
                          # Follow the link and use the relpath wrt link as label.
                          realp = os.path.realpath(filepath)
                          realp = os.path.relpath(realp, filepath)
                          #realp = os.path.relpath(realp, self.top)
                          #print(filepath, realp)
                          #g.node(realp, **node_kwargs(realp))
                          g.edge(filepath, realp, **edge_kwargs)
  
                  for dirname in dirs:
                      dirpath = os.path.join(root, dirname)
                      #head, basename = os.path.split(dirpath)
                      new_cluster_name = "cluster_%s" % dirpath
                      #rank = "source" if os.listdir(dirpath) else "sink"
                      #g.node(dirpath, rank=rank, **node_kwargs(dirpath))
                      #g.edge(dirpath, new_cluster_name, **edge_kwargs)
                      #d.edge(cluster_name, new_cluster_name, minlen="2", **edge_kwargs)
                      d.edge(cluster_name, new_cluster_name, **edge_kwargs)
          return g