0

I want to be able to export a graph made by OSMnx (in other words, NetworkX graph) into CSV and to call it back later. Couldn't find any good way to do that so I try to export it into Numpy / Pandas and to export that. So I built this little example:

import networkx as nx
import osmnx as ox
G = ox.graph_from_place('Bar Ilan University, Israel')
F = nx.to_numpy_matrix(G)
G = nx.from_numpy_matrix(F, create_using=nx.MultiDiGraph)
ox.plot.plot_graph(G)

and it returns this error and nothing seems to help:

--------------------------------------------------------------------------- TypeError Traceback (most recent call last) in 4 F = nx.to_numpy_matrix(G) 5 G = nx.from_numpy_matrix(F, create_using=nx.MultiDiGraph) ----> 6 ox.plot.plot_graph(G)

~\Anaconda3\envs\ox\lib\site-packages\osmnx\plot.py in plot_graph(G, bbox, fig_height, fig_width, margin, axis_off, equal_aspect, bgcolor, show, save, close, file_format, filename, dpi, annotate, node_color, node_size, node_alpha, node_edgecolor, node_zorder, edge_color, edge_linewidth, edge_alpha, use_geom) 353 354 log('Begin plotting the graph...') --> 355 node_Xs = [float(x) for _, x in G.nodes(data='x')] 356 node_Ys = [float(y) for _, y in G.nodes(data='y')] 357

~\Anaconda3\envs\ox\lib\site-packages\osmnx\plot.py in (.0) 353 354 log('Begin plotting the graph...') --> 355 node_Xs = [float(x) for _, x in G.nodes(data='x')] 356 node_Ys = [float(y) for _, y in G.nodes(data='y')] 357

TypeError: float() argument must be a string or a number, not 'NoneType'

  • What can I do?
  • Is there is any simple method that I'm missing?
Guy
  • 161
  • 1
  • 1
  • 8

2 Answers2

2

The osmnx graph's nodes look like this:

G.nodes(data=True)

NodeDataView({970069268: {'y': 32.0682358, 'x': 34.841011, 'osmid': 970069268}, 970069273: {'y': 32.0722176, 'x': 34.8442006, 'osmid': 970069273}, 970069285: {'y': 32.0695886, 'x': 34.8419506, 'osmid': 970069285, 'highway': 'mini_roundabout'},
[...]
})

Converting this graph into an adjacency matrix retains only the information about which nodes are connected, not about where the individual nodes are positioned, nor about any other attributes. So, the graph created from the adjacency matrix looks like this:

G.nodes(data=True)

out:
NodeDataView({0: {}, 1: {}, 2: {}, 3: {}, 4: {}, 5: {}, 6: {}, 7: {}, 8: {}, 9: {}, 10: {}, 
[...]
})

The osmnx plotting function tries to retrieve the position information:

node_Xs = [float(x) for _, x in G.nodes(data="x")]

but gets None, which is not the expected format, hence the error.

what you could do:

save the node info to csv:

def nodes_to_csv(G, savepath):
    unpacked = [pd.DataFrame({**{'node': node, **data}}, index=[i]) for i, (node, data) in enumerate(G.nodes(data=True))]
    df = pd.concat(unpacked)
    df.to_csv(savepath)
    return df

def nodes_from_csv(path):
    df = pd.read_csv(path, index_col=0)
    nodes = []
    
    for ix , row in df.iterrows():
        d = dict(row)
        node = d.pop('node')
        nodes.append((node, {k:v for k,v in d.items() if v}))
        
    return nodes

#saving and retrieving:
nodes_to_csv(G, 'test.csv')
nodes = nodes_from_csv('test.csv')

# saving the adjacency info is more conveniently done with
# to_pandas_edgelist, because to_numpy_matrix loses the node 
# names as well.
adj_matrix = nx.to_pandas_edgelist(G)


# graph construction:
H = nx.from_pandas_edgelist(adj_matrix, create_using=nx.MultiDiGraph)
H.update(nodes=nodes) # adds node info

# osmnx stores metadata in the .graph attribute
# the plotting function accesses that, so in order
# to use the plotting function, 
# you need to also transfer metadata:
q = G.graph.copy()
H.graph=q

ox.plot.plot_graph(H)
warped
  • 8,947
  • 3
  • 22
  • 49
  • Sorry for late response! During the process updating my code using yours there where some problems but the general logic worked and help me a lot. I'm sure that anyone who will need it will find it easy to apply. Thank you very much!! – Guy Sep 05 '20 at 20:44
1

@warped gave a thorough answer on how to serialize to/from CSV. To take another perspective, if your goal is merely to serialize to/from disk and the file format (ie, CSV) is not essential, then consider using OSMnx's save_graphml and load_graphml functions.

gboeing
  • 5,691
  • 2
  • 15
  • 41