Search code examples
graphvizlayeredges

Graphviz how to eliminate edges between layers when only one layer should be drawn and how to shrink the output dimension of the result?


I am using multiple layers in graphviz and define nodes (UML-Style) for them like (original has ~1700 lines of code and 5 layers):


    strict digraph G
     {
      compound=true;
      rankdir = TD
      clusterrank = local
      layers="beans:classes";
      node [shape = record]

      subgraph clusterApplicationContext
       {
        label = "applicationContext";
        "springBean1" [layer="beans"]
       }

      subgraph clusterPackageTest
       {
        label = "Package test";
        "Bean1" [layer="classes", label = "{Bean1|\l|\l}"]
       }

      edge [arrowhead = vee, style = dashed]
      "springBean1" -> {"Bean1"} [layer="beans:classes"]
     }

When I know run this through dot with

dot.exe -Glayerselect=classes -Tsvg beans.dot -o beans.svg

then the edge to the not visible springBean1 will also be drawn, which makes no sense from my point of view, because edges should only be drawn when both nodes are present (visible). Is there a way to change this, except with having additional layers for edges that connect nodes on different layers?

Also it looks like the whole graph (including the invisible layers) will be drawn, which makes my original image very large when only selecting a small layer of it - is there a way to only draw the visible part and have a small output size?


Solution

  • Seems to be that this could only be done with gvpr:

    beans.bat:

    set layers=beans:classes
    rem beans:jsps:classes:http:externals
    
    gvpr.exe -o beansFiltered.dot -a %layers% -f beansFilter.gvpr beans.dot
    dot.exe -Glayerselect=%layers% -Tsvg beansFiltered.dot -o beans.svg
    

    beansFilter.gvpr:

    BEGIN
     {
      int i;
      int j;
      int k;
      string wantedLayers[int];
      string layersArr[int];
      int found;
      j = 0;
      for (i = 0; i < ARGC; ++i)
       {
        unset(layersArr);
        split(ARGV[i], layersArr, ':');
        for (k = 0; k < #layersArr; ++k)
         {
          wantedLayers[j++] = layersArr[k];
         }
       }
     }
    
    BEG_G
     {
      $tgtname = $.name;
      for (i = 0; i < #wantedLayers; ++i)
       {
        $tgtname = sprintf("%s%s%s", $tgtname, "_", wantedLayers[i]);
       }
      graph_t subgraphs[int];
      graph_t subgraph;
      subgraph = fstsubg($);
      i = 0;
      while (subgraph != NULL)
       {
        if (substr(subgraph.name, 0, 1) != "%")
         {
          subgraphs[i++] = subgraph;
         }
        subgraph = nxtsubg(subgraph);
       }
     }
    
    N
     [
      unset(layersArr);
      split(layer, layersArr, ':');
      for (i = 0; i < #layersArr; ++i)
       {
        found = 0;
        for (j = 0; j < #wantedLayers; ++j)
         {
          if (layersArr[i] == wantedLayers[j])
           {
            found = 1;
           }
         }
        if (found == 0)
         {
          return 0;
         }
       }
      return 1;
     ]
     {
      found = 0;
      for (i = 0; i < #subgraphs; ++i)
       {
        if (isSubnode(subgraphs[i], $))
         {
          graph_t sg = subg($T, subgraphs[i].name);
          copyA(subgraphs[i], sg);
          subnode(sg, $);
          ++found;
          break;
         }
       }
      if (found  == 0)
       {
        node_t newnode = node($T, $.name);
        copyA($, newnode);
       }
     }
    
    E
     [
      unset(layersArr);
      split(layer, layersArr, ':');
      for (i = 0; i < #layersArr; ++i)
       {
        found = 0;
        for (j = 0; j < #wantedLayers; ++j)
         {
          if (layersArr[i] == wantedLayers[j])
           {
            found = 1;
           }
         }
        if (found == 0)
         {
          return 0;
         }
       }
      return 1;
     ]
    

    This solves both problems for me the filtering of unwanted edges and the final image size.