user34235: Does anyone here knows how to turn a PGN, let's say for example

1.e4 c5 2.Nf3 ( 2.c3 Nf6 ( 2...f6 3.Na3 ) 3.e5 Nd5 ) Nc6 3.d4 cxd4 4.Nxd4 ( 4.c3 ) g6

into an image? I preferably would like to put out a *.dot-file (Graphviz) that manually created looks like this in the example
digraph chess_openings {
    {
        node [shape=box];
        n1 [label="e4"]; n1-> n2;
        n2 [label="c5", style=filled]; n2 -> n3; n2 -> n4;
        n3 [label="Nf3"]; n3 -> n8;
        n4 [label="c3"]; n4 -> n5;
        n5 [label="Nf6", style=filled]; n5 -> n6;
        n6 [label="e5"]; n6 -> n7;
        n7 [label="d5", style=filled];
        n8 [label="Nc6", style=filled]; n8 -> n9;
        n9 [label="d4"]; n9 -> n10;
        n10 [label="cxd4", style=filled]; n10 -> n11;
        n11 [label="Nxd4"]; n11 -> n12;
        n12 [label="g6", style=filled];
    }
}

which Graphviz turns into that kind of image

So I'm looking for either a simple and free software that can create such graphs automatically or a script that converts a pgn-file into a dot-file. Can anyone help?

user13674: The free program DiagTransfer version 3.0.1 will make a position diagram from a pgn or epd file. Works well on Windows 10. I've used it hundreds of times to insert chess positions into word processor files or print diagrams on file cards. Has several options including adding arrows.

user34235: OMG guys! I did it. With my limited skills it took me two days to come up with a script that turn PGN of an opening to a nice graph. All you need to do is insert the PGN and run Graphviz with "dot -Tsvg graph.dot > output.svg" after running the python script.
import ast

pgn = "1.e4 c5 2.Nf3 ( 2.c3 Nf6 ( 2...f6 3.Na3 ) 3.e5 Nd5 ) Nc6 3.d4 cxd4 4.Nxd4 ( 4.c3 ) g6"

hauptzaehler = 0
knoten = []

class Node:
  def __init__(self, name, move, parent):
    self.name = name
    self.move = move
    self.is_white = None
    self.parent = parent

def pgn_to_list(pgn):
  pgn = pgn[pgn.find("1."):]
  pgn = pgn.split("*", 1)[0]
  for i in range(11,26):
    pgn = pgn.replace(str(i) + ".", "")
  for i in range(1,11):
    pgn = pgn.replace(str(i) + ".", "")
  pgn = pgn.replace(".", "")
  pgn = pgn.rstrip()
  pgn = pgn.replace(" ", "\", \"")
  pgn = pgn.replace("\"(\", ", "[")
  pgn = pgn.replace(", \")\"", "]")
  pgn = "[\"" + pgn + "\"]"
  pgn = pgn.replace(", \")\"", "]")
  feld = ast.literal_eval(pgn)
  return feld

pgn = pgn_to_list(pgn)

def mache_dicts(feld):
  global hauptzaehler
  for i in feld:
    if type(i) != list:
      feld[feld.index(i)] = {"index": hauptzaehler, "zug": i, "parent": None}
      hauptzaehler += 1
    else:
      mache_dicts(i)
  return feld

def parentify1(feld):
  for i in range(len(feld)-1,-1,-1):
    if type(feld[i]) != list:
      if (i == 0):
        feld[0]["parent"] = None
      else:
        for x in range(i-1,-1,-1):
          if type(feld[x]) != list:
            eltern = feld[x]["index"]
            feld[i]["parent"] = eltern
            break
    else:
      parentify1(feld[i])
  return None

def parentify2(feld):
  eltern0 = None
  eltern1 = None
  for i in range(0,len(feld)):
    if type(feld[i]) != list:
      eltern0 = eltern1
      eltern1 = feld[i]["index"]
    else:
      feld[i][0]["parent"] = eltern0
      parentify2(feld[i])
  return None

def knotenliste(pgn):
  global knoten
  for i in pgn:
    if type(i) != list:
      knoten.append(Node(i["index"],i["zug"],i["parent"]))
    else:
      knotenliste(i)
  return None

def get_parent(feld, parent):
  for i in feld:
    if (i.name == parent):
      return i

def einfaerben(knoten):
  for i in knoten:
    if (i.parent == None):
      i.is_white = True
    elif (get_parent(knoten, i.parent).is_white == True):
      i.is_white = False
    elif (get_parent(knoten, i.parent).is_white == False):
      i.is_white = True
  return None

def get_kinder(feld, index):
  kinder = []
  for i in feld:
    if (i.parent == index):
      kinder.append(i.name)
  kinderstring = ""
  for x in kinder:
    kinderstring = kinderstring + " n" + str(index) + " -> n" + str(x) + ";"
  return kinderstring

def write_dot(knotenfeld):
  open("graph.dot", "w").close()
  dot = open("graph.dot", "a")
  dot.write("digraph chess_openings {\n  {\n    node [shape=box];\n")
  for i in knotenfeld:
    schwarz = ""
    if (i.is_white == False):
      schwarz = ", style=filled"
    dot.write("    n" + str(i.name) + "[label=\"" + i.move + "\"" + schwarz + "];" + get_kinder(knotenfeld, i.name) + "\n")
  dot.write("  }\n}")
  dot.close()
  return None

pgn = mache_dicts(pgn)
parentify1(pgn)
parentify2(pgn)
knotenliste(pgn)
for i in range(0,len(knoten)):
  einfaerben(knoten)
write_dot(knoten)


34235: <p>Does anyone here knows how to turn a PGN, let's say for example</p>
<blockquote>
<p>1.e4 c5 2.Nf3 ( 2.c3 Nf6 ( 2...f6 3.Na3 ) 3.e5 Nd5 ) Nc6 3.d4 cxd4 4.Nxd4 ( 4.c3 ) g6</p>
</blockquote>
<p>into an image? I preferably would like to put out a *.dot-file (Graphviz) that manually created looks like this in the example</p>
<pre><code>digraph chess_openings {
    {
        node [shape=box];
        n1 [label=&quot;e4&quot;]; n1-&gt; n2;
        n2 [label=&quot;c5&quot;, style=filled]; n2 -&gt; n3; n2 -&gt; n4;
        n3 [label=&quot;Nf3&quot;]; n3 -&gt; n8;
        n4 [label=&quot;c3&quot;]; n4 -&gt; n5;
        n5 [label=&quot;Nf6&quot;, style=filled]; n5 -&gt; n6;
        n6 [label=&quot;e5&quot;]; n6 -&gt; n7;
        n7 [label=&quot;d5&quot;, style=filled];
        n8 [label=&quot;Nc6&quot;, style=filled]; n8 -&gt; n9;
        n9 [label=&quot;d4&quot;]; n9 -&gt; n10;
        n10 [label=&quot;cxd4&quot;, style=filled]; n10 -&gt; n11;
        n11 [label=&quot;Nxd4&quot;]; n11 -&gt; n12;
        n12 [label=&quot;g6&quot;, style=filled];
    }
}
</code></pre>
<p>which Graphviz turns into that kind of image</p>
<p><a href="https://i.stack.imgur.com/1bYDn.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/1bYDn.png" alt="enter image description here" /></a></p>
<p>So I'm looking for either a simple and free software that can create such graphs automatically or a script that converts a pgn-file into a dot-file. Can anyone help?</p>
 13674: <p>The free program DiagTransfer version 3.0.1 will make a position diagram from a pgn or epd file. Works well on Windows 10. I've used it hundreds of times to insert chess positions into word processor files or print diagrams on file cards. Has several options including adding arrows.</p>
 34235: <p>OMG guys! I did it. With my limited skills it took me two days to come up with a script that turn PGN of an opening to a nice graph. All you need to do is insert the PGN and run Graphviz with &quot;dot -Tsvg graph.dot &gt; output.svg&quot; after running the python script.</p>
<pre><code>import ast

pgn = &quot;1.e4 c5 2.Nf3 ( 2.c3 Nf6 ( 2...f6 3.Na3 ) 3.e5 Nd5 ) Nc6 3.d4 cxd4 4.Nxd4 ( 4.c3 ) g6&quot;

hauptzaehler = 0
knoten = []

class Node:
  def __init__(self, name, move, parent):
    self.name = name
    self.move = move
    self.is_white = None
    self.parent = parent

def pgn_to_list(pgn):
  pgn = pgn[pgn.find(&quot;1.&quot;):]
  pgn = pgn.split(&quot;*&quot;, 1)[0]
  for i in range(11,26):
    pgn = pgn.replace(str(i) + &quot;.&quot;, &quot;&quot;)
  for i in range(1,11):
    pgn = pgn.replace(str(i) + &quot;.&quot;, &quot;&quot;)
  pgn = pgn.replace(&quot;.&quot;, &quot;&quot;)
  pgn = pgn.rstrip()
  pgn = pgn.replace(&quot; &quot;, &quot;\&quot;, \&quot;&quot;)
  pgn = pgn.replace(&quot;\&quot;(\&quot;, &quot;, &quot;[&quot;)
  pgn = pgn.replace(&quot;, \&quot;)\&quot;&quot;, &quot;]&quot;)
  pgn = &quot;[\&quot;&quot; + pgn + &quot;\&quot;]&quot;
  pgn = pgn.replace(&quot;, \&quot;)\&quot;&quot;, &quot;]&quot;)
  feld = ast.literal_eval(pgn)
  return feld

pgn = pgn_to_list(pgn)

def mache_dicts(feld):
  global hauptzaehler
  for i in feld:
    if type(i) != list:
      feld[feld.index(i)] = {&quot;index&quot;: hauptzaehler, &quot;zug&quot;: i, &quot;parent&quot;: None}
      hauptzaehler += 1
    else:
      mache_dicts(i)
  return feld

def parentify1(feld):
  for i in range(len(feld)-1,-1,-1):
    if type(feld[i]) != list:
      if (i == 0):
        feld[0][&quot;parent&quot;] = None
      else:
        for x in range(i-1,-1,-1):
          if type(feld[x]) != list:
            eltern = feld[x][&quot;index&quot;]
            feld[i][&quot;parent&quot;] = eltern
            break
    else:
      parentify1(feld[i])
  return None

def parentify2(feld):
  eltern0 = None
  eltern1 = None
  for i in range(0,len(feld)):
    if type(feld[i]) != list:
      eltern0 = eltern1
      eltern1 = feld[i][&quot;index&quot;]
    else:
      feld[i][0][&quot;parent&quot;] = eltern0
      parentify2(feld[i])
  return None

def knotenliste(pgn):
  global knoten
  for i in pgn:
    if type(i) != list:
      knoten.append(Node(i[&quot;index&quot;],i[&quot;zug&quot;],i[&quot;parent&quot;]))
    else:
      knotenliste(i)
  return None

def get_parent(feld, parent):
  for i in feld:
    if (i.name == parent):
      return i

def einfaerben(knoten):
  for i in knoten:
    if (i.parent == None):
      i.is_white = True
    elif (get_parent(knoten, i.parent).is_white == True):
      i.is_white = False
    elif (get_parent(knoten, i.parent).is_white == False):
      i.is_white = True
  return None

def get_kinder(feld, index):
  kinder = []
  for i in feld:
    if (i.parent == index):
      kinder.append(i.name)
  kinderstring = &quot;&quot;
  for x in kinder:
    kinderstring = kinderstring + &quot; n&quot; + str(index) + &quot; -&gt; n&quot; + str(x) + &quot;;&quot;
  return kinderstring

def write_dot(knotenfeld):
  open(&quot;graph.dot&quot;, &quot;w&quot;).close()
  dot = open(&quot;graph.dot&quot;, &quot;a&quot;)
  dot.write(&quot;digraph chess_openings {\n  {\n    node [shape=box];\n&quot;)
  for i in knotenfeld:
    schwarz = &quot;&quot;
    if (i.is_white == False):
      schwarz = &quot;, style=filled&quot;
    dot.write(&quot;    n&quot; + str(i.name) + &quot;[label=\&quot;&quot; + i.move + &quot;\&quot;&quot; + schwarz + &quot;];&quot; + get_kinder(knotenfeld, i.name) + &quot;\n&quot;)
  dot.write(&quot;  }\n}&quot;)
  dot.close()
  return None

pgn = mache_dicts(pgn)
parentify1(pgn)
parentify2(pgn)
knotenliste(pgn)
for i in range(0,len(knoten)):
  einfaerben(knoten)
write_dot(knoten)
</code></pre>
