0

I am trying to read a GML (graph modelling language) file from networkX, but it returns a ParseError.

I just wrote a couple of lines of code:

import networkx as nx
G = nx.read_gml('test.gml')
print G.node

This is the GML file:

graph [
  directed 1
  node [
    id 0
    label 1
    shape 
    name "square"
    center (132, 258)
  ]
  node [
    id 1
    label 2
    shape 
    name "triangle"
    center (132, 128)
  ]
  edge [
    source 0
    target 1
    relation "below"
  ]
  edge [
    source 1
    target 0
    relation "above"
  ]
]

And this is the error I got:

ParseException: Expected "]" (at char 23), (line:3, col:3)

However, I don't see any ] missing

John Powell
  • 12,253
  • 6
  • 59
  • 67
Francesco Sgaramella
  • 1,009
  • 5
  • 21
  • 39

1 Answers1

3

Immediate Problem

The parser is getting confused with your input. I have never used gml before but I built your gml file up one piece at a time and found two problems.

  1. the shape key with no value
  2. the keys that have tuple-like values (132, 258)

Assuming that this reference is correct, there are 4 possible value types:

A value may have one out of four possible types, an integer (type gml$ _$int), a double (type gml$ _$double), a string (type gml$ _$string), or a list of GML objects (type gml$ _$list).

Therefore (132, 258) is not valid and I believe having no value also would not be valid.

Try the below commented-out gml and it will load.

graph [
  directed 1
  node [
    id 0
    label 1
    #shape 
    name "square"
    #center (132, 258)
  ]
  node [
    id 1
    label 2
    #shape 
    name "triangle"
    #center (132, 128)
  ]
  edge [
    source 0
    target 1
    relation "below"
  ]
  edge [
    source 1
    target 0
    relation "above"
  ]
]

Alternative Solution

I found somewhere that nx.write_gml does not support mixed graphs including nested graphs. So even if you are creating the graph correctly, it's not going to write it correctly to a file.

Here is an alternative flat structure that will write although I don't know if this is a good way to structure the data. It makes labels that can be constructed to identify the corners of each shape.

import networkx as nx

dg = nx.DiGraph()

# square data
square_label = '0'
square_corners = [(0, 0), (0, 1), (1, 1), (1, 0)]

# main square node
dg.add_node(square_label, name='square')
# shape data for square
base_id = '{0}.corners.'.format(square_label)
last_corner_id = '{0}{1}'.format(base_id, len(square_corners)-1)
for i, corner in enumerate(square_corners):
    x, y = corner
    corner_id = '{0}{1}'.format(base_id, i)
    dg.add_node(corner_id, x=x, y=y)
    # instead of linking the square to every corner, you might want to link
    # only to one corner and handle the cycle with edges between the corners
    # or whatever. there are many ways it could be done I guess.
    dg.add_edge(square_label, corner_id)  # link from square to each corner
    dg.add_edge(last_corner_id, corner_id)  # corner to corner edges
    last_corner_id = corner_id

nx.write_gml(dg, 'test.gml')

output:

graph [
  directed 1
  node [
    id 1
    label "0"
    name "square"
  ]
  node [
    id 0
    label "0.corners.1"
    y 1
    x 0
  ]
  node [
    id 2
    label "0.corners.3"
    y 0
    x 1
  ]
  node [
    id 3
    label "0.corners.2"
    y 1
    x 1
  ]
  node [
    id 4
    label "0.corners.0"
    y 0
    x 0
  ]
  edge [
    source 0
    target 3
  ]
  edge [
    source 1
    target 0
  ]
  edge [
    source 1
    target 4
  ]
  edge [
    source 1
    target 2
  ]
  edge [
    source 1
    target 3
  ]
  edge [
    source 2
    target 4
  ]
  edge [
    source 3
    target 2
  ]
  edge [
    source 4
    target 0
  ]
]
KobeJohn
  • 7,390
  • 6
  • 41
  • 62
  • centers of shapes are not a problem since I can delete them from the graph. I don't need them in the GML file. While shape is really important. It is a subgraph of the corner points composing the shape saved as node. In the main python program, I save a node called "triangle" with shape having a subgraph of the corner points. So I don't know why it is not saved into the GML file. `G.add_node(count, name = 'triangle', shape=tr)` where `tr = tr.subgraph(['p1','p2','p3'])` is what I do. Myabe it's wrong, I don't know. – Francesco Sgaramella Feb 27 '14 at 15:05
  • what is `tr` in `tr.subgraph(...)`? Unless it is one of the 4 types I wrote above, I'm pretty sure that is invalid. Do you actually want to put a subgraph within the triangle node? I think you have to do a separate `G1.add_node(G2, ...)` to do that. – KobeJohn Feb 27 '14 at 15:25
  • Imagine different layers of a hierarchy: at the top level there should be a graph G containing just the shape's name (nodes) and the relations between them (edges). At bottom level there should be as many graphs as the number of shapes. Each of those graphs should contain the corner points of the shapes as nodes and the lines connecting them as edges. So that is why I made `G` as the main graph and `tr` as the graph containing the corner points of the triangle. – Francesco Sgaramella Feb 27 '14 at 15:31
  • Right. And I think that is not the right way to do it although I am not sure. If I understand correctly, you are trying to add a subgraph as an attribute but you need to add it explicitly as a subgraph. Instead of `G.add_node(...shape=vertices)` you need `G.add_node(vertices)` where `vertices` is a new graph. HOWEVER, please see the edit regarding nested graphs. – KobeJohn Feb 27 '14 at 16:09