Source code for splot._viz_esda_mpl

import warnings

import geopandas as gpd
import matplotlib.pyplot as plt
import numpy
import seaborn as sbn
from esda.moran import Moran, Moran_BV, Moran_Local, Moran_Local_BV
from libpysal.weights.spatial_lag import lag_spatial
from matplotlib import colors, patches
from spreg import OLS

from ._viz_utils import mask_local_auto, moran_hot_cold_spots, splot_colors

"""
Lightweight visualizations for esda using Matplotlib and Geopandas

TODO
* geopandas plotting, change round shapes in legends to boxes
* prototype moran_facet using `seaborn.FacetGrid`
"""

__author__ = "Stefanie Lumnitz <stefanie.lumitz@gmail.com>"


def _create_moran_fig_ax(ax, figsize, aspect_equal):
    """
    Creates matplotlib figure and axes instances
    for plotting moran visualizations. Adds common viz design.
    """
    if ax is None:
        fig = plt.figure(figsize=figsize)
        ax = fig.add_subplot(111)
    else:
        fig = ax.get_figure()
    ax.spines["left"].set_position(("axes", -0.05))
    ax.spines["right"].set_color("none")
    ax.spines["bottom"].set_position(("axes", -0.05))
    ax.spines["top"].set_color("none")
    if aspect_equal is True:
        ax.set_aspect("equal")
    return fig, ax


[docs]def moran_scatterplot( moran, zstandard=True, p=None, aspect_equal=True, ax=None, scatter_kwds=None, fitline_kwds=None, ): """ Moran Scatterplot Parameters ---------- moran : esda.moran instance Values of Moran's I Global, Bivariate and Local Autocorrelation Statistics zstandard : bool, optional If True, Moran Scatterplot will show z-standardized attribute and spatial lag values. Default =True. p : float, optional If given, the p-value threshold for significance for Local Autocorrelation analysis. Points will be colored by significance. By default it will not be colored. Default =None. aspect_equal : bool, optional If True, Axes will show the same aspect or visual proportions for Moran Scatterplot. ax : Matplotlib Axes instance, optional If given, the Moran plot will be created inside this axis. Default =None. scatter_kwds : keyword arguments, optional Keywords used for creating and designing the scatter points. Default =None. fitline_kwds : keyword arguments, optional Keywords used for creating and designing the moran fitline. Default =None. Returns ------- fig : Matplotlib Figure instance Moran scatterplot figure ax : matplotlib Axes instance Axes in which the figure is plotted Examples -------- Imports >>> import matplotlib.pyplot as plt >>> from libpysal.weights.contiguity import Queen >>> from libpysal import examples >>> import geopandas as gpd >>> from esda.moran import (Moran, Moran_BV, ... Moran_Local, Moran_Local_BV) >>> from splot.esda import moran_scatterplot Load data and calculate weights >>> guerry = examples.load_example('Guerry') >>> link_to_data = guerry.get_path('guerry.shp') >>> gdf = gpd.read_file(link_to_data) >>> x = gdf['Suicids'].values >>> y = gdf['Donatns'].values >>> w = Queen.from_dataframe(gdf) >>> w.transform = 'r' Calculate esda.moran Objects >>> moran = Moran(y, w) >>> moran_bv = Moran_BV(y, x, w) >>> moran_loc = Moran_Local(y, w) >>> moran_loc_bv = Moran_Local_BV(y, x, w) Plot >>> fig, axs = plt.subplots(2, 2, figsize=(10,10), ... subplot_kw={'aspect': 'equal'}) >>> moran_scatterplot(moran, p=0.05, ax=axs[0,0]) >>> moran_scatterplot(moran_loc, p=0.05, ax=axs[1,0]) >>> moran_scatterplot(moran_bv, p=0.05, ax=axs[0,1]) >>> moran_scatterplot(moran_loc_bv, p=0.05, ax=axs[1,1]) >>> plt.show() """ if isinstance(moran, Moran): if p is not None: warnings.warn( "`p` is only used for plotting `esda.moran.Moran_Local`\n" "or `Moran_Local_BV` objects" ) fig, ax = _moran_global_scatterplot( moran=moran, zstandard=zstandard, ax=ax, aspect_equal=aspect_equal, scatter_kwds=scatter_kwds, fitline_kwds=fitline_kwds, ) elif isinstance(moran, Moran_BV): if p is not None: warnings.warn( "`p` is only used for plotting `esda.moran.Moran_Local` " "or `Moran_Local_BV` objects." ) fig, ax = _moran_bv_scatterplot( moran_bv=moran, ax=ax, aspect_equal=aspect_equal, scatter_kwds=scatter_kwds, fitline_kwds=fitline_kwds, ) elif isinstance(moran, Moran_Local): fig, ax = _moran_loc_scatterplot( moran_loc=moran, zstandard=zstandard, ax=ax, p=p, aspect_equal=aspect_equal, scatter_kwds=scatter_kwds, fitline_kwds=fitline_kwds, ) elif isinstance(moran, Moran_Local_BV): fig, ax = _moran_loc_bv_scatterplot( moran_loc_bv=moran, ax=ax, p=p, aspect_equal=aspect_equal, scatter_kwds=scatter_kwds, fitline_kwds=fitline_kwds, ) ax.xaxis.set_ticks_position("bottom") ax.yaxis.set_ticks_position("left") return fig, ax
def _moran_global_scatterplot( moran, zstandard=True, aspect_equal=True, ax=None, scatter_kwds=None, fitline_kwds=None, ): """ Global Moran's I Scatterplot. Parameters ---------- moran : esda.moran.Moran instance Values of Moran's I Global Autocorrelation Statistics zstandard : bool, optional If True, Moran Scatterplot will show z-standardized attribute and spatial lag values. Default =True. aspect_equal : bool, optional If True, Axes will show the same aspect or visual proportions. ax : Matplotlib Axes instance, optional If given, the Moran plot will be created inside this axis. Default =None. scatter_kwds : keyword arguments, optional Keywords used for creating and designing the scatter points. Default =None. fitline_kwds : keyword arguments, optional Keywords used for creating and designing the moran fitline. Default =None. Returns ------- fig : Matplotlib Figure instance Moran scatterplot figure ax : matplotlib Axes instance Axes in which the figure is plotted Examples -------- Imports >>> import matplotlib.pyplot as plt >>> from libpysal.weights.contiguity import Queen >>> from libpysal import examples >>> import geopandas as gpd >>> from esda.moran import Moran >>> from splot.esda import moran_scatterplot Load data and calculate weights >>> guerry = examples.load_example('Guerry') >>> link_to_data = guerry.get_path('guerry.shp') >>> gdf = gpd.read_file(link_to_data) >>> y = gdf['Donatns'].values >>> w = Queen.from_dataframe(gdf) >>> w.transform = 'r' Calculate Global Moran >>> moran = Moran(y, w) plot >>> moran_scatterplot(moran) >>> plt.show() customize plot >>> fig, ax = moran_scatterplot(moran, zstandard=False, ... fitline_kwds=dict(color='#4393c3')) >>> ax.set_xlabel('Donations') >>> plt.show() """ # 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() # define customization defaults scatter_kwds.setdefault("alpha", 0.6) scatter_kwds.setdefault("color", splot_colors["moran_base"]) scatter_kwds.setdefault("s", 40) fitline_kwds.setdefault("alpha", 0.9) fitline_kwds.setdefault("color", splot_colors["moran_fit"]) # get fig and ax fig, ax = _create_moran_fig_ax(ax, figsize=(7, 7), aspect_equal=aspect_equal) # set labels ax.set_xlabel("Attribute") ax.set_ylabel("Spatial Lag") ax.set_title("Moran Scatterplot" + " (" + str(round(moran.I, 2)) + ")") # plot and set standards if zstandard is True: lag = lag_spatial(moran.w, moran.z) fit = OLS(moran.z[:, None], lag[:, None]) # plot ax.scatter(moran.z, lag, **scatter_kwds) ax.plot(lag, fit.predy, **fitline_kwds) # v- and hlines ax.axvline(0, alpha=0.5, color="k", linestyle="--") ax.axhline(0, alpha=0.5, color="k", linestyle="--") else: lag = lag_spatial(moran.w, moran.y) b, a = numpy.polyfit(moran.y, lag, 1) # plot ax.scatter(moran.y, lag, **scatter_kwds) ax.plot(moran.y, a + b * moran.y, **fitline_kwds) # dashed vert at mean of the attribute ax.vlines(moran.y.mean(), lag.min(), lag.max(), alpha=0.5, linestyle="--") # dashed horizontal at mean of lagged attribute ax.hlines(lag.mean(), moran.y.min(), moran.y.max(), alpha=0.5, linestyle="--") return fig, ax
[docs]def plot_moran_simulation( moran, aspect_equal=True, ax=None, fitline_kwds=None, **kwargs ): """ Global Moran's I simulated reference distribution. Parameters ---------- moran : esda.moran.Moran instance Values of Moran's I Global Autocorrelation Statistics aspect_equal : bool, optional If True, Axes of Moran Scatterplot will show the same aspect or visual proportions. ax : Matplotlib Axes instance, optional If given, the Moran plot will be created inside this axis. Default =None. fitline_kwds : keyword arguments, optional Keywords used for creating and designing the vertical moran fitline. Default =None. **kwargs : keyword arguments, optional Keywords used for creating and designing the figure, passed to seaborn.kdeplot. Returns ------- fig : Matplotlib Figure instance Simulated reference distribution figure ax : matplotlib Axes instance Axes in which the figure is plotted Examples -------- Imports >>> import matplotlib.pyplot as plt >>> from libpysal.weights.contiguity import Queen >>> from libpysal import examples >>> import geopandas as gpd >>> from esda.moran import Moran >>> from splot.esda import plot_moran_simulation Load data and calculate weights >>> guerry = examples.load_example('Guerry') >>> link_to_data = guerry.get_path('guerry.shp') >>> gdf = gpd.read_file(link_to_data) >>> y = gdf['Donatns'].values >>> w = Queen.from_dataframe(gdf) >>> w.transform = 'r' Calculate Global Moran >>> moran = Moran(y, w) plot >>> plot_moran_simulation(moran) >>> plt.show() customize plot >>> plot_moran_simulation(moran, fitline_kwds=dict(color='#4393c3')) >>> plt.show() """ # to set default as an empty dictionary that is later filled with defaults if fitline_kwds is None: fitline_kwds = dict() figsize = kwargs.pop("figsize", (7, 7)) # get fig and ax fig, ax = _create_moran_fig_ax(ax, figsize, aspect_equal=aspect_equal) # plot distribution shade = kwargs.pop("shade", True) color = kwargs.pop("color", splot_colors["moran_base"]) sbn.kdeplot(moran.sim, fill=shade, color=color, ax=ax, **kwargs) # customize plot fitline_kwds.setdefault("color", splot_colors["moran_fit"]) ax.vlines(moran.I, 0, 1, **fitline_kwds) ax.vlines(moran.EI, 0, 1) ax.set_title("Reference Distribution") ax.set_xlabel("Moran I: " + str(round(moran.I, 2))) return fig, ax
[docs]def plot_moran( moran, zstandard=True, aspect_equal=True, scatter_kwds=None, fitline_kwds=None, **kwargs ): """ Global Moran's I simulated reference distribution and scatterplot. Parameters ---------- moran : esda.moran.Moran instance Values of Moran's I Global Autocorrelation Statistics zstandard : bool, optional If True, Moran Scatterplot will show z-standardized attribute and spatial lag values. Default =True. aspect_equal : bool, optional If True, Axes of Moran Scatterplot will show the same aspect or visual proportions. scatter_kwds : keyword arguments, optional Keywords used for creating and designing the scatter points. Default =None. fitline_kwds : keyword arguments, optional Keywords used for creating and designing the moran fitline and vertical fitline. Default =None. **kwargs : keyword arguments, optional Keywords used for creating and designing the figure, passed to seaborne.kdeplot. Returns ------- fig : Matplotlib Figure instance Moran scatterplot and reference distribution figure ax : matplotlib Axes instance Axes in which the figure is plotted Examples -------- Imports >>> import matplotlib.pyplot as plt >>> from libpysal.weights.contiguity import Queen >>> from libpysal import examples >>> import geopandas as gpd >>> from esda.moran import Moran >>> from splot.esda import plot_moran Load data and calculate weights >>> guerry = examples.load_example('Guerry') >>> link_to_data = guerry.get_path('guerry.shp') >>> gdf = gpd.read_file(link_to_data) >>> y = gdf['Donatns'].values >>> w = Queen.from_dataframe(gdf) >>> w.transform = 'r' Calculate Global Moran >>> moran = Moran(y, w) plot >>> plot_moran(moran) >>> plt.show() customize plot >>> plot_moran(moran, zstandard=False, ... fitline_kwds=dict(color='#4393c3')) >>> plt.show() """ figsize = kwargs.pop("figsize", (10, 4)) fig, axs = plt.subplots(1, 2, figsize=figsize, subplot_kw={"aspect": "equal"}) plot_moran_simulation(moran, ax=axs[0], fitline_kwds=fitline_kwds, **kwargs) moran_scatterplot( moran, zstandard=zstandard, ax=axs[1], scatter_kwds=scatter_kwds, fitline_kwds=fitline_kwds, ) axs[0].set(aspect="auto") if aspect_equal is True: axs[1].set_aspect("equal", "datalim") else: axs[1].set_aspect("auto") return fig, axs
def _moran_bv_scatterplot( moran_bv, ax=None, aspect_equal=True, scatter_kwds=None, fitline_kwds=None ): """ Bivariate Moran Scatterplot. Parameters ---------- moran_bv : esda.moran.Moran_BV instance Values of Bivariate Moran's I Autocorrelation Statistics ax : Matplotlib Axes instance, optional If given, the Moran plot will be created inside this axis. Default =None. aspect_equal : bool, optional If True, Axes of Moran Scatterplot will show the same aspect or visual proportions. scatter_kwds : keyword arguments, optional Keywords used for creating and designing the scatter points. Default =None. fitline_kwds : keyword arguments, optional Keywords used for creating and designing the moran fitline. Default =None. Returns ------- fig : Matplotlib Figure instance Bivariate moran scatterplot figure ax : matplotlib Axes instance Axes in which the figure is plotted Examples -------- Imports >>> import matplotlib.pyplot as plt >>> from libpysal.weights.contiguity import Queen >>> from libpysal import examples >>> import geopandas as gpd >>> from esda.moran import Moran_BV >>> from splot.esda import moran_scatterplot Load data and calculate weights >>> guerry = examples.load_example('Guerry') >>> link_to_data = guerry.get_path('guerry.shp') >>> gdf = gpd.read_file(link_to_data) >>> x = gdf['Suicids'].values >>> y = gdf['Donatns'].values >>> w = Queen.from_dataframe(gdf) >>> w.transform = 'r' Calculate Bivariate Moran >>> moran_bv = Moran_BV(x, y, w) plot >>> moran_scatterplot(moran_bv) >>> plt.show() customize plot >>> moran_scatterplot(moran_bv, ... fitline_kwds=dict(color='#4393c3')) >>> plt.show() """ # 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() # define customization scatter_kwds.setdefault("alpha", 0.6) scatter_kwds.setdefault("color", splot_colors["moran_base"]) scatter_kwds.setdefault("s", 40) fitline_kwds.setdefault("alpha", 0.9) fitline_kwds.setdefault("color", splot_colors["moran_fit"]) # get fig and ax fig, ax = _create_moran_fig_ax(ax, figsize=(7, 7), aspect_equal=aspect_equal) # set labels ax.set_xlabel("Attribute X") ax.set_ylabel("Spatial Lag of Y") ax.set_title("Bivariate Moran Scatterplot" + " (" + str(round(moran_bv.I, 2)) + ")") # plot and set standards lag = lag_spatial(moran_bv.w, moran_bv.zy) fit = OLS(moran_bv.zy[:, None], lag[:, None]) # plot ax.scatter(moran_bv.zx, lag, **scatter_kwds) ax.plot(lag, fit.predy, **fitline_kwds) # v- and hlines ax.axvline(0, alpha=0.5, color="k", linestyle="--") ax.axhline(0, alpha=0.5, color="k", linestyle="--") return fig, ax
[docs]def plot_moran_bv_simulation( moran_bv, ax=None, aspect_equal=True, fitline_kwds=None, **kwargs ): """ Bivariate Moran's I simulated reference distribution. Parameters ---------- moran_bv : esda.moran.Moran_BV instance Values of Bivariate Moran's I Autocorrelation Statistics ax : Matplotlib Axes instance, optional If given, the Moran plot will be created inside this axis. Default =None. aspect_equal : bool, optional If True, Axes of Moran Scatterplot will show the same aspect or visual proportions. fitline_kwds : keyword arguments, optional Keywords used for creating and designing the vertical moran fitline. Default =None. **kwargs : keyword arguments, optional Keywords used for creating and designing the figure, passed to seaborne.kdeplot. Returns ------- fig : Matplotlib Figure instance Bivariate moran reference distribution figure ax : matplotlib Axes instance Axes in which the figure is plotted Examples -------- Imports >>> import matplotlib.pyplot as plt >>> from libpysal.weights.contiguity import Queen >>> from libpysal import examples >>> import geopandas as gpd >>> from esda.moran import Moran_BV >>> from splot.esda import plot_moran_bv_simulation Load data and calculate weights >>> guerry = examples.load_example('Guerry') >>> link_to_data = guerry.get_path('guerry.shp') >>> gdf = gpd.read_file(link_to_data) >>> x = gdf['Suicids'].values >>> y = gdf['Donatns'].values >>> w = Queen.from_dataframe(gdf) >>> w.transform = 'r' Calculate Bivariate Moran >>> moran_bv = Moran_BV(x, y, w) plot >>> plot_moran_bv_simulation(moran_bv) >>> plt.show() customize plot >>> plot_moran_bv_simulation(moran_bv, ... fitline_kwds=dict(color='#4393c3')) >>> plt.show() """ # to set default as an empty dictionary that is later filled with defaults if fitline_kwds is None: fitline_kwds = dict() figsize = kwargs.pop("figsize", (7, 7)) # get fig and ax fig, ax = _create_moran_fig_ax(ax, figsize, aspect_equal=aspect_equal) # plot distribution shade = kwargs.pop("shade", True) color = kwargs.pop("color", splot_colors["moran_base"]) sbn.kdeplot(moran_bv.sim, fill=shade, color=color, ax=ax, **kwargs) # customize plot fitline_kwds.setdefault("color", splot_colors["moran_fit"]) ax.vlines(moran_bv.I, 0, 1, **fitline_kwds) ax.vlines(moran_bv.EI_sim, 0, 1) ax.set_title("Reference Distribution") ax.set_xlabel("Bivariate Moran I: " + str(round(moran_bv.I, 2))) return fig, ax
[docs]def plot_moran_bv( moran_bv, aspect_equal=True, scatter_kwds=None, fitline_kwds=None, **kwargs ): """ Bivariate Moran's I simulated reference distribution and scatterplot. Parameters ---------- moran_bv : esda.moran.Moran_BV instance Values of Bivariate Moran's I Autocorrelation Statistics aspect_equal : bool, optional If True, Axes of Moran Scatterplot will show the same aspect or visual proportions. scatter_kwds : keyword arguments, optional Keywords used for creating and designing the scatter points. Default =None. fitline_kwds : keyword arguments, optional Keywords used for creating and designing the moran fitline and vertical fitline. Default =None. **kwargs : keyword arguments, optional Keywords used for creating and designing the figure, passed to seaborne.kdeplot. Returns ------- fig : Matplotlib Figure instance Bivariate moran scatterplot and reference distribution figure ax : matplotlib Axes instance Axes in which the figure is plotted Examples -------- Imports >>> import matplotlib.pyplot as plt >>> from libpysal.weights.contiguity import Queen >>> from libpysal import examples >>> import geopandas as gpd >>> from esda.moran import Moran_BV >>> from splot.esda import plot_moran_bv Load data and calculate weights >>> guerry = examples.load_example('Guerry') >>> link_to_data = guerry.get_path('guerry.shp') >>> gdf = gpd.read_file(link_to_data) >>> x = gdf['Suicids'].values >>> y = gdf['Donatns'].values >>> w = Queen.from_dataframe(gdf) >>> w.transform = 'r' Calculate Bivariate Moran >>> moran_bv = Moran_BV(x, y, w) plot >>> plot_moran_bv(moran_bv) >>> plt.show() customize plot >>> plot_moran_bv(moran_bv, fitline_kwds=dict(color='#4393c3')) >>> plt.show() """ figsize = kwargs.pop("figsize", (10, 4)) fig, axs = plt.subplots(1, 2, figsize=figsize, subplot_kw={"aspect": "equal"}) plot_moran_bv_simulation(moran_bv, ax=axs[0], fitline_kwds=fitline_kwds, **kwargs) moran_scatterplot( moran_bv, ax=axs[1], aspect_equal=aspect_equal, scatter_kwds=scatter_kwds, fitline_kwds=fitline_kwds, ) axs[0].set(aspect="auto") if aspect_equal is True: axs[1].set_aspect("equal", "datalim") else: axs[1].set(aspect="auto") return fig, axs
def _moran_loc_scatterplot( moran_loc, zstandard=True, p=None, aspect_equal=True, ax=None, scatter_kwds=None, fitline_kwds=None, ): """ Moran Scatterplot with option of coloring of Local Moran Statistics Parameters ---------- moran_loc : esda.moran.Moran_Local instance Values of Moran's I Local Autocorrelation Statistics p : float, optional If given, the p-value threshold for significance. Points will be colored by significance. By default it will not be colored. Default =None. aspect_equal : bool, optional If True, Axes of Moran Scatterplot will show the same aspect or visual proportions. ax : Matplotlib Axes instance, optional If given, the Moran plot will be created inside this axis. Default =None. scatter_kwds : keyword arguments, optional Keywords used for creating and designing the scatter points. Default =None. fitline_kwds : keyword arguments, optional Keywords used for creating and designing the moran fitline. Default =None. Returns ------- fig : Matplotlib Figure instance Moran Local scatterplot figure ax : matplotlib Axes instance Axes in which the figure is plotted Examples -------- Imports >>> import matplotlib.pyplot as plt >>> import geopandas as gpd >>> from libpysal.weights.contiguity import Queen >>> from libpysal import examples >>> from esda.moran import Moran_Local >>> from splot.esda import moran_scatterplot Load data and calculate Moran Local statistics >>> guerry = examples.load_example('Guerry') >>> link_to_data = guerry.get_path('guerry.shp') >>> gdf = gpd.read_file(link_to_data) >>> y = gdf['Donatns'].values >>> w = Queen.from_dataframe(gdf) >>> w.transform = 'r' >>> m = Moran_Local(y, w) plot >>> moran_scatterplot(m) >>> plt.show() customize plot >>> moran_scatterplot(m, p=0.05, ... fitline_kwds=dict(color='#4393c3')) >>> plt.show() """ # 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 p is not None: if not isinstance(moran_loc, Moran_Local): raise ValueError( "`moran_loc` is not a\n " + "esda.moran.Moran_Local instance" ) if "color" in scatter_kwds or "c" in scatter_kwds or "cmap" in scatter_kwds: warnings.warn( "To change the color use cmap with a colormap of 5,\n" + " color defines the LISA category" ) # colors spots = moran_hot_cold_spots(moran_loc, p) hmap = colors.ListedColormap( ["#bababa", "#d7191c", "#abd9e9", "#2c7bb6", "#fdae61"] ) # define customization scatter_kwds.setdefault("alpha", 0.6) scatter_kwds.setdefault("s", 40) fitline_kwds.setdefault("alpha", 0.9) # get fig and ax fig, ax = _create_moran_fig_ax(ax, figsize=(7, 7), aspect_equal=aspect_equal) # set labels ax.set_xlabel("Attribute") ax.set_ylabel("Spatial Lag") ax.set_title("Moran Local Scatterplot") # plot and set standards if zstandard is True: lag = lag_spatial(moran_loc.w, moran_loc.z) fit = OLS(moran_loc.z[:, None], lag[:, None]) # v- and hlines ax.axvline(0, alpha=0.5, color="k", linestyle="--") ax.axhline(0, alpha=0.5, color="k", linestyle="--") if p is not None: fitline_kwds.setdefault("color", "k") scatter_kwds.setdefault("cmap", hmap) scatter_kwds.setdefault("c", spots) ax.plot(lag, fit.predy, **fitline_kwds) ax.scatter(moran_loc.z, fit.predy, **scatter_kwds) else: scatter_kwds.setdefault("color", splot_colors["moran_base"]) fitline_kwds.setdefault("color", splot_colors["moran_fit"]) ax.plot(lag, fit.predy, **fitline_kwds) ax.scatter(moran_loc.z, fit.predy, **scatter_kwds) else: lag = lag_spatial(moran_loc.w, moran_loc.y) b, a = numpy.polyfit(moran_loc.y, lag, 1) # dashed vert at mean of the attribute ax.vlines(moran_loc.y.mean(), lag.min(), lag.max(), alpha=0.5, linestyle="--") # dashed horizontal at mean of lagged attribute ax.hlines( lag.mean(), moran_loc.y.min(), moran_loc.y.max(), alpha=0.5, linestyle="--" ) if p is not None: fitline_kwds.setdefault("color", "k") scatter_kwds.setdefault("cmap", hmap) scatter_kwds.setdefault("c", spots) ax.plot(moran_loc.y, a + b * moran_loc.y, **fitline_kwds) ax.scatter(moran_loc.y, lag, **scatter_kwds) else: scatter_kwds.setdefault("c", splot_colors["moran_base"]) fitline_kwds.setdefault("color", splot_colors["moran_fit"]) ax.plot(moran_loc.y, a + b * moran_loc.y, **fitline_kwds) ax.scatter(moran_loc.y, lag, **scatter_kwds) return fig, ax
[docs]def lisa_cluster( moran_loc, gdf, p=0.05, ax=None, legend=True, legend_kwds=None, **kwargs ): """ Create a LISA Cluster map Parameters ---------- moran_loc : esda.moran.Moran_Local or Moran_Local_BV instance Values of Moran's Local Autocorrelation Statistic gdf : geopandas dataframe instance The Dataframe containing information to plot. Note that `gdf` will be modified, so calling functions should use a copy of the user provided `gdf`. (either using gdf.assign() or gdf.copy()) p : float, optional The p-value threshold for significance. Points will be colored by significance. ax : matplotlib Axes instance, optional Axes in which to plot the figure in multiple Axes layout. Default = None legend : boolean, optional If True, legend for maps will be depicted. Default = True legend_kwds : dict, optional Dictionary to control legend formatting options. Example: ``legend_kwds={'loc': 'upper left', 'bbox_to_anchor': (0.92, 1.05)}`` Default = None **kwargs : keyword arguments, optional Keywords designing and passed to geopandas.GeoDataFrame.plot(). Returns ------- fig : matplotlip Figure instance Figure of LISA cluster map ax : matplotlib Axes instance Axes in which the figure is plotted Examples -------- Imports >>> import matplotlib.pyplot as plt >>> from libpysal.weights.contiguity import Queen >>> from libpysal import examples >>> import geopandas as gpd >>> from esda.moran import Moran_Local >>> from splot.esda import lisa_cluster Data preparation and statistical analysis >>> guerry = examples.load_example('Guerry') >>> link_to_data = guerry.get_path('guerry.shp') >>> gdf = gpd.read_file(link_to_data) >>> y = gdf['Donatns'].values >>> w = Queen.from_dataframe(gdf) >>> w.transform = 'r' >>> moran_loc = Moran_Local(y, w) Plotting >>> fig = lisa_cluster(moran_loc, gdf) >>> plt.show() """ # retrieve colors5 and labels from mask_local_auto _, colors5, _, labels = mask_local_auto(moran_loc, p=p) # define ListedColormap hmap = colors.ListedColormap(colors5) if ax is None: figsize = kwargs.pop("figsize", None) fig, ax = plt.subplots(1, figsize=figsize) else: fig = ax.get_figure() # check for Polygon, else no edgecolor if gdf.geom_type.isin(["Polygon", "MultiPolygon"]).any(): gdf.assign(cl=labels).plot( column="cl", categorical=True, k=2, cmap=hmap, linewidth=0.1, ax=ax, edgecolor="white", legend=legend, legend_kwds=legend_kwds, **kwargs ) else: gdf.assign(cl=labels).plot( column="cl", categorical=True, k=2, cmap=hmap, linewidth=1.5, ax=ax, legend=legend, legend_kwds=legend_kwds, **kwargs ) ax.set_axis_off() ax.set_aspect("equal") return fig, ax
[docs]def plot_local_autocorrelation( moran_loc, gdf, attribute, p=0.05, region_column=None, mask=None, mask_color="#636363", quadrant=None, aspect_equal=True, legend=True, scheme="Quantiles", cmap="YlGnBu", figsize=(15, 4), scatter_kwds=None, fitline_kwds=None, ): """ Produce three-plot visualisation of Moran Scatteprlot, LISA cluster and Choropleth maps, with Local Moran region and quadrant masking Parameters ---------- moran_loc : esda.moran.Moran_Local or Moran_Local_BV instance Values of Moran's Local Autocorrelation Statistic gdf : geopandas dataframe The Dataframe containing information to plot the two maps. attribute : str Column name of attribute which should be depicted in Choropleth map. p : float, optional The p-value threshold for significance. Points and polygons will be colored by significance. Default = 0.05. region_column: string, optional Column name containing mask region of interest. Default = None mask: str, float, int, optional Identifier or name of the region to highlight. Default = None Use the same dtype to specifiy as in original dataset. mask_color: str, optional Color of mask. Default = '#636363' quadrant : int, optional Quadrant 1-4 in scatterplot masking values in LISA cluster and Choropleth maps. Default = None aspect_equal : bool, optional If True, Axes of Moran Scatterplot will show the same aspect or visual proportions. figsize: tuple, optional W, h of figure. Default = (15,4) legend: boolean, optional If True, legend for maps will be depicted. Default = True scheme: str, optional Name of PySAL classifier to be used. Default = 'Quantiles' cmap: str, optional Name of matplotlib colormap used for plotting the Choropleth. Default = 'YlGnBu' scatter_kwds : keyword arguments, optional Keywords used for creating and designing the scatter points. Default =None. fitline_kwds : keyword arguments, optional Keywords used for creating and designing the moran fitline in the scatterplot. Default =None. Returns ------- fig : Matplotlib figure instance Moran Scatterplot, LISA cluster map and Choropleth. axs : list of Matplotlib axes Lisat of Matplotlib axes plotted. Examples -------- Imports >>> import matplotlib.pyplot as plt >>> from libpysal.weights.contiguity import Queen >>> from libpysal import examples >>> import geopandas as gpd >>> from esda.moran import Moran_Local >>> from splot.esda import plot_local_autocorrelation Data preparation and analysis >>> guerry = examples.load_example('Guerry') >>> link_to_data = guerry.get_path('guerry.shp') >>> gdf = gpd.read_file(link_to_data) >>> y = gdf['Donatns'].values >>> w = Queen.from_dataframe(gdf) >>> w.transform = 'r' >>> moran_loc = Moran_Local(y, w) Plotting with quadrant mask and region mask >>> fig = plot_local_autocorrelation(moran_loc, gdf, 'Donatns', p=0.05, ... region_column='Dprtmnt', ... mask=['Ain'], quadrant=1) >>> plt.show() """ fig, axs = plt.subplots( 1, 3, figsize=figsize, subplot_kw={"aspect": "equal", "adjustable": "datalim"} ) # Moran Scatterplot moran_scatterplot( moran_loc, p=p, ax=axs[0], scatter_kwds=scatter_kwds, fitline_kwds=fitline_kwds ) if aspect_equal is True: axs[0].set_aspect("equal", "datalim") else: axs[0].set_aspect("auto") # Lisa cluster map # TODO: Fix legend_kwds: display boxes instead of points lisa_cluster( moran_loc, gdf, p=p, ax=axs[1], legend=legend, legend_kwds={"loc": "upper left", "bbox_to_anchor": (0.92, 1.05)}, ) axs[1].set_aspect("equal") # Choropleth for attribute gdf.plot( column=attribute, scheme=scheme, cmap=cmap, legend=legend, legend_kwds={"loc": "upper left", "bbox_to_anchor": (0.92, 1.05)}, ax=axs[2], alpha=1, ) axs[2].set_axis_off() axs[2].set_aspect("equal") # MASKING QUADRANT VALUES if quadrant is not None: # Quadrant masking in Scatterplot mask_angles = {1: 0, 2: 90, 3: 180, 4: 270} # rectangle angles # We don't want to change the axis data limits, so use the current ones xmin, xmax = axs[0].get_xlim() ymin, ymax = axs[0].get_ylim() # We are rotating, so we start from 0 degrees and # figured out the right dimensions for the rectangles for other angles mask_width = {1: abs(xmax), 2: abs(ymax), 3: abs(xmin), 4: abs(ymin)} mask_height = {1: abs(ymax), 2: abs(xmin), 3: abs(ymin), 4: abs(xmax)} axs[0].add_patch( patches.Rectangle( (0, 0), width=mask_width[quadrant], height=mask_height[quadrant], angle=mask_angles[quadrant], color="#E5E5E5", zorder=-1, alpha=0.8, ) ) # quadrant selection in maps non_quadrant = ~(moran_loc.q == quadrant) mask_quadrant = gdf[non_quadrant] df_quadrant = gdf.iloc[~non_quadrant] union2 = df_quadrant.unary_union.boundary # LISA Cluster mask and cluster boundary with warnings.catch_warnings(): # temorarily surpress geopandas warning warnings.filterwarnings("ignore", category=UserWarning) mask_quadrant.plot( column=attribute, scheme=scheme, color="white", ax=axs[1], alpha=0.7, zorder=1, ) gpd.GeoSeries([union2]).plot(linewidth=1, ax=axs[1], color="#E5E5E5") # CHOROPLETH MASK with warnings.catch_warnings(): # temorarily surpress geopandas warning warnings.filterwarnings("ignore", category=UserWarning) mask_quadrant.plot( column=attribute, scheme=scheme, color="white", ax=axs[2], alpha=0.7, zorder=1, ) gpd.GeoSeries([union2]).plot(linewidth=1, ax=axs[2], color="#E5E5E5") # REGION MASKING if region_column is not None: # masking inside axs[0] or Moran Scatterplot # enforce the same dtype of list and mask if not isinstance(mask[0], type(gdf[region_column].iloc[0])): warnings.warn( "Values in `mask` are not the same dtype as" + " values in `region_column`. Converting `mask` values" + " to dtype of first observation in region_column." ) data_type = type(gdf[region_column][0].item()) mask = list(map(data_type, mask)) ix = gdf[region_column].isin(mask) if not ix.any(): raise ValueError( "Specified values {} in `mask` not in `region_column`".format(mask) ) df_mask = gdf[ix] x_mask = moran_loc.z[ix] y_mask = lag_spatial(moran_loc.w, moran_loc.z)[ix] axs[0].plot( x_mask, y_mask, color=mask_color, marker="o", markersize=14, alpha=0.8, linestyle="None", zorder=-1, ) # masking inside axs[1] or Lisa cluster map union = df_mask.unary_union.boundary gpd.GeoSeries([union]).plot(linewidth=2, ax=axs[1], color=mask_color) # masking inside axs[2] or Chloropleth gpd.GeoSeries([union]).plot(linewidth=2, ax=axs[2], color=mask_color) return fig, axs
def _moran_loc_bv_scatterplot( moran_loc_bv, p=None, aspect_equal=True, ax=None, scatter_kwds=None, fitline_kwds=None, ): """ Moran Bivariate Scatterplot with option of coloring of Local Moran Statistics Parameters ---------- moran_loc : esda.moran.Moran_Local_BV instance Values of Moran's I Local Autocorrelation Statistics p : float, optional If given, the p-value threshold for significance. Points will be colored by significance. By default it will not be colored. Default =None. aspect_equal : bool, optional If True, Axes of Moran Scatterplot will show the same aspect or visual proportions. ax : Matplotlib Axes instance, optional If given, the Moran plot will be created inside this axis. Default =None. scatter_kwds : keyword arguments, optional Keywords used for creating and designing the scatter points. Default =None. fitline_kwds : keyword arguments, optional Keywords used for creating and designing the moran fitline. Default =None. Returns ------- fig : Matplotlib Figure instance Bivariate Moran Local scatterplot figure ax : matplotlib Axes instance Axes in which the figure is plotted Examples -------- Imports >>> import matplotlib.pyplot as plt >>> import geopandas as gpd >>> from libpysal.weights.contiguity import Queen >>> from libpysal import examples >>> from esda.moran import Moran_Local_BV >>> from splot.esda import moran_scatterplot Load data and calculate Moran Local statistics >>> guerry = examples.load_example('Guerry') >>> link_to_data = guerry.get_path('guerry.shp') >>> gdf = gpd.read_file(link_to_data) >>> x = gdf['Suicids'].values >>> y = gdf['Donatns'].values >>> w = Queen.from_dataframe(gdf) >>> w.transform = 'r' >>> m = Moran_Local_BV(x, y, w) Plot >>> moran_scatterplot(m) >>> plt.show() Customize plot >>> moran_scatterplot(m, p=0.05, ... fitline_kwds=dict(color='#4393c3'))) >>> plt.show() """ # 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 p is not None: if not isinstance(moran_loc_bv, Moran_Local_BV): raise ValueError( "`moran_loc_bv` is not a\n" + "esda.moran.Moran_Local_BV instance" ) if "color" in scatter_kwds or "c" in scatter_kwds or "cmap" in scatter_kwds: warnings.warn( "To change the color use cmap with a colormap of 5,\n" + "c defines the LISA category, color will interfere with c" ) # colors spots_bv = moran_hot_cold_spots(moran_loc_bv, p) hmap = colors.ListedColormap( ["#bababa", "#d7191c", "#abd9e9", "#2c7bb6", "#fdae61"] ) # define customization scatter_kwds.setdefault("alpha", 0.6) scatter_kwds.setdefault("s", 40) fitline_kwds.setdefault("alpha", 0.9) # get fig and ax fig, ax = _create_moran_fig_ax(ax, figsize=(7, 7), aspect_equal=aspect_equal) # set labels ax.set_xlabel("Attribute") ax.set_ylabel("Spatial Lag") ax.set_title("Moran BV Local Scatterplot") # plot and set standards lag = lag_spatial(moran_loc_bv.w, moran_loc_bv.zy) fit = OLS(moran_loc_bv.zy[:, None], lag[:, None]) # v- and hlines ax.axvline(0, alpha=0.5, color="k", linestyle="--") ax.axhline(0, alpha=0.5, color="k", linestyle="--") if p is not None: fitline_kwds.setdefault("color", "k") scatter_kwds.setdefault("cmap", hmap) scatter_kwds.setdefault("c", spots_bv) ax.plot(lag, fit.predy, **fitline_kwds) ax.scatter(moran_loc_bv.zx, fit.predy, **scatter_kwds) else: scatter_kwds.setdefault("color", splot_colors["moran_base"]) fitline_kwds.setdefault("color", splot_colors["moran_fit"]) ax.plot(lag, fit.predy, **fitline_kwds) ax.scatter(moran_loc_bv.zy, fit.predy, **scatter_kwds) return fig, ax
[docs]def moran_facet( moran_matrix, figsize=(16, 12), scatter_bv_kwds=None, fitline_bv_kwds=None, scatter_glob_kwds=dict(color="#737373"), fitline_glob_kwds=None, ): """ Moran Facet visualization. Includes BV Morans and Global Morans on the diagonal. Parameters ---------- moran_matrix : esda.moran.Moran_BV_matrix instance Dictionary of Moran_BV objects figsize : tuple, optional W, h of figure. Default =(16,12) scatter_bv_kwds : keyword arguments, optional Keywords used for creating and designing the scatter points of off-diagonal Moran_BV plots. Default =None. fitline_bv_kwds : keyword arguments, optional Keywords used for creating and designing the moran fitline of off-diagonal Moran_BV plots. Default =None. scatter_glob_kwds : keyword arguments, optional Keywords used for creating and designing the scatter points of diagonal Moran plots. Default =None. fitline_glob_kwds : keyword arguments, optional Keywords used for creating and designing the moran fitline of diagonal Moran plots. Default =None. Returns ------- fig : Matplotlib Figure instance Bivariate Moran Local scatterplot figure axarr : matplotlib Axes instance Axes in which the figure is plotted Examples -------- Imports >>> import matplotlib.pyplot as plt >>> import libpysal as lp >>> import numpy as np >>> import geopandas as gpd >>> from esda.moran import Moran_BV_matrix >>> from splot.esda import moran_facet Load data and calculate Moran Local statistics >>> f = gpd.read_file(lp.examples.get_path("sids2.dbf")) >>> varnames = ['SIDR74', 'SIDR79', 'NWR74', 'NWR79'] >>> vars = [numpy.array(f[var]) for var in varnames] >>> w = lp.io.open(lp.examples.get_path("sids2.gal")).read() >>> moran_matrix = Moran_BV_matrix(vars, w, varnames = varnames) Plot >>> fig, axarr = moran_facet(moran_matrix) >>> plt.show() Customize plot >>> fig, axarr = moran_facet(moran_matrix, ... fitline_bv_kwds=dict(color='#4393c3')) >>> plt.show() """ nrows = int(numpy.sqrt(len(moran_matrix))) + 1 ncols = nrows fig, axarr = plt.subplots(nrows, ncols, figsize=figsize, sharey=True, sharex=True) fig.suptitle("Moran Facet") for row in range(nrows): for col in range(ncols): if row == col: global_m = Moran( moran_matrix[row, (row + 1) % 4].zy, moran_matrix[row, (row + 1) % 4].w, ) _moran_global_scatterplot( global_m, ax=axarr[row, col], scatter_kwds=scatter_glob_kwds, fitline_kwds=fitline_glob_kwds, ) axarr[row, col].set_facecolor("#d9d9d9") else: _moran_bv_scatterplot( moran_matrix[row, col], ax=axarr[row, col], scatter_kwds=scatter_bv_kwds, fitline_kwds=fitline_bv_kwds, ) axarr[row, col].spines["bottom"].set_visible(False) axarr[row, col].spines["left"].set_visible(False) if row == nrows - 1: axarr[row, col].set_xlabel( str(moran_matrix[(col + 1) % 4, col].varnames["x"]).format(col) ) axarr[row, col].spines["bottom"].set_visible(True) else: axarr[row, col].set_xlabel("") if col == 0: axarr[row, col].set_ylabel( ( "Spatial Lag of " + str(moran_matrix[row, (row + 1) % 4].varnames["y"]) ).format(row) ) axarr[row, col].spines["left"].set_visible(True) else: axarr[row, col].set_ylabel("") axarr[row, col].set_title("") plt.tight_layout() return fig, axarr