Source code for splot._viz_libpysal_mpl
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.collections import LineCollection
"""
Lightweight visualizations for libpysal using Matplotlib and Geopandas
TODO
* make gdf argument in plot_spatial_weights optional
"""
__author__ = ("Stefanie Lumnitz <stefanie.lumitz@gmail.com>")
[docs]def plot_spatial_weights(w, gdf, indexed_on=None, ax=None,
figsize=(10,10), node_kws=None, edge_kws=None,
nonplanar_edge_kws=None):
"""
Plot spatial weights network.
NOTE: Additionally plots `w.non_planar_joins` if
`libpysal.weights.util.nonplanar_neighbors()` was applied.
Parameters
----------
w : libpysal.W object
Values of libpysal weights object.
gdf : geopandas dataframe
The original shapes whose topological relations are
modelled in W.
indexed_on : str, optional
Column of gdf which the weights object uses as an index.
Default =None, so the geodataframe's index is used.
ax : matplotlib axis, optional
Axis on which to plot the weights.
Default =None, so plots on the current figure.
figsize : tuple, optional
W, h of figure. Default =(10,10)
node_kws : keyword argument dictionary, optional
Dictionary of keyword arguments to send to pyplot.scatter,
which provide fine-grained control over the aesthetics
of the nodes in the plot. Default =None.
edge_kws : keyword argument dictionary, optional
Dictionary of keyword arguments to send to pyplot.plot,
which provide fine-grained control over the aesthetics
of the edges in the plot. Default =None.
nonplanar_edge_kws : keyword argument dictionary, optional
Dictionary of keyword arguments to send to pyplot.plot,
which provide fine-grained control over the aesthetics
of the edges from `weights.non_planar_joins` in the plot.
Default =None.
Returns
-------
fig : matplotlip Figure instance
Figure of spatial weight network.
ax : matplotlib Axes instance
Axes in which the figure is plotted.
Examples
--------
Imports
>>> from libpysal.weights.contiguity import Queen
>>> import geopandas as gpd
>>> import libpysal
>>> from libpysal import examples
>>> import matplotlib.pyplot as plt
>>> from splot.libpysal import plot_spatial_weights
Data preparation and statistical analysis
>>> gdf = gpd.read_file(examples.get_path('map_RS_BR.shp'))
>>> weights = Queen.from_dataframe(gdf)
>>> wnp = libpysal.weights.util.nonplanar_neighbors(weights, gdf)
Plot weights
>>> plot_spatial_weights(weights, gdf)
>>> plt.show()
Plot corrected weights
>>> plot_spatial_weights(wnp, gdf)
>>> plt.show()
"""
if ax is None:
fig = plt.figure(figsize=figsize)
ax = fig.add_subplot(111)
else:
fig = ax.get_figure()
# default for node_kws
if node_kws is None:
node_kws = dict(markersize=10, facecolor='#4d4d4d', edgecolor='#4d4d4d')
# default for edge_kws
if edge_kws is None:
edge_kws = dict(colors='#4393c3')
# default for nonplanar_edge_kws
if nonplanar_edge_kws is None:
edge_kws.setdefault('lw', 0.7)
nonplanar_edge_kws = edge_kws.copy()
nonplanar_edge_kws['colors'] = '#d6604d'
node_has_nonplanar_join = []
if hasattr(w, 'non_planar_joins'):
# This attribute is present when an instance is created by the user
# calling `weights.util.nonplanar_neighbors`. If so, treat those
# edges differently by default.
node_has_nonplanar_join = w.non_planar_joins.keys()
centroids_shp = gdf.centroid.values
segments = []
non_planar_segments = []
if indexed_on is not None:
dict_index = dict(zip(gdf[indexed_on].values, range(len(gdf))))
for idx in w.id_order:
if idx in w.islands:
continue
# Find the centroid of the polygon we're looking at now
origin = np.array(centroids_shp[dict_index[idx]].coords)[0]
for jdx in w.neighbors[idx]:
dest = np.array(centroids_shp[dict_index[jdx]].coords)[0]
if (idx in node_has_nonplanar_join) and (jdx in w.non_planar_joins[idx]):
# This is a non-planar edge
non_planar_segments.append([origin, dest])
else:
segments.append([origin, dest])
else:
for idx in w.id_order:
if idx in w.islands:
continue
# Find the centroid of the polygon we're looking at now
origin = np.array(centroids_shp[idx].coords)[0]
for j in w.neighbors[idx]:
jdx = w.id2i[j]
dest = np.array(centroids_shp[jdx].coords)[0]
if (idx in node_has_nonplanar_join) and (jdx in w.non_planar_joins[idx]):
# This is a non-planar edge
non_planar_segments.append([origin, dest])
else:
segments.append([origin, dest])
# Plot the polygons from the geodataframe as a base layer
gdf.plot(ax=ax, color='#bababa', edgecolor='w')
# plot polygon centroids
gdf.centroid.plot(ax=ax, **node_kws)
# plot weight edges
non_planar_segs_plot = LineCollection(np.array(non_planar_segments), **nonplanar_edge_kws)
segs_plot = LineCollection(np.array(segments), **edge_kws)
ax.add_collection(segs_plot)
ax.add_collection(non_planar_segs_plot)
ax.set_axis_off()
ax.set_aspect('equal')
return fig, ax