Repository: Zeroto521/my-data-toolkit

Issue:
BUG: `GeoDataFrame.repeat` return `DataFrame`
```python
>>> import dtoolkit.geoaccessor
>>> import geopandas as gpd
>>> from shapely import Point
>>> df = (
...     gpd.GeoDataFrame(
...         {
...             "label": ["a", "b"],
...             "geometry": [Point(100, 1), Point(122, 55)],
...         },
...         crs=4326,
...     )
...     .repeat(2)
... )
>>> df
  label        geometry
0     a   POINT (100 1)
0     a   POINT (100 1)
1     b  POINT (122 55)
1     b  POINT (122 55)
>>> type(df)
<class 'pandas.core.frame.DataFrame'>
```
BUG: `GeoDataFrame.repeat` return `DataFrame`
```python
>>> import dtoolkit.geoaccessor
>>> import geopandas as gpd
>>> from shapely import Point
>>> df = (
...     gpd.GeoDataFrame(
...         {
...             "label": ["a", "b"],
...             "geometry": [Point(100, 1), Point(122, 55)],
...         },
...         crs=4326,
...     )
...     .repeat(2)
... )
>>> df
  label        geometry
0     a   POINT (100 1)
0     a   POINT (100 1)
1     b  POINT (122 55)
1     b  POINT (122 55)
>>> type(df)
<class 'pandas.core.frame.DataFrame'>
```


Discussion:

Resolving patch:
diff --git a/dtoolkit/accessor/dataframe/repeat.py b/dtoolkit/accessor/dataframe/repeat.py
--- a/dtoolkit/accessor/dataframe/repeat.py
+++ b/dtoolkit/accessor/dataframe/repeat.py
@@ -2,7 +2,6 @@
 
 from typing import Hashable
 
-import numpy as np
 import pandas as pd
 from pandas.api.types import is_number
 
@@ -99,9 +98,4 @@ def repeat(
     if not is_number(repeats) and isinstance(repeats, Hashable):
         repeats = df[repeats]
 
-    axis = df._get_axis_number(axis)
-    return pd.DataFrame(
-        np.repeat(df._values, repeats, axis=axis),
-        index=df.index.repeat(repeats) if axis == 0 else df.index,
-        columns=df.columns.repeat(repeats) if axis == 1 else df.columns,
-    )
+    return df.reindex(df._get_axis(axis).repeat(repeats), axis=axis)
diff --git a/dtoolkit/geoaccessor/geoseries/to_h3.py b/dtoolkit/geoaccessor/geoseries/to_h3.py
--- a/dtoolkit/geoaccessor/geoseries/to_h3.py
+++ b/dtoolkit/geoaccessor/geoseries/to_h3.py
@@ -83,26 +83,26 @@ def to_h3(
     0     a  POLYGON ((1.00000 0.00000, 1.00000 1.00000, 0....
     1     b  POLYGON ((2.00000 1.00000, 2.00000 2.00000, 1....
     >>> df.to_h3(4)
-                       label                             geometry
-    596538839648960511     a  POLYGON ((1 0, 1 1, 0 1, 0 0, 1 0))
-    596538693620072447     a  POLYGON ((1 0, 1 1, 0 1, 0 0, 1 0))
-    596538685030137855     a  POLYGON ((1 0, 1 1, 0 1, 0 0, 1 0))
-    596538848238895103     a  POLYGON ((1 0, 1 1, 0 1, 0 0, 1 0))
-    596537920525959167     a  POLYGON ((1 0, 1 1, 0 1, 0 0, 1 0))
-    596538813879156735     a  POLYGON ((1 0, 1 1, 0 1, 0 0, 1 0))
-    596538856828829695     a  POLYGON ((1 0, 1 1, 0 1, 0 0, 1 0))
-    596538805289222143     a  POLYGON ((1 0, 1 1, 0 1, 0 0, 1 0))
-    596538229763604479     b  POLYGON ((2 1, 2 2, 1 2, 1 1, 2 1))
-    596537946295762943     b  POLYGON ((2 1, 2 2, 1 2, 1 1, 2 1))
-    596540780974178303     b  POLYGON ((2 1, 2 2, 1 2, 1 1, 2 1))
-    596540729434570751     b  POLYGON ((2 1, 2 2, 1 2, 1 1, 2 1))
-    596540772384243711     b  POLYGON ((2 1, 2 2, 1 2, 1 1, 2 1))
-    596538212583735295     b  POLYGON ((2 1, 2 2, 1 2, 1 1, 2 1))
-    596540763794309119     b  POLYGON ((2 1, 2 2, 1 2, 1 1, 2 1))
-    596537954885697535     b  POLYGON ((2 1, 2 2, 1 2, 1 1, 2 1))
-    596540746614439935     b  POLYGON ((2 1, 2 2, 1 2, 1 1, 2 1))
-    596538195403866111     b  POLYGON ((2 1, 2 2, 1 2, 1 1, 2 1))
-    596541030082281471     b  POLYGON ((2 1, 2 2, 1 2, 1 1, 2 1))
+                       label                                           geometry
+    596538839648960511     a  POLYGON ((1.00000 0.00000, 1.00000 1.00000, 0....
+    596538693620072447     a  POLYGON ((1.00000 0.00000, 1.00000 1.00000, 0....
+    596538685030137855     a  POLYGON ((1.00000 0.00000, 1.00000 1.00000, 0....
+    596538848238895103     a  POLYGON ((1.00000 0.00000, 1.00000 1.00000, 0....
+    596537920525959167     a  POLYGON ((1.00000 0.00000, 1.00000 1.00000, 0....
+    596538813879156735     a  POLYGON ((1.00000 0.00000, 1.00000 1.00000, 0....
+    596538856828829695     a  POLYGON ((1.00000 0.00000, 1.00000 1.00000, 0....
+    596538805289222143     a  POLYGON ((1.00000 0.00000, 1.00000 1.00000, 0....
+    596538229763604479     b  POLYGON ((2.00000 1.00000, 2.00000 2.00000, 1....
+    596537946295762943     b  POLYGON ((2.00000 1.00000, 2.00000 2.00000, 1....
+    596540780974178303     b  POLYGON ((2.00000 1.00000, 2.00000 2.00000, 1....
+    596540729434570751     b  POLYGON ((2.00000 1.00000, 2.00000 2.00000, 1....
+    596540772384243711     b  POLYGON ((2.00000 1.00000, 2.00000 2.00000, 1....
+    596538212583735295     b  POLYGON ((2.00000 1.00000, 2.00000 2.00000, 1....
+    596540763794309119     b  POLYGON ((2.00000 1.00000, 2.00000 2.00000, 1....
+    596537954885697535     b  POLYGON ((2.00000 1.00000, 2.00000 2.00000, 1....
+    596540746614439935     b  POLYGON ((2.00000 1.00000, 2.00000 2.00000, 1....
+    596538195403866111     b  POLYGON ((2.00000 1.00000, 2.00000 2.00000, 1....
+    596541030082281471     b  POLYGON ((2.00000 1.00000, 2.00000 2.00000, 1....
 
     Also support str (hexadecimal) format.
 


Test patch:
diff --git a/test/_compat.py b/test/_compat.py
new file mode 100644
--- /dev/null
+++ b/test/_compat.py
@@ -0,0 +1,13 @@
+# -----------------------------------------------------------------------------
+# geopandas compat
+# -----------------------------------------------------------------------------
+
+HAS_GEOPANDAS = None
+
+try:
+    import geopandas  # noqa: F401
+
+    HAS_GEOPANDAS = True
+
+except ImportError:
+    HAS_GEOPANDAS = False
diff --git a/test/accessor/dataframe/test_repeat.py b/test/accessor/dataframe/test_repeat.py
--- a/test/accessor/dataframe/test_repeat.py
+++ b/test/accessor/dataframe/test_repeat.py
@@ -2,7 +2,8 @@
 import pytest
 from pandas.testing import assert_frame_equal
 
-from dtoolkit.accessor.dataframe import repeat  # noqa: F401
+from dtoolkit.accessor.dataframe import repeat
+from test._compat import HAS_GEOPANDAS
 
 
 @pytest.mark.parametrize(
@@ -47,7 +48,7 @@
 )
 def test_work(repeats, axis, expected):
     df = pd.DataFrame({"a": [1, 2], "b": [3, 4]})
-    result = df.repeat(repeats, axis=axis)
+    result = repeat(df, repeats, axis=axis)
 
     assert_frame_equal(result, expected)
 
@@ -56,4 +57,25 @@ def test_work(repeats, axis, expected):
 def test_error(axis):
     df = pd.DataFrame({"a": [1, 2], "b": [3, 4]})
     with pytest.raises(ValueError):
-        df.repeat(2, axis)
+        repeat(df, 2, axis)
+
+
+# https://github.com/Zeroto521/my-data-toolkit/issues/823
+@pytest.mark.skipif(
+    not HAS_GEOPANDAS,
+    reason="could not import 'geopandas': No module named 'geopandas'",
+)
+def test_inputing_geodataframe_return_geodataframe():
+    import geopandas as gpd
+    from shapely import Point
+
+    df = gpd.GeoDataFrame(
+        {
+            "label": ["a", "b"],
+            "geometry": [Point(100, 1), Point(122, 55)],
+        },
+        crs=4326,
+    ).repeat(2)
+
+    assert isinstance(df, gpd.GeoDataFrame)
+    assert df.crs == 4326