Codebase list python-geopandas / 0246bb2
New upstream version 0.6.2 Bas Couwenberg 4 years ago
11 changed file(s) with 298 addition(s) and 22 deletion(s). Raw diff Collapse all Expand all
00 Changes
11 =======
22
3 Version 0.6.1 (July 11, 2019)
4 -----------------------------
3
4 Version 0.6.2 (November 18, 2019)
5 ---------------------------------
6
7 Small bug-fix release fixing a few regressions:
8
9 - Fix a regression in passing an array of RRB(A) tuples to the ``.plot()``
10 method (#1178, #1211).
11 - Fix the ``bounds`` and ``total_bounds`` attributes for empty GeoSeries, which
12 also fixes the repr of an empty or all-NA GeoSeries (#1184, #1195).
13 - Fix filtering of a GeoDataFrame to preserve the index type when ending up
14 with an empty result (#1190).
15
16
17 Version 0.6.1 (October 12, 2019)
18 --------------------------------
519
620 Small bug-fix release fixing a few regressions:
721
77 # -----------------------------------------------------------------------------
88
99 PANDAS_GE_024 = str(pd.__version__) >= LooseVersion("0.24.0")
10 PANDAS_GE_025 = str(pd.__version__) >= LooseVersion("0.25.0")
1011
1112
1213 # -----------------------------------------------------------------------------
2121 # setup.py/versioneer.py will grep for the variable names, so they must
2222 # each be defined on a line of their own. _version.py will just call
2323 # get_keywords().
24 git_refnames = " (tag: v0.6.1)"
25 git_full = "7df43d1375fee9174eb9314567c2464ed2d7e7a1"
24 git_refnames = " (tag: v0.6.2, 0.6.x)"
25 git_full = "34fe94357b8131afb49da76b1e5b14d9477f9e37"
2626 keywords = {"refnames": git_refnames, "full": git_full}
2727 return keywords
2828
731731
732732 @property
733733 def bounds(self):
734 # ensure that for empty arrays, the result has the correct shape
735 if len(self) == 0:
736 return np.empty((0, 4), dtype="float64")
734737 # need to explicitly check for empty (in addition to missing) geometries,
735738 # as those return an empty tuple, not resulting in a 2D array
736739 bounds = np.array(
745748
746749 @property
747750 def total_bounds(self):
751 if len(self) == 0:
752 # numpy 'min' cannot handle empty arrays
753 # TODO with numpy >= 1.15, the 'initial' argument can be used
754 return np.array([np.nan, np.nan, np.nan, np.nan])
748755 b = self.bounds
749756 return np.array(
750757 (
7171 # TODO do we want to raise / return normal DataFrame in this case?
7272 if geometry is None and "geometry" in self.columns:
7373 # only if we have actual geometry values -> call set_geometry
74 index = self.index
7475 try:
7576 self["geometry"] = _ensure_geometry(self["geometry"].values)
7677 except TypeError:
7778 pass
7879 else:
80 if self.index is not index:
81 # With pandas < 1.0 and an empty frame (no rows), the index
82 # gets reset to a default RangeIndex -> set back the original
83 # index if needed
84 self.index = index
7985 geometry = "geometry"
8086
8187 if geometry is not None:
172178
173179 # Check that we are using a listlike of geometries
174180 level = _ensure_geometry(level)
181 index = frame.index
175182 frame[geo_column_name] = level
183 if frame.index is not index and len(frame.index) == len(index):
184 # With pandas < 1.0 and an empty frame (no rows), the index gets reset
185 # to a default RangeIndex -> set back the original index if needed
186 frame.index = index
176187 frame._geometry_column_name = geo_column_name
177188 frame.crs = crs
178189 frame._invalidate_sindex()
8989 "The descartes package is required for plotting polygons in geopandas."
9090 )
9191 from matplotlib.collections import PatchCollection
92 from matplotlib.colors import is_color_like
9293
9394 geoms, multiindex = _flatten_multi_geoms(geoms, range(len(geoms)))
9495 if values is not None:
95 values = np.take(values, multiindex)
96 values = np.take(values, multiindex, axis=0)
9697
9798 # PatchCollection does not accept some kwargs.
9899 if "markersize" in kwargs:
99100 del kwargs["markersize"]
100101 if color is not None:
101 kwargs["color"] = color
102 if pd.api.types.is_list_like(color):
103 kwargs["color"] = np.take(color, multiindex)
102 if is_color_like(color):
103 kwargs["color"] = color
104 elif pd.api.types.is_list_like(color):
105 kwargs["color"] = np.take(color, multiindex, axis=0)
104106 else:
105 kwargs["color"] = color
107 raise TypeError(
108 "Color attribute has to be a single color or sequence of colors."
109 )
110
106111 else:
107112 for att in ["facecolor", "edgecolor"]:
108113 if att in kwargs:
109 if pd.api.types.is_list_like(kwargs[att]):
110 kwargs[att] = np.take(kwargs[att], multiindex)
114 if not is_color_like(kwargs[att]):
115 if pd.api.types.is_list_like(kwargs[att]):
116 kwargs[att] = np.take(kwargs[att], multiindex, axis=0)
117 elif kwargs[att] is not None:
118 raise TypeError(
119 "Color attribute has to be a single color or sequence "
120 "of colors."
121 )
111122
112123 collection = PatchCollection([PolygonPatch(poly) for poly in geoms], **kwargs)
113124
151162
152163 """
153164 from matplotlib.collections import LineCollection
165 from matplotlib.colors import is_color_like
154166
155167 geoms, multiindex = _flatten_multi_geoms(geoms, range(len(geoms)))
156168 if values is not None:
157 values = np.take(values, multiindex)
169 values = np.take(values, multiindex, axis=0)
158170
159171 # LineCollection does not accept some kwargs.
160172 if "markersize" in kwargs:
162174
163175 # color=None gives black instead of default color cycle
164176 if color is not None:
165 if pd.api.types.is_list_like(color):
166 kwargs["color"] = np.take(color, multiindex)
177 if is_color_like(color):
178 kwargs["color"] = color
179 elif pd.api.types.is_list_like(color):
180 kwargs["color"] = np.take(color, multiindex, axis=0)
167181 else:
168 kwargs["color"] = color
182 raise TypeError(
183 "Color attribute has to be a single color or sequence of colors."
184 )
169185
170186 segments = [np.array(linestring)[:, :2] for linestring in geoms]
171187 collection = LineCollection(segments, **kwargs)
214230 -------
215231 collection : matplotlib.collections.Collection that was plotted
216232 """
233 from matplotlib.colors import is_color_like
234
217235 if values is not None and color is not None:
218236 raise ValueError("Can only specify one of 'values' and 'color' kwargs")
219237
220238 geoms, multiindex = _flatten_multi_geoms(geoms, range(len(geoms)))
221239 if values is not None:
222 values = np.take(values, multiindex)
240 values = np.take(values, multiindex, axis=0)
223241
224242 x = [p.x for p in geoms]
225243 y = [p.y for p in geoms]
231249 kwargs["s"] = markersize
232250
233251 if color is not None:
234 if pd.api.types.is_list_like(color):
235 color = np.take(color, multiindex)
252 if not is_color_like(color):
253 if pd.api.types.is_list_like(color):
254 color = np.take(color, multiindex, axis=0)
255 else:
256 raise TypeError(
257 "Color attribute has to be a single color or sequence of colors."
258 )
236259
237260 if "norm" not in kwargs:
238261 collection = ax.scatter(
88 import shapely.geometry
99 from shapely.geometry.base import CAP_STYLE, JOIN_STYLE
1010 import shapely.wkb
11 from shapely._buildcfg import geos_version
1112
1213 import geopandas
1314 from geopandas.array import (
393394 )
394395 def test_unary_predicates(attr):
395396 na_value = False
396 if attr == "is_simple":
397 # poly.is_simple raises an error for empty polygon
397 if attr == "is_simple" and geos_version < (3, 8):
398 # poly.is_simple raises an error for empty polygon for GEOS < 3.8
398399 with pytest.raises(Exception):
399400 T.is_simple
400401 vals = triangle_no_missing
615616 assert result.dtype == "float64"
616617 np.testing.assert_allclose(result, np.array([[np.nan] * 4]))
617618
619 # empty array (https://github.com/geopandas/geopandas/issues/1195)
620 E = from_shapely([])
621 result = E.bounds
622 assert result.shape == (0, 4)
623 assert result.dtype == "float64"
624
625
626 def test_total_bounds():
627 result = T.total_bounds
628 bounds = np.array(
629 [t.bounds if not (t is None or t.is_empty) else [np.nan] * 4 for t in triangles]
630 )
631 expected = np.array(
632 [
633 bounds[:, 0].min(), # minx
634 bounds[:, 1].min(), # miny
635 bounds[:, 2].max(), # maxx
636 bounds[:, 3].max(), # maxy
637 ]
638 )
639 np.testing.assert_allclose(result, expected)
640
641 # additional check for empty array or one empty / missing
642 for geoms in [[], [None], [shapely.geometry.Polygon()]]:
643 E = from_shapely(geoms)
644 result = E.total_bounds
645 assert result.ndim == 1
646 assert result.dtype == "float64"
647 np.testing.assert_allclose(result, np.array([np.nan] * 4))
648
618649
619650 def test_getitem():
620651 points = [shapely.geometry.Point(i, i) for i in range(10)]
285285 for i, r in df.iterrows():
286286 assert i == r["geometry"].x
287287 assert i == r["geometry"].y
288
289 def test_set_geometry_empty(self):
290 df = pd.DataFrame(columns=["a", "geometry"], index=pd.DatetimeIndex([]))
291 result = df.set_geometry("geometry")
292 assert isinstance(result, GeoDataFrame)
293 assert isinstance(result.index, pd.DatetimeIndex)
288294
289295 def test_align(self):
290296 df = self.df2
298298 result = gdf.bounds
299299 assert_frame_equal(expected, result)
300300
301 def test_bounds_empty(self):
302 # test bounds of empty GeoSeries
303 # https://github.com/geopandas/geopandas/issues/1195
304 s = GeoSeries([])
305 result = s.bounds
306 expected = DataFrame(
307 columns=["minx", "miny", "maxx", "maxy"], index=s.index, dtype="float64"
308 )
309 assert_frame_equal(result, expected)
310
301311 def test_unary_union(self):
302312 p1 = self.t1
303313 p2 = Polygon([(2, 0), (3, 0), (3, 1)])
1111
1212 import geopandas
1313 from geopandas import GeoDataFrame, GeoSeries
14 from geopandas._compat import PANDAS_GE_024
14 from geopandas._compat import PANDAS_GE_024, PANDAS_GE_025
1515 from geopandas.array import from_shapely
1616
17 from geopandas.tests.util import assert_geoseries_equal
17 from geopandas.testing import assert_geodataframe_equal, assert_geoseries_equal
1818 from pandas.util.testing import assert_frame_equal, assert_series_equal
1919 import pytest
2020
3838 def test_repr(s, df):
3939 assert "POINT" in repr(s)
4040 assert "POINT" in repr(df)
41 assert "POINT" in df._repr_html_()
4142
4243
4344 @pytest.mark.skipif(
6162
6263 geopandas.options.display_precision = 9
6364 assert "POINT (10.123456789 50.123456789)" in repr(s1)
65
66
67 def test_repr_all_missing():
68 # https://github.com/geopandas/geopandas/issues/1195
69 s = GeoSeries([None, None, None])
70 assert "None" in repr(s)
71 df = GeoDataFrame({"a": [1, 2, 3], "geometry": s})
72 assert "None" in repr(df)
73 assert "geometry" in df._repr_html_()
74
75
76 def test_repr_empty():
77 # https://github.com/geopandas/geopandas/issues/1195
78 s = GeoSeries([])
79 if PANDAS_GE_025:
80 # repr with correct name fixed in pandas 0.25
81 assert repr(s) == "GeoSeries([], dtype: geometry)"
82 else:
83 assert repr(s) == "Series([], dtype: geometry)"
84 df = GeoDataFrame({"a": [], "geometry": s})
85 assert "Empty GeoDataFrame" in repr(df)
86 # https://github.com/geopandas/geopandas/issues/1184
87 assert "geometry" in df._repr_html_()
6488
6589
6690 def test_indexing(s, df):
118142
119143 # TODO df.reindex(columns=['value1', 'value2']) still returns GeoDataFrame,
120144 # should it return DataFrame instead ?
145
146
147 def test_take(s, df):
148 inds = np.array([0, 2])
149
150 # GeoSeries take
151 result = s.take(inds)
152 expected = s.iloc[[0, 2]]
153 assert isinstance(result, GeoSeries)
154 assert_geoseries_equal(result, expected)
155
156 # GeoDataFrame take axis 0
157 result = df.take(inds, axis=0)
158 expected = df.iloc[[0, 2], :]
159 assert isinstance(result, GeoDataFrame)
160 assert_geodataframe_equal(result, expected)
161
162 # GeoDataFrame take axis 1
163 df = df.reindex(columns=["value1", "value2", "geometry"]) # ensure consistent order
164 result = df.take(inds, axis=1)
165 expected = df[["value1", "geometry"]]
166 assert isinstance(result, GeoDataFrame)
167 assert_geodataframe_equal(result, expected)
168
169 result = df.take(np.array([0, 1]), axis=1)
170 expected = df[["value1", "value2"]]
171 assert isinstance(result, pd.DataFrame)
172 assert_frame_equal(result, expected)
173
174
175 def test_take_empty(s, df):
176 # ensure that index type is preserved in an empty take
177 # https://github.com/geopandas/geopandas/issues/1190
178 inds = np.array([], dtype="int64")
179
180 # use non-default index
181 df.index = pd.date_range("2012-01-01", periods=len(df))
182
183 result = df.take(inds, axis=0)
184 assert isinstance(result, GeoDataFrame)
185 assert result.shape == (0, 3)
186 assert isinstance(result.index, pd.DatetimeIndex)
187
188 # the original bug report was an empty boolean mask
189 for result in [df.loc[df["value1"] > 100], df[df["value1"] > 100]]:
190 assert isinstance(result, GeoDataFrame)
191 assert result.shape == (0, 3)
192 assert isinstance(result.index, pd.DatetimeIndex)
121193
122194
123195 def test_assignment(s, df):
117117
118118 ax = self.df.plot(color="green")
119119 _check_colors(self.N, ax.collections[0].get_facecolors(), ["green"] * self.N)
120
121 # check rgba tuple GH1178
122 ax = self.df.plot(color=(0.5, 0.5, 0.5))
123 _check_colors(
124 self.N, ax.collections[0].get_facecolors(), [(0.5, 0.5, 0.5)] * self.N
125 )
126 ax = self.df.plot(color=(0.5, 0.5, 0.5, 0.5))
127 _check_colors(
128 self.N, ax.collections[0].get_facecolors(), [(0.5, 0.5, 0.5, 0.5)] * self.N
129 )
130 with pytest.raises(TypeError):
131 self.df.plot(color="not color")
120132
121133 with warnings.catch_warnings(record=True) as _: # don't print warning
122134 # 'color' overrides 'column'
267279 ax = self.df.plot(color="green")
268280 _check_colors(self.N, ax.collections[0].get_colors(), ["green"] * self.N)
269281
282 # check rgba tuple GH1178
283 ax = self.df.plot(color=(0.5, 0.5, 0.5, 0.5))
284 _check_colors(
285 self.N, ax.collections[0].get_colors(), [(0.5, 0.5, 0.5, 0.5)] * self.N
286 )
287 ax = self.df.plot(color=(0.5, 0.5, 0.5, 0.5))
288 _check_colors(
289 self.N, ax.collections[0].get_colors(), [(0.5, 0.5, 0.5, 0.5)] * self.N
290 )
291 with pytest.raises(TypeError):
292 self.df.plot(color="not color")
293
270294 with warnings.catch_warnings(record=True) as _: # don't print warning
271295 # 'color' overrides 'column'
272296 ax = self.df.plot(column="values", color="green")
353377 _check_colors(2, ax.collections[0].get_facecolors(), ["green"] * 2)
354378 _check_colors(2, ax.collections[0].get_edgecolors(), ["k"] * 2)
355379
380 # check rgba tuple GH1178
381 ax = self.df.plot(color=(0.5, 0.5, 0.5))
382 _check_colors(2, ax.collections[0].get_facecolors(), [(0.5, 0.5, 0.5)] * 2)
383 ax = self.df.plot(color=(0.5, 0.5, 0.5, 0.5))
384 _check_colors(2, ax.collections[0].get_facecolors(), [(0.5, 0.5, 0.5, 0.5)] * 2)
385 with pytest.raises(TypeError):
386 self.df.plot(color="not color")
387
356388 with warnings.catch_warnings(record=True) as _: # don't print warning
357389 # 'color' overrides 'values'
358390 ax = self.df.plot(column="values", color="green")
402434 ax = self.polys.plot(facecolor="g", edgecolor="r", alpha=0.4)
403435 _check_colors(2, ax.collections[0].get_facecolors(), ["g"] * 2, alpha=0.4)
404436 _check_colors(2, ax.collections[0].get_edgecolors(), ["r"] * 2, alpha=0.4)
437
438 # check rgba tuple GH1178 for face and edge
439 ax = self.df.plot(facecolor=(0.5, 0.5, 0.5), edgecolor=(0.4, 0.5, 0.6))
440 _check_colors(2, ax.collections[0].get_facecolors(), [(0.5, 0.5, 0.5)] * 2)
441 _check_colors(2, ax.collections[0].get_edgecolors(), [(0.4, 0.5, 0.6)] * 2)
442
443 ax = self.df.plot(
444 facecolor=(0.5, 0.5, 0.5, 0.5), edgecolor=(0.4, 0.5, 0.6, 0.5)
445 )
446 _check_colors(2, ax.collections[0].get_facecolors(), [(0.5, 0.5, 0.5, 0.5)] * 2)
447 _check_colors(2, ax.collections[0].get_edgecolors(), [(0.4, 0.5, 0.6, 0.5)] * 2)
405448
406449 def test_legend_kwargs(self):
407450
666709 _check_colors(self.N, coll.get_edgecolors(), ["r", "g", "b"])
667710 ax.cla()
668711
712 coll = plot_point_collection(
713 ax,
714 self.points,
715 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)],
716 )
717 _check_colors(
718 self.N,
719 coll.get_facecolors(),
720 [(0.5, 0.5, 0.5, 0.5), (0.1, 0.2, 0.3, 0.5), (0.4, 0.5, 0.6, 0.5)],
721 )
722 _check_colors(
723 self.N,
724 coll.get_edgecolors(),
725 [(0.5, 0.5, 0.5, 0.5), (0.1, 0.2, 0.3, 0.5), (0.4, 0.5, 0.6, 0.5)],
726 )
727 ax.cla()
728
729 # not a color
730 with pytest.raises(TypeError):
731 plot_point_collection(ax, self.points, color="not color")
732
669733 def test_points_values(self):
670734 from geopandas.plotting import plot_point_collection
671735
709773 _check_colors(self.N, coll.get_colors(), ["r", "g", "b"])
710774 ax.cla()
711775
776 coll = plot_linestring_collection(
777 ax,
778 self.lines,
779 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)],
780 )
781 _check_colors(
782 self.N,
783 coll.get_colors(),
784 [(0.5, 0.5, 0.5, 0.5), (0.1, 0.2, 0.3, 0.5), (0.4, 0.5, 0.6, 0.5)],
785 )
786 ax.cla()
787
712788 # pass through of kwargs
713789 coll = plot_linestring_collection(ax, self.lines, linestyle="--", linewidth=1)
714790 exp_ls = _style_to_linestring_onoffseq("dashed", 1)
717793 assert res_ls[1] == exp_ls[1]
718794 ax.cla()
719795
796 # not a color
797 with pytest.raises(TypeError):
798 plot_linestring_collection(ax, self.lines, color="not color")
799
720800 def test_linestrings_values(self):
721801 from geopandas.plotting import plot_linestring_collection
722802
773853 _check_colors(self.N, coll.get_edgecolor(), ["g", "b", "r"])
774854 ax.cla()
775855
856 coll = plot_polygon_collection(
857 ax,
858 self.polygons,
859 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)],
860 )
861 _check_colors(
862 self.N,
863 coll.get_facecolor(),
864 [(0.5, 0.5, 0.5, 0.5), (0.1, 0.2, 0.3, 0.5), (0.4, 0.5, 0.6, 0.5)],
865 )
866 _check_colors(
867 self.N,
868 coll.get_edgecolor(),
869 [(0.5, 0.5, 0.5, 0.5), (0.1, 0.2, 0.3, 0.5), (0.4, 0.5, 0.6, 0.5)],
870 )
871 ax.cla()
872
776873 # only setting facecolor keeps default for edgecolor
777874 coll = plot_polygon_collection(ax, self.polygons, facecolor="g")
778875 _check_colors(self.N, coll.get_facecolor(), ["g"] * self.N)
784881 _check_colors(self.N, coll.get_facecolor(), ["g"] * self.N)
785882 _check_colors(self.N, coll.get_edgecolor(), ["r"] * self.N)
786883 ax.cla()
884
885 # not a color
886 with pytest.raises(TypeError):
887 plot_polygon_collection(ax, self.polygons, color="not color")
787888
788889 def test_polygons_values(self):
789890 from geopandas.plotting import plot_polygon_collection