Merging graphs in Graphviz











up vote
1
down vote

favorite












I have a collection of digraphs encoded in DOT language, and i want to merge them into a single digraph where nodes with the same name in different input graphs are merged together.



For example given the following files:



1.dot:



digraph {
A -> B
A -> C
}


2.dot:



digraph {
D -> E
E -> F
}


3.dot:



digraph {
D -> G
G -> A
}


I would like to obtain the following result.dot:



digraph {
subgraph {
A -> B
A -> C
}
subgraph {
D -> E
E -> F
}
subgraph {
D -> G
G -> A
}
}




I tried to use gvpack but it renames duplicate nodes.



> gvpack -u 1.dot 2.dot 3.dot
Warning: node D in graph[2] %15 already defined
Some nodes will be renamed.
digraph root {
node [label="N"];
{
node [label="N"];
A -> B;
A -> C;
}
{
node [label="N"];
D -> E;
E -> F;
}
{
node [label="N"];
D_gv1 -> G;
G -> A_gv1;
}
}


I found a similar question on SO that suggest using sed to rename the renamed nodes, but that doesn't seem very clean.



Is there a way to merge the graphs the way i would like them?










share|improve this question


























    up vote
    1
    down vote

    favorite












    I have a collection of digraphs encoded in DOT language, and i want to merge them into a single digraph where nodes with the same name in different input graphs are merged together.



    For example given the following files:



    1.dot:



    digraph {
    A -> B
    A -> C
    }


    2.dot:



    digraph {
    D -> E
    E -> F
    }


    3.dot:



    digraph {
    D -> G
    G -> A
    }


    I would like to obtain the following result.dot:



    digraph {
    subgraph {
    A -> B
    A -> C
    }
    subgraph {
    D -> E
    E -> F
    }
    subgraph {
    D -> G
    G -> A
    }
    }




    I tried to use gvpack but it renames duplicate nodes.



    > gvpack -u 1.dot 2.dot 3.dot
    Warning: node D in graph[2] %15 already defined
    Some nodes will be renamed.
    digraph root {
    node [label="N"];
    {
    node [label="N"];
    A -> B;
    A -> C;
    }
    {
    node [label="N"];
    D -> E;
    E -> F;
    }
    {
    node [label="N"];
    D_gv1 -> G;
    G -> A_gv1;
    }
    }


    I found a similar question on SO that suggest using sed to rename the renamed nodes, but that doesn't seem very clean.



    Is there a way to merge the graphs the way i would like them?










    share|improve this question
























      up vote
      1
      down vote

      favorite









      up vote
      1
      down vote

      favorite











      I have a collection of digraphs encoded in DOT language, and i want to merge them into a single digraph where nodes with the same name in different input graphs are merged together.



      For example given the following files:



      1.dot:



      digraph {
      A -> B
      A -> C
      }


      2.dot:



      digraph {
      D -> E
      E -> F
      }


      3.dot:



      digraph {
      D -> G
      G -> A
      }


      I would like to obtain the following result.dot:



      digraph {
      subgraph {
      A -> B
      A -> C
      }
      subgraph {
      D -> E
      E -> F
      }
      subgraph {
      D -> G
      G -> A
      }
      }




      I tried to use gvpack but it renames duplicate nodes.



      > gvpack -u 1.dot 2.dot 3.dot
      Warning: node D in graph[2] %15 already defined
      Some nodes will be renamed.
      digraph root {
      node [label="N"];
      {
      node [label="N"];
      A -> B;
      A -> C;
      }
      {
      node [label="N"];
      D -> E;
      E -> F;
      }
      {
      node [label="N"];
      D_gv1 -> G;
      G -> A_gv1;
      }
      }


      I found a similar question on SO that suggest using sed to rename the renamed nodes, but that doesn't seem very clean.



      Is there a way to merge the graphs the way i would like them?










      share|improve this question













      I have a collection of digraphs encoded in DOT language, and i want to merge them into a single digraph where nodes with the same name in different input graphs are merged together.



      For example given the following files:



      1.dot:



      digraph {
      A -> B
      A -> C
      }


      2.dot:



      digraph {
      D -> E
      E -> F
      }


      3.dot:



      digraph {
      D -> G
      G -> A
      }


      I would like to obtain the following result.dot:



      digraph {
      subgraph {
      A -> B
      A -> C
      }
      subgraph {
      D -> E
      E -> F
      }
      subgraph {
      D -> G
      G -> A
      }
      }




      I tried to use gvpack but it renames duplicate nodes.



      > gvpack -u 1.dot 2.dot 3.dot
      Warning: node D in graph[2] %15 already defined
      Some nodes will be renamed.
      digraph root {
      node [label="N"];
      {
      node [label="N"];
      A -> B;
      A -> C;
      }
      {
      node [label="N"];
      D -> E;
      E -> F;
      }
      {
      node [label="N"];
      D_gv1 -> G;
      G -> A_gv1;
      }
      }


      I found a similar question on SO that suggest using sed to rename the renamed nodes, but that doesn't seem very clean.



      Is there a way to merge the graphs the way i would like them?







      graphviz dot






      share|improve this question













      share|improve this question











      share|improve this question




      share|improve this question










      asked Nov 8 at 6:32









      Gauthier

      2,3071822




      2,3071822
























          3 Answers
          3






          active

          oldest

          votes

















          up vote
          2
          down vote













          For exactly the situation you are describing, using the sample files you provide, there is a very simple answer using m4 - a standard GNU Linux tool that should be installed by default in most distributions.



          Create a file merge123.m4 with this content:



          digraph 123 {
          define(`digraph',`subgraph')
          include(1.dot)
          include(2.dot)
          include(3.dot)
          }


          and execute it with the command



          m4 merge123.m4 > 123.dot


          and the resulting 123.dot file will be



          digraph 123 {

          subgraph {
          A -> B
          A -> C
          }

          subgraph {
          D -> E
          E -> F
          }

          subgraph {
          D -> G
          G -> A
          }

          }


          If you don't like the empty lines, close each line in the script with dnl (the builtin dnl stands for “Discard to Next Line”:), for example



          include(1.dot)dnl


          m4 is extremely useful as it adds features to graphviz that are really helpful for more involved projects; see also this SO question.



          EDITED to answer the question in the comment:



          If you need to include files and don't know their number and names, you have (at least) two options:



          1) If the number of files is rather small and you know all names that they could possibly have, you can sinclude() them all:



          digraph 123 {
          define(`digraph',`subgraph')
          sinclude(1.dot)
          sinclude(2.dot)
          sinclude(3.dot)
          sinclude(4.dot)
          sinclude(5.dot)
          }


          m4 will only include the files that actually exist, and not complain about the missing ones (the s means "silent").



          2) If you produce a larger number of.dot files with unpredictable names, you will need to do some pre-processing. Create a shell script include.sh similar to this one



          #!/bin/sh
          # get *.dot files (or any pattern you like) into one place
          ls *.dot > files.txt
          # bring them into a format m4 likes
          awk '{print "include(" $1 ")" "dnl"}' files.txt > includes.txt
          #done


          includes.txt now provides m4 with the necessary information:



          include(1.dot)dnl
          include(2.dot)dnl
          include(3.dot)dnl


          Now modify your merge.m4 file, enabling it to make use of the file list provided (I'm adding dnl here to avoid lots of empty space in the resulting merged file):



          ### merge dot files
          digraph 123 {
          define(`digraph',`subgraph')dnl
          syscmd(`./include.sh')dnl
          include(`includes.txt')dnl
          }


          In order to keep the resulting file separate from the input files, better use a different extension when merging:



          m4 merge.m4 > merged.gv


          which now looks like



          ### merge dot files
          digraph 123 {
          subgraph {
          A -> B
          A -> C
          }
          subgraph {
          D -> E
          E -> F
          }
          subgraph {
          D -> G
          G -> A
          }
          }





          share|improve this answer























          • Thanks, that's interesting. Is there a way to use m4 if the number of input files as well as their names is variable?
            – Gauthier
            Nov 9 at 3:00






          • 1




            see edits in my original answer
            – vaettchen
            Nov 10 at 3:35


















          up vote
          0
          down vote













          If it's really just a minor edit of the input files joined, then perl is a natural fit:



          use strict;
          sub main {
          local $/ = undef;
          print "digraph {n";
          for my $f (@ARGV) {
          open(F, $f) or die $!;
          my $text = <F>;
          close(F);
          $text =~ s/digraph/subgraph/;
          $text =~s/^/ /mg;
          print $text;
          }
          print "}n";
          }

          main;


          Then



          $ perl merge.pl 1.dot 2.dot 3.dot
          digraph {
          subgraph {
          A -> B
          A -> C
          }
          subgraph {
          D -> E
          E -> F
          }
          subgraph {
          D -> G
          G -> A
          }
          }





          share|improve this answer




























            up vote
            0
            down vote



            accepted










            I ended up using a Java library to perform the merge, and much more!



            With the library i could easily tap into the data structure, change nodes if need be, and add attributes to the graph.



            A quick example in Kotlin:



            // prepare root graph and set direction
            val wamap = mutGraph("wamap")
            .setDirected(true)
            wamap.graphAttrs().add(RankDir.LEFT_TO_RIGHT)

            // add subgraphs from the content of .gv files from disk
            Files.walk(Paths.get("D:\src\work\Wamap"), 1)
            .filter { Files.isRegularFile(it) }
            .filter { it.fileName.toString().endsWith(".gv") }
            .map { Parser.read(it.toFile()) }
            .forEach { it.addTo(wamap) }

            // normalize node names to lowercase, to ensure nodes with same name are the same node
            wamap.graphs()
            .flatMap { it.nodes() }
            .forEach { it.setName(it.name().toString().toLowerCase()) }

            // output as file, but also render the image directly with all the possible Graphviz layout engines
            File("out/wamap.gv").writeText(wamap.toString())
            Engine.values()
            .forEach { engine ->
            Graphviz.fromGraph(wamap).engine(engine).render(Format.PNG).toFile(File("out/wamap-$engine.png"))
            }





            share|improve this answer





















              Your Answer






              StackExchange.ifUsing("editor", function () {
              StackExchange.using("externalEditor", function () {
              StackExchange.using("snippets", function () {
              StackExchange.snippets.init();
              });
              });
              }, "code-snippets");

              StackExchange.ready(function() {
              var channelOptions = {
              tags: "".split(" "),
              id: "1"
              };
              initTagRenderer("".split(" "), "".split(" "), channelOptions);

              StackExchange.using("externalEditor", function() {
              // Have to fire editor after snippets, if snippets enabled
              if (StackExchange.settings.snippets.snippetsEnabled) {
              StackExchange.using("snippets", function() {
              createEditor();
              });
              }
              else {
              createEditor();
              }
              });

              function createEditor() {
              StackExchange.prepareEditor({
              heartbeatType: 'answer',
              convertImagesToLinks: true,
              noModals: true,
              showLowRepImageUploadWarning: true,
              reputationToPostImages: 10,
              bindNavPrevention: true,
              postfix: "",
              imageUploader: {
              brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
              contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
              allowUrls: true
              },
              onDemand: true,
              discardSelector: ".discard-answer"
              ,immediatelyShowMarkdownHelp:true
              });


              }
              });














              draft saved

              draft discarded


















              StackExchange.ready(
              function () {
              StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53202550%2fmerging-graphs-in-graphviz%23new-answer', 'question_page');
              }
              );

              Post as a guest















              Required, but never shown

























              3 Answers
              3






              active

              oldest

              votes








              3 Answers
              3






              active

              oldest

              votes









              active

              oldest

              votes






              active

              oldest

              votes








              up vote
              2
              down vote













              For exactly the situation you are describing, using the sample files you provide, there is a very simple answer using m4 - a standard GNU Linux tool that should be installed by default in most distributions.



              Create a file merge123.m4 with this content:



              digraph 123 {
              define(`digraph',`subgraph')
              include(1.dot)
              include(2.dot)
              include(3.dot)
              }


              and execute it with the command



              m4 merge123.m4 > 123.dot


              and the resulting 123.dot file will be



              digraph 123 {

              subgraph {
              A -> B
              A -> C
              }

              subgraph {
              D -> E
              E -> F
              }

              subgraph {
              D -> G
              G -> A
              }

              }


              If you don't like the empty lines, close each line in the script with dnl (the builtin dnl stands for “Discard to Next Line”:), for example



              include(1.dot)dnl


              m4 is extremely useful as it adds features to graphviz that are really helpful for more involved projects; see also this SO question.



              EDITED to answer the question in the comment:



              If you need to include files and don't know their number and names, you have (at least) two options:



              1) If the number of files is rather small and you know all names that they could possibly have, you can sinclude() them all:



              digraph 123 {
              define(`digraph',`subgraph')
              sinclude(1.dot)
              sinclude(2.dot)
              sinclude(3.dot)
              sinclude(4.dot)
              sinclude(5.dot)
              }


              m4 will only include the files that actually exist, and not complain about the missing ones (the s means "silent").



              2) If you produce a larger number of.dot files with unpredictable names, you will need to do some pre-processing. Create a shell script include.sh similar to this one



              #!/bin/sh
              # get *.dot files (or any pattern you like) into one place
              ls *.dot > files.txt
              # bring them into a format m4 likes
              awk '{print "include(" $1 ")" "dnl"}' files.txt > includes.txt
              #done


              includes.txt now provides m4 with the necessary information:



              include(1.dot)dnl
              include(2.dot)dnl
              include(3.dot)dnl


              Now modify your merge.m4 file, enabling it to make use of the file list provided (I'm adding dnl here to avoid lots of empty space in the resulting merged file):



              ### merge dot files
              digraph 123 {
              define(`digraph',`subgraph')dnl
              syscmd(`./include.sh')dnl
              include(`includes.txt')dnl
              }


              In order to keep the resulting file separate from the input files, better use a different extension when merging:



              m4 merge.m4 > merged.gv


              which now looks like



              ### merge dot files
              digraph 123 {
              subgraph {
              A -> B
              A -> C
              }
              subgraph {
              D -> E
              E -> F
              }
              subgraph {
              D -> G
              G -> A
              }
              }





              share|improve this answer























              • Thanks, that's interesting. Is there a way to use m4 if the number of input files as well as their names is variable?
                – Gauthier
                Nov 9 at 3:00






              • 1




                see edits in my original answer
                – vaettchen
                Nov 10 at 3:35















              up vote
              2
              down vote













              For exactly the situation you are describing, using the sample files you provide, there is a very simple answer using m4 - a standard GNU Linux tool that should be installed by default in most distributions.



              Create a file merge123.m4 with this content:



              digraph 123 {
              define(`digraph',`subgraph')
              include(1.dot)
              include(2.dot)
              include(3.dot)
              }


              and execute it with the command



              m4 merge123.m4 > 123.dot


              and the resulting 123.dot file will be



              digraph 123 {

              subgraph {
              A -> B
              A -> C
              }

              subgraph {
              D -> E
              E -> F
              }

              subgraph {
              D -> G
              G -> A
              }

              }


              If you don't like the empty lines, close each line in the script with dnl (the builtin dnl stands for “Discard to Next Line”:), for example



              include(1.dot)dnl


              m4 is extremely useful as it adds features to graphviz that are really helpful for more involved projects; see also this SO question.



              EDITED to answer the question in the comment:



              If you need to include files and don't know their number and names, you have (at least) two options:



              1) If the number of files is rather small and you know all names that they could possibly have, you can sinclude() them all:



              digraph 123 {
              define(`digraph',`subgraph')
              sinclude(1.dot)
              sinclude(2.dot)
              sinclude(3.dot)
              sinclude(4.dot)
              sinclude(5.dot)
              }


              m4 will only include the files that actually exist, and not complain about the missing ones (the s means "silent").



              2) If you produce a larger number of.dot files with unpredictable names, you will need to do some pre-processing. Create a shell script include.sh similar to this one



              #!/bin/sh
              # get *.dot files (or any pattern you like) into one place
              ls *.dot > files.txt
              # bring them into a format m4 likes
              awk '{print "include(" $1 ")" "dnl"}' files.txt > includes.txt
              #done


              includes.txt now provides m4 with the necessary information:



              include(1.dot)dnl
              include(2.dot)dnl
              include(3.dot)dnl


              Now modify your merge.m4 file, enabling it to make use of the file list provided (I'm adding dnl here to avoid lots of empty space in the resulting merged file):



              ### merge dot files
              digraph 123 {
              define(`digraph',`subgraph')dnl
              syscmd(`./include.sh')dnl
              include(`includes.txt')dnl
              }


              In order to keep the resulting file separate from the input files, better use a different extension when merging:



              m4 merge.m4 > merged.gv


              which now looks like



              ### merge dot files
              digraph 123 {
              subgraph {
              A -> B
              A -> C
              }
              subgraph {
              D -> E
              E -> F
              }
              subgraph {
              D -> G
              G -> A
              }
              }





              share|improve this answer























              • Thanks, that's interesting. Is there a way to use m4 if the number of input files as well as their names is variable?
                – Gauthier
                Nov 9 at 3:00






              • 1




                see edits in my original answer
                – vaettchen
                Nov 10 at 3:35













              up vote
              2
              down vote










              up vote
              2
              down vote









              For exactly the situation you are describing, using the sample files you provide, there is a very simple answer using m4 - a standard GNU Linux tool that should be installed by default in most distributions.



              Create a file merge123.m4 with this content:



              digraph 123 {
              define(`digraph',`subgraph')
              include(1.dot)
              include(2.dot)
              include(3.dot)
              }


              and execute it with the command



              m4 merge123.m4 > 123.dot


              and the resulting 123.dot file will be



              digraph 123 {

              subgraph {
              A -> B
              A -> C
              }

              subgraph {
              D -> E
              E -> F
              }

              subgraph {
              D -> G
              G -> A
              }

              }


              If you don't like the empty lines, close each line in the script with dnl (the builtin dnl stands for “Discard to Next Line”:), for example



              include(1.dot)dnl


              m4 is extremely useful as it adds features to graphviz that are really helpful for more involved projects; see also this SO question.



              EDITED to answer the question in the comment:



              If you need to include files and don't know their number and names, you have (at least) two options:



              1) If the number of files is rather small and you know all names that they could possibly have, you can sinclude() them all:



              digraph 123 {
              define(`digraph',`subgraph')
              sinclude(1.dot)
              sinclude(2.dot)
              sinclude(3.dot)
              sinclude(4.dot)
              sinclude(5.dot)
              }


              m4 will only include the files that actually exist, and not complain about the missing ones (the s means "silent").



              2) If you produce a larger number of.dot files with unpredictable names, you will need to do some pre-processing. Create a shell script include.sh similar to this one



              #!/bin/sh
              # get *.dot files (or any pattern you like) into one place
              ls *.dot > files.txt
              # bring them into a format m4 likes
              awk '{print "include(" $1 ")" "dnl"}' files.txt > includes.txt
              #done


              includes.txt now provides m4 with the necessary information:



              include(1.dot)dnl
              include(2.dot)dnl
              include(3.dot)dnl


              Now modify your merge.m4 file, enabling it to make use of the file list provided (I'm adding dnl here to avoid lots of empty space in the resulting merged file):



              ### merge dot files
              digraph 123 {
              define(`digraph',`subgraph')dnl
              syscmd(`./include.sh')dnl
              include(`includes.txt')dnl
              }


              In order to keep the resulting file separate from the input files, better use a different extension when merging:



              m4 merge.m4 > merged.gv


              which now looks like



              ### merge dot files
              digraph 123 {
              subgraph {
              A -> B
              A -> C
              }
              subgraph {
              D -> E
              E -> F
              }
              subgraph {
              D -> G
              G -> A
              }
              }





              share|improve this answer














              For exactly the situation you are describing, using the sample files you provide, there is a very simple answer using m4 - a standard GNU Linux tool that should be installed by default in most distributions.



              Create a file merge123.m4 with this content:



              digraph 123 {
              define(`digraph',`subgraph')
              include(1.dot)
              include(2.dot)
              include(3.dot)
              }


              and execute it with the command



              m4 merge123.m4 > 123.dot


              and the resulting 123.dot file will be



              digraph 123 {

              subgraph {
              A -> B
              A -> C
              }

              subgraph {
              D -> E
              E -> F
              }

              subgraph {
              D -> G
              G -> A
              }

              }


              If you don't like the empty lines, close each line in the script with dnl (the builtin dnl stands for “Discard to Next Line”:), for example



              include(1.dot)dnl


              m4 is extremely useful as it adds features to graphviz that are really helpful for more involved projects; see also this SO question.



              EDITED to answer the question in the comment:



              If you need to include files and don't know their number and names, you have (at least) two options:



              1) If the number of files is rather small and you know all names that they could possibly have, you can sinclude() them all:



              digraph 123 {
              define(`digraph',`subgraph')
              sinclude(1.dot)
              sinclude(2.dot)
              sinclude(3.dot)
              sinclude(4.dot)
              sinclude(5.dot)
              }


              m4 will only include the files that actually exist, and not complain about the missing ones (the s means "silent").



              2) If you produce a larger number of.dot files with unpredictable names, you will need to do some pre-processing. Create a shell script include.sh similar to this one



              #!/bin/sh
              # get *.dot files (or any pattern you like) into one place
              ls *.dot > files.txt
              # bring them into a format m4 likes
              awk '{print "include(" $1 ")" "dnl"}' files.txt > includes.txt
              #done


              includes.txt now provides m4 with the necessary information:



              include(1.dot)dnl
              include(2.dot)dnl
              include(3.dot)dnl


              Now modify your merge.m4 file, enabling it to make use of the file list provided (I'm adding dnl here to avoid lots of empty space in the resulting merged file):



              ### merge dot files
              digraph 123 {
              define(`digraph',`subgraph')dnl
              syscmd(`./include.sh')dnl
              include(`includes.txt')dnl
              }


              In order to keep the resulting file separate from the input files, better use a different extension when merging:



              m4 merge.m4 > merged.gv


              which now looks like



              ### merge dot files
              digraph 123 {
              subgraph {
              A -> B
              A -> C
              }
              subgraph {
              D -> E
              E -> F
              }
              subgraph {
              D -> G
              G -> A
              }
              }






              share|improve this answer














              share|improve this answer



              share|improve this answer








              edited Nov 10 at 5:18

























              answered Nov 8 at 8:50









              vaettchen

              4,9751332




              4,9751332












              • Thanks, that's interesting. Is there a way to use m4 if the number of input files as well as their names is variable?
                – Gauthier
                Nov 9 at 3:00






              • 1




                see edits in my original answer
                – vaettchen
                Nov 10 at 3:35


















              • Thanks, that's interesting. Is there a way to use m4 if the number of input files as well as their names is variable?
                – Gauthier
                Nov 9 at 3:00






              • 1




                see edits in my original answer
                – vaettchen
                Nov 10 at 3:35
















              Thanks, that's interesting. Is there a way to use m4 if the number of input files as well as their names is variable?
              – Gauthier
              Nov 9 at 3:00




              Thanks, that's interesting. Is there a way to use m4 if the number of input files as well as their names is variable?
              – Gauthier
              Nov 9 at 3:00




              1




              1




              see edits in my original answer
              – vaettchen
              Nov 10 at 3:35




              see edits in my original answer
              – vaettchen
              Nov 10 at 3:35












              up vote
              0
              down vote













              If it's really just a minor edit of the input files joined, then perl is a natural fit:



              use strict;
              sub main {
              local $/ = undef;
              print "digraph {n";
              for my $f (@ARGV) {
              open(F, $f) or die $!;
              my $text = <F>;
              close(F);
              $text =~ s/digraph/subgraph/;
              $text =~s/^/ /mg;
              print $text;
              }
              print "}n";
              }

              main;


              Then



              $ perl merge.pl 1.dot 2.dot 3.dot
              digraph {
              subgraph {
              A -> B
              A -> C
              }
              subgraph {
              D -> E
              E -> F
              }
              subgraph {
              D -> G
              G -> A
              }
              }





              share|improve this answer

























                up vote
                0
                down vote













                If it's really just a minor edit of the input files joined, then perl is a natural fit:



                use strict;
                sub main {
                local $/ = undef;
                print "digraph {n";
                for my $f (@ARGV) {
                open(F, $f) or die $!;
                my $text = <F>;
                close(F);
                $text =~ s/digraph/subgraph/;
                $text =~s/^/ /mg;
                print $text;
                }
                print "}n";
                }

                main;


                Then



                $ perl merge.pl 1.dot 2.dot 3.dot
                digraph {
                subgraph {
                A -> B
                A -> C
                }
                subgraph {
                D -> E
                E -> F
                }
                subgraph {
                D -> G
                G -> A
                }
                }





                share|improve this answer























                  up vote
                  0
                  down vote










                  up vote
                  0
                  down vote









                  If it's really just a minor edit of the input files joined, then perl is a natural fit:



                  use strict;
                  sub main {
                  local $/ = undef;
                  print "digraph {n";
                  for my $f (@ARGV) {
                  open(F, $f) or die $!;
                  my $text = <F>;
                  close(F);
                  $text =~ s/digraph/subgraph/;
                  $text =~s/^/ /mg;
                  print $text;
                  }
                  print "}n";
                  }

                  main;


                  Then



                  $ perl merge.pl 1.dot 2.dot 3.dot
                  digraph {
                  subgraph {
                  A -> B
                  A -> C
                  }
                  subgraph {
                  D -> E
                  E -> F
                  }
                  subgraph {
                  D -> G
                  G -> A
                  }
                  }





                  share|improve this answer












                  If it's really just a minor edit of the input files joined, then perl is a natural fit:



                  use strict;
                  sub main {
                  local $/ = undef;
                  print "digraph {n";
                  for my $f (@ARGV) {
                  open(F, $f) or die $!;
                  my $text = <F>;
                  close(F);
                  $text =~ s/digraph/subgraph/;
                  $text =~s/^/ /mg;
                  print $text;
                  }
                  print "}n";
                  }

                  main;


                  Then



                  $ perl merge.pl 1.dot 2.dot 3.dot
                  digraph {
                  subgraph {
                  A -> B
                  A -> C
                  }
                  subgraph {
                  D -> E
                  E -> F
                  }
                  subgraph {
                  D -> G
                  G -> A
                  }
                  }






                  share|improve this answer












                  share|improve this answer



                  share|improve this answer










                  answered Nov 8 at 6:47









                  Gene

                  37.4k44273




                  37.4k44273






















                      up vote
                      0
                      down vote



                      accepted










                      I ended up using a Java library to perform the merge, and much more!



                      With the library i could easily tap into the data structure, change nodes if need be, and add attributes to the graph.



                      A quick example in Kotlin:



                      // prepare root graph and set direction
                      val wamap = mutGraph("wamap")
                      .setDirected(true)
                      wamap.graphAttrs().add(RankDir.LEFT_TO_RIGHT)

                      // add subgraphs from the content of .gv files from disk
                      Files.walk(Paths.get("D:\src\work\Wamap"), 1)
                      .filter { Files.isRegularFile(it) }
                      .filter { it.fileName.toString().endsWith(".gv") }
                      .map { Parser.read(it.toFile()) }
                      .forEach { it.addTo(wamap) }

                      // normalize node names to lowercase, to ensure nodes with same name are the same node
                      wamap.graphs()
                      .flatMap { it.nodes() }
                      .forEach { it.setName(it.name().toString().toLowerCase()) }

                      // output as file, but also render the image directly with all the possible Graphviz layout engines
                      File("out/wamap.gv").writeText(wamap.toString())
                      Engine.values()
                      .forEach { engine ->
                      Graphviz.fromGraph(wamap).engine(engine).render(Format.PNG).toFile(File("out/wamap-$engine.png"))
                      }





                      share|improve this answer

























                        up vote
                        0
                        down vote



                        accepted










                        I ended up using a Java library to perform the merge, and much more!



                        With the library i could easily tap into the data structure, change nodes if need be, and add attributes to the graph.



                        A quick example in Kotlin:



                        // prepare root graph and set direction
                        val wamap = mutGraph("wamap")
                        .setDirected(true)
                        wamap.graphAttrs().add(RankDir.LEFT_TO_RIGHT)

                        // add subgraphs from the content of .gv files from disk
                        Files.walk(Paths.get("D:\src\work\Wamap"), 1)
                        .filter { Files.isRegularFile(it) }
                        .filter { it.fileName.toString().endsWith(".gv") }
                        .map { Parser.read(it.toFile()) }
                        .forEach { it.addTo(wamap) }

                        // normalize node names to lowercase, to ensure nodes with same name are the same node
                        wamap.graphs()
                        .flatMap { it.nodes() }
                        .forEach { it.setName(it.name().toString().toLowerCase()) }

                        // output as file, but also render the image directly with all the possible Graphviz layout engines
                        File("out/wamap.gv").writeText(wamap.toString())
                        Engine.values()
                        .forEach { engine ->
                        Graphviz.fromGraph(wamap).engine(engine).render(Format.PNG).toFile(File("out/wamap-$engine.png"))
                        }





                        share|improve this answer























                          up vote
                          0
                          down vote



                          accepted







                          up vote
                          0
                          down vote



                          accepted






                          I ended up using a Java library to perform the merge, and much more!



                          With the library i could easily tap into the data structure, change nodes if need be, and add attributes to the graph.



                          A quick example in Kotlin:



                          // prepare root graph and set direction
                          val wamap = mutGraph("wamap")
                          .setDirected(true)
                          wamap.graphAttrs().add(RankDir.LEFT_TO_RIGHT)

                          // add subgraphs from the content of .gv files from disk
                          Files.walk(Paths.get("D:\src\work\Wamap"), 1)
                          .filter { Files.isRegularFile(it) }
                          .filter { it.fileName.toString().endsWith(".gv") }
                          .map { Parser.read(it.toFile()) }
                          .forEach { it.addTo(wamap) }

                          // normalize node names to lowercase, to ensure nodes with same name are the same node
                          wamap.graphs()
                          .flatMap { it.nodes() }
                          .forEach { it.setName(it.name().toString().toLowerCase()) }

                          // output as file, but also render the image directly with all the possible Graphviz layout engines
                          File("out/wamap.gv").writeText(wamap.toString())
                          Engine.values()
                          .forEach { engine ->
                          Graphviz.fromGraph(wamap).engine(engine).render(Format.PNG).toFile(File("out/wamap-$engine.png"))
                          }





                          share|improve this answer












                          I ended up using a Java library to perform the merge, and much more!



                          With the library i could easily tap into the data structure, change nodes if need be, and add attributes to the graph.



                          A quick example in Kotlin:



                          // prepare root graph and set direction
                          val wamap = mutGraph("wamap")
                          .setDirected(true)
                          wamap.graphAttrs().add(RankDir.LEFT_TO_RIGHT)

                          // add subgraphs from the content of .gv files from disk
                          Files.walk(Paths.get("D:\src\work\Wamap"), 1)
                          .filter { Files.isRegularFile(it) }
                          .filter { it.fileName.toString().endsWith(".gv") }
                          .map { Parser.read(it.toFile()) }
                          .forEach { it.addTo(wamap) }

                          // normalize node names to lowercase, to ensure nodes with same name are the same node
                          wamap.graphs()
                          .flatMap { it.nodes() }
                          .forEach { it.setName(it.name().toString().toLowerCase()) }

                          // output as file, but also render the image directly with all the possible Graphviz layout engines
                          File("out/wamap.gv").writeText(wamap.toString())
                          Engine.values()
                          .forEach { engine ->
                          Graphviz.fromGraph(wamap).engine(engine).render(Format.PNG).toFile(File("out/wamap-$engine.png"))
                          }






                          share|improve this answer












                          share|improve this answer



                          share|improve this answer










                          answered Nov 14 at 6:56









                          Gauthier

                          2,3071822




                          2,3071822






























                              draft saved

                              draft discarded




















































                              Thanks for contributing an answer to Stack Overflow!


                              • Please be sure to answer the question. Provide details and share your research!

                              But avoid



                              • Asking for help, clarification, or responding to other answers.

                              • Making statements based on opinion; back them up with references or personal experience.


                              To learn more, see our tips on writing great answers.





                              Some of your past answers have not been well-received, and you're in danger of being blocked from answering.


                              Please pay close attention to the following guidance:


                              • Please be sure to answer the question. Provide details and share your research!

                              But avoid



                              • Asking for help, clarification, or responding to other answers.

                              • Making statements based on opinion; back them up with references or personal experience.


                              To learn more, see our tips on writing great answers.




                              draft saved


                              draft discarded














                              StackExchange.ready(
                              function () {
                              StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53202550%2fmerging-graphs-in-graphviz%23new-answer', 'question_page');
                              }
                              );

                              Post as a guest















                              Required, but never shown





















































                              Required, but never shown














                              Required, but never shown












                              Required, but never shown







                              Required, but never shown

































                              Required, but never shown














                              Required, but never shown












                              Required, but never shown







                              Required, but never shown







                              這個網誌中的熱門文章

                              Academy of Television Arts & Sciences

                              L'Équipe

                              1995 France bombings