[Git][debian-gis-team/python-geopandas][upstream] New upstream version 0.6.2

Bas Couwenberg gitlab at salsa.debian.org
Tue Nov 19 04:47:02 GMT 2019



Bas Couwenberg pushed to branch upstream at Debian GIS Project / python-geopandas


Commits:
0246bb2c by Bas Couwenberg at 2019-11-19T04:25:41Z
New upstream version 0.6.2
- - - - -


11 changed files:

- CHANGELOG.md
- geopandas/_compat.py
- geopandas/_version.py
- geopandas/array.py
- geopandas/geodataframe.py
- geopandas/plotting.py
- geopandas/tests/test_array.py
- geopandas/tests/test_geodataframe.py
- geopandas/tests/test_geom_methods.py
- geopandas/tests/test_pandas_methods.py
- geopandas/tests/test_plotting.py


Changes:

=====================================
CHANGELOG.md
=====================================
@@ -1,8 +1,22 @@
 Changes
 =======
 
-Version 0.6.1 (July 11, 2019)
------------------------------
+
+Version 0.6.2 (November 18, 2019)
+---------------------------------
+
+Small bug-fix release fixing a few regressions:
+
+- Fix a regression in passing an array of RRB(A) tuples to the ``.plot()``
+  method (#1178, #1211).
+- Fix the ``bounds`` and ``total_bounds`` attributes for empty GeoSeries, which
+  also fixes the repr of an empty or all-NA GeoSeries (#1184, #1195).
+- Fix filtering of a GeoDataFrame to preserve the index type when ending up
+  with an empty result (#1190).
+
+
+Version 0.6.1 (October 12, 2019)
+--------------------------------
 
 Small bug-fix release fixing a few regressions:
 


=====================================
geopandas/_compat.py
=====================================
@@ -8,6 +8,7 @@ import six
 # -----------------------------------------------------------------------------
 
 PANDAS_GE_024 = str(pd.__version__) >= LooseVersion("0.24.0")
+PANDAS_GE_025 = str(pd.__version__) >= LooseVersion("0.25.0")
 
 
 # -----------------------------------------------------------------------------


=====================================
geopandas/_version.py
=====================================
@@ -22,8 +22,8 @@ def get_keywords():
     # setup.py/versioneer.py will grep for the variable names, so they must
     # each be defined on a line of their own. _version.py will just call
     # get_keywords().
-    git_refnames = " (tag: v0.6.1)"
-    git_full = "7df43d1375fee9174eb9314567c2464ed2d7e7a1"
+    git_refnames = " (tag: v0.6.2, 0.6.x)"
+    git_full = "34fe94357b8131afb49da76b1e5b14d9477f9e37"
     keywords = {"refnames": git_refnames, "full": git_full}
     return keywords
 


=====================================
geopandas/array.py
=====================================
@@ -732,6 +732,9 @@ class GeometryArray(ExtensionArray):
 
     @property
     def bounds(self):
+        # ensure that for empty arrays, the result has the correct shape
+        if len(self) == 0:
+            return np.empty((0, 4), dtype="float64")
         # need to explicitly check for empty (in addition to missing) geometries,
         # as those return an empty tuple, not resulting in a 2D array
         bounds = np.array(
@@ -746,6 +749,10 @@ class GeometryArray(ExtensionArray):
 
     @property
     def total_bounds(self):
+        if len(self) == 0:
+            # numpy 'min' cannot handle empty arrays
+            # TODO with numpy >= 1.15, the 'initial' argument can be used
+            return np.array([np.nan, np.nan, np.nan, np.nan])
         b = self.bounds
         return np.array(
             (


=====================================
geopandas/geodataframe.py
=====================================
@@ -72,11 +72,17 @@ class GeoDataFrame(GeoPandasBase, DataFrame):
         # TODO do we want to raise / return normal DataFrame in this case?
         if geometry is None and "geometry" in self.columns:
             # only if we have actual geometry values -> call set_geometry
+            index = self.index
             try:
                 self["geometry"] = _ensure_geometry(self["geometry"].values)
             except TypeError:
                 pass
             else:
+                if self.index is not index:
+                    # With pandas < 1.0 and an empty frame (no rows), the index
+                    # gets reset to a default RangeIndex -> set back the original
+                    # index if needed
+                    self.index = index
                 geometry = "geometry"
 
         if geometry is not None:
@@ -173,7 +179,12 @@ class GeoDataFrame(GeoPandasBase, DataFrame):
 
         # Check that we are using a listlike of geometries
         level = _ensure_geometry(level)
+        index = frame.index
         frame[geo_column_name] = level
+        if frame.index is not index and len(frame.index) == len(index):
+            # With pandas < 1.0 and an empty frame (no rows), the index gets reset
+            # to a default RangeIndex -> set back the original index if needed
+            frame.index = index
         frame._geometry_column_name = geo_column_name
         frame.crs = crs
         frame._invalidate_sindex()


=====================================
geopandas/plotting.py
=====================================
@@ -90,25 +90,36 @@ def plot_polygon_collection(
             "The descartes package is required for plotting polygons in geopandas."
         )
     from matplotlib.collections import PatchCollection
+    from matplotlib.colors import is_color_like
 
     geoms, multiindex = _flatten_multi_geoms(geoms, range(len(geoms)))
     if values is not None:
-        values = np.take(values, multiindex)
+        values = np.take(values, multiindex, axis=0)
 
     # PatchCollection does not accept some kwargs.
     if "markersize" in kwargs:
         del kwargs["markersize"]
     if color is not None:
-        kwargs["color"] = color
-        if pd.api.types.is_list_like(color):
-            kwargs["color"] = np.take(color, multiindex)
-        else:
+        if is_color_like(color):
             kwargs["color"] = color
+        elif pd.api.types.is_list_like(color):
+            kwargs["color"] = np.take(color, multiindex, axis=0)
+        else:
+            raise TypeError(
+                "Color attribute has to be a single color or sequence of colors."
+            )
+
     else:
         for att in ["facecolor", "edgecolor"]:
             if att in kwargs:
-                if pd.api.types.is_list_like(kwargs[att]):
-                    kwargs[att] = np.take(kwargs[att], multiindex)
+                if not is_color_like(kwargs[att]):
+                    if pd.api.types.is_list_like(kwargs[att]):
+                        kwargs[att] = np.take(kwargs[att], multiindex, axis=0)
+                    elif kwargs[att] is not None:
+                        raise TypeError(
+                            "Color attribute has to be a single color or sequence "
+                            "of colors."
+                        )
 
     collection = PatchCollection([PolygonPatch(poly) for poly in geoms], **kwargs)
 
@@ -152,10 +163,11 @@ def plot_linestring_collection(
 
     """
     from matplotlib.collections import LineCollection
+    from matplotlib.colors import is_color_like
 
     geoms, multiindex = _flatten_multi_geoms(geoms, range(len(geoms)))
     if values is not None:
-        values = np.take(values, multiindex)
+        values = np.take(values, multiindex, axis=0)
 
     # LineCollection does not accept some kwargs.
     if "markersize" in kwargs:
@@ -163,10 +175,14 @@ def plot_linestring_collection(
 
     # color=None gives black instead of default color cycle
     if color is not None:
-        if pd.api.types.is_list_like(color):
-            kwargs["color"] = np.take(color, multiindex)
-        else:
+        if is_color_like(color):
             kwargs["color"] = color
+        elif pd.api.types.is_list_like(color):
+            kwargs["color"] = np.take(color, multiindex, axis=0)
+        else:
+            raise TypeError(
+                "Color attribute has to be a single color or sequence of colors."
+            )
 
     segments = [np.array(linestring)[:, :2] for linestring in geoms]
     collection = LineCollection(segments, **kwargs)
@@ -215,12 +231,14 @@ def plot_point_collection(
     -------
     collection : matplotlib.collections.Collection that was plotted
     """
+    from matplotlib.colors import is_color_like
+
     if values is not None and color is not None:
         raise ValueError("Can only specify one of 'values' and 'color' kwargs")
 
     geoms, multiindex = _flatten_multi_geoms(geoms, range(len(geoms)))
     if values is not None:
-        values = np.take(values, multiindex)
+        values = np.take(values, multiindex, axis=0)
 
     x = [p.x for p in geoms]
     y = [p.y for p in geoms]
@@ -232,8 +250,13 @@ def plot_point_collection(
         kwargs["s"] = markersize
 
     if color is not None:
-        if pd.api.types.is_list_like(color):
-            color = np.take(color, multiindex)
+        if not is_color_like(color):
+            if pd.api.types.is_list_like(color):
+                color = np.take(color, multiindex, axis=0)
+            else:
+                raise TypeError(
+                    "Color attribute has to be a single color or sequence of colors."
+                )
 
     if "norm" not in kwargs:
         collection = ax.scatter(


=====================================
geopandas/tests/test_array.py
=====================================
@@ -9,6 +9,7 @@ import shapely.affinity
 import shapely.geometry
 from shapely.geometry.base import CAP_STYLE, JOIN_STYLE
 import shapely.wkb
+from shapely._buildcfg import geos_version
 
 import geopandas
 from geopandas.array import (
@@ -394,8 +395,8 @@ def test_binary_geo_scalar(attr):
 )
 def test_unary_predicates(attr):
     na_value = False
-    if attr == "is_simple":
-        # poly.is_simple raises an error for empty polygon
+    if attr == "is_simple" and geos_version < (3, 8):
+        # poly.is_simple raises an error for empty polygon for GEOS < 3.8
         with pytest.raises(Exception):
             T.is_simple
         vals = triangle_no_missing
@@ -616,6 +617,36 @@ def test_bounds():
         assert result.dtype == "float64"
         np.testing.assert_allclose(result, np.array([[np.nan] * 4]))
 
+    # empty array (https://github.com/geopandas/geopandas/issues/1195)
+    E = from_shapely([])
+    result = E.bounds
+    assert result.shape == (0, 4)
+    assert result.dtype == "float64"
+
+
+def test_total_bounds():
+    result = T.total_bounds
+    bounds = np.array(
+        [t.bounds if not (t is None or t.is_empty) else [np.nan] * 4 for t in triangles]
+    )
+    expected = np.array(
+        [
+            bounds[:, 0].min(),  # minx
+            bounds[:, 1].min(),  # miny
+            bounds[:, 2].max(),  # maxx
+            bounds[:, 3].max(),  # maxy
+        ]
+    )
+    np.testing.assert_allclose(result, expected)
+
+    # additional check for empty array or one empty / missing
+    for geoms in [[], [None], [shapely.geometry.Polygon()]]:
+        E = from_shapely(geoms)
+        result = E.total_bounds
+        assert result.ndim == 1
+        assert result.dtype == "float64"
+        np.testing.assert_allclose(result, np.array([np.nan] * 4))
+
 
 def test_getitem():
     points = [shapely.geometry.Point(i, i) for i in range(10)]


=====================================
geopandas/tests/test_geodataframe.py
=====================================
@@ -287,6 +287,12 @@ class TestDataFrame:
             assert i == r["geometry"].x
             assert i == r["geometry"].y
 
+    def test_set_geometry_empty(self):
+        df = pd.DataFrame(columns=["a", "geometry"], index=pd.DatetimeIndex([]))
+        result = df.set_geometry("geometry")
+        assert isinstance(result, GeoDataFrame)
+        assert isinstance(result.index, pd.DatetimeIndex)
+
     def test_align(self):
         df = self.df2
 


=====================================
geopandas/tests/test_geom_methods.py
=====================================
@@ -299,6 +299,16 @@ class TestGeomMethods:
         result = gdf.bounds
         assert_frame_equal(expected, result)
 
+    def test_bounds_empty(self):
+        # test bounds of empty GeoSeries
+        # https://github.com/geopandas/geopandas/issues/1195
+        s = GeoSeries([])
+        result = s.bounds
+        expected = DataFrame(
+            columns=["minx", "miny", "maxx", "maxy"], index=s.index, dtype="float64"
+        )
+        assert_frame_equal(result, expected)
+
     def test_unary_union(self):
         p1 = self.t1
         p2 = Polygon([(2, 0), (3, 0), (3, 1)])


=====================================
geopandas/tests/test_pandas_methods.py
=====================================
@@ -12,10 +12,10 @@ from shapely.geometry import Point, GeometryCollection
 
 import geopandas
 from geopandas import GeoDataFrame, GeoSeries
-from geopandas._compat import PANDAS_GE_024
+from geopandas._compat import PANDAS_GE_024, PANDAS_GE_025
 from geopandas.array import from_shapely
 
-from geopandas.tests.util import assert_geoseries_equal
+from geopandas.testing import assert_geodataframe_equal, assert_geoseries_equal
 from pandas.util.testing import assert_frame_equal, assert_series_equal
 import pytest
 
@@ -39,6 +39,7 @@ def df():
 def test_repr(s, df):
     assert "POINT" in repr(s)
     assert "POINT" in repr(df)
+    assert "POINT" in df._repr_html_()
 
 
 @pytest.mark.skipif(
@@ -64,6 +65,29 @@ def test_repr_boxed_display_precision():
     assert "POINT (10.123456789 50.123456789)" in repr(s1)
 
 
+def test_repr_all_missing():
+    # https://github.com/geopandas/geopandas/issues/1195
+    s = GeoSeries([None, None, None])
+    assert "None" in repr(s)
+    df = GeoDataFrame({"a": [1, 2, 3], "geometry": s})
+    assert "None" in repr(df)
+    assert "geometry" in df._repr_html_()
+
+
+def test_repr_empty():
+    # https://github.com/geopandas/geopandas/issues/1195
+    s = GeoSeries([])
+    if PANDAS_GE_025:
+        # repr with correct name fixed in pandas 0.25
+        assert repr(s) == "GeoSeries([], dtype: geometry)"
+    else:
+        assert repr(s) == "Series([], dtype: geometry)"
+    df = GeoDataFrame({"a": [], "geometry": s})
+    assert "Empty GeoDataFrame" in repr(df)
+    # https://github.com/geopandas/geopandas/issues/1184
+    assert "geometry" in df._repr_html_()
+
+
 def test_indexing(s, df):
 
     # accessing scalar from the geometry (colunm)
@@ -121,6 +145,54 @@ def test_reindex(s, df):
     # should it return DataFrame instead ?
 
 
+def test_take(s, df):
+    inds = np.array([0, 2])
+
+    # GeoSeries take
+    result = s.take(inds)
+    expected = s.iloc[[0, 2]]
+    assert isinstance(result, GeoSeries)
+    assert_geoseries_equal(result, expected)
+
+    # GeoDataFrame take axis 0
+    result = df.take(inds, axis=0)
+    expected = df.iloc[[0, 2], :]
+    assert isinstance(result, GeoDataFrame)
+    assert_geodataframe_equal(result, expected)
+
+    # GeoDataFrame take axis 1
+    df = df.reindex(columns=["value1", "value2", "geometry"])  # ensure consistent order
+    result = df.take(inds, axis=1)
+    expected = df[["value1", "geometry"]]
+    assert isinstance(result, GeoDataFrame)
+    assert_geodataframe_equal(result, expected)
+
+    result = df.take(np.array([0, 1]), axis=1)
+    expected = df[["value1", "value2"]]
+    assert isinstance(result, pd.DataFrame)
+    assert_frame_equal(result, expected)
+
+
+def test_take_empty(s, df):
+    # ensure that index type is preserved in an empty take
+    # https://github.com/geopandas/geopandas/issues/1190
+    inds = np.array([], dtype="int64")
+
+    # use non-default index
+    df.index = pd.date_range("2012-01-01", periods=len(df))
+
+    result = df.take(inds, axis=0)
+    assert isinstance(result, GeoDataFrame)
+    assert result.shape == (0, 3)
+    assert isinstance(result.index, pd.DatetimeIndex)
+
+    # the original bug report was an empty boolean mask
+    for result in [df.loc[df["value1"] > 100], df[df["value1"] > 100]]:
+        assert isinstance(result, GeoDataFrame)
+        assert result.shape == (0, 3)
+        assert isinstance(result.index, pd.DatetimeIndex)
+
+
 def test_assignment(s, df):
     exp = GeoSeries([Point(10, 10), Point(1, 1), Point(2, 2)])
 


=====================================
geopandas/tests/test_plotting.py
=====================================
@@ -119,6 +119,18 @@ class TestPointPlotting:
         ax = self.df.plot(color="green")
         _check_colors(self.N, ax.collections[0].get_facecolors(), ["green"] * self.N)
 
+        # check rgba tuple GH1178
+        ax = self.df.plot(color=(0.5, 0.5, 0.5))
+        _check_colors(
+            self.N, ax.collections[0].get_facecolors(), [(0.5, 0.5, 0.5)] * self.N
+        )
+        ax = self.df.plot(color=(0.5, 0.5, 0.5, 0.5))
+        _check_colors(
+            self.N, ax.collections[0].get_facecolors(), [(0.5, 0.5, 0.5, 0.5)] * self.N
+        )
+        with pytest.raises(TypeError):
+            self.df.plot(color="not color")
+
         with warnings.catch_warnings(record=True) as _:  # don't print warning
             # 'color' overrides 'column'
             ax = self.df.plot(column="values", color="green")
@@ -268,6 +280,18 @@ class TestLineStringPlotting:
         ax = self.df.plot(color="green")
         _check_colors(self.N, ax.collections[0].get_colors(), ["green"] * self.N)
 
+        # check rgba tuple GH1178
+        ax = self.df.plot(color=(0.5, 0.5, 0.5, 0.5))
+        _check_colors(
+            self.N, ax.collections[0].get_colors(), [(0.5, 0.5, 0.5, 0.5)] * self.N
+        )
+        ax = self.df.plot(color=(0.5, 0.5, 0.5, 0.5))
+        _check_colors(
+            self.N, ax.collections[0].get_colors(), [(0.5, 0.5, 0.5, 0.5)] * self.N
+        )
+        with pytest.raises(TypeError):
+            self.df.plot(color="not color")
+
         with warnings.catch_warnings(record=True) as _:  # don't print warning
             # 'color' overrides 'column'
             ax = self.df.plot(column="values", color="green")
@@ -354,6 +378,14 @@ class TestPolygonPlotting:
         _check_colors(2, ax.collections[0].get_facecolors(), ["green"] * 2)
         _check_colors(2, ax.collections[0].get_edgecolors(), ["k"] * 2)
 
+        # check rgba tuple GH1178
+        ax = self.df.plot(color=(0.5, 0.5, 0.5))
+        _check_colors(2, ax.collections[0].get_facecolors(), [(0.5, 0.5, 0.5)] * 2)
+        ax = self.df.plot(color=(0.5, 0.5, 0.5, 0.5))
+        _check_colors(2, ax.collections[0].get_facecolors(), [(0.5, 0.5, 0.5, 0.5)] * 2)
+        with pytest.raises(TypeError):
+            self.df.plot(color="not color")
+
         with warnings.catch_warnings(record=True) as _:  # don't print warning
             # 'color' overrides 'values'
             ax = self.df.plot(column="values", color="green")
@@ -404,6 +436,17 @@ class TestPolygonPlotting:
         _check_colors(2, ax.collections[0].get_facecolors(), ["g"] * 2, alpha=0.4)
         _check_colors(2, ax.collections[0].get_edgecolors(), ["r"] * 2, alpha=0.4)
 
+        # check rgba tuple GH1178 for face and edge
+        ax = self.df.plot(facecolor=(0.5, 0.5, 0.5), edgecolor=(0.4, 0.5, 0.6))
+        _check_colors(2, ax.collections[0].get_facecolors(), [(0.5, 0.5, 0.5)] * 2)
+        _check_colors(2, ax.collections[0].get_edgecolors(), [(0.4, 0.5, 0.6)] * 2)
+
+        ax = self.df.plot(
+            facecolor=(0.5, 0.5, 0.5, 0.5), edgecolor=(0.4, 0.5, 0.6, 0.5)
+        )
+        _check_colors(2, ax.collections[0].get_facecolors(), [(0.5, 0.5, 0.5, 0.5)] * 2)
+        _check_colors(2, ax.collections[0].get_edgecolors(), [(0.4, 0.5, 0.6, 0.5)] * 2)
+
     def test_legend_kwargs(self):
 
         ax = self.df.plot(
@@ -667,6 +710,27 @@ class TestPlotCollections:
         _check_colors(self.N, coll.get_edgecolors(), ["r", "g", "b"])
         ax.cla()
 
+        coll = plot_point_collection(
+            ax,
+            self.points,
+            color=[(0.5, 0.5, 0.5, 0.5), (0.1, 0.2, 0.3, 0.5), (0.4, 0.5, 0.6, 0.5)],
+        )
+        _check_colors(
+            self.N,
+            coll.get_facecolors(),
+            [(0.5, 0.5, 0.5, 0.5), (0.1, 0.2, 0.3, 0.5), (0.4, 0.5, 0.6, 0.5)],
+        )
+        _check_colors(
+            self.N,
+            coll.get_edgecolors(),
+            [(0.5, 0.5, 0.5, 0.5), (0.1, 0.2, 0.3, 0.5), (0.4, 0.5, 0.6, 0.5)],
+        )
+        ax.cla()
+
+        # not a color
+        with pytest.raises(TypeError):
+            plot_point_collection(ax, self.points, color="not color")
+
     def test_points_values(self):
         from geopandas.plotting import plot_point_collection
 
@@ -710,6 +774,18 @@ class TestPlotCollections:
         _check_colors(self.N, coll.get_colors(), ["r", "g", "b"])
         ax.cla()
 
+        coll = plot_linestring_collection(
+            ax,
+            self.lines,
+            color=[(0.5, 0.5, 0.5, 0.5), (0.1, 0.2, 0.3, 0.5), (0.4, 0.5, 0.6, 0.5)],
+        )
+        _check_colors(
+            self.N,
+            coll.get_colors(),
+            [(0.5, 0.5, 0.5, 0.5), (0.1, 0.2, 0.3, 0.5), (0.4, 0.5, 0.6, 0.5)],
+        )
+        ax.cla()
+
         # pass through of kwargs
         coll = plot_linestring_collection(ax, self.lines, linestyle="--", linewidth=1)
         exp_ls = _style_to_linestring_onoffseq("dashed", 1)
@@ -718,6 +794,10 @@ class TestPlotCollections:
         assert res_ls[1] == exp_ls[1]
         ax.cla()
 
+        # not a color
+        with pytest.raises(TypeError):
+            plot_linestring_collection(ax, self.lines, color="not color")
+
     def test_linestrings_values(self):
         from geopandas.plotting import plot_linestring_collection
 
@@ -774,6 +854,23 @@ class TestPlotCollections:
         _check_colors(self.N, coll.get_edgecolor(), ["g", "b", "r"])
         ax.cla()
 
+        coll = plot_polygon_collection(
+            ax,
+            self.polygons,
+            color=[(0.5, 0.5, 0.5, 0.5), (0.1, 0.2, 0.3, 0.5), (0.4, 0.5, 0.6, 0.5)],
+        )
+        _check_colors(
+            self.N,
+            coll.get_facecolor(),
+            [(0.5, 0.5, 0.5, 0.5), (0.1, 0.2, 0.3, 0.5), (0.4, 0.5, 0.6, 0.5)],
+        )
+        _check_colors(
+            self.N,
+            coll.get_edgecolor(),
+            [(0.5, 0.5, 0.5, 0.5), (0.1, 0.2, 0.3, 0.5), (0.4, 0.5, 0.6, 0.5)],
+        )
+        ax.cla()
+
         # only setting facecolor keeps default for edgecolor
         coll = plot_polygon_collection(ax, self.polygons, facecolor="g")
         _check_colors(self.N, coll.get_facecolor(), ["g"] * self.N)
@@ -786,6 +883,10 @@ class TestPlotCollections:
         _check_colors(self.N, coll.get_edgecolor(), ["r"] * self.N)
         ax.cla()
 
+        # not a color
+        with pytest.raises(TypeError):
+            plot_polygon_collection(ax, self.polygons, color="not color")
+
     def test_polygons_values(self):
         from geopandas.plotting import plot_polygon_collection
 



View it on GitLab: https://salsa.debian.org/debian-gis-team/python-geopandas/commit/0246bb2c367e653ec6ca42c8249a6ea2b4252bfc

-- 
View it on GitLab: https://salsa.debian.org/debian-gis-team/python-geopandas/commit/0246bb2c367e653ec6ca42c8249a6ea2b4252bfc
You're receiving this email because of your account on salsa.debian.org.


-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://alioth-lists.debian.net/pipermail/pkg-grass-devel/attachments/20191119/19e8ebde/attachment-0001.html>


More information about the Pkg-grass-devel mailing list