-
Notifications
You must be signed in to change notification settings - Fork 58
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
ENH: add Moran scatterplot ported from splot (#356)
* implementation * docstring * tests * expose on Moran as well * Apply suggestions from code review Co-authored-by: James Gaboardi <[email protected]> * cleanup * use plot_scatter --------- Co-authored-by: James Gaboardi <[email protected]>
- Loading branch information
1 parent
e095b21
commit e38e151
Showing
2 changed files
with
306 additions
and
10 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -9,7 +9,7 @@ | |
"Levi John Wolf <[email protected]>" | ||
) | ||
|
||
from warnings import simplefilter | ||
from warnings import simplefilter, warn | ||
|
||
import numpy as np | ||
import pandas as pd | ||
|
@@ -321,6 +321,37 @@ def by_col( | |
**stat_kws, | ||
) | ||
|
||
def plot_scatter( | ||
self, | ||
ax=None, | ||
scatter_kwds=None, | ||
fitline_kwds=None, | ||
): | ||
""" | ||
Plot a Moran scatterplot with optional coloring for significant points. | ||
Parameters | ||
---------- | ||
ax : matplotlib.axes.Axes, optional | ||
Pre-existing axes for the plot, by default None. | ||
scatter_kwds : dict, optional | ||
Additional keyword arguments for scatter plot, by default None. | ||
fitline_kwds : dict, optional | ||
Additional keyword arguments for fit line, by default None. | ||
Returns | ||
------- | ||
matplotlib.axes.Axes | ||
Axes object with the Moran scatterplot. | ||
""" | ||
return _scatterplot( | ||
self, | ||
crit_value=None, | ||
ax=ax, | ||
scatter_kwds=scatter_kwds, | ||
fitline_kwds=fitline_kwds, | ||
) | ||
|
||
|
||
class Moran_BV: # noqa: N801 | ||
""" | ||
|
@@ -1272,6 +1303,40 @@ def plot(self, gdf, crit_value=0.05, **kwargs): | |
gdf["Moran Cluster"] = self.get_cluster_labels(crit_value) | ||
return _viz_local_moran(self, gdf, crit_value, "plot", **kwargs) | ||
|
||
def plot_scatter( | ||
self, | ||
crit_value=0.05, | ||
ax=None, | ||
scatter_kwds=None, | ||
fitline_kwds=None, | ||
): | ||
""" | ||
Plot a Moran scatterplot with optional coloring for significant points. | ||
Parameters | ||
---------- | ||
crit_value : float, optional | ||
Critical value to determine statistical significance, by default 0.05. | ||
ax : matplotlib.axes.Axes, optional | ||
Pre-existing axes for the plot, by default None. | ||
scatter_kwds : dict, optional | ||
Additional keyword arguments for scatter plot, by default None. | ||
fitline_kwds : dict, optional | ||
Additional keyword arguments for fit line, by default None. | ||
Returns | ||
------- | ||
matplotlib.axes.Axes | ||
Axes object with the Moran scatterplot. | ||
""" | ||
return _scatterplot( | ||
self, | ||
crit_value=crit_value, | ||
ax=ax, | ||
scatter_kwds=scatter_kwds, | ||
fitline_kwds=fitline_kwds, | ||
) | ||
|
||
|
||
class Moran_Local_BV: # noqa: N801 | ||
"""Bivariate Local Moran Statistics. | ||
|
@@ -1863,6 +1928,102 @@ def _get_cluster_labels(moran_local, crit_value): | |
return gdf["Moran Cluster"].values | ||
|
||
|
||
def _scatterplot( | ||
moran, | ||
crit_value=0.05, | ||
ax=None, | ||
scatter_kwds=None, | ||
fitline_kwds=None, | ||
): | ||
"""Generates a Moran Local or Global Scatterplot. | ||
Parameters | ||
---------- | ||
moran : Moran object | ||
An instance of a Moran or Moran_Local object. | ||
crit_value : float, optional | ||
The critical value for significance. Default is 0.05. | ||
ax : matplotlib.axes.Axes, optional | ||
The axes on which to draw the plot. If None, a new figure and axes are created. | ||
scatter_kwds : dict, optional | ||
Additional keyword arguments to pass to the scatter plot. | ||
fitline_kwds : dict, optional | ||
Additional keyword arguments to pass to the fit line plot. | ||
Returns | ||
------- | ||
ax : matplotlib.axes.Axes | ||
The axes with the Moran Scatterplot. | ||
Raises | ||
------ | ||
ImportError | ||
If matplotlib is not installed. | ||
""" | ||
|
||
try: | ||
from matplotlib import pyplot as plt | ||
except ImportError as err: | ||
raise ImportError( | ||
"matplotlib library must be installed to use the scatterplot feature" | ||
) from err | ||
|
||
# to set default as an empty dictionary that is later filled with defaults | ||
if scatter_kwds is None: | ||
scatter_kwds = dict() | ||
if fitline_kwds is None: | ||
fitline_kwds = dict() | ||
|
||
if crit_value is not None: | ||
labels = moran.get_cluster_labels(crit_value) | ||
# TODO: allow customization of colors in here and in plot and explore | ||
# TODO: in a way to keep them easily synced | ||
colors5_mpl = { | ||
"High-High": "#d7191c", | ||
"Low-High": "#89cff0", | ||
"Low-Low": "#2c7bb6", | ||
"High-Low": "#fdae61", | ||
"Insignificant": "lightgrey", | ||
} | ||
colors5 = [colors5_mpl[i] for i in labels] # for mpl | ||
|
||
# define customization | ||
scatter_kwds.setdefault("alpha", 0.6) | ||
fitline_kwds.setdefault("alpha", 0.9) | ||
|
||
if ax is None: | ||
_, ax = plt.subplots() | ||
|
||
# set labels | ||
ax.set_xlabel("Attribute") | ||
ax.set_ylabel("Spatial Lag") | ||
ax.set_title("Moran Local Scatterplot") | ||
|
||
# plot and set standards | ||
lag = lag_spatial(moran.w, moran.z) | ||
fit = stats.linregress( | ||
moran.z, | ||
lag, | ||
) | ||
# v- and hlines | ||
ax.axvline(0, alpha=0.5, color="k", linestyle="--") | ||
ax.axhline(0, alpha=0.5, color="k", linestyle="--") | ||
if crit_value is not None: | ||
fitline_kwds.setdefault("color", "k") | ||
scatter_kwds.setdefault("c", colors5) | ||
ax.plot(moran.z, fit.intercept + fit.slope * moran.z, **fitline_kwds) | ||
ax.scatter(moran.z, lag, **scatter_kwds) | ||
else: | ||
scatter_kwds.setdefault("color", "#bababa") | ||
fitline_kwds.setdefault("color", "#d6604d") | ||
ax.plot(moran.z, fit.intercept + fit.slope * moran.z, **fitline_kwds) | ||
ax.scatter(moran.z, lag, **scatter_kwds) | ||
|
||
ax.set_aspect("equal") | ||
|
||
return ax | ||
|
||
|
||
# -------------------------------------------------------------- | ||
# Conditional Randomization Moment Estimators | ||
# -------------------------------------------------------------- | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters