in libs/apls/plot_road.py [0:0]
def plot_graph(G, im=None, bbox=None, use_geom=True, color_dict={},
fig_height=6, fig_width=None, margin=0.02,
axis_off=True, equal_aspect=False, bgcolor='w',
invert_yaxis=True, invert_xaxis=False,
annotate=False, node_color='#66ccff', node_size=15,
node_alpha=1, node_edgecolor='none', node_zorder=1,
edge_color='#999999', edge_linewidth=1, edge_alpha=1,
edge_color_key='speed_mph',
edge_width_key='speed_mph', edge_width_mult=1./25,
fig=None, ax=None):
"""
Plot a networkx spatial graph.
Parameters
----------
G : networkx multidigraph
bbox : tuple
bounding box as north,south,east,west - if None will calculate from
spatial extents of data. if passing a bbox, you probably also want to
pass margin=0 to constrain it.
use_geom : bool
if True, use the spatial geometry attribute of the edges to draw
geographically accurate edges, rather than just lines straight from node
to node
color_dict : dict
No doc provided
fig_height : int
matplotlib figure height in inches
fig_width : int
matplotlib figure width in inches
margin : float
relative margin around the figure
axis_off : bool
if True turn off the matplotlib axis
equal_aspect : bool
if True set the axis aspect ratio equal
bgcolor : string
the background color of the figure and axis
invert_yaxis : bool
invert y axis
invert_xaxis : bool
invert x axis
annotate : bool
if True, annotate the nodes in the figure
node_color : string
the color of the nodes
node_size : int
the size of the nodes
node_alpha : float
the opacity of the nodes
node_edgecolor : string
the color of the node's marker's border
node_zorder : int
zorder to plot nodes, edges are always 2, so make node_zorder 1 to plot
nodes beneath them or 3 to plot nodes atop them
edge_color : string
the color of the edges' lines
edge_linewidth : float
the width of the edges' lines
edge_alpha : float
the opacity of the edges' lines
edge_width_key : str
optional: key in edge propwerties to determine edge width,
supercedes edge_linewidth, default to "speed_mph"
edge_width_mult : float
factor to rescale width for plotting, default to 1./25, which gives
a line width of 1 for 25 mph speed limit.
Returns
-------
fig, ax : tuple
"""
node_Xs = [float(x) for _, x in G.nodes(data='x_pix')]
node_Ys = [float(y) for _, y in G.nodes(data='y_pix')]
# get north, south, east, west values either from bbox parameter or from the
# spatial extent of the edges' geometries
if bbox is None:
edges = graph_to_gdfs_pix(G, nodes=False, fill_edge_geometry=True)
west, south, east, north = gpd.GeoSeries(edges['geometry_pix']).total_bounds
else:
north, south, east, west = bbox
# if caller did not pass in a fig_width, calculate it proportionately from
# the fig_height and bounding box aspect ratio
bbox_aspect_ratio = (north-south)/(east-west)
if fig_width is None:
fig_width = fig_height / bbox_aspect_ratio
# create the figure and axis
if im is not None:
if fig==None and ax==None:
fig, ax = plt.subplots(figsize=(fig_width, fig_height))
ax.imshow(im)
else:
if fig==None and ax==None:
fig, ax = plt.subplots(figsize=(fig_width, fig_height), facecolor=bgcolor)
ax.set_facecolor(bgcolor)
# draw the edges as lines from node to node
lines = []
widths = []
edge_colors = []
for u, v, data in G.edges(keys=False, data=True):
if 'geometry_pix' in data and use_geom:
# if it has a geometry attribute (a list of line segments), add them
# to the list of lines to plot
xs, ys = data['geometry_pix'].xy
lines.append(list(zip(xs, ys)))
else:
# if it doesn't have a geometry attribute, the edge is a straight
# line from node to node
x1 = G.nodes[u]['x_pix']
y1 = G.nodes[u]['y_pix']
x2 = G.nodes[v]['x_pix']
y2 = G.nodes[v]['y_pix']
line = [(x1, y1), (x2, y2)]
lines.append(line)
# get widths
if edge_width_key in data.keys():
width = int(np.rint(data[edge_width_key] * edge_width_mult))
else:
width = edge_linewidth
widths.append(width)
if edge_color_key and color_dict:
color_key_val = int(data[edge_color_key])
edge_colors.append(color_dict[color_key_val])
else:
edge_colors.append(edge_color)
# add the lines to the axis as a linecollection
lc = LineCollection(lines, colors=edge_colors,
linewidths=widths,
alpha=edge_alpha, zorder=2)
ax.add_collection(lc)
# scatter plot the nodes
ax.scatter(node_Xs, node_Ys, s=node_size, c=node_color, alpha=node_alpha,
edgecolor=node_edgecolor, zorder=node_zorder)
# set the extent of the figure
margin_ns = (north - south) * margin
margin_ew = (east - west) * margin
ax.set_ylim((south - margin_ns, north + margin_ns))
ax.set_xlim((west - margin_ew, east + margin_ew))
if invert_yaxis:
ax.invert_yaxis()
if invert_xaxis:
ax.invert_xaxis()
# configure axis appearance
xaxis = ax.get_xaxis()
yaxis = ax.get_yaxis()
xaxis.get_major_formatter().set_useOffset(False)
yaxis.get_major_formatter().set_useOffset(False)
# if axis_off, turn off the axis display set the margins to zero and point
# the ticks in so there's no space around the plot
if axis_off:
ax.axis('off')
ax.margins(0)
ax.tick_params(which='both', direction='in')
xaxis.set_visible(False)
yaxis.set_visible(False)
fig.canvas.draw()
if equal_aspect:
# make everything square
ax.set_aspect('equal')
fig.canvas.draw()
else:
# if the graph is not projected, conform the aspect ratio to not stretch the plot
if G.graph['crs'] == ox_settings.default_crs:
coslat = np.cos((min(node_Ys) + max(node_Ys)) / 2. / 180. * np.pi)
ax.set_aspect(1. / coslat)
fig.canvas.draw()
# annotate the axis with node IDs if annotate=True
if annotate:
for node, data in G.nodes(data=True):
ax.annotate(node, xy=(data['x_pix'], data['y_pix']))
return fig, ax