Skip to content

Commit

Permalink
Fix shapely deprecation warnings and remove descartes dependency (#210)
Browse files Browse the repository at this point in the history
  • Loading branch information
fmaussion authored Nov 8, 2021
1 parent b6a6283 commit c1a183e
Show file tree
Hide file tree
Showing 14 changed files with 105 additions and 28 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/run-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -70,5 +70,5 @@ jobs:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
COVERALLS_SERVICE_NAME: github
run: |
pip3 install --upgrade coveralls &&
pip3 install --upgrade coveralls==3.2.0 &&
coveralls --finish
3 changes: 1 addition & 2 deletions ci/requirements-py37-all.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,10 @@ dependencies:
- matplotlib
- scikit-image
- Pillow
- descartes
- cartopy
- pip
- pip:
- coveralls
- coveralls==3.2.0
- pytest-cov
- pytest-mpl
- motionless
3 changes: 1 addition & 2 deletions ci/requirements-py38-all-rc.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,10 @@ dependencies:
- matplotlib
- Pillow
- scikit-image
- descartes
- cartopy
- pip
- pip:
- coveralls
- coveralls==3.2.0
- pytest-cov
- pytest-mpl
- motionless
3 changes: 1 addition & 2 deletions ci/requirements-py38-all.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,10 @@ dependencies:
- matplotlib
- scikit-image
- Pillow
- descartes
- cartopy
- pip
- pip:
- coveralls
- coveralls==3.2.0
- pytest-cov
- pytest-mpl
- motionless
2 changes: 1 addition & 1 deletion ci/requirements-py38-min.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,5 +13,5 @@ dependencies:
- xarray
- pip
- pip:
- coveralls
- coveralls==3.2.0
- pytest-cov
3 changes: 1 addition & 2 deletions ci/requirements-py38-xarray-dev.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,11 @@ dependencies:
- matplotlib
- Pillow
- scikit-image
- descartes
- cartopy
- pip
- pip:
- git+https://github.com/pydata/xarray.git
- coveralls
- coveralls==3.2.0
- pytest-cov
- pytest-mpl
- motionless
2 changes: 1 addition & 1 deletion ci/requirements-py38-xr.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,5 +14,5 @@ dependencies:
- dask
- pip
- pip:
- coveralls
- coveralls==3.2.0
- pytest-cov
3 changes: 1 addition & 2 deletions ci/requirements-py39-all.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,10 @@ dependencies:
- matplotlib
- scikit-image
- Pillow
- descartes
- cartopy
- pip
- pip:
- coveralls
- coveralls==3.2.0
- pytest-cov
- pytest-mpl
- motionless
1 change: 0 additions & 1 deletion docs/environment.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ dependencies:
- joblib
- geopandas
- xarray
- descartes
- sphinx-gallery
- scikit-image
- motionless
1 change: 0 additions & 1 deletion docs/installing.rst
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,6 @@ For plotting
- `matplotlib <http://matplotlib.org/>`__: required for :ref:`plotting`
- `pillow <http://pillow.readthedocs.io>`__: required for salem.Map
- `scikit-image <https://scikit-image.org>`__: required for salem.Map
- `descartes <https://pypi.python.org/pypi/descartes/>`__: for paths and patches on maps
- `motionless <https://github.com/ryancox/motionless/>`__: for google static maps


Expand Down
76 changes: 76 additions & 0 deletions salem/descartes.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
"""Paths and patches
This file is part of the package "descartes" by sgilles,
apparently discontinued today.
https://pypi.org/project/descartes
License: BSD License (BSD)
"""

from matplotlib.patches import PathPatch
from matplotlib.path import Path
from numpy import asarray, concatenate, ones


class Polygon(object):
# Adapt Shapely or GeoJSON/geo_interface polygons to a common interface
def __init__(self, context):
if hasattr(context, 'interiors'):
self.context = context
else:
self.context = getattr(context, '__geo_interface__', context)

@property
def geom_type(self):
return (getattr(self.context, 'geom_type', None)
or self.context['type'])

@property
def exterior(self):
return (getattr(self.context, 'exterior', None)
or self.context['coordinates'][0])

@property
def interiors(self):
value = getattr(self.context, 'interiors', None)
if value is None:
value = self.context['coordinates'][1:]
return value


def PolygonPath(polygon):
"""Constructs a compound matplotlib path from a Shapely or GeoJSON-like
geometric object"""
this = Polygon(polygon)
assert this.geom_type == 'Polygon'

def coding(ob):
# The codes will be all "LINETO" commands, except for "MOVETO"s at the
# beginning of each subpath
n = len(getattr(ob, 'coords', None) or ob)
vals = ones(n, dtype=Path.code_type) * Path.LINETO
vals[0] = Path.MOVETO
return vals

vertices = concatenate(
[asarray(this.exterior.coords)[:, :2]]
+ [asarray(r.coords)[:, :2] for r in this.interiors])
codes = concatenate(
[coding(this.exterior)]
+ [coding(r) for r in this.interiors])
return Path(vertices, codes)


def PolygonPatch(polygon, **kwargs):
"""Constructs a matplotlib patch from a geometric object
The `polygon` may be a Shapely or GeoJSON-like object with or without holes.
The `kwargs` are those supported by the matplotlib.patches.Polygon class
constructor. Returns an instance of matplotlib.patches.PathPatch.
Example (using Shapely Point and a matplotlib axes):
>>> b = Point(0, 0).buffer(1.0)
>>> patch = PolygonPatch(b, fc='blue', ec='blue', alpha=0.5)
>>> axis.add_patch(patch)
"""
return PathPatch(PolygonPath(polygon), **kwargs)
16 changes: 8 additions & 8 deletions salem/graphics.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
from mpl_toolkits.axes_grid1 import make_axes_locatable
from matplotlib.collections import PatchCollection, LineCollection
from shapely.geometry import MultiPoint, LineString, Polygon
from descartes.patch import PolygonPatch
from salem.descartes import PolygonPatch
from matplotlib.transforms import Transform as MPLTranform

from salem import utils, gis, sio, Grid, wgs84, sample_data_dir, GeoTiff
Expand Down Expand Up @@ -624,7 +624,7 @@ def set_geometry(self, geometry=None, crs=wgs84, text=None,

# Save
if 'Multi' in geom.type:
for g in geom:
for g in geom.geoms:
self._geometries.append((g, kwargs))
# dirty solution: I should use collections instead
if 'label' in kwargs:
Expand Down Expand Up @@ -717,7 +717,7 @@ def set_shapefile(self, shape=None, countries=False, oceans=False,
patches = []
for g in shape.geometry:
if 'Multi' in g.type:
for gg in g:
for gg in g.geoms:
patches.append(PolygonPatch(gg))
else:
patches.append(PolygonPatch(g))
Expand All @@ -730,10 +730,10 @@ def set_shapefile(self, shape=None, countries=False, oceans=False,
lines = []
for g in shape.geometry:
if 'Multi' in g.type:
for gg in g:
lines.append(np.array(gg))
for gg in g.geoms:
lines.append(np.array(gg.coords))
else:
lines.append(np.array(g))
lines.append(np.array(g.coords))
self._collections.append(LineCollection(lines, **kwargs))
else:
raise NotImplementedError(geomtype)
Expand Down Expand Up @@ -1146,7 +1146,7 @@ def plot(self, ax):
kwargs.setdefault('facecolor', 'none')
plot_polygon(ax, g, **kwargs) # was g.buffer(0). Why?
if g.type in ['LineString', 'LinearRing']:
a = np.array(g)
a = np.array(g.coords)
kwargs.setdefault('color', 'k')
ax.plot(a[:, 0], a[:, 1], **kwargs)
if g.type == 'Point':
Expand Down Expand Up @@ -1193,7 +1193,7 @@ def plot(self, ax):
def plot_polygon(ax, poly, edgecolor='black', **kwargs):
""" Plot a single Polygon geometry """

a = np.asarray(poly.exterior)
a = np.asarray(poly.exterior.coords)
# without Descartes, we could make a Patch of exterior
ax.add_patch(PolygonPatch(poly, **kwargs))
ax.plot(a[:, 0], a[:, 1], color=edgecolor)
Expand Down
3 changes: 2 additions & 1 deletion salem/tests/test_gis.py
Original file line number Diff line number Diff line change
Expand Up @@ -1056,7 +1056,8 @@ def test_geometry(self):
p = shpg.MultiPoint([shpg.Point(i, j) for i, j in zip(x.flatten(),
y.flatten())])
o = gis.transform_geometry(p, to_crs=g.proj)
assert_allclose([_p.coords for _p in o], [_p.coords for _p in p])
assert_allclose([_p.coords for _p in o.geoms],
[_p.coords for _p in p.geoms])

@requires_geopandas
def test_shape(self):
Expand Down
15 changes: 11 additions & 4 deletions salem/tests/test_graphics.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
from __future__ import division
from distutils.version import LooseVersion

import copy
import warnings
import os
import shutil
Expand Down Expand Up @@ -263,7 +262,11 @@ def test_map(self):
a[2, 2] = 2.2
a[2, 4] = 1.9
a[3, 3] = 9
cmap = copy.deepcopy(mpl.cm.get_cmap('jet'))
try:
cmap = mpl.cm.get_cmap('jet').copy()
except AttributeError:
import copy
cmap = copy.deepcopy(mpl.cm.get_cmap('jet'))

# ll_corner (type geotiff)
g = Grid(nxny=(5, 4), dxdy=(1, 1), x0y0=(0, 0), proj=wgs84,
Expand Down Expand Up @@ -398,7 +401,11 @@ def test_datalevels():
a[2, 4] = 1.9
a[3, 3] = 9

cm = copy.copy(mpl.cm.get_cmap('jet'))
try:
cm = mpl.cm.get_cmap('jet').copy()
except AttributeError:
import copy
cm = copy.deepcopy(mpl.cm.get_cmap('jet'))
cm.set_bad('pink')

# fig, axes = plt.subplots(nrows=3, ncols=2)
Expand Down Expand Up @@ -641,6 +648,7 @@ def test_oceans():
@requires_matplotlib
@pytest.mark.mpl_image_compare(baseline_dir=baseline_dir)
def test_geometries():

# UL Corner
g = Grid(nxny=(5, 4), dxdy=(10, 10), x0y0=(-20, -15), proj=wgs84,
pixel_ref='corner')
Expand Down Expand Up @@ -929,7 +937,6 @@ def test_colormaps():
@requires_matplotlib
@pytest.mark.mpl_image_compare(baseline_dir=baseline_dir, tolerance=5)
def test_geogrid_simulator():

from salem.wrftools import geogrid_simulator
g, maps = geogrid_simulator(get_demo_file('namelist_mercator.wps'),
do_maps=True)
Expand Down

0 comments on commit c1a183e

Please sign in to comment.