venv
This commit is contained in:
@@ -1,28 +1,25 @@
|
||||
import itertools
|
||||
from packaging.version import Version
|
||||
import warnings
|
||||
from packaging.version import Version
|
||||
|
||||
import numpy as np
|
||||
import pandas as pd
|
||||
|
||||
from shapely import wkt
|
||||
from shapely.affinity import rotate
|
||||
from shapely.geometry import (
|
||||
MultiPolygon,
|
||||
Polygon,
|
||||
LineString,
|
||||
LinearRing,
|
||||
Point,
|
||||
MultiPoint,
|
||||
MultiLineString,
|
||||
GeometryCollection,
|
||||
LinearRing,
|
||||
LineString,
|
||||
MultiLineString,
|
||||
MultiPoint,
|
||||
MultiPolygon,
|
||||
Point,
|
||||
Polygon,
|
||||
box,
|
||||
)
|
||||
|
||||
|
||||
from geopandas import GeoDataFrame, GeoSeries, read_file
|
||||
from geopandas.datasets import get_path
|
||||
import geopandas._compat as compat
|
||||
from geopandas import GeoDataFrame, GeoSeries, read_file
|
||||
from geopandas.plotting import GeoplotAccessor
|
||||
|
||||
import pytest
|
||||
@@ -304,17 +301,9 @@ class TestPointPlotting:
|
||||
assert len(ax.collections) == 0
|
||||
|
||||
def test_empty_geometry(self):
|
||||
if compat.USE_PYGEOS:
|
||||
s = GeoSeries([wkt.loads("POLYGON EMPTY")])
|
||||
s = GeoSeries(
|
||||
[Polygon([(0, 0), (1, 0), (1, 1)]), wkt.loads("POLYGON EMPTY")]
|
||||
)
|
||||
ax = s.plot()
|
||||
assert len(ax.collections) == 1
|
||||
if not compat.USE_PYGEOS:
|
||||
s = GeoSeries([Polygon([(0, 0), (1, 0), (1, 1)]), Polygon()])
|
||||
ax = s.plot()
|
||||
assert len(ax.collections) == 1
|
||||
s = GeoSeries([Polygon([(0, 0), (1, 0), (1, 1)]), Polygon()])
|
||||
ax = s.plot()
|
||||
assert len(ax.collections) == 1
|
||||
|
||||
# more complex case with GEOMETRYCOLLECTION EMPTY, POINT EMPTY and NONE
|
||||
poly = Polygon([(-1, -1), (-1, 2), (2, 2), (2, -1), (-1, -1)])
|
||||
@@ -324,7 +313,14 @@ class TestPointPlotting:
|
||||
|
||||
gdf = GeoDataFrame(geometry=[point, empty_point, point_])
|
||||
gdf["geometry"] = gdf.intersection(poly)
|
||||
gdf.loc[3] = [None]
|
||||
with warnings.catch_warnings():
|
||||
# loc to add row calls concat internally, warning for pandas >=2.1
|
||||
warnings.filterwarnings(
|
||||
"ignore",
|
||||
"The behavior of DataFrame concatenation with empty",
|
||||
FutureWarning,
|
||||
)
|
||||
gdf.loc[3] = [None]
|
||||
ax = gdf.plot()
|
||||
assert len(ax.collections) == 1
|
||||
|
||||
@@ -498,6 +494,28 @@ class TestLineStringPlotting:
|
||||
)
|
||||
self.df3 = GeoDataFrame({"geometry": self.linearrings, "values": values})
|
||||
|
||||
def test_autolim_false(self):
|
||||
"""Test linestring plot preserving axes limits."""
|
||||
ax = self.lines[: self.N // 2].plot()
|
||||
ylim = ax.get_ylim()
|
||||
self.lines.plot(ax=ax, autolim=False)
|
||||
assert ax.get_ylim() == ylim
|
||||
ax = self.df[: self.N // 2].plot()
|
||||
ylim = ax.get_ylim()
|
||||
self.df.plot(ax=ax, autolim=False)
|
||||
assert ax.get_ylim() == ylim
|
||||
|
||||
def test_autolim_true(self):
|
||||
"""Test linestring plot autoscaling axes limits."""
|
||||
ax = self.lines[: self.N // 2].plot()
|
||||
ylim = ax.get_ylim()
|
||||
self.lines.plot(ax=ax, autolim=True)
|
||||
assert ax.get_ylim() != ylim
|
||||
ax = self.df[: self.N // 2].plot()
|
||||
ylim = ax.get_ylim()
|
||||
self.df.plot(ax=ax, autolim=True)
|
||||
assert ax.get_ylim() != ylim
|
||||
|
||||
def test_single_color(self):
|
||||
ax = self.lines.plot(color="green")
|
||||
_check_colors(self.N, ax.collections[0].get_colors(), ["green"] * self.N)
|
||||
@@ -641,6 +659,28 @@ class TestPolygonPlotting:
|
||||
df_nan = GeoDataFrame({"geometry": t3, "values": [np.nan]})
|
||||
self.df3 = pd.concat([self.df, df_nan])
|
||||
|
||||
def test_autolim_false(self):
|
||||
"""Test polygon plot preserving axes limits."""
|
||||
ax = self.polys[:1].plot()
|
||||
xlim = ax.get_xlim()
|
||||
self.polys.plot(ax=ax, autolim=False)
|
||||
assert ax.get_xlim() == xlim
|
||||
ax = self.df[:1].plot()
|
||||
xlim = ax.get_xlim()
|
||||
self.df.plot(ax=ax, autolim=False)
|
||||
assert ax.get_xlim() == xlim
|
||||
|
||||
def test_autolim_true(self):
|
||||
"""Test polygon plot autoscaling axes limits."""
|
||||
ax = self.polys[:1].plot()
|
||||
xlim = ax.get_xlim()
|
||||
self.polys.plot(ax=ax, autolim=True)
|
||||
assert ax.get_xlim() != xlim
|
||||
ax = self.df[:1].plot()
|
||||
xlim = ax.get_xlim()
|
||||
self.df.plot(ax=ax, autolim=True)
|
||||
assert ax.get_xlim() != xlim
|
||||
|
||||
def test_single_color(self):
|
||||
ax = self.polys.plot(color="green")
|
||||
_check_colors(2, ax.collections[0].get_facecolors(), ["green"] * 2)
|
||||
@@ -1070,16 +1110,20 @@ class TestNonuniformGeometryPlotting:
|
||||
# )
|
||||
|
||||
|
||||
class TestGeographicAspect:
|
||||
def setup_class(self):
|
||||
pth = get_path("naturalearth_lowres")
|
||||
df = read_file(pth)
|
||||
self.north = df.loc[df.continent == "North America"]
|
||||
self.north_proj = self.north.to_crs("ESRI:102008")
|
||||
bounds = self.north.total_bounds
|
||||
y_coord = np.mean([bounds[1], bounds[3]])
|
||||
self.exp = 1 / np.cos(y_coord * np.pi / 180)
|
||||
@pytest.fixture(scope="class")
|
||||
def _setup_class_geographic_aspect(naturalearth_lowres, request):
|
||||
"""Attach naturalearth_lowres class attribute for unittest style setup_method"""
|
||||
df = read_file(naturalearth_lowres)
|
||||
request.cls.north = df.loc[df.continent == "North America"]
|
||||
request.cls.north_proj = request.cls.north.to_crs("ESRI:102008")
|
||||
bounds = request.cls.north.total_bounds
|
||||
y_coord = np.mean([bounds[1], bounds[3]])
|
||||
request.cls.exp = 1 / np.cos(y_coord * np.pi / 180)
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("_setup_class_geographic_aspect")
|
||||
@pytest.mark.skipif(not compat.HAS_PYPROJ, reason="pyproj not available")
|
||||
class TestGeographicAspect:
|
||||
def test_auto(self):
|
||||
ax = self.north.geometry.plot()
|
||||
assert ax.get_aspect() == self.exp
|
||||
@@ -1133,6 +1177,9 @@ class TestGeographicAspect:
|
||||
assert ax3.get_aspect() == 0.5
|
||||
|
||||
|
||||
@pytest.mark.filterwarnings(
|
||||
"ignore:Numba not installed. Using slow pure python version.:UserWarning"
|
||||
)
|
||||
class TestMapclassifyPlotting:
|
||||
@classmethod
|
||||
def setup_class(cls):
|
||||
@@ -1143,31 +1190,40 @@ class TestMapclassifyPlotting:
|
||||
cls.mc = mapclassify
|
||||
cls.classifiers = list(mapclassify.classifiers.CLASSIFIERS)
|
||||
cls.classifiers.remove("UserDefined")
|
||||
pth = get_path("naturalearth_lowres")
|
||||
cls.df = read_file(pth)
|
||||
cls.df["NEGATIVES"] = np.linspace(-10, 10, len(cls.df.index))
|
||||
cls.df["low_vals"] = np.linspace(0, 0.3, cls.df.shape[0])
|
||||
cls.df["mid_vals"] = np.linspace(0.3, 0.7, cls.df.shape[0])
|
||||
cls.df["high_vals"] = np.linspace(0.7, 1.0, cls.df.shape[0])
|
||||
cls.df.loc[cls.df.index[:20:2], "high_vals"] = np.nan
|
||||
cls.nybb = read_file(get_path("nybb"))
|
||||
cls.nybb["vals"] = [0.001, 0.002, 0.003, 0.004, 0.005]
|
||||
|
||||
def test_legend(self):
|
||||
@pytest.fixture
|
||||
def df(self, naturalearth_lowres):
|
||||
# version of naturalearth_lowres for mapclassify plotting tests
|
||||
df = read_file(naturalearth_lowres)
|
||||
df["NEGATIVES"] = np.linspace(-10, 10, len(df.index))
|
||||
df["low_vals"] = np.linspace(0, 0.3, df.shape[0])
|
||||
df["mid_vals"] = np.linspace(0.3, 0.7, df.shape[0])
|
||||
df["high_vals"] = np.linspace(0.7, 1.0, df.shape[0])
|
||||
df.loc[df.index[:20:2], "high_vals"] = np.nan
|
||||
return df
|
||||
|
||||
@pytest.fixture
|
||||
def nybb(self, nybb_filename):
|
||||
# version of nybb for mapclassify plotting tests
|
||||
df = read_file(nybb_filename)
|
||||
df["vals"] = [0.001, 0.002, 0.003, 0.004, 0.005]
|
||||
return df
|
||||
|
||||
def test_legend(self, df):
|
||||
with warnings.catch_warnings(record=True) as _: # don't print warning
|
||||
# warning coming from scipy.stats
|
||||
ax = self.df.plot(
|
||||
ax = df.plot(
|
||||
column="pop_est", scheme="QUANTILES", k=3, cmap="OrRd", legend=True
|
||||
)
|
||||
labels = [t.get_text() for t in ax.get_legend().get_texts()]
|
||||
expected = [
|
||||
s.split("|")[0][1:-2]
|
||||
for s in str(self.mc.Quantiles(self.df["pop_est"], k=3)).split("\n")[4:]
|
||||
for s in str(self.mc.Quantiles(df["pop_est"], k=3)).split("\n")[4:]
|
||||
]
|
||||
assert labels == expected
|
||||
|
||||
def test_bin_labels(self):
|
||||
ax = self.df.plot(
|
||||
def test_bin_labels(self, df):
|
||||
ax = df.plot(
|
||||
column="pop_est",
|
||||
scheme="QUANTILES",
|
||||
k=3,
|
||||
@@ -1179,9 +1235,9 @@ class TestMapclassifyPlotting:
|
||||
expected = ["foo", "bar", "baz"]
|
||||
assert labels == expected
|
||||
|
||||
def test_invalid_labels_length(self):
|
||||
def test_invalid_labels_length(self, df):
|
||||
with pytest.raises(ValueError):
|
||||
self.df.plot(
|
||||
df.plot(
|
||||
column="pop_est",
|
||||
scheme="QUANTILES",
|
||||
k=3,
|
||||
@@ -1190,16 +1246,16 @@ class TestMapclassifyPlotting:
|
||||
legend_kwds={"labels": ["foo", "bar"]},
|
||||
)
|
||||
|
||||
def test_negative_legend(self):
|
||||
ax = self.df.plot(
|
||||
def test_negative_legend(self, df):
|
||||
ax = df.plot(
|
||||
column="NEGATIVES", scheme="FISHER_JENKS", k=3, cmap="OrRd", legend=True
|
||||
)
|
||||
labels = [t.get_text() for t in ax.get_legend().get_texts()]
|
||||
expected = ["-10.00, -3.41", " -3.41, 3.30", " 3.30, 10.00"]
|
||||
assert labels == expected
|
||||
|
||||
def test_fmt(self):
|
||||
ax = self.df.plot(
|
||||
def test_fmt(self, df):
|
||||
ax = df.plot(
|
||||
column="NEGATIVES",
|
||||
scheme="FISHER_JENKS",
|
||||
k=3,
|
||||
@@ -1211,8 +1267,8 @@ class TestMapclassifyPlotting:
|
||||
expected = ["-10, -3", " -3, 3", " 3, 10"]
|
||||
assert labels == expected
|
||||
|
||||
def test_interval(self):
|
||||
ax = self.df.plot(
|
||||
def test_interval(self, df):
|
||||
ax = df.plot(
|
||||
column="NEGATIVES",
|
||||
scheme="FISHER_JENKS",
|
||||
k=3,
|
||||
@@ -1225,17 +1281,17 @@ class TestMapclassifyPlotting:
|
||||
assert labels == expected
|
||||
|
||||
@pytest.mark.parametrize("scheme", ["FISHER_JENKS", "FISHERJENKS"])
|
||||
def test_scheme_name_compat(self, scheme):
|
||||
ax = self.df.plot(column="NEGATIVES", scheme=scheme, k=3, legend=True)
|
||||
def test_scheme_name_compat(self, scheme, df):
|
||||
ax = df.plot(column="NEGATIVES", scheme=scheme, k=3, legend=True)
|
||||
assert len(ax.get_legend().get_texts()) == 3
|
||||
|
||||
def test_schemes(self):
|
||||
def test_schemes(self, df):
|
||||
# test if all available classifiers pass
|
||||
for scheme in self.classifiers:
|
||||
self.df.plot(column="pop_est", scheme=scheme, legend=True)
|
||||
df.plot(column="pop_est", scheme=scheme, legend=True)
|
||||
|
||||
def test_classification_kwds(self):
|
||||
ax = self.df.plot(
|
||||
def test_classification_kwds(self, df):
|
||||
ax = df.plot(
|
||||
column="pop_est",
|
||||
scheme="percentiles",
|
||||
k=3,
|
||||
@@ -1246,21 +1302,19 @@ class TestMapclassifyPlotting:
|
||||
labels = [t.get_text() for t in ax.get_legend().get_texts()]
|
||||
expected = [
|
||||
s.split("|")[0][1:-2]
|
||||
for s in str(self.mc.Percentiles(self.df["pop_est"], pct=[50, 100])).split(
|
||||
"\n"
|
||||
)[4:]
|
||||
for s in str(self.mc.Percentiles(df["pop_est"], pct=[50, 100])).split("\n")[
|
||||
4:
|
||||
]
|
||||
]
|
||||
|
||||
assert labels == expected
|
||||
|
||||
def test_invalid_scheme(self):
|
||||
def test_invalid_scheme(self, df):
|
||||
with pytest.raises(ValueError):
|
||||
scheme = "invalid_scheme_*#&)(*#"
|
||||
self.df.plot(
|
||||
column="gdp_md_est", scheme=scheme, k=3, cmap="OrRd", legend=True
|
||||
)
|
||||
df.plot(column="gdp_md_est", scheme=scheme, k=3, cmap="OrRd", legend=True)
|
||||
|
||||
def test_cax_legend_passing(self):
|
||||
def test_cax_legend_passing(self, df):
|
||||
"""Pass a 'cax' argument to 'df.plot(.)', that is valid only if 'ax' is
|
||||
passed as well (if not, a new figure is created ad hoc, and 'cax' is
|
||||
ignored)
|
||||
@@ -1271,15 +1325,15 @@ class TestMapclassifyPlotting:
|
||||
divider = make_axes_locatable(ax)
|
||||
cax = divider.append_axes("right", size="5%", pad=0.1)
|
||||
with pytest.raises(ValueError):
|
||||
ax = self.df.plot(column="pop_est", cmap="OrRd", legend=True, cax=cax)
|
||||
ax = df.plot(column="pop_est", cmap="OrRd", legend=True, cax=cax)
|
||||
|
||||
def test_cax_legend_height(self):
|
||||
def test_cax_legend_height(self, df):
|
||||
"""Pass a cax argument to 'df.plot(.)', the legend location must be
|
||||
aligned with those of main plot
|
||||
"""
|
||||
# base case
|
||||
with warnings.catch_warnings(record=True) as _: # don't print warning
|
||||
ax = self.df.plot(column="pop_est", cmap="OrRd", legend=True)
|
||||
ax = df.plot(column="pop_est", cmap="OrRd", legend=True)
|
||||
plot_height = _get_ax(ax.get_figure(), "").get_position().height
|
||||
legend_height = _get_ax(ax.get_figure(), "<colorbar>").get_position().height
|
||||
assert abs(plot_height - legend_height) >= 1e-6
|
||||
@@ -1290,16 +1344,14 @@ class TestMapclassifyPlotting:
|
||||
divider = make_axes_locatable(ax2)
|
||||
cax = divider.append_axes("right", size="5%", pad=0.1, label="fixed_colorbar")
|
||||
with warnings.catch_warnings(record=True) as _:
|
||||
ax2 = self.df.plot(
|
||||
column="pop_est", cmap="OrRd", legend=True, cax=cax, ax=ax2
|
||||
)
|
||||
ax2 = df.plot(column="pop_est", cmap="OrRd", legend=True, cax=cax, ax=ax2)
|
||||
plot_height = _get_ax(fig, "").get_position().height
|
||||
legend_height = _get_ax(fig, "fixed_colorbar").get_position().height
|
||||
assert abs(plot_height - legend_height) < 1e-6
|
||||
|
||||
def test_empty_bins(self):
|
||||
def test_empty_bins(self, df):
|
||||
bins = np.arange(1, 11) / 10
|
||||
ax = self.df.plot(
|
||||
ax = df.plot(
|
||||
"low_vals",
|
||||
scheme="UserDefined",
|
||||
classification_kwds={"bins": bins},
|
||||
@@ -1348,7 +1400,7 @@ class TestMapclassifyPlotting:
|
||||
line.get_markerfacecolor() for line in ax.get_legend().get_lines()
|
||||
] == legend_colors_exp
|
||||
|
||||
ax2 = self.df.plot(
|
||||
ax2 = df.plot(
|
||||
"mid_vals",
|
||||
scheme="UserDefined",
|
||||
classification_kwds={"bins": bins},
|
||||
@@ -1386,7 +1438,7 @@ class TestMapclassifyPlotting:
|
||||
line.get_markerfacecolor() for line in ax2.get_legend().get_lines()
|
||||
] == legend_colors_exp
|
||||
|
||||
ax3 = self.df.plot(
|
||||
ax3 = df.plot(
|
||||
"high_vals",
|
||||
scheme="UserDefined",
|
||||
classification_kwds={"bins": bins},
|
||||
@@ -1411,8 +1463,8 @@ class TestMapclassifyPlotting:
|
||||
line.get_markerfacecolor() for line in ax3.get_legend().get_lines()
|
||||
] == legend_colors_exp
|
||||
|
||||
def test_equally_formatted_bins(self):
|
||||
ax = self.nybb.plot(
|
||||
def test_equally_formatted_bins(self, nybb):
|
||||
ax = nybb.plot(
|
||||
"vals",
|
||||
scheme="quantiles",
|
||||
legend=True,
|
||||
@@ -1427,7 +1479,7 @@ class TestMapclassifyPlotting:
|
||||
]
|
||||
assert labels == expected
|
||||
|
||||
ax2 = self.nybb.plot(
|
||||
ax2 = nybb.plot(
|
||||
"vals", scheme="quantiles", legend=True, legend_kwds={"fmt": "{:.3f}"}
|
||||
)
|
||||
labels = [t.get_text() for t in ax2.get_legend().get_texts()]
|
||||
@@ -1454,9 +1506,10 @@ class TestPlotCollections:
|
||||
)
|
||||
|
||||
def test_points(self):
|
||||
from geopandas.plotting import _plot_point_collection, plot_point_collection
|
||||
from matplotlib.collections import PathCollection
|
||||
|
||||
from geopandas.plotting import _plot_point_collection
|
||||
|
||||
fig, ax = plt.subplots()
|
||||
coll = _plot_point_collection(ax, self.points)
|
||||
assert isinstance(coll, PathCollection)
|
||||
@@ -1508,10 +1561,6 @@ class TestPlotCollections:
|
||||
with pytest.raises((TypeError, ValueError)):
|
||||
_plot_point_collection(ax, self.points, color="not color")
|
||||
|
||||
# check FutureWarning
|
||||
with pytest.warns(FutureWarning):
|
||||
plot_point_collection(ax, self.points)
|
||||
|
||||
def test_points_values(self):
|
||||
from geopandas.plotting import _plot_point_collection
|
||||
|
||||
@@ -1526,12 +1575,10 @@ class TestPlotCollections:
|
||||
# _check_colors(self.N, coll.get_edgecolors(), expected_colors)
|
||||
|
||||
def test_linestrings(self):
|
||||
from geopandas.plotting import (
|
||||
_plot_linestring_collection,
|
||||
plot_linestring_collection,
|
||||
)
|
||||
from matplotlib.collections import LineCollection
|
||||
|
||||
from geopandas.plotting import _plot_linestring_collection
|
||||
|
||||
fig, ax = plt.subplots()
|
||||
coll = _plot_linestring_collection(ax, self.lines)
|
||||
assert isinstance(coll, LineCollection)
|
||||
@@ -1581,9 +1628,6 @@ class TestPlotCollections:
|
||||
# not a color
|
||||
with pytest.raises((TypeError, ValueError)):
|
||||
_plot_linestring_collection(ax, self.lines, color="not color")
|
||||
# check FutureWarning
|
||||
with pytest.warns(FutureWarning):
|
||||
plot_linestring_collection(ax, self.lines)
|
||||
|
||||
def test_linestrings_values(self):
|
||||
from geopandas.plotting import _plot_linestring_collection
|
||||
@@ -1615,9 +1659,10 @@ class TestPlotCollections:
|
||||
ax.cla()
|
||||
|
||||
def test_polygons(self):
|
||||
from geopandas.plotting import _plot_polygon_collection, plot_polygon_collection
|
||||
from matplotlib.collections import PatchCollection
|
||||
|
||||
from geopandas.plotting import _plot_polygon_collection
|
||||
|
||||
fig, ax = plt.subplots()
|
||||
coll = _plot_polygon_collection(ax, self.polygons)
|
||||
assert isinstance(coll, PatchCollection)
|
||||
@@ -1673,9 +1718,6 @@ class TestPlotCollections:
|
||||
# not a color
|
||||
with pytest.raises((TypeError, ValueError)):
|
||||
_plot_polygon_collection(ax, self.polygons, color="not color")
|
||||
# check FutureWarning
|
||||
with pytest.warns(FutureWarning):
|
||||
plot_polygon_collection(ax, self.polygons)
|
||||
|
||||
def test_polygons_values(self):
|
||||
from geopandas.plotting import _plot_polygon_collection
|
||||
@@ -1830,9 +1872,10 @@ def test_column_values():
|
||||
def test_polygon_patch():
|
||||
# test adapted from descartes by Sean Gillies
|
||||
# (BSD license, https://pypi.org/project/descartes).
|
||||
from geopandas.plotting import _PolygonPatch
|
||||
from matplotlib.patches import PathPatch
|
||||
|
||||
from geopandas.plotting import _PolygonPatch
|
||||
|
||||
polygon = (
|
||||
Point(0, 0).buffer(10.0).difference(MultiPoint([(-5, 0), (5, 0)]).buffer(3.0))
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user