venv
This commit is contained in:
@@ -1,24 +1,23 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
import typing
|
||||
from typing import Optional, Any, Callable, Dict
|
||||
import warnings
|
||||
from packaging.version import Version
|
||||
from typing import Any, Callable, Dict, Optional
|
||||
|
||||
import numpy as np
|
||||
import pandas as pd
|
||||
from pandas import Series, MultiIndex
|
||||
from pandas import Series
|
||||
from pandas.core.internals import SingleBlockManager
|
||||
|
||||
from pyproj import CRS
|
||||
import shapely
|
||||
from shapely.geometry.base import BaseGeometry
|
||||
from shapely.geometry import GeometryCollection
|
||||
from shapely.geometry.base import BaseGeometry
|
||||
|
||||
from geopandas.base import GeoPandasBase, _delegate_property
|
||||
from geopandas.plotting import plot_series
|
||||
from geopandas.explore import _explore_geoseries
|
||||
import geopandas
|
||||
from geopandas.base import GeoPandasBase, _delegate_property
|
||||
from geopandas.explore import _explore_geoseries
|
||||
from geopandas.plotting import plot_series
|
||||
|
||||
from . import _compat as compat
|
||||
from ._decorator import doc
|
||||
@@ -51,20 +50,16 @@ def _geoseries_constructor_with_fallback(
|
||||
return Series(data=data, index=index, **kwargs)
|
||||
|
||||
|
||||
def _geoseries_expanddim(data=None, *args, **kwargs):
|
||||
def _expanddim_logic(df):
|
||||
"""Shared logic for _constructor_expanddim and _constructor_from_mgr_expanddim."""
|
||||
from geopandas import GeoDataFrame
|
||||
|
||||
# pd.Series._constructor_expanddim == pd.DataFrame
|
||||
df = pd.DataFrame(data, *args, **kwargs)
|
||||
geo_col_name = None
|
||||
if isinstance(data, GeoSeries):
|
||||
# pandas default column name is 0, keep convention
|
||||
geo_col_name = data.name if data.name is not None else 0
|
||||
|
||||
if df.shape[1] == 1:
|
||||
geo_col_name = df.columns[0]
|
||||
|
||||
if (df.dtypes == "geometry").sum() > 0:
|
||||
if df.shape[1] == 1:
|
||||
geo_col_name = df.columns[0]
|
||||
else:
|
||||
geo_col_name = None
|
||||
|
||||
if geo_col_name is None or not is_geometry_type(df[geo_col_name]):
|
||||
df = GeoDataFrame(df)
|
||||
df._geometry_column_name = None
|
||||
@@ -74,6 +69,13 @@ def _geoseries_expanddim(data=None, *args, **kwargs):
|
||||
return df
|
||||
|
||||
|
||||
def _geoseries_expanddim(data=None, *args, **kwargs):
|
||||
# pd.Series._constructor_expanddim == pd.DataFrame, we start
|
||||
# with that then specialize.
|
||||
df = pd.DataFrame(data, *args, **kwargs)
|
||||
return _expanddim_logic(df)
|
||||
|
||||
|
||||
class GeoSeries(GeoPandasBase, Series):
|
||||
"""
|
||||
A Series object designed to store shapely geometry objects.
|
||||
@@ -99,9 +101,9 @@ class GeoSeries(GeoPandasBase, Series):
|
||||
>>> from shapely.geometry import Point
|
||||
>>> s = geopandas.GeoSeries([Point(1, 1), Point(2, 2), Point(3, 3)])
|
||||
>>> s
|
||||
0 POINT (1.00000 1.00000)
|
||||
1 POINT (2.00000 2.00000)
|
||||
2 POINT (3.00000 3.00000)
|
||||
0 POINT (1 1)
|
||||
1 POINT (2 2)
|
||||
2 POINT (3 3)
|
||||
dtype: geometry
|
||||
|
||||
>>> s = geopandas.GeoSeries(
|
||||
@@ -127,9 +129,9 @@ class GeoSeries(GeoPandasBase, Series):
|
||||
... [Point(1, 1), Point(2, 2), Point(3, 3)], index=["a", "b", "c"], crs=4326
|
||||
... )
|
||||
>>> s
|
||||
a POINT (1.00000 1.00000)
|
||||
b POINT (2.00000 2.00000)
|
||||
c POINT (3.00000 3.00000)
|
||||
a POINT (1 1)
|
||||
b POINT (2 2)
|
||||
c POINT (3 3)
|
||||
dtype: geometry
|
||||
|
||||
>>> s.crs
|
||||
@@ -152,11 +154,13 @@ class GeoSeries(GeoPandasBase, Series):
|
||||
|
||||
"""
|
||||
|
||||
_metadata = ["name"]
|
||||
|
||||
def __init__(self, data=None, index=None, crs: Optional[Any] = None, **kwargs):
|
||||
if hasattr(data, "crs") and crs:
|
||||
if not data.crs:
|
||||
if (
|
||||
hasattr(data, "crs")
|
||||
or (isinstance(data, pd.Series) and hasattr(data.array, "crs"))
|
||||
) and crs:
|
||||
data_crs = data.crs if hasattr(data, "crs") else data.array.crs
|
||||
if not data_crs:
|
||||
# make a copy to avoid setting CRS to passed GeometryArray
|
||||
data = data.copy()
|
||||
else:
|
||||
@@ -189,7 +193,7 @@ class GeoSeries(GeoPandasBase, Series):
|
||||
# https://github.com/pandas-dev/pandas/issues/26469
|
||||
kwargs.pop("dtype", None)
|
||||
# Use Series constructor to handle input data
|
||||
with compat.ignore_shapely2_warnings():
|
||||
with warnings.catch_warnings():
|
||||
# suppress additional warning from pandas for empty data
|
||||
# (will always give object dtype instead of float dtype in the future,
|
||||
# making the `if s.empty: s = s.astype(object)` below unnecessary)
|
||||
@@ -207,9 +211,16 @@ class GeoSeries(GeoPandasBase, Series):
|
||||
"Non geometry data passed to GeoSeries constructor, "
|
||||
f"received data of dtype '{s.dtype}'"
|
||||
)
|
||||
# try to convert to GeometryArray, if fails return plain Series
|
||||
# extract object-dtype numpy array from pandas Series; with CoW this
|
||||
# gives a read-only array, so we try to set the flag back to writeable
|
||||
data = s.to_numpy()
|
||||
try:
|
||||
data = from_shapely(s.values, crs)
|
||||
data.flags.writeable = True
|
||||
except ValueError:
|
||||
pass
|
||||
# try to convert to GeometryArray
|
||||
try:
|
||||
data = from_shapely(data, crs)
|
||||
except TypeError:
|
||||
raise TypeError(
|
||||
"Non geometry data passed to GeoSeries constructor, "
|
||||
@@ -225,6 +236,18 @@ class GeoSeries(GeoPandasBase, Series):
|
||||
def append(self, *args, **kwargs) -> GeoSeries:
|
||||
return self._wrapped_pandas_method("append", *args, **kwargs)
|
||||
|
||||
@GeoPandasBase.crs.setter
|
||||
def crs(self, value):
|
||||
if self.crs is not None:
|
||||
warnings.warn(
|
||||
"Overriding the CRS of a GeoSeries that already has CRS. "
|
||||
"This unsafe behavior will be deprecated in future versions. "
|
||||
"Use GeoSeries.set_crs method instead.",
|
||||
stacklevel=2,
|
||||
category=DeprecationWarning,
|
||||
)
|
||||
self.geometry.values.crs = value
|
||||
|
||||
@property
|
||||
def geometry(self) -> GeoSeries:
|
||||
return self
|
||||
@@ -318,7 +341,7 @@ class GeoSeries(GeoPandasBase, Series):
|
||||
"""Alternate constructor to create a ``GeoSeries`` from a file.
|
||||
|
||||
Can load a ``GeoSeries`` from a file from any format recognized by
|
||||
`fiona`. See http://fiona.readthedocs.io/en/latest/manual.html for details.
|
||||
`pyogrio`. See http://pyogrio.readthedocs.io/ for details.
|
||||
From a file with attributes loads only geometry column. Note that to do
|
||||
that, GeoPandas first loads the whole GeoDataFrame.
|
||||
|
||||
@@ -327,10 +350,10 @@ class GeoSeries(GeoPandasBase, Series):
|
||||
filename : str
|
||||
File path or file handle to read from. Depending on which kwargs
|
||||
are included, the content of filename may vary. See
|
||||
http://fiona.readthedocs.io/en/latest/README.html#usage for usage details.
|
||||
:func:`pyogrio.read_dataframe` for usage details.
|
||||
kwargs : key-word arguments
|
||||
These arguments are passed to fiona.open, and can be used to
|
||||
access multi-layer data, data stored within archives (zip files),
|
||||
These arguments are passed to :func:`pyogrio.read_dataframe`, and can be
|
||||
used to access multi-layer data, data stored within archives (zip files),
|
||||
etc.
|
||||
|
||||
Examples
|
||||
@@ -358,7 +381,7 @@ class GeoSeries(GeoPandasBase, Series):
|
||||
|
||||
@classmethod
|
||||
def from_wkb(
|
||||
cls, data, index=None, crs: Optional[Any] = None, **kwargs
|
||||
cls, data, index=None, crs: Optional[Any] = None, on_invalid="raise", **kwargs
|
||||
) -> GeoSeries:
|
||||
"""
|
||||
Alternate constructor to create a ``GeoSeries``
|
||||
@@ -375,6 +398,12 @@ class GeoSeries(GeoPandasBase, Series):
|
||||
accepted by
|
||||
:meth:`pyproj.CRS.from_user_input() <pyproj.crs.CRS.from_user_input>`,
|
||||
such as an authority string (eg "EPSG:4326") or a WKT string.
|
||||
on_invalid: {"raise", "warn", "ignore"}, default "raise"
|
||||
- raise: an exception will be raised if a WKB input geometry is invalid.
|
||||
- warn: a warning will be raised and invalid WKB geometries will be returned
|
||||
as None.
|
||||
- ignore: invalid WKB geometries will be returned as None without a warning.
|
||||
|
||||
kwargs
|
||||
Additional arguments passed to the Series constructor,
|
||||
e.g. ``name``.
|
||||
@@ -388,11 +417,13 @@ class GeoSeries(GeoPandasBase, Series):
|
||||
GeoSeries.from_wkt
|
||||
|
||||
"""
|
||||
return cls._from_wkb_or_wkb(from_wkb, data, index=index, crs=crs, **kwargs)
|
||||
return cls._from_wkb_or_wkt(
|
||||
from_wkb, data, index=index, crs=crs, on_invalid=on_invalid, **kwargs
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def from_wkt(
|
||||
cls, data, index=None, crs: Optional[Any] = None, **kwargs
|
||||
cls, data, index=None, crs: Optional[Any] = None, on_invalid="raise", **kwargs
|
||||
) -> GeoSeries:
|
||||
"""
|
||||
Alternate constructor to create a ``GeoSeries``
|
||||
@@ -409,6 +440,13 @@ class GeoSeries(GeoPandasBase, Series):
|
||||
accepted by
|
||||
:meth:`pyproj.CRS.from_user_input() <pyproj.crs.CRS.from_user_input>`,
|
||||
such as an authority string (eg "EPSG:4326") or a WKT string.
|
||||
on_invalid : {"raise", "warn", "ignore"}, default "raise"
|
||||
- raise: an exception will be raised if a WKT input geometry is invalid.
|
||||
- warn: a warning will be raised and invalid WKT geometries will be
|
||||
returned as ``None``.
|
||||
- ignore: invalid WKT geometries will be returned as ``None`` without a
|
||||
warning.
|
||||
|
||||
kwargs
|
||||
Additional arguments passed to the Series constructor,
|
||||
e.g. ``name``.
|
||||
@@ -431,12 +469,14 @@ class GeoSeries(GeoPandasBase, Series):
|
||||
... ]
|
||||
>>> s = geopandas.GeoSeries.from_wkt(wkts)
|
||||
>>> s
|
||||
0 POINT (1.00000 1.00000)
|
||||
1 POINT (2.00000 2.00000)
|
||||
2 POINT (3.00000 3.00000)
|
||||
0 POINT (1 1)
|
||||
1 POINT (2 2)
|
||||
2 POINT (3 3)
|
||||
dtype: geometry
|
||||
"""
|
||||
return cls._from_wkb_or_wkb(from_wkt, data, index=index, crs=crs, **kwargs)
|
||||
return cls._from_wkb_or_wkt(
|
||||
from_wkt, data, index=index, crs=crs, on_invalid=on_invalid, **kwargs
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def from_xy(cls, x, y, z=None, index=None, crs=None, **kwargs) -> GeoSeries:
|
||||
@@ -478,9 +518,9 @@ class GeoSeries(GeoPandasBase, Series):
|
||||
>>> y = [0.5, 1, 1.5]
|
||||
>>> s = geopandas.GeoSeries.from_xy(x, y, crs="EPSG:4326")
|
||||
>>> s
|
||||
0 POINT (2.50000 0.50000)
|
||||
1 POINT (5.00000 1.00000)
|
||||
2 POINT (-3.00000 1.50000)
|
||||
0 POINT (2.5 0.5)
|
||||
1 POINT (5 1)
|
||||
2 POINT (-3 1.5)
|
||||
dtype: geometry
|
||||
"""
|
||||
if index is None:
|
||||
@@ -494,12 +534,13 @@ class GeoSeries(GeoPandasBase, Series):
|
||||
return cls(points_from_xy(x, y, z, crs=crs), index=index, crs=crs, **kwargs)
|
||||
|
||||
@classmethod
|
||||
def _from_wkb_or_wkb(
|
||||
def _from_wkb_or_wkt(
|
||||
cls,
|
||||
from_wkb_or_wkt_function: Callable,
|
||||
data,
|
||||
index=None,
|
||||
crs: Optional[Any] = None,
|
||||
on_invalid: str = "raise",
|
||||
**kwargs,
|
||||
) -> GeoSeries:
|
||||
"""Create a GeoSeries from either WKT or WKB values"""
|
||||
@@ -509,7 +550,46 @@ class GeoSeries(GeoPandasBase, Series):
|
||||
else:
|
||||
index = data.index
|
||||
data = data.values
|
||||
return cls(from_wkb_or_wkt_function(data, crs=crs), index=index, **kwargs)
|
||||
return cls(
|
||||
from_wkb_or_wkt_function(data, crs=crs, on_invalid=on_invalid),
|
||||
index=index,
|
||||
**kwargs,
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def from_arrow(cls, arr, **kwargs) -> GeoSeries:
|
||||
"""
|
||||
Construct a GeoSeries from a Arrow array object with a GeoArrow
|
||||
extension type.
|
||||
|
||||
See https://geoarrow.org/ for details on the GeoArrow specification.
|
||||
|
||||
This functions accepts any Arrow array object implementing
|
||||
the `Arrow PyCapsule Protocol`_ (i.e. having an ``__arrow_c_array__``
|
||||
method).
|
||||
|
||||
.. _Arrow PyCapsule Protocol: https://arrow.apache.org/docs/format/CDataInterface/PyCapsuleInterface.html
|
||||
|
||||
.. versionadded:: 1.0
|
||||
|
||||
Parameters
|
||||
----------
|
||||
arr : pyarrow.Array, Arrow array
|
||||
Any array object implementing the Arrow PyCapsule Protocol
|
||||
(i.e. has an ``__arrow_c_array__`` or ``__arrow_c_stream__``
|
||||
method). The type of the array should be one of the
|
||||
geoarrow geometry types.
|
||||
**kwargs
|
||||
Other parameters passed to the GeoSeries constructor.
|
||||
|
||||
Returns
|
||||
-------
|
||||
GeoSeries
|
||||
|
||||
"""
|
||||
from geopandas.io._geoarrow import arrow_to_geometry_array
|
||||
|
||||
return cls(arrow_to_geometry_array(arr), **kwargs)
|
||||
|
||||
@property
|
||||
def __geo_interface__(self) -> Dict:
|
||||
@@ -548,7 +628,7 @@ class GeoSeries(GeoPandasBase, Series):
|
||||
"""Write the ``GeoSeries`` to a file.
|
||||
|
||||
By default, an ESRI shapefile is written, but any OGR data source
|
||||
supported by Fiona can be written.
|
||||
supported by Pyogrio or Fiona can be written.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
@@ -578,18 +658,19 @@ class GeoSeries(GeoPandasBase, Series):
|
||||
will determine the crs based on crs df attribute.
|
||||
The value can be anything accepted
|
||||
by :meth:`pyproj.CRS.from_user_input() <pyproj.crs.CRS.from_user_input>`,
|
||||
such as an authority string (eg "EPSG:4326") or a WKT string.
|
||||
engine : str, "fiona" or "pyogrio"
|
||||
such as an authority string (eg "EPSG:4326") or a WKT string. The keyword
|
||||
is not supported for the "pyogrio" engine.
|
||||
engine : str, "pyogrio" or "fiona"
|
||||
The underlying library that is used to write the file. Currently, the
|
||||
supported options are "fiona" and "pyogrio". Defaults to "fiona" if
|
||||
installed, otherwise tries "pyogrio".
|
||||
supported options are "pyogrio" and "fiona". Defaults to "pyogrio" if
|
||||
installed, otherwise tries "fiona".
|
||||
**kwargs :
|
||||
Keyword args to be passed to the engine, and can be used to write
|
||||
to multi-layer data, store data within archives (zip files), etc.
|
||||
In case of the "fiona" engine, the keyword arguments are passed to
|
||||
fiona.open`. For more information on possible keywords, type:
|
||||
``import fiona; help(fiona.open)``. In case of the "pyogrio" engine,
|
||||
the keyword arguments are passed to `pyogrio.write_dataframe`.
|
||||
In case of the "pyogrio" engine, the keyword arguments are passed to
|
||||
`pyogrio.write_dataframe`. In case of the "fiona" engine, the keyword
|
||||
arguments are passed to fiona.open`. For more information on possible
|
||||
keywords, type: ``import pyogrio; help(pyogrio.write_dataframe)``.
|
||||
|
||||
See Also
|
||||
--------
|
||||
@@ -608,7 +689,6 @@ class GeoSeries(GeoPandasBase, Series):
|
||||
from geopandas import GeoDataFrame
|
||||
|
||||
data = GeoDataFrame({"geometry": self}, index=self.index)
|
||||
data.crs = self.crs
|
||||
data.to_file(filename, driver, index=index, **kwargs)
|
||||
|
||||
#
|
||||
@@ -619,10 +699,22 @@ class GeoSeries(GeoPandasBase, Series):
|
||||
def _constructor(self):
|
||||
return _geoseries_constructor_with_fallback
|
||||
|
||||
def _constructor_from_mgr(self, mgr, axes):
|
||||
assert isinstance(mgr, SingleBlockManager)
|
||||
|
||||
if not isinstance(mgr.blocks[0].dtype, GeometryDtype):
|
||||
return Series._from_mgr(mgr, axes)
|
||||
|
||||
return GeoSeries._from_mgr(mgr, axes)
|
||||
|
||||
@property
|
||||
def _constructor_expanddim(self):
|
||||
return _geoseries_expanddim
|
||||
|
||||
def _constructor_expanddim_from_mgr(self, mgr, axes):
|
||||
df = pd.DataFrame._from_mgr(mgr, axes)
|
||||
return _expanddim_logic(df)
|
||||
|
||||
def _wrapped_pandas_method(self, mtd, *args, **kwargs):
|
||||
"""Wrap a generic pandas method to ensure it returns a GeoSeries"""
|
||||
val = getattr(super(), mtd)(*args, **kwargs)
|
||||
@@ -647,7 +739,7 @@ class GeoSeries(GeoPandasBase, Series):
|
||||
return self._wrapped_pandas_method("select", *args, **kwargs)
|
||||
|
||||
@doc(pd.Series)
|
||||
def apply(self, func, convert_dtype: bool = None, args=(), **kwargs):
|
||||
def apply(self, func, convert_dtype: Optional[bool] = None, args=(), **kwargs):
|
||||
if convert_dtype is not None:
|
||||
kwargs["convert_dtype"] = convert_dtype
|
||||
else:
|
||||
@@ -686,10 +778,11 @@ class GeoSeries(GeoPandasBase, Series):
|
||||
... [Polygon([(0, 0), (1, 1), (0, 1)]), None, Polygon([])]
|
||||
... )
|
||||
>>> s
|
||||
0 POLYGON ((0.00000 0.00000, 1.00000 1.00000, 0....
|
||||
1 None
|
||||
2 POLYGON EMPTY
|
||||
0 POLYGON ((0 0, 1 1, 0 1, 0 0))
|
||||
1 None
|
||||
2 POLYGON EMPTY
|
||||
dtype: geometry
|
||||
|
||||
>>> s.isna()
|
||||
0 False
|
||||
1 True
|
||||
@@ -730,10 +823,11 @@ class GeoSeries(GeoPandasBase, Series):
|
||||
... [Polygon([(0, 0), (1, 1), (0, 1)]), None, Polygon([])]
|
||||
... )
|
||||
>>> s
|
||||
0 POLYGON ((0.00000 0.00000, 1.00000 1.00000, 0....
|
||||
1 None
|
||||
2 POLYGON EMPTY
|
||||
0 POLYGON ((0 0, 1 1, 0 1, 0 0))
|
||||
1 None
|
||||
2 POLYGON EMPTY
|
||||
dtype: geometry
|
||||
|
||||
>>> s.notna()
|
||||
0 True
|
||||
1 False
|
||||
@@ -765,12 +859,10 @@ class GeoSeries(GeoPandasBase, Series):
|
||||
"""Alias for `notna` method. See `notna` for more detail."""
|
||||
return self.notna()
|
||||
|
||||
def fillna(self, value=None, method=None, inplace: bool = False, **kwargs):
|
||||
def fillna(self, value=None, inplace: bool = False, limit=None, **kwargs):
|
||||
"""
|
||||
Fill NA values with geometry (or geometries).
|
||||
|
||||
``method`` is currently not implemented.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
value : shapely geometry or GeoSeries, default None
|
||||
@@ -780,6 +872,9 @@ class GeoSeries(GeoPandasBase, Series):
|
||||
are passed, missing values will be filled based on the corresponding index
|
||||
locations. If pd.NA or np.nan are passed, values will be filled with
|
||||
``None`` (not GEOMETRYCOLLECTION EMPTY).
|
||||
limit : int, default None
|
||||
This is the maximum number of entries along the entire axis
|
||||
where NaNs will be filled. Must be greater than 0 if not None.
|
||||
|
||||
Returns
|
||||
-------
|
||||
@@ -796,25 +891,25 @@ class GeoSeries(GeoPandasBase, Series):
|
||||
... ]
|
||||
... )
|
||||
>>> s
|
||||
0 POLYGON ((0.00000 0.00000, 1.00000 1.00000, 0....
|
||||
1 None
|
||||
2 POLYGON ((0.00000 0.00000, -1.00000 1.00000, 0...
|
||||
0 POLYGON ((0 0, 1 1, 0 1, 0 0))
|
||||
1 None
|
||||
2 POLYGON ((0 0, -1 1, 0 -1, 0 0))
|
||||
dtype: geometry
|
||||
|
||||
Filled with an empty polygon.
|
||||
|
||||
>>> s.fillna()
|
||||
0 POLYGON ((0.00000 0.00000, 1.00000 1.00000, 0....
|
||||
1 GEOMETRYCOLLECTION EMPTY
|
||||
2 POLYGON ((0.00000 0.00000, -1.00000 1.00000, 0...
|
||||
0 POLYGON ((0 0, 1 1, 0 1, 0 0))
|
||||
1 GEOMETRYCOLLECTION EMPTY
|
||||
2 POLYGON ((0 0, -1 1, 0 -1, 0 0))
|
||||
dtype: geometry
|
||||
|
||||
Filled with a specific polygon.
|
||||
|
||||
>>> s.fillna(Polygon([(0, 1), (2, 1), (1, 2)]))
|
||||
0 POLYGON ((0.00000 0.00000, 1.00000 1.00000, 0....
|
||||
1 POLYGON ((0.00000 1.00000, 2.00000 1.00000, 1....
|
||||
2 POLYGON ((0.00000 0.00000, -1.00000 1.00000, 0...
|
||||
0 POLYGON ((0 0, 1 1, 0 1, 0 0))
|
||||
1 POLYGON ((0 1, 2 1, 1 2, 0 1))
|
||||
2 POLYGON ((0 0, -1 1, 0 -1, 0 0))
|
||||
dtype: geometry
|
||||
|
||||
Filled with another GeoSeries.
|
||||
@@ -828,9 +923,9 @@ class GeoSeries(GeoPandasBase, Series):
|
||||
... ]
|
||||
... )
|
||||
>>> s.fillna(s_fill)
|
||||
0 POLYGON ((0.00000 0.00000, 1.00000 1.00000, 0....
|
||||
1 POINT (1.00000 1.00000)
|
||||
2 POLYGON ((0.00000 0.00000, -1.00000 1.00000, 0...
|
||||
0 POLYGON ((0 0, 1 1, 0 1, 0 0))
|
||||
1 POINT (1 1)
|
||||
2 POLYGON ((0 0, -1 1, 0 -1, 0 0))
|
||||
dtype: geometry
|
||||
|
||||
See Also
|
||||
@@ -838,8 +933,8 @@ class GeoSeries(GeoPandasBase, Series):
|
||||
GeoSeries.isna : detect missing values
|
||||
"""
|
||||
if value is None:
|
||||
value = GeometryCollection() if compat.SHAPELY_GE_20 else BaseGeometry()
|
||||
return super().fillna(value=value, method=method, inplace=inplace, **kwargs)
|
||||
value = GeometryCollection()
|
||||
return super().fillna(value=value, limit=limit, inplace=inplace, **kwargs)
|
||||
|
||||
def __contains__(self, other) -> bool:
|
||||
"""Allow tests of the form "geom in s"
|
||||
@@ -862,7 +957,7 @@ class GeoSeries(GeoPandasBase, Series):
|
||||
"""Interactive map based on folium/leaflet.js"""
|
||||
return _explore_geoseries(self, *args, **kwargs)
|
||||
|
||||
def explode(self, ignore_index=False, index_parts=None) -> GeoSeries:
|
||||
def explode(self, ignore_index=False, index_parts=False) -> GeoSeries:
|
||||
"""
|
||||
Explode multi-part geometries into multiple single geometries.
|
||||
|
||||
@@ -875,7 +970,7 @@ class GeoSeries(GeoPandasBase, Series):
|
||||
ignore_index : bool, default False
|
||||
If True, the resulting index will be labelled 0, 1, …, n - 1,
|
||||
ignoring `index_parts`.
|
||||
index_parts : boolean, default True
|
||||
index_parts : boolean, default False
|
||||
If True, the resulting index will be a multi-index (original
|
||||
index with an additional level indicating the multiple
|
||||
geometries: a new zero-based index for each single part geometry
|
||||
@@ -894,16 +989,16 @@ class GeoSeries(GeoPandasBase, Series):
|
||||
... [MultiPoint([(0, 0), (1, 1)]), MultiPoint([(2, 2), (3, 3), (4, 4)])]
|
||||
... )
|
||||
>>> s
|
||||
0 MULTIPOINT (0.00000 0.00000, 1.00000 1.00000)
|
||||
1 MULTIPOINT (2.00000 2.00000, 3.00000 3.00000, ...
|
||||
0 MULTIPOINT ((0 0), (1 1))
|
||||
1 MULTIPOINT ((2 2), (3 3), (4 4))
|
||||
dtype: geometry
|
||||
|
||||
>>> s.explode(index_parts=True)
|
||||
0 0 POINT (0.00000 0.00000)
|
||||
1 POINT (1.00000 1.00000)
|
||||
1 0 POINT (2.00000 2.00000)
|
||||
1 POINT (3.00000 3.00000)
|
||||
2 POINT (4.00000 4.00000)
|
||||
0 0 POINT (0 0)
|
||||
1 POINT (1 1)
|
||||
1 0 POINT (2 2)
|
||||
1 POINT (3 3)
|
||||
2 POINT (4 4)
|
||||
dtype: geometry
|
||||
|
||||
See also
|
||||
@@ -913,70 +1008,21 @@ class GeoSeries(GeoPandasBase, Series):
|
||||
"""
|
||||
from .base import _get_index_for_parts
|
||||
|
||||
if index_parts is None and not ignore_index:
|
||||
warnings.warn(
|
||||
"Currently, index_parts defaults to True, but in the future, "
|
||||
"it will default to False to be consistent with Pandas. "
|
||||
"Use `index_parts=True` to keep the current behavior and True/False "
|
||||
"to silence the warning.",
|
||||
FutureWarning,
|
||||
stacklevel=2,
|
||||
)
|
||||
index_parts = True
|
||||
geometries, outer_idx = shapely.get_parts(self.values._data, return_index=True)
|
||||
|
||||
if compat.USE_SHAPELY_20 or (compat.USE_PYGEOS and compat.PYGEOS_GE_09):
|
||||
if compat.USE_SHAPELY_20:
|
||||
geometries, outer_idx = shapely.get_parts(
|
||||
self.values._data, return_index=True
|
||||
)
|
||||
else:
|
||||
import pygeos
|
||||
|
||||
geometries, outer_idx = pygeos.get_parts(
|
||||
self.values._data, return_index=True
|
||||
)
|
||||
|
||||
index = _get_index_for_parts(
|
||||
self.index,
|
||||
outer_idx,
|
||||
ignore_index=ignore_index,
|
||||
index_parts=index_parts,
|
||||
)
|
||||
|
||||
return GeoSeries(geometries, index=index, crs=self.crs).__finalize__(self)
|
||||
|
||||
# else PyGEOS is not available or version <= 0.8
|
||||
|
||||
index = []
|
||||
geometries = []
|
||||
for idx, s in self.geometry.items():
|
||||
if s.geom_type.startswith("Multi") or s.geom_type == "GeometryCollection":
|
||||
geoms = s.geoms
|
||||
idxs = [(idx, i) for i in range(len(geoms))]
|
||||
else:
|
||||
geoms = [s]
|
||||
idxs = [(idx, 0)]
|
||||
index.extend(idxs)
|
||||
geometries.extend(geoms)
|
||||
|
||||
if ignore_index:
|
||||
index = range(len(geometries))
|
||||
|
||||
elif index_parts:
|
||||
# if self.index is a MultiIndex then index is a list of nested tuples
|
||||
if isinstance(self.index, MultiIndex):
|
||||
index = [tuple(outer) + (inner,) for outer, inner in index]
|
||||
index = MultiIndex.from_tuples(index, names=self.index.names + [None])
|
||||
|
||||
else:
|
||||
index = [idx for idx, _ in index]
|
||||
index = _get_index_for_parts(
|
||||
self.index,
|
||||
outer_idx,
|
||||
ignore_index=ignore_index,
|
||||
index_parts=index_parts,
|
||||
)
|
||||
|
||||
return GeoSeries(geometries, index=index, crs=self.crs).__finalize__(self)
|
||||
|
||||
#
|
||||
# Additional methods
|
||||
#
|
||||
|
||||
@compat.requires_pyproj
|
||||
def set_crs(
|
||||
self,
|
||||
crs: Optional[Any] = None,
|
||||
@@ -987,12 +1033,16 @@ class GeoSeries(GeoPandasBase, Series):
|
||||
"""
|
||||
Set the Coordinate Reference System (CRS) of a ``GeoSeries``.
|
||||
|
||||
NOTE: The underlying geometries are not transformed to this CRS. To
|
||||
Pass ``None`` to remove CRS from the ``GeoSeries``.
|
||||
|
||||
Notes
|
||||
-----
|
||||
The underlying geometries are not transformed to this CRS. To
|
||||
transform the geometries to a new CRS, use the ``to_crs`` method.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
crs : pyproj.CRS, optional if `epsg` is specified
|
||||
crs : pyproj.CRS | None, optional
|
||||
The value can be anything accepted
|
||||
by :meth:`pyproj.CRS.from_user_input() <pyproj.crs.CRS.from_user_input>`,
|
||||
such as an authority string (eg "EPSG:4326") or a WKT string.
|
||||
@@ -1015,9 +1065,9 @@ class GeoSeries(GeoPandasBase, Series):
|
||||
>>> from shapely.geometry import Point
|
||||
>>> s = geopandas.GeoSeries([Point(1, 1), Point(2, 2), Point(3, 3)])
|
||||
>>> s
|
||||
0 POINT (1.00000 1.00000)
|
||||
1 POINT (2.00000 2.00000)
|
||||
2 POINT (3.00000 3.00000)
|
||||
0 POINT (1 1)
|
||||
1 POINT (2 2)
|
||||
2 POINT (3 3)
|
||||
dtype: geometry
|
||||
|
||||
Setting CRS to a GeoSeries without one:
|
||||
@@ -1054,12 +1104,12 @@ class GeoSeries(GeoPandasBase, Series):
|
||||
GeoSeries.to_crs : re-project to another CRS
|
||||
|
||||
"""
|
||||
from pyproj import CRS
|
||||
|
||||
if crs is not None:
|
||||
crs = CRS.from_user_input(crs)
|
||||
elif epsg is not None:
|
||||
crs = CRS.from_epsg(epsg)
|
||||
else:
|
||||
raise ValueError("Must pass either crs or epsg.")
|
||||
|
||||
if not allow_override and self.crs is not None and not self.crs == crs:
|
||||
raise ValueError(
|
||||
@@ -1072,7 +1122,7 @@ class GeoSeries(GeoPandasBase, Series):
|
||||
result = self.copy()
|
||||
else:
|
||||
result = self
|
||||
result.crs = crs
|
||||
result.array.crs = crs
|
||||
return result
|
||||
|
||||
def to_crs(
|
||||
@@ -1109,9 +1159,9 @@ class GeoSeries(GeoPandasBase, Series):
|
||||
>>> from shapely.geometry import Point
|
||||
>>> s = geopandas.GeoSeries([Point(1, 1), Point(2, 2), Point(3, 3)], crs=4326)
|
||||
>>> s
|
||||
0 POINT (1.00000 1.00000)
|
||||
1 POINT (2.00000 2.00000)
|
||||
2 POINT (3.00000 3.00000)
|
||||
0 POINT (1 1)
|
||||
1 POINT (2 2)
|
||||
2 POINT (3 3)
|
||||
dtype: geometry
|
||||
>>> s.crs # doctest: +SKIP
|
||||
<Geographic 2D CRS: EPSG:4326>
|
||||
@@ -1157,7 +1207,7 @@ class GeoSeries(GeoPandasBase, Series):
|
||||
self.values.to_crs(crs=crs, epsg=epsg), index=self.index, name=self.name
|
||||
)
|
||||
|
||||
def estimate_utm_crs(self, datum_name: str = "WGS 84") -> CRS:
|
||||
def estimate_utm_crs(self, datum_name: str = "WGS 84"):
|
||||
"""Returns the estimated UTM CRS based on the bounds of the dataset.
|
||||
|
||||
.. versionadded:: 0.9
|
||||
@@ -1195,12 +1245,31 @@ class GeoSeries(GeoPandasBase, Series):
|
||||
"""
|
||||
return self.values.estimate_utm_crs(datum_name)
|
||||
|
||||
def to_json(self, **kwargs) -> str:
|
||||
def to_json(
|
||||
self,
|
||||
show_bbox: bool = True,
|
||||
drop_id: bool = False,
|
||||
to_wgs84: bool = False,
|
||||
**kwargs,
|
||||
) -> str:
|
||||
"""
|
||||
Returns a GeoJSON string representation of the GeoSeries.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
show_bbox : bool, optional, default: True
|
||||
Include bbox (bounds) in the geojson
|
||||
drop_id : bool, default: False
|
||||
Whether to retain the index of the GeoSeries as the id property
|
||||
in the generated GeoJSON. Default is False, but may want True
|
||||
if the index is just arbitrary row numbers.
|
||||
to_wgs84: bool, optional, default: False
|
||||
If the CRS is set on the active geometry column it is exported as
|
||||
WGS84 (EPSG:4326) to meet the `2016 GeoJSON specification
|
||||
<https://tools.ietf.org/html/rfc7946>`_.
|
||||
Set to True to force re-projection and set to False to ignore CRS. False by
|
||||
default.
|
||||
|
||||
*kwargs* that will be passed to json.dumps().
|
||||
|
||||
Returns
|
||||
@@ -1212,9 +1281,9 @@ class GeoSeries(GeoPandasBase, Series):
|
||||
>>> from shapely.geometry import Point
|
||||
>>> s = geopandas.GeoSeries([Point(1, 1), Point(2, 2), Point(3, 3)])
|
||||
>>> s
|
||||
0 POINT (1.00000 1.00000)
|
||||
1 POINT (2.00000 2.00000)
|
||||
2 POINT (3.00000 3.00000)
|
||||
0 POINT (1 1)
|
||||
1 POINT (2 2)
|
||||
2 POINT (3 3)
|
||||
dtype: geometry
|
||||
|
||||
>>> s.to_json()
|
||||
@@ -1229,7 +1298,9 @@ e": "Feature", "properties": {}, "geometry": {"type": "Point", "coordinates": [3
|
||||
--------
|
||||
GeoSeries.to_file : write GeoSeries to file
|
||||
"""
|
||||
return json.dumps(self.__geo_interface__, **kwargs)
|
||||
return self.to_frame("geometry").to_json(
|
||||
na="null", show_bbox=show_bbox, drop_id=drop_id, to_wgs84=to_wgs84, **kwargs
|
||||
)
|
||||
|
||||
def to_wkb(self, hex: bool = False, **kwargs) -> Series:
|
||||
"""
|
||||
@@ -1242,8 +1313,7 @@ e": "Feature", "properties": {}, "geometry": {"type": "Point", "coordinates": [3
|
||||
The default is to return a binary bytes object.
|
||||
kwargs
|
||||
Additional keyword args will be passed to
|
||||
:func:`shapely.to_wkb` if shapely >= 2 is installed or
|
||||
:func:`pygeos.to_wkb` if pygeos is installed.
|
||||
:func:`shapely.to_wkb`.
|
||||
|
||||
Returns
|
||||
-------
|
||||
@@ -1263,8 +1333,7 @@ e": "Feature", "properties": {}, "geometry": {"type": "Point", "coordinates": [3
|
||||
Parameters
|
||||
----------
|
||||
kwargs
|
||||
Keyword args will be passed to :func:`pygeos.to_wkt`
|
||||
if pygeos is installed.
|
||||
Keyword args will be passed to :func:`shapely.to_wkt`.
|
||||
|
||||
Returns
|
||||
-------
|
||||
@@ -1276,9 +1345,9 @@ e": "Feature", "properties": {}, "geometry": {"type": "Point", "coordinates": [3
|
||||
>>> from shapely.geometry import Point
|
||||
>>> s = geopandas.GeoSeries([Point(1, 1), Point(2, 2), Point(3, 3)])
|
||||
>>> s
|
||||
0 POINT (1.00000 1.00000)
|
||||
1 POINT (2.00000 2.00000)
|
||||
2 POINT (3.00000 3.00000)
|
||||
0 POINT (1 1)
|
||||
1 POINT (2 2)
|
||||
2 POINT (3 3)
|
||||
dtype: geometry
|
||||
|
||||
>>> s.to_wkt()
|
||||
@@ -1293,48 +1362,105 @@ e": "Feature", "properties": {}, "geometry": {"type": "Point", "coordinates": [3
|
||||
"""
|
||||
return Series(to_wkt(self.array, **kwargs), index=self.index)
|
||||
|
||||
#
|
||||
# Implement standard operators for GeoSeries
|
||||
#
|
||||
def to_arrow(self, geometry_encoding="WKB", interleaved=True, include_z=None):
|
||||
"""Encode a GeoSeries to GeoArrow format.
|
||||
|
||||
def __xor__(self, other):
|
||||
"""Implement ^ operator as for builtin set type"""
|
||||
warnings.warn(
|
||||
"'^' operator will be deprecated. Use the 'symmetric_difference' "
|
||||
"method instead.",
|
||||
FutureWarning,
|
||||
stacklevel=2,
|
||||
See https://geoarrow.org/ for details on the GeoArrow specification.
|
||||
|
||||
This functions returns a generic Arrow array object implementing
|
||||
the `Arrow PyCapsule Protocol`_ (i.e. having an ``__arrow_c_array__``
|
||||
method). This object can then be consumed by your Arrow implementation
|
||||
of choice that supports this protocol.
|
||||
|
||||
.. _Arrow PyCapsule Protocol: https://arrow.apache.org/docs/format/CDataInterface/PyCapsuleInterface.html
|
||||
|
||||
.. versionadded:: 1.0
|
||||
|
||||
Parameters
|
||||
----------
|
||||
geometry_encoding : {'WKB', 'geoarrow' }, default 'WKB'
|
||||
The GeoArrow encoding to use for the data conversion.
|
||||
interleaved : bool, default True
|
||||
Only relevant for 'geoarrow' encoding. If True, the geometries'
|
||||
coordinates are interleaved in a single fixed size list array.
|
||||
If False, the coordinates are stored as separate arrays in a
|
||||
struct type.
|
||||
include_z : bool, default None
|
||||
Only relevant for 'geoarrow' encoding (for WKB, the dimensionality
|
||||
of the individial geometries is preserved).
|
||||
If False, return 2D geometries. If True, include the third dimension
|
||||
in the output (if a geometry has no third dimension, the z-coordinates
|
||||
will be NaN). By default, will infer the dimensionality from the
|
||||
input geometries. Note that this inference can be unreliable with
|
||||
empty geometries (for a guaranteed result, it is recommended to
|
||||
specify the keyword).
|
||||
|
||||
Returns
|
||||
-------
|
||||
GeoArrowArray
|
||||
A generic Arrow array object with geometry data encoded to GeoArrow.
|
||||
|
||||
Examples
|
||||
--------
|
||||
>>> from shapely.geometry import Point
|
||||
>>> gser = geopandas.GeoSeries([Point(1, 2), Point(2, 1)])
|
||||
>>> gser
|
||||
0 POINT (1 2)
|
||||
1 POINT (2 1)
|
||||
dtype: geometry
|
||||
|
||||
>>> arrow_array = gser.to_arrow()
|
||||
>>> arrow_array
|
||||
<geopandas.io._geoarrow.GeoArrowArray object at ...>
|
||||
|
||||
The returned array object needs to be consumed by a library implementing
|
||||
the Arrow PyCapsule Protocol. For example, wrapping the data as a
|
||||
pyarrow.Array (requires pyarrow >= 14.0):
|
||||
|
||||
>>> import pyarrow as pa
|
||||
>>> array = pa.array(arrow_array)
|
||||
>>> array
|
||||
<pyarrow.lib.BinaryArray object at ...>
|
||||
[
|
||||
0101000000000000000000F03F0000000000000040,
|
||||
01010000000000000000000040000000000000F03F
|
||||
]
|
||||
|
||||
"""
|
||||
import pyarrow as pa
|
||||
|
||||
from geopandas.io._geoarrow import (
|
||||
GeoArrowArray,
|
||||
construct_geometry_array,
|
||||
construct_wkb_array,
|
||||
)
|
||||
return self.symmetric_difference(other)
|
||||
|
||||
def __or__(self, other):
|
||||
"""Implement | operator as for builtin set type"""
|
||||
warnings.warn(
|
||||
"'|' operator will be deprecated. Use the 'union' method instead.",
|
||||
FutureWarning,
|
||||
stacklevel=2,
|
||||
)
|
||||
return self.union(other)
|
||||
field_name = self.name if self.name is not None else ""
|
||||
|
||||
def __and__(self, other):
|
||||
"""Implement & operator as for builtin set type"""
|
||||
warnings.warn(
|
||||
"'&' operator will be deprecated. Use the 'intersection' method instead.",
|
||||
FutureWarning,
|
||||
stacklevel=2,
|
||||
)
|
||||
return self.intersection(other)
|
||||
if geometry_encoding.lower() == "geoarrow":
|
||||
if Version(pa.__version__) < Version("10.0.0"):
|
||||
raise ValueError("Converting to 'geoarrow' requires pyarrow >= 10.0.")
|
||||
|
||||
def __sub__(self, other):
|
||||
"""Implement - operator as for builtin set type"""
|
||||
warnings.warn(
|
||||
"'-' operator will be deprecated. Use the 'difference' method instead.",
|
||||
FutureWarning,
|
||||
stacklevel=2,
|
||||
)
|
||||
return self.difference(other)
|
||||
field, geom_arr = construct_geometry_array(
|
||||
np.array(self.array),
|
||||
include_z=include_z,
|
||||
field_name=field_name,
|
||||
crs=self.crs,
|
||||
interleaved=interleaved,
|
||||
)
|
||||
elif geometry_encoding.lower() == "wkb":
|
||||
field, geom_arr = construct_wkb_array(
|
||||
np.asarray(self.array), field_name=field_name, crs=self.crs
|
||||
)
|
||||
else:
|
||||
raise ValueError(
|
||||
"Expected geometry encoding 'WKB' or 'geoarrow' "
|
||||
f"got {geometry_encoding}"
|
||||
)
|
||||
|
||||
def clip(self, mask, keep_geom_type: bool = False) -> GeoSeries:
|
||||
return GeoArrowArray(field, geom_arr)
|
||||
|
||||
def clip(self, mask, keep_geom_type: bool = False, sort=False) -> GeoSeries:
|
||||
"""Clip points, lines, or polygon geometries to the mask extent.
|
||||
|
||||
Both layers must be in the same Coordinate Reference System (CRS).
|
||||
@@ -1357,6 +1483,10 @@ e": "Feature", "properties": {}, "geometry": {"type": "Point", "coordinates": [3
|
||||
If True, return only geometries of original type in case of intersection
|
||||
resulting in multiple geometry types or GeometryCollections.
|
||||
If False, return all resulting geometries (potentially mixed-types).
|
||||
sort : boolean, default False
|
||||
If True, the order of rows in the clipped GeoSeries will be preserved
|
||||
at small performance cost.
|
||||
If False the order of rows in the clipped GeoSeries will be random.
|
||||
|
||||
Returns
|
||||
-------
|
||||
@@ -1387,4 +1517,4 @@ e": "Feature", "properties": {}, "geometry": {"type": "Point", "coordinates": [3
|
||||
>>> nws_groceries.shape
|
||||
(7,)
|
||||
"""
|
||||
return geopandas.clip(self, mask=mask, keep_geom_type=keep_geom_type)
|
||||
return geopandas.clip(self, mask=mask, keep_geom_type=keep_geom_type, sort=sort)
|
||||
|
||||
Reference in New Issue
Block a user