Source code for ue_solver.conversions

from __future__ import absolute_import, division, print_function
from future.builtins.misc import input
from ue_solver.utils import check_savepath
import networkx as nx
from networkx.readwrite import json_graph
import geopandas as gpd
import pandas as pd
import numpy as np
import json
import csv


########################Networkx_to_geojson########################
[docs]def networkx_to_geojson(graph_f, geojson_outf, simple_geom=False): ''' Converts graph_f (a networkx graph) into a pandas DataFrame, then converts the DataFrame into a geoJSON file :graph_f: networkx file :geojson_outf: file to write to :simple_geom: set to True if user wants to use less memory by only saving straight-line paths between origin and destination, rather than actual shape of path ''' df = networkx_to_df(graph_f, simple_geom) df_to_geoJson(df, geojson_outf)
def networkx_to_df(graph, simple_geom = False): if type(graph) == str: with open (graph) as f: data = json.load(f) network_g = json_graph.node_link_graph(data) else: network_g = graph # with open (networkx_f) as f: # network_g = json.load(f) # create links and nodes dataframes n_links = len(network_g.edges()) links = {} for key in network_g.edges(data=True)[0][-1].keys(): attr = list(network_g.edges_iter(data=key, default=None)) links[key] = [i[-1] for i in attr] #New fix because was getting an error here: # links[key] = [network_g.edges(data=True)[i][2][key] # if key in network_g.edges(data=True)[i][2].keys() # else 'None' for i in range(n_links)] links_df = pd.DataFrame.from_dict(links) if simple_geom: links_df = links_df.apply(simple_geom_fn, axis = 1) return links_df def simple_geom_fn(row): row['geom'] = [row['geom'][0], row['geom'][-1]] return row ########################DF_to_geojson######################## def begin_feature(type): string = ' "type": "Feature",\n "geometry": {\n' begin_coord = ' "coordinates": [\n' return string + ' "type": "{}",\n'.format(type) + begin_coord def coord(lat,lon,type): if type == "LineString": return ' [{}, {}],\n'.format(lon,lat) if type == "Point": return ' [{}, {}]'.format(lon,lat) def linestr(linestr,type): if type == "LineString": return ' {},\n'.format(linestr) # if type == "Point": return ' [{}, {}]'.format(lon,lat) def end_prop(next): if next: return ' }},{\n' return ' }}]\n' def prop(name, value): if type(value).__name__ in ["str", "unicode"]: return ' "{}": "{}",\n'.format(name, value) return ' "{}": {},\n'.format(name, value)
[docs]def df_to_geoJson(df, geojson_fileout, with_flow=False): ''' df: type regular pandas dataframe (rather than a geopandas df), but it must have a geom column containing a list of coordinates for the line or linestring: [[lon0, lat0],[lon1,lat1],...] all other columns in the dataframe will be converted to properties in the geojson file. geojson_fileout: type str, file path for out file ''' begin = ' {"type": "FeatureCollection",\n "features": [{ \n' begin_prop = ' ]},\n "properties": {\n' type = 'LineString' out = begin for i in df.index.tolist(): #(len(df)): out += begin_feature(type) geom = df.loc[i]['geom'] for g in geom: out += coord(g[1], g[0], type) out += begin_prop property_list = list(df.columns) property_list.remove('geom') for p in property_list: out += prop(p, df.loc[i][p]) if i < df.index.tolist()[-1]: out += end_prop(next = True) else: out += end_prop(next = False) out += '\n' out+= '}' with open(geojson_fileout, 'w') as f: f.write(out) ########################Geojson_to_networkx########################
def geojson_to_networkx(geojson_f, graph_f=None, indices = ['osm_init','osm_term']): geof = gpd.GeoDataFrame.from_file(geojson_f) edge_tuples = [tuple(edge) for edge in geof[indices].values] geof['key'] = 0 geof = geof.set_index(indices+['key']) geo_dict = geof.to_dict() # construct networkx graph from geojson G=nx.MultiDiGraph() G.add_edges_from(edge_tuples) # create a node dict from osm_id to network node id: # print {k: {'nid': k} for k in geof.index} if 'init' in indices: node_dict={k[0]: {'nid': k[0]} for k in geof.index} else: node_dict={k[0]: {'nid': v} for (k, v) in geo_dict['init'].items()} if 'term' in indices: node_dict2={k[1]: {'nid': k[1]} for k in geof.index} else: node_dict2={k[1]: {'nid': v} for (k, v) in geo_dict['term'].items()} node_dict.update(node_dict2) geo_dict[indices[0]] = {} geo_dict[indices[1]] = {} for link in list(geo_dict.values())[0].keys(): geo_dict[indices[0]][link] = link[0] geo_dict[indices[1]][link] = link[1] for key0 in geo_dict.keys(): for key,value in geo_dict[key0].items(): if value is None: geo_dict[key0][key] = "None" for key in geo_dict.keys(): if key != 'geometry': nx.set_edge_attributes(G, key, geo_dict[key]) else: geoms = {} for e in geo_dict['geometry'].keys(): geoms[e] = np.vstack(geo_dict['geometry'][e].xy).T.tolist() node_dict[e[0]]['coords'] = geoms[e][0] node_dict[e[1]]['coords'] = geoms[e][-1] nx.set_edge_attributes(G, 'geom', geoms) for node in G.nodes_iter(): G.node[node] = node_dict[node] if graph_f != None: save_graph(G, graph_f) return G ########################Save_graph_and_network_files######################## #custom encoder from http://stackoverflow.com/questions/27050108/convert-numpy-type-to-python/27050186#27050186 class MyEncoder(json.JSONEncoder): def default(self, obj): if isinstance(obj, np.integer): return int(obj) elif isinstance(obj, np.floating): return float(obj) elif isinstance(obj, np.ndarray): return obj.tolist() else: return super(MyEncoder, self).default(obj) def save_graph(G, filepath): data = json_graph.node_link_data(G) # dump json to a file save_results = check_savepath(filepath) if save_results: with open(filepath, 'w') as outfile: json.dump(data, fp = outfile, cls = MyEncoder)
[docs]def graph_to_network_file(graph, filepath): ''' Writes networkx traffic graph to a text file according to the FW program requirements. Format is '~ Init/Term/Cap/Length/FreeFlowTime/B=0.15/Power=4/Speed limit/Toll/Type;' tab delineated, with meta-data. :param G = networkx graph :param filename is a string, path of the place where the graph file should be saved ''' if type(graph) == str: with open (graph) as f: data = json.load(f) G = json_graph.node_link_graph(data) else: G = graph with open(filepath, 'w') as outfile: f = csv.writer(outfile, delimiter='\t') f.writerow(['<NUMBER OF ZONES> 1']) f.writerow(['<NUMBER OF NODES> ' + str(len(G.nodes()))]) f.writerow(['<FIRST THRU NODE> 1']) f.writerow(['<NUMBER OF LINKS> ' + str(len(G.edges()))]) f.writerow(['<END OF METADATA>']) f.writerow(['~ Init/Term/Cap/Length/FreeFlowTime/B=0.15/Power=4/Speed limit/Toll/Type']) #for i,j in G.edges_iter(): for i,j,data in sorted(G.edges(data=True), key = lambda x: (x[2]['init'], x[2]['term'])): try: row = [G.edge[i][j][0][x] for x in ['init', 'term', 'capacity', 'length', 'fftt', 'B', 'power', 'freeflow_speed', 'toll', 'type']] except KeyError: row = [G.edge[i][j][x] for x in ['init', 'term', 'capacity', 'length', 'fftt', 'B', 'power', 'freeflow_speed', 'toll', 'type']] if not row[-1].endswith(';'): row[-1] += ';' f.writerow(row)