Five NMVFO volunteers and five NMWild new-hires met at Tres Piedras Ranger Station to be certified as crosscut sawyers, in a two-day class taught by Craig, Jennifer, and Courtney from the Carson National Forest. The first day of the new USFS curriculum is theory, presented as Powerpoint with embedded videos.
Volunteers car-camped at nearby 64-G dispersed camping area.
The next day was all field instruction and evaluation.
A big thanks goes out to our instructors with the Carson, and volunteers for dedicating time to level-up and maintain their trail skills.
In a previous article we showed how to extract a rudimentary databook from a route on a OSMnx graph. Now let us see how we can improve the output.
Reversing Simplify
One problem noticed since that article is that the OSMnx simplify_graph() function that removes 2nodes can cause trail names to be concatenated together, making it hard to know what trail you are supposed to be on. Another issue is that we want to list in our databook each time a trail crosses a road or another trail, and that information was lost when we simplified and removed 1nodes.
After simplify_graph(), here is an example of a ‘name’ attribute on a trail section (edge):
Cooney Canyon Trail (201),Cooney Canyon/Mineral Creek Trail,McKean
These concatenated names are also displayed on our map when you hover over trails, and also on my tracks that I exported for use by a GPS app.
The simplify_graph() function has an argument that preserves all the node pairs in a simplified edge, saving them in the edge attribute ‘merged_edges‘. From the node pairs we should be able to go back to the original graph and “desimplify” to see all individual trail segments before they are concatenated together.
for u,v,k,d in J.edges(keys=True,data=True):
if 'merged_edges' in d:
merged_edges = d['merged_edges']
else:
merged_edges = [ [u,v] ]
if len(merged_edges)==0:
continue
for s,t in merged_edges:
if GTR.has_edge(s,t):
for kg in GTR[s][t]: #fix improve
dat = GTR[s][t][kg]
K.add_edge(s,t,key=None,**dat)
break
elif GTR.has_edge(t,s): # in case 1-way divided street around Silver City
for kg in GTR[t][s]: #fix improve
dat = GTR[t][s][kg]
K.add_edge(t,s,key=None,**dat)
break
else:
print('FATAL ERROR WITH MERGED EDGES',s,t)
continue
The resulting graph is rather large, with edges typically 0.1 miles in length or smaller, showing each bend in the trail, going from 217 nodes in the simplified graph to over 40000 in the unsimplified.
In a previous post we imported elevation information into our graph and databook, using a JSON query to an open data website.
#https://stackoverflow.com/questions/68534454/python-obtaining-elevation-from-latitude-and-longitude-values/68540685#68540685
def get_elevation(lat, long):
return 0
query = ('https://api.open-elevation.com/api/v1/lookup'
f'?locations={lat},{long}')
r = requests.get(query).json() # json object, various ways you can extract value
elevation = pd.json_normalize(r, 'results')['elevation'].values[0]
return elevation # returns in meters, not freedom units
Now, in preparation to revisiting our databook code, we will take advantage of the elevation module in OSMNX, reading in elevations for all nodes in the graph with one function call. (Even though the API call is add_node_elevations_google with ‘google‘ in the name, we are not required to use the Google service, for which I do not have a key).
(If you use the service at open-elevation.com, please throw them a donation.)
We can colorize our nodes and edges by elevation, making the crude approximation that an edge elevation is the mean elevation of its two nodes.
def colorize_elevation(Q):
QR = Q.copy()
for node, dat in Q.nodes(data=True):
dat['color'] = dat['elevation']
QR.add_node(node,**dat) #replace node value
for u, v, k, dat in Q.edges(keys=True,data=True):
e1 = Q.nodes[u]['elevation']
e2 = Q.nodes[v]['elevation']
dat['color'] = (e1 + e2)/2.0
QR.add_edge(u,v,key=k,**dat)
QR.graph['color']=True
return QR
A small change to our draw() function uses magma as our pre-defined cmap.
Because my graph is simplified, meaning many 2nodes are merged together, the elevation appears to have large steps. We will address this in the next post.