Repository: Zeroto521/my-data-toolkit

Issue:
ENH: GeoAccessor `xy` for `GeoDataFrame`
<!--
Thanks for contributing a pull request!

Please follow these standard acronyms to start the commit message:

- ENH: enhancement
- BUG: bug fix
- DOC: documentation
- TYP: type annotations
- TST: addition or modification of tests
- MAINT: maintenance commit (refactoring, typos, etc.)
- BLD: change related to building
- REL: related to releasing
- API: an (incompatible) API change
- DEP: deprecate something, or remove a deprecated object
- DEV: development tool or utility
- REV: revert an earlier commit
- PERF: performance improvement
- BOT: always commit via a bot
- CI: related to CI or CD
- CLN: Code cleanup
-->

- [ ] closes #xxxx
- [x] whatsnew entry

```python
    >>> import dtoolkit.geoaccessor
    >>> import geopandas as gpd
    >>> from shapely.geometry import Point
    >>> df = gpd.GeoDataFrame({
    ...     "label": ["a", "b", "c"],
    ...     "geometry": [Point(0, 1), Point(0, 2), Point(0, 3)],
    ... })
    >>> df.xy(drop=False)
      label                 geometry    x    y
    0     a  POINT (0.00000 1.00000)  0.0  1.0
    1     b  POINT (0.00000 2.00000)  0.0  2.0
    2     c  POINT (0.00000 3.00000)  0.0  3.0
```


Discussion:
# [Codecov](https://codecov.io/gh/Zeroto521/my-data-toolkit/pull/794?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=40%25) Report
> Merging [#794](https://codecov.io/gh/Zeroto521/my-data-toolkit/pull/794?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=40%25) (fdb7fb1) into [main](https://codecov.io/gh/Zeroto521/my-data-toolkit/commit/bb38b34a343651e3ab08926e9a8c4bc29310ca1e?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=40%25) (bb38b34) will **increase** coverage by `0.00%`.
> The diff coverage is `100.00%`.

```diff
@@           Coverage Diff           @@
##             main     #794   +/-   ##
=======================================
  Coverage   99.66%   99.66%           
=======================================
  Files         132      133    +1     
  Lines        1766     1786   +20     
  Branches      373      379    +6     
=======================================
+ Hits         1760     1780   +20     
  Misses          1        1           
  Partials        5        5           
```


| [Impacted Files](https://codecov.io/gh/Zeroto521/my-data-toolkit/pull/794?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=40%25) | Coverage Δ | |
|---|---|---|
| [dtoolkit/geoaccessor/geodataframe/\_\_init\_\_.py](https://codecov.io/gh/Zeroto521/my-data-toolkit/pull/794/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=40%25#diff-ZHRvb2xraXQvZ2VvYWNjZXNzb3IvZ2VvZGF0YWZyYW1lL19faW5pdF9fLnB5) | `100.00% <100.00%> (ø)` | |
| [dtoolkit/geoaccessor/geodataframe/xy.py](https://codecov.io/gh/Zeroto521/my-data-toolkit/pull/794/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=40%25#diff-ZHRvb2xraXQvZ2VvYWNjZXNzb3IvZ2VvZGF0YWZyYW1lL3h5LnB5) | `100.00% <100.00%> (ø)` | |
| [dtoolkit/geoaccessor/geoseries/geobuffer.py](https://codecov.io/gh/Zeroto521/my-data-toolkit/pull/794/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=40%25#diff-ZHRvb2xraXQvZ2VvYWNjZXNzb3IvZ2Vvc2VyaWVzL2dlb2J1ZmZlci5weQ==) | `100.00% <100.00%> (ø)` | |
| [...oolkit/geoaccessor/geoseries/geodistance\_matrix.py](https://codecov.io/gh/Zeroto521/my-data-toolkit/pull/794/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=40%25#diff-ZHRvb2xraXQvZ2VvYWNjZXNzb3IvZ2Vvc2VyaWVzL2dlb2Rpc3RhbmNlX21hdHJpeC5weQ==) | `100.00% <100.00%> (ø)` | |
| [dtoolkit/geoaccessor/geoseries/xy.py](https://codecov.io/gh/Zeroto521/my-data-toolkit/pull/794/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=40%25#diff-ZHRvb2xraXQvZ2VvYWNjZXNzb3IvZ2Vvc2VyaWVzL3h5LnB5) | `100.00% <100.00%> (ø)` | |

:mega: We’re building smart automated test selection to slash your CI/CD build times. [Learn more](https://about.codecov.io/iterative-testing/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=40%25)


Resolving patch:
diff --git a/dtoolkit/geoaccessor/geodataframe/xy.py b/dtoolkit/geoaccessor/geodataframe/xy.py
--- a/dtoolkit/geoaccessor/geodataframe/xy.py
+++ b/dtoolkit/geoaccessor/geodataframe/xy.py
@@ -5,7 +5,7 @@
 import geopandas as gpd
 import pandas as pd
 
-from dtoolkit._typing import SeriesOrFrame
+from dtoolkit.geoaccessor.geodataframe.drop_geometry import drop_geometry
 from dtoolkit.geoaccessor.geoseries import xy as s_xy
 from dtoolkit.geoaccessor.register import register_geodataframe_method
 
@@ -18,7 +18,7 @@ def xy(
     frame: bool = True,
     drop: bool = True,
     name: Hashable | tuple[Hashable, Hashable] = ("x", "y"),
-) -> SeriesOrFrame | gpd.GeoDataFrame:
+) -> pd.DataFrame | gpd.GeoDataFrame:
     """
     Return the x and y location of Point geometries in a GeoDataFrame.
 
@@ -39,13 +39,13 @@ def xy(
 
     Returns
     -------
-    Series, DataFrame, or GeoDataFrame
-        - If ``drop=Fasle``, return a GeoDataFrame.
+    DataFrame or GeoDataFrame
+        - If ``drop=Fasle``, return a GeoDataFrame with the coordinates.
 
         - If ``drop=True`` and ``frame=True``, return a DataFrame with x and y two
           columns.
 
-        - IF ``drop=True`` and ``frame=False``, return a Series with tuple of
+        - If ``drop=True`` and ``frame=False``, return a DataFrame with tuple of
           coordinate.
 
     See Also
@@ -71,27 +71,27 @@ def xy(
 
     Get the x and y coordinates of each point as a tuple.
 
-    >>> df.xy(frame=False, name=None)
-    0    (0.0, 1.0)
-    1    (0.0, 2.0)
-    2    (0.0, 3.0)
-    dtype: object
+    >>> df.xy(frame=False, name="geometry")
+      label    geometry
+    0     a  (0.0, 1.0)
+    1     b  (0.0, 2.0)
+    2     c  (0.0, 3.0)
 
     Set ``reverse=True`` to return (y, x).
 
-    >>> df.xy(reverse=True, frame=False, name=None)
-    0    (1.0, 0.0)
-    1    (2.0, 0.0)
-    2    (3.0, 0.0)
-    dtype: object
+    >>> df.xy(reverse=True, frame=False, name="geometry")
+      label    geometry
+    0     a  (1.0, 0.0)
+    1     b  (2.0, 0.0)
+    2     c  (3.0, 0.0)
 
     Set ``frame=True`` to return a DataFrame with x and y columns.
 
     >>> df.xy()
-         x    y
-    0  0.0  1.0
-    1  0.0  2.0
-    2  0.0  3.0
+      label    x    y
+    0     a  0.0  1.0
+    1     b  0.0  2.0
+    2     c  0.0  3.0
 
     Keep the original geometry column.
 
@@ -102,5 +102,10 @@ def xy(
     2     c  POINT (0.00000 3.00000)  0.0  3.0
     """
 
-    coords = s_xy(df.geometry, reverse=reverse, frame=frame, name=name)
-    return coords if drop else pd.concat((df, coords), axis=1)
+    return pd.concat(
+        (
+            drop_geometry(df) if drop else df,
+            s_xy(df.geometry, reverse=reverse, frame=frame, name=name),
+        ),
+        axis=1,
+    )
diff --git a/dtoolkit/geoaccessor/geoseries/xy.py b/dtoolkit/geoaccessor/geoseries/xy.py
--- a/dtoolkit/geoaccessor/geoseries/xy.py
+++ b/dtoolkit/geoaccessor/geoseries/xy.py
@@ -71,7 +71,7 @@ def xy(
         - If ``drop=True`` and ``frame=True``, return a DataFrame with x and y two
           columns.
 
-        - IF ``drop=True`` and ``frame=False``, return a Series with tuple of
+        - If ``drop=True`` and ``frame=False``, return a Series with tuple of
           coordinate.
 
     See Also


Test patch: