matejker/everystreet

Possibility to save gpx

Closed this issue ยท 15 comments

Possibility to save gpx

Hi bartsaintgermain!,

Thanks for raising an issue! The file is in XML format so all you need to do is to hit Ctrl + S as save it as e.g. .gpx.

I tried to add download flied to do <a> as is recommended. Unfortunately, it is not working and I assume because the GPX file isn't on the same domain ๐Ÿ‘‡

[path] that resolves to an URL on the same origin. That means the page and the file must share the same domain, subdomain, protocol (HTTP vs. HTTPS), and port (if specified). Exceptions are blob: and data: (which always work), and file: (which never works). (https://stackoverflow.com/a/18678698)

In the next release, I will try to take deeper look into :)

Matej

Is this also possible when running locally. I did succeed in generating the png files but could not find the gpx/xml file.

Hmm, interesting. It is created as XML file so when you download it, you should get XML and not png.

I have the same question. If I download the python code and run the program locally I can generate the .png's given in the example of "The Grange". However, the code as given does not generate a .gpx file. The website generates a .gpx file so it must be possible to generate one. How can we generate a .gpx in the vein of the code example you provide. Thanks.

I think that understand your question now. Sure, the jupyter notebook / the Grange example doesn't have the .gpx output.
You can do it simply by converting networkx nodes into geo coordinates, e.g. using this function convert_final_path_to_coordinates(org_graph, final_path) and using a newly added gpx_formatter.py. Putting all together, you can try something like:

from libs.tools import *
from libs.gpx_formatter import TEMPLATE, TRACE_POINT

... 

# List all edges of the extended graph including original edges and edges from minimal matching
single_edges = [(u, v) for u, v, k in graph.edges]
added_edges = get_shortest_paths(graph, matched_edges_with_weights)
edges = map_osmnx_edges2integers(graph, single_edges + added_edges)

# Finds the Eulerian path
network = Network(len(graph.nodes), edges, weighted=True)
eulerian_path = hierholzer(network)
converted_eulerian_path = convert_integer_path2osmnx_nodes(eulerian_path, graph.nodes())
double_edge_heap = get_double_edge_heap(org_graph)

# Finds the final path with edge IDs
final_path = convert_path(graph, converted_eulerian_path, double_edge_heap)
coordinates_path = convert_final_path_to_coordinates(org_graph, final_path)

# Route statistics from OSMnx 
ex = ox.extended_stats(org_graph, ecc=True)
center_node = org_graph.nodes[ex["center"][0]]

trace_points = "\n\t\t\t".join([TRACE_POINT.format(
    lat=lat, lon=lon, id=i, timestamp=datetime.now().isoformat()
) for i, (lat, lon) in enumerate(coordinates_path)])

gpx_payload = TEMPLATE.format(
    name="Name your everystreet route",
    trace_points=trace_points,
    center_lat=center_node["y"],
    center_lon=center_node["x"]
)

with open("gpx_output.gpx", "w") as f:
    f.write(gpx_payload)

I believe this could work ๐Ÿ˜„

Thank you so much! That works great. The .xml format doesn't play nice with the mapping software I am using, but plugging it into this website : https://mygeodata.cloud/converter/mapfactor-to-gpx generates a .gpx file that works.
I also had to use datetime.now() -> datetime.datetime.now().

Glad to hear that! Oh yeah, I could name it open("gpx_output.gpx", "w") and it would work.
BTW, did you know that you can generate the GPX file on http://www.everystreetchallenge.com?

Thx.
Would be great to generate from site but quickly hit on 3km2 limit.

I agree that the 3km^2 limit is annoying, on the other hand I think you will understand it is a webserver and the algorithm is a bit "heavy" ๐Ÿ˜„

Maybe different question, I guess you have tried to find a route on larger area and you saw that it takes a while, it is basically undoable to generate larger areas such as whole cities. I tired to generate Edinburgh and after an hour I had to kill it. I believe that some optimisation (such as multiprocessing) could help. What would be a decent area size for you as a user? Or what is the area that you are trying to generate?

sure, I fully understand the limit.

my area is about 50m2 but mostly rural area. I guess the number of streets and intersections are also determining the complexity.

Yeah, the area it self isn't a problem, even the number of nodes / edges, but the issue are odd-degree nodes. I thought, it might be simpler to and easier to understand to restrict it based on the area size than based on the number of odd-degree nodes.

1J2B commented

Hello @matejker,
Your job on that CPP is great, thanks a lot ! However, I've tried many things to save the route as GPX on www.everystreetchallenge.com (ctrl+s, save as, source code display, both on PC & MAC, etc.), but I cannot get anything else than HTML or TXT. Did I miss something ? Because that wold be SO useful !
JB

did you know that you can generate the GPX file on http://www.everystreetchallenge.com?

I think that functionality might be broken? At least just like @1J2B I can't seem to find a way to export the result.

I think that understand your question now. Sure, the jupyter notebook / the Grange example doesn't have the .gpx output. You can do it simply by converting networkx nodes into geo coordinates, e.g. using this function convert_final_path_to_coordinates(org_graph, final_path) and using a newly added gpx_formatter.py. Putting all together, you can try something like:

from libs.tools import *
from libs.gpx_formatter import TEMPLATE, TRACE_POINT

... 

# List all edges of the extended graph including original edges and edges from minimal matching
single_edges = [(u, v) for u, v, k in graph.edges]
added_edges = get_shortest_paths(graph, matched_edges_with_weights)
edges = map_osmnx_edges2integers(graph, single_edges + added_edges)

# Finds the Eulerian path
network = Network(len(graph.nodes), edges, weighted=True)
eulerian_path = hierholzer(network)
converted_eulerian_path = convert_integer_path2osmnx_nodes(eulerian_path, graph.nodes())
double_edge_heap = get_double_edge_heap(org_graph)

# Finds the final path with edge IDs
final_path = convert_path(graph, converted_eulerian_path, double_edge_heap)
coordinates_path = convert_final_path_to_coordinates(org_graph, final_path)

# Route statistics from OSMnx 
ex = ox.extended_stats(org_graph, ecc=True)
center_node = org_graph.nodes[ex["center"][0]]

trace_points = "\n\t\t\t".join([TRACE_POINT.format(
    lat=lat, lon=lon, id=i, timestamp=datetime.now().isoformat()
) for i, (lat, lon) in enumerate(coordinates_path)])

gpx_payload = TEMPLATE.format(
    name="Name your everystreet route",
    trace_points=trace_points,
    center_lat=center_node["y"],
    center_lon=center_node["x"]
)

with open("gpx_output.gpx", "w") as f:
    f.write(gpx_payload)

I believe this could work ๐Ÿ˜„

Hi Thanks for this fun tool.
In order to get this GPX output i had to (in addition to install scipy):

  1. add "import datetime"
  2. add an extra "datetime." to get the following:
    lat=lat, lon=lon, id=i, timestamp=datetime.datetime.now().isoformat()

find an example (replace .txt by .ipynb)
example.txt

Function extended_stats was deprecated for a while before it was eventually removed.

use NetworkX :

from libs.gpx_formatter import TEMPLATE, TRACE_POINT
from datetime import datetime
...
# List all edges of the extended graph including original edges and edges from minimal matching
single_edges = [(u, v) for u, v, k in graph.edges]
added_edges = get_shortest_paths(graph, matched_edges_with_weights)
edges = map_osmnx_edges2integers(graph, single_edges + added_edges)

# Finds the Eulerian path
network = Network(len(graph.nodes), edges, weighted=True)
eulerian_path = hierholzer(network)
converted_eulerian_path = convert_integer_path2osmnx_nodes(eulerian_path, graph.nodes())
double_edge_heap = get_double_edge_heap(org_graph)

# Finds the final path with edge IDs
final_path = convert_path(graph, converted_eulerian_path, double_edge_heap)
coordinates_path = convert_final_path_to_coordinates(org_graph, final_path)

eccentricity = nx.eccentricity(graph)
center = nx.center(graph)
center_node = graph.nodes[center[0]]

trace_points = "\n\t\t\t".join([TRACE_POINT.format(
    lat=lat, lon=lon, id=i, timestamp=datetime.now().isoformat()
) for i, (lat, lon) in enumerate(coordinates_path)])

gpx_payload = TEMPLATE.format(
    name="Name your everystreet route",
    trace_points=trace_points,
    center_lat=center_node["y"],
    center_lon=center_node["x"]
)

with open("gpx_output.gpx", "w") as f:
    f.write(gpx_payload)