esda icon indicating copy to clipboard operation
esda copied to clipboard

implement `.plot()`, `.scatterplot()` and `.lisa_map()` methods for `Moran_Local` object

Open slumnitz opened this issue 6 years ago • 11 comments

implement visualisation methods for esda.moran.Moran_Local called from splot

write documentation and tests for methods

slumnitz avatar Jun 21 '18 01:06 slumnitz

Travis depends on this pull request to be able to install splot and call splot.esda from the master branch of the splot repository.

The last error in Travis seems unrelated: ERROR: test_by_col (esda.tests.test_moran.Moran_Rate_Tester)

@sjsrey @darribas @ljwolf

slumnitz avatar Jun 21 '18 06:06 slumnitz

@slumnitz I'm hitting an error trying to test this off of the branch slumnitz:splot-method: (All in a notebook but kludgy, so cut and paste here)

import matplotlib.pyplot as plt
import libpysal.api as lp
from libpysal import examples
from esda.moran import Moran_Local
import geopandas as gpd
link = examples.get_path('columbus.shp')
gdf = gpd.read_file(link)
y = gdf['HOVAL'].values
w = lp.Queen.from_dataframe(gdf)
w.transform = 'r'
mloc = Moran_Local(y, w)
fig, _ = mloc.plot(gdf, 'HOVAL')
plt.close(fig)

Is resulting in:

---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-3-bab1aa5c2c4b> in <module>()
     10 w.transform = 'r'
     11 mloc = Moran_Local(y, w)
---> 12 fig, _ = mloc.plot(gdf, 'HOVAL')
     13 plt.close(fig)

~/Dropbox/p/pysal/src/subpackages/esda/esda/moran.py in plot(self, gdf, attribute, p, region_column, mask, mask_color, quadrant, legend, scheme, cmap, figsize)
   1008                                                         scheme=scheme,
   1009                                                         cmap=cmap,
-> 1010                                                         figsize=figsize)
   1011         return fig, axs
   1012 

~/Dropbox/p/pysal/src/subpackages/splot/splot/_viz_esda_mpl.py in plot_local_autocorrelation(moran_loc, gdf, attribute, p, region_column, mask, mask_color, quadrant, legend, scheme, cmap, figsize)
    270     lisa_cluster(moran_loc, gdf, p=p, ax=axs[1], legend=legend,
    271                  legend_kwds={'loc': 'upper left',
--> 272                  'bbox_to_anchor': (0.92, 1.05)})
    273     axs[1].set_aspect('equal')
    274 

~/Dropbox/p/pysal/src/subpackages/splot/splot/_viz_esda_mpl.py in lisa_cluster(moran_loc, gdf, p, ax, legend, legend_kwds, **kwargs)
    187                               k=2, cmap=hmap, linewidth=0.1, ax=ax,
    188                               edgecolor='white', legend=legend,
--> 189                               legend_kwds=legend_kwds, **kwargs)
    190     ax.set_axis_off()
    191     ax.set_aspect('equal')

~/anaconda3/envs/libpysal3/lib/python3.6/site-packages/geopandas/geodataframe.py in plot(self, *args, **kwargs)
    467     def plot(self, *args, **kwargs):
    468 
--> 469         return plot_dataframe(self, *args, **kwargs)
    470 
    471     plot.__doc__ = plot_dataframe.__doc__

~/anaconda3/envs/libpysal3/lib/python3.6/site-packages/geopandas/plotting.py in plot_dataframe(df, column, cmap, color, ax, categorical, legend, scheme, k, vmin, vmax, figsize, **style_kwds)
    440     if not polys.empty:
    441         plot_polygon_collection(ax, polys, values[poly_idx],
--> 442                                 vmin=mn, vmax=mx, cmap=cmap, **style_kwds)
    443 
    444     # plot all LineStrings and MultiLineString components in same collection

~/anaconda3/envs/libpysal3/lib/python3.6/site-packages/geopandas/plotting.py in plot_polygon_collection(ax, geoms, values, color, cmap, vmin, vmax, **kwargs)
     95 
     96     collection = PatchCollection([PolygonPatch(poly) for poly in geoms],
---> 97                                  **kwargs)
     98 
     99     if values is not None:

~/anaconda3/envs/libpysal3/lib/python3.6/site-packages/matplotlib/collections.py in __init__(self, patches, match_original, **kwargs)
   1731             kwargs['antialiaseds'] = [p.get_antialiased() for p in patches]
   1732 
-> 1733         Collection.__init__(self, **kwargs)
   1734 
   1735         self.set_paths(patches)

~/anaconda3/envs/libpysal3/lib/python3.6/site-packages/matplotlib/collections.py in __init__(self, edgecolors, facecolors, linewidths, linestyles, capstyle, joinstyle, antialiaseds, offsets, transOffset, norm, cmap, pickradius, hatch, urls, offset_position, zorder, **kwargs)
    168 
    169         self._path_effects = None
--> 170         self.update(kwargs)
    171         self._paths = None
    172 

~/anaconda3/envs/libpysal3/lib/python3.6/site-packages/matplotlib/artist.py in update(self, props)
    886         try:
    887             ret = [_update_property(self, k, v)
--> 888                    for k, v in props.items()]
    889         finally:
    890             self.eventson = store

~/anaconda3/envs/libpysal3/lib/python3.6/site-packages/matplotlib/artist.py in <listcomp>(.0)
    886         try:
    887             ret = [_update_property(self, k, v)
--> 888                    for k, v in props.items()]
    889         finally:
    890             self.eventson = store

~/anaconda3/envs/libpysal3/lib/python3.6/site-packages/matplotlib/artist.py in _update_property(self, k, v)
    879                 func = getattr(self, 'set_' + k, None)
    880                 if not callable(func):
--> 881                     raise AttributeError('Unknown property %s' % k)
    882                 return func(v)
    883 

AttributeError: Unknown property legend_kwds

sjsrey avatar Jun 25 '18 04:06 sjsrey

legend_kwds is currently only available in the geopandas master branch. It has not been included in the gdf.plot() method in the last release of geopandas. Maybe @jorisvandenbossche has some info about if this is going to be included in a next release? @sjsrey I can add a warning here that the plot methods depend on the geopandas master branch?

slumnitz avatar Jun 25 '18 17:06 slumnitz

@slumnitz sorry for the delay in reviewing. I believe the issue here is due to the way the testing methods for unittest have not kept up to date with numpy's revisions.

Can you try changing self.assertEquals to numpy.testing.assert_allclose where that fails in the by_col test? I believe that would resolve.

ljwolf avatar Jun 26 '18 17:06 ljwolf

@ljwolf I tried adapt your suggestion. It still failed for me setting atol=ATOL and rtol=RTOL. Then I tried testing with values atol=0, rtol=1e-7 and so on, but it still kept failing. I am not sure what is happening but it seems like the actual p-value might be off?

slumnitz avatar Jun 26 '18 18:06 slumnitz

you're right. Note that a seed is not set in this testing class's setUp.

We need to set the seed and ensure that the resulting pval is right in the comparison.

on my box I get anything from .01 to .011.

ljwolf avatar Jun 27 '18 00:06 ljwolf

I fixed the by_col issue and found the source of the other problem: https://github.com/pysal/splot/pull/16

Once this is merged Travis will hopefully pass.

slumnitz avatar Jun 27 '18 03:06 slumnitz

Another issue with dependencies:

ModuleNotFoundError: No module named 'seaborn'

This should be installed when splot is installed. I will try to fix this in splot first. I'll include that in https://github.com/pysal/splot/pull/19

slumnitz avatar Jun 30 '18 01:06 slumnitz

@slumnitz can we close this?

sjsrey avatar Mar 04 '19 17:03 sjsrey

@sjsrey this PR was opened to call splot plotting methods from esda. I recall it was not merged for a while, because of open PRs in splot. If it is still of interest to call splot methods with .plot() in esda, I am happy to clean this up. I am not sure how difficult this will be since no-one has found out why splot fails at the moment. Otherwise it can be closed or closed and added as an issue in splot for future implementation? Your choice. :)

slumnitz avatar Mar 12 '19 03:03 slumnitz

@slumnitz I left notes for you regarding the splot testing failures. Although I have not had the time to track down the specific trigger for the segfault, the issue seems to be memory (code 139).

jGaboardi avatar Mar 12 '19 14:03 jGaboardi