ENH: Add where filter to read_file (#2552)

This commit is contained in:
Alan D. Snow
2022-09-23 22:46:35 +02:00
committed by GitHub
parent 12f34b8689
commit 437b1ac95d
4 changed files with 59 additions and 6 deletions
+2
View File
@@ -6,6 +6,8 @@ Development version
New features and improvements:
- Add where filter to ``read_file`` (#2552)
Deprecations and compatibility notes:
Bug fixes:
+17
View File
@@ -177,6 +177,23 @@ Skip loading geometry from the file:
)
SQL WHERE Filter
^^^^^^^^^^^^^^^^^
.. versionadded:: 0.12
Load in a subset of data with a `SQL WHERE clause <https://gdal.org/user/ogr_sql_dialect.html#where>`__.
.. note:: Requires Fiona 1.9+ or the pyogrio engine.
.. code-block:: python
gdf = geopandas.read_file(
geopandas.datasets.get_path("naturalearth_lowres"),
where="continent='Africa'",
)
Writing Spatial Data
---------------------
+21 -6
View File
@@ -26,12 +26,14 @@ _VALID_URLS.discard("")
fiona = None
fiona_env = None
fiona_import_error = None
FIONA_GE_19 = False
def _import_fiona():
global fiona
global fiona_env
global fiona_import_error
global FIONA_GE_19
if fiona is None:
try:
@@ -48,6 +50,9 @@ def _import_fiona():
except ImportError:
fiona_env = None
FIONA_GE_19 = Version(Version(fiona.__version__).base_version) >= Version(
"1.9.0"
)
except ImportError as err:
fiona = False
fiona_import_error = str(err)
@@ -263,8 +268,11 @@ def _read_file(filename, bbox=None, mask=None, rows=None, engine=None, **kwargs)
def _read_file_fiona(
path_or_bytes, from_bytes, bbox=None, mask=None, rows=None, **kwargs
path_or_bytes, from_bytes, bbox=None, mask=None, rows=None, where=None, **kwargs
):
if where is not None and not FIONA_GE_19:
raise NotImplementedError("where requires fiona 1.9+")
if not from_bytes:
# Opening a file via URL or file-like-object above automatically detects a
# zipped file. In order to match that behavior, attempt to add a zip scheme
@@ -319,17 +327,24 @@ def _read_file_fiona(
mask = mapping(mask.to_crs(crs).unary_union)
elif isinstance(mask, BaseGeometry):
mask = mapping(mask)
filters = {}
if bbox is not None:
filters["bbox"] = bbox
if mask is not None:
filters["mask"] = mask
if where is not None:
filters["where"] = where
# setup the data loading filter
if rows is not None:
if isinstance(rows, int):
rows = slice(rows)
elif not isinstance(rows, slice):
raise TypeError("'rows' must be an integer or a slice.")
f_filt = features.filter(
rows.start, rows.stop, rows.step, bbox=bbox, mask=mask
)
elif any((bbox, mask)):
f_filt = features.filter(bbox=bbox, mask=mask)
f_filt = features.filter(rows.start, rows.stop, rows.step, **filters)
elif filters:
f_filt = features.filter(**filters)
else:
f_filt = features
# get list of columns
+19
View File
@@ -37,10 +37,12 @@ try:
FIONA_GE_1814 = Version(fiona.__version__) >= Version("1.8.14")
# invalid datetime handling
FIONA_GE_1821 = Version(fiona.__version__) >= Version("1.8.21")
FIONA_GE_19 = Version(Version(fiona.__version__).base_version) >= Version("1.9.0")
except ImportError:
fiona = False
FIONA_GE_1814 = False
FIONA_GE_1821 = False
FIONA_GE_19 = False
PYOGRIO_MARK = pytest.mark.skipif(not pyogrio, reason="pyogrio not installed")
@@ -766,6 +768,23 @@ def test_read_file__ignore_all_fields(engine):
assert gdf.columns.tolist() == ["geometry"]
def test_read_file__where_filter(engine):
if FIONA_GE_19 or engine == "pyogrio":
gdf = geopandas.read_file(
geopandas.datasets.get_path("naturalearth_lowres"),
where="continent='Africa'",
engine=engine,
)
assert gdf.continent.unique().tolist() == ["Africa"]
else:
with pytest.raises(NotImplementedError):
geopandas.read_file(
geopandas.datasets.get_path("naturalearth_lowres"),
where="continent='Africa'",
engine="fiona",
)
@PYOGRIO_MARK
def test_read_file__columns():
# TODO: this is only support for pyogrio, but we could mimic it for fiona as well