prompt: We are currently solving the following issue within our repository. Here is the issue text:
  --- BEGIN ISSUE ---
  ENH: New geoaccessor `geocentroid` to get the center point of points
  <!--
  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 import Point
      >>> df = gpd.GeoDataFrame(
      ...     geometry=[
      ...         Point(100, 32),
      ...         Point(120, 50),
      ...         Point(122, 55)
      ...     ],
      ...     crs=4326,
      ... )
      >>> df
                           geometry
      0  POINT (100.00000 32.00000)
      1  POINT (120.00000 50.00000)
      2  POINT (122.00000 55.00000)
      >>> df.geocentroid()
      <POINT (112.213 44.119)>
  ```
  
  --- END ISSUE ---
  
  Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
  --- BEGIN FILES ---
  Path: `dtoolkit/geoaccessor/geoseries/geocentroid.py`
  Content:
  ```
  1 import geopandas as gpd
  2 import numpy as np
  3 import pandas as pd
  4 from shapely import Point
  5 
  6 from dtoolkit.geoaccessor.geoseries.geodistance import geodistance
  7 from dtoolkit.geoaccessor.geoseries.xy import xy
  8 from dtoolkit.geoaccessor.register import register_geoseries_method
  9 
  10 
  11 @register_geoseries_method
  12 def geocentroid(
  13     s: gpd.GeoSeries,
  14     /,
  15     weights: pd.Series = None,
  16     max_iter: int = 300,
  17     tol: float = 1e-4,
  18 ) -> Point:
  19     """
  20     Return the centroid of all points via the center of gravity method.
  21 
  22     Parameters
  23     ----------
  24     weights : Hashable or 1d array-like, optional
  25         - None : All weights will be set to 1.
  26         - Hashable : Only for DataFrame, the column name.
  27         - 1d array-like : The weights of each point.
  28 
  29     max_iter : int, default 300
  30         Maximum number of iterations to perform.
  31 
  32     tol : float, default 1e-4
  33         Tolerance for convergence.
  34 
  35     Returns
  36     -------
  37     Point
  38 
  39     Raises
  40     ------
  41     ValueError
  42         If the CRS is not ``ESGP:4326``.
  43 
  44     See Also
  45     --------
  46     geopandas.GeoSeries.centroid
  47     dtoolkit.geoaccessor.geoseries.geocentroid
  48     dtoolkit.geoaccessor.geodataframe.geocentroid
  49 
  50     Examples
  51     --------
  52     >>> import dtoolkit.geoaccessor
  53     >>> import geopandas as gpd
  54     >>> from shapely import Point
  55     >>> df = gpd.GeoDataFrame(
  56     ...     {
  57     ...         "weights": [1, 2, 3],
  58     ...         "geometry": [Point(100, 32), Point(120, 50), Point(122, 55)],
  59     ...     },
  60     ...     crs=4326,
  61     ... )
  62     >>> df
  63        weights                    geometry
  64     0        1  POINT (100.00000 32.00000)
  65     1        2  POINT (120.00000 50.00000)
  66     2        3  POINT (122.00000 55.00000)
  67     >>> df.geocentroid()
  68     <POINT (112.375 44.276)>
  69 
  70     Set weights for each point.
  71 
  72     >>> df.geocentroid("weights")
  73     <POINT (114.516 46.675)>
  74     >>> df.geocentroid([1, 2, 3])
  75     <POINT (114.516 46.675)>
  76     """
  77 
  78     if s.crs != 4326:
  79         raise ValueError(f"Only support 'EPSG:4326' CRS, but got {s.crs!r}.")
  80 
  81     weights = np.asarray(weights) if weights is not None else 1
  82     coord = xy(s)
  83     X = coord.mean()
  84     for _ in range(max_iter):
  85         dis = geodistance(s, Point(*X.tolist())).mul(weights, axis=0)
  86         Xt = coord.mul(dis, axis=0).sum() / dis.sum()
  87 
  88         if ((X - Xt).abs() <= tol).all():
  89             X = Xt
  90             break
  91 
  92         X = Xt
  93 
  94     return Point(*X.tolist())
  95
  ```
  
  Path: `dtoolkit/geoaccessor/geodataframe/geocentroid.py`
  Content:
  ```
  1 from __future__ import annotations
  2 
  3 from typing import Hashable
  4 
  5 import geopandas as gpd
  6 import pandas as pd
  7 from pandas.util._decorators import doc
  8 from shapely import Point
  9 
  10 from dtoolkit.geoaccessor.geoseries import geocentroid as s_geocentroid
  11 from dtoolkit.geoaccessor.register import register_geodataframe_method
  12 
  13 
  14 @register_geodataframe_method
  15 @doc(s_geocentroid)
  16 def geocentroid(
  17     df: gpd.GeoDataFrame,
  18     /,
  19     weights: Hashable | pd.Series = None,
  20     max_iter: int = 300,
  21     tol: float = 1e-4,
  22 ) -> Point:
  23     if weights is not None and isinstance(weights, Hashable):
  24         weights = df[weights]
  25 
  26     return s_geocentroid(df.geometry, weights=weights, max_iter=max_iter, tol=tol)
  27
  ```
  --- END FILES ---
  
  Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.
  
  Here is an example:
  
  ```diff
  diff --git a/examples/server_async.py b/examples/server_async.py
  --- a/examples/server_async.py
  +++ b/examples/server_async.py
  @@ -313,4 +313,4 @@
   
   
   if __name__ == "__main__":
  -    asyncio.run(run_async_server("."), debug=True)
  +    asyncio.run(run_async_server(), debug=True)
  diff --git a/examples/server_sync.py b/examples/server_sync.py
  --- a/examples/server_sync.py
  +++ b/examples/server_sync.py
  @@ -313,5 +313,5 @@
   
   
   if __name__ == "__main__":
  -    server = run_sync_server(".")
  +    server = run_sync_server()
       server.shutdown()
  
  ```
  
golden_diff: diff --git a/dtoolkit/geoaccessor/geodataframe/geocentroid.py b/dtoolkit/geoaccessor/geodataframe/geocentroid.py
  --- a/dtoolkit/geoaccessor/geodataframe/geocentroid.py
  +++ b/dtoolkit/geoaccessor/geodataframe/geocentroid.py
  @@ -18,7 +18,7 @@
       /,
       weights: Hashable | pd.Series = None,
       max_iter: int = 300,
  -    tol: float = 1e-4,
  +    tol: float = 1e-5,
   ) -> Point:
       if weights is not None and isinstance(weights, Hashable):
           weights = df[weights]
  diff --git a/dtoolkit/geoaccessor/geoseries/geocentroid.py b/dtoolkit/geoaccessor/geoseries/geocentroid.py
  --- a/dtoolkit/geoaccessor/geoseries/geocentroid.py
  +++ b/dtoolkit/geoaccessor/geoseries/geocentroid.py
  @@ -14,11 +14,21 @@
       /,
       weights: pd.Series = None,
       max_iter: int = 300,
  -    tol: float = 1e-4,
  +    tol: float = 1e-5,
   ) -> Point:
  -    """
  +    r"""
       Return the centroid of all points via the center of gravity method.
   
  +    .. math::
  +
  +        \left\{\begin{matrix}
  +            d_i &=& D(P(\bar{x}_n, \bar{y}_n), P(x_i, y_i))  \\
  +            \bar{x}_0 &=& \frac{\sum w_i x_i}{\sum w_i} \\
  +            \bar{y}_0 &=& \frac{\sum w_i y_i}{\sum w_i} \\
  +            \bar{x}_{n+1} &=& \frac{\sum w_i x_i / d_i}{\sum w_i / d_i} \\
  +            \bar{y}_{n+1} &=& \frac{\sum w_i y_i / d_i}{\sum w_i / d_i} \\
  +        \end{matrix}\right.
  +
       Parameters
       ----------
       weights : Hashable or 1d array-like, optional
  @@ -29,18 +39,13 @@
       max_iter : int, default 300
           Maximum number of iterations to perform.
   
  -    tol : float, default 1e-4
  +    tol : float, default 1e-5
           Tolerance for convergence.
   
       Returns
       -------
       Point
   
  -    Raises
  -    ------
  -    ValueError
  -        If the CRS is not ``ESGP:4326``.
  -
       See Also
       --------
       geopandas.GeoSeries.centroid
  @@ -65,24 +70,21 @@
       1        2  POINT (120.00000 50.00000)
       2        3  POINT (122.00000 55.00000)
       >>> df.geocentroid()
  -    <POINT (112.375 44.276)>
  +    <POINT (120 50)>
   
       Set weights for each point.
   
       >>> df.geocentroid("weights")
  -    <POINT (114.516 46.675)>
  +    <POINT (121.999 54.998)>
       >>> df.geocentroid([1, 2, 3])
  -    <POINT (114.516 46.675)>
  +    <POINT (121.999 54.998)>
       """
   
  -    if s.crs != 4326:
  -        raise ValueError(f"Only support 'EPSG:4326' CRS, but got {s.crs!r}.")
  -
       weights = np.asarray(weights) if weights is not None else 1
       coord = xy(s)
       X = coord.mean()
       for _ in range(max_iter):
  -        dis = geodistance(s, Point(*X.tolist())).mul(weights, axis=0)
  +        dis = geodistance(s, Point(*X.tolist())).rdiv(1).mul(weights, axis=0)
           Xt = coord.mul(dis, axis=0).sum() / dis.sum()
   
           if ((X - Xt).abs() <= tol).all():
  
verification_info: {"golden_diff": "diff --git a/dtoolkit/geoaccessor/geodataframe/geocentroid.py b/dtoolkit/geoaccessor/geodataframe/geocentroid.py\n--- a/dtoolkit/geoaccessor/geodataframe/geocentroid.py\n+++ b/dtoolkit/geoaccessor/geodataframe/geocentroid.py\n@@ -18,7 +18,7 @@\n     /,\n     weights: Hashable | pd.Series = None,\n     max_iter: int = 300,\n-    tol: float = 1e-4,\n+    tol: float = 1e-5,\n ) -> Point:\n     if weights is not None and isinstance(weights, Hashable):\n         weights = df[weights]\ndiff --git a/dtoolkit/geoaccessor/geoseries/geocentroid.py b/dtoolkit/geoaccessor/geoseries/geocentroid.py\n--- a/dtoolkit/geoaccessor/geoseries/geocentroid.py\n+++ b/dtoolkit/geoaccessor/geoseries/geocentroid.py\n@@ -14,11 +14,21 @@\n     /,\n     weights: pd.Series = None,\n     max_iter: int = 300,\n-    tol: float = 1e-4,\n+    tol: float = 1e-5,\n ) -> Point:\n-    \"\"\"\n+    r\"\"\"\n     Return the centroid of all points via the center of gravity method.\n \n+    .. math::\n+\n+        \\left\\{\\begin{matrix}\n+            d_i &=& D(P(\\bar{x}_n, \\bar{y}_n), P(x_i, y_i))  \\\\\n+            \\bar{x}_0 &=& \\frac{\\sum w_i x_i}{\\sum w_i} \\\\\n+            \\bar{y}_0 &=& \\frac{\\sum w_i y_i}{\\sum w_i} \\\\\n+            \\bar{x}_{n+1} &=& \\frac{\\sum w_i x_i / d_i}{\\sum w_i / d_i} \\\\\n+            \\bar{y}_{n+1} &=& \\frac{\\sum w_i y_i / d_i}{\\sum w_i / d_i} \\\\\n+        \\end{matrix}\\right.\n+\n     Parameters\n     ----------\n     weights : Hashable or 1d array-like, optional\n@@ -29,18 +39,13 @@\n     max_iter : int, default 300\n         Maximum number of iterations to perform.\n \n-    tol : float, default 1e-4\n+    tol : float, default 1e-5\n         Tolerance for convergence.\n \n     Returns\n     -------\n     Point\n \n-    Raises\n-    ------\n-    ValueError\n-        If the CRS is not ``ESGP:4326``.\n-\n     See Also\n     --------\n     geopandas.GeoSeries.centroid\n@@ -65,24 +70,21 @@\n     1        2  POINT (120.00000 50.00000)\n     2        3  POINT (122.00000 55.00000)\n     >>> df.geocentroid()\n-    <POINT (112.375 44.276)>\n+    <POINT (120 50)>\n \n     Set weights for each point.\n \n     >>> df.geocentroid(\"weights\")\n-    <POINT (114.516 46.675)>\n+    <POINT (121.999 54.998)>\n     >>> df.geocentroid([1, 2, 3])\n-    <POINT (114.516 46.675)>\n+    <POINT (121.999 54.998)>\n     \"\"\"\n \n-    if s.crs != 4326:\n-        raise ValueError(f\"Only support 'EPSG:4326' CRS, but got {s.crs!r}.\")\n-\n     weights = np.asarray(weights) if weights is not None else 1\n     coord = xy(s)\n     X = coord.mean()\n     for _ in range(max_iter):\n-        dis = geodistance(s, Point(*X.tolist())).mul(weights, axis=0)\n+        dis = geodistance(s, Point(*X.tolist())).rdiv(1).mul(weights, axis=0)\n         Xt = coord.mul(dis, axis=0).sum() / dis.sum()\n \n         if ((X - Xt).abs() <= tol).all():\n", "issue": "ENH: New geoaccessor `geocentroid` to get the center point of points\n<!--\r\nThanks for contributing a pull request!\r\n\r\nPlease follow these standard acronyms to start the commit message:\r\n\r\n- ENH: enhancement\r\n- BUG: bug fix\r\n- DOC: documentation\r\n- TYP: type annotations\r\n- TST: addition or modification of tests\r\n- MAINT: maintenance commit (refactoring, typos, etc.)\r\n- BLD: change related to building\r\n- REL: related to releasing\r\n- API: an (incompatible) API change\r\n- DEP: deprecate something, or remove a deprecated object\r\n- DEV: development tool or utility\r\n- REV: revert an earlier commit\r\n- PERF: performance improvement\r\n- BOT: always commit via a bot\r\n- CI: related to CI or CD\r\n- CLN: Code cleanup\r\n-->\r\n\r\n- [ ] closes #xxxx\r\n- [x] whatsnew entry\r\n\r\n```python\r\n    >>> import dtoolkit.geoaccessor\r\n    >>> import geopandas as gpd\r\n    >>> from shapely import Point\r\n    >>> df = gpd.GeoDataFrame(\r\n    ...     geometry=[\r\n    ...         Point(100, 32),\r\n    ...         Point(120, 50),\r\n    ...         Point(122, 55)\r\n    ...     ],\r\n    ...     crs=4326,\r\n    ... )\r\n    >>> df\r\n                         geometry\r\n    0  POINT (100.00000 32.00000)\r\n    1  POINT (120.00000 50.00000)\r\n    2  POINT (122.00000 55.00000)\r\n    >>> df.geocentroid()\r\n    <POINT (112.213 44.119)>\r\n```\n", "before_files": [{"content": "import geopandas as gpd\nimport numpy as np\nimport pandas as pd\nfrom shapely import Point\n\nfrom dtoolkit.geoaccessor.geoseries.geodistance import geodistance\nfrom dtoolkit.geoaccessor.geoseries.xy import xy\nfrom dtoolkit.geoaccessor.register import register_geoseries_method\n\n\n@register_geoseries_method\ndef geocentroid(\n    s: gpd.GeoSeries,\n    /,\n    weights: pd.Series = None,\n    max_iter: int = 300,\n    tol: float = 1e-4,\n) -> Point:\n    \"\"\"\n    Return the centroid of all points via the center of gravity method.\n\n    Parameters\n    ----------\n    weights : Hashable or 1d array-like, optional\n        - None : All weights will be set to 1.\n        - Hashable : Only for DataFrame, the column name.\n        - 1d array-like : The weights of each point.\n\n    max_iter : int, default 300\n        Maximum number of iterations to perform.\n\n    tol : float, default 1e-4\n        Tolerance for convergence.\n\n    Returns\n    -------\n    Point\n\n    Raises\n    ------\n    ValueError\n        If the CRS is not ``ESGP:4326``.\n\n    See Also\n    --------\n    geopandas.GeoSeries.centroid\n    dtoolkit.geoaccessor.geoseries.geocentroid\n    dtoolkit.geoaccessor.geodataframe.geocentroid\n\n    Examples\n    --------\n    >>> import dtoolkit.geoaccessor\n    >>> import geopandas as gpd\n    >>> from shapely import Point\n    >>> df = gpd.GeoDataFrame(\n    ...     {\n    ...         \"weights\": [1, 2, 3],\n    ...         \"geometry\": [Point(100, 32), Point(120, 50), Point(122, 55)],\n    ...     },\n    ...     crs=4326,\n    ... )\n    >>> df\n       weights                    geometry\n    0        1  POINT (100.00000 32.00000)\n    1        2  POINT (120.00000 50.00000)\n    2        3  POINT (122.00000 55.00000)\n    >>> df.geocentroid()\n    <POINT (112.375 44.276)>\n\n    Set weights for each point.\n\n    >>> df.geocentroid(\"weights\")\n    <POINT (114.516 46.675)>\n    >>> df.geocentroid([1, 2, 3])\n    <POINT (114.516 46.675)>\n    \"\"\"\n\n    if s.crs != 4326:\n        raise ValueError(f\"Only support 'EPSG:4326' CRS, but got {s.crs!r}.\")\n\n    weights = np.asarray(weights) if weights is not None else 1\n    coord = xy(s)\n    X = coord.mean()\n    for _ in range(max_iter):\n        dis = geodistance(s, Point(*X.tolist())).mul(weights, axis=0)\n        Xt = coord.mul(dis, axis=0).sum() / dis.sum()\n\n        if ((X - Xt).abs() <= tol).all():\n            X = Xt\n            break\n\n        X = Xt\n\n    return Point(*X.tolist())\n", "path": "dtoolkit/geoaccessor/geoseries/geocentroid.py"}, {"content": "from __future__ import annotations\n\nfrom typing import Hashable\n\nimport geopandas as gpd\nimport pandas as pd\nfrom pandas.util._decorators import doc\nfrom shapely import Point\n\nfrom dtoolkit.geoaccessor.geoseries import geocentroid as s_geocentroid\nfrom dtoolkit.geoaccessor.register import register_geodataframe_method\n\n\n@register_geodataframe_method\n@doc(s_geocentroid)\ndef geocentroid(\n    df: gpd.GeoDataFrame,\n    /,\n    weights: Hashable | pd.Series = None,\n    max_iter: int = 300,\n    tol: float = 1e-4,\n) -> Point:\n    if weights is not None and isinstance(weights, Hashable):\n        weights = df[weights]\n\n    return s_geocentroid(df.geometry, weights=weights, max_iter=max_iter, tol=tol)\n", "path": "dtoolkit/geoaccessor/geodataframe/geocentroid.py"}], "after_files": [{"content": "import geopandas as gpd\nimport numpy as np\nimport pandas as pd\nfrom shapely import Point\n\nfrom dtoolkit.geoaccessor.geoseries.geodistance import geodistance\nfrom dtoolkit.geoaccessor.geoseries.xy import xy\nfrom dtoolkit.geoaccessor.register import register_geoseries_method\n\n\n@register_geoseries_method\ndef geocentroid(\n    s: gpd.GeoSeries,\n    /,\n    weights: pd.Series = None,\n    max_iter: int = 300,\n    tol: float = 1e-5,\n) -> Point:\n    r\"\"\"\n    Return the centroid of all points via the center of gravity method.\n\n    .. math::\n\n        \\left\\{\\begin{matrix}\n            d_i &=& D(P(\\bar{x}_n, \\bar{y}_n), P(x_i, y_i))  \\\\\n            \\bar{x}_0 &=& \\frac{\\sum w_i x_i}{\\sum w_i} \\\\\n            \\bar{y}_0 &=& \\frac{\\sum w_i y_i}{\\sum w_i} \\\\\n            \\bar{x}_{n+1} &=& \\frac{\\sum w_i x_i / d_i}{\\sum w_i / d_i} \\\\\n            \\bar{y}_{n+1} &=& \\frac{\\sum w_i y_i / d_i}{\\sum w_i / d_i} \\\\\n        \\end{matrix}\\right.\n\n    Parameters\n    ----------\n    weights : Hashable or 1d array-like, optional\n        - None : All weights will be set to 1.\n        - Hashable : Only for DataFrame, the column name.\n        - 1d array-like : The weights of each point.\n\n    max_iter : int, default 300\n        Maximum number of iterations to perform.\n\n    tol : float, default 1e-5\n        Tolerance for convergence.\n\n    Returns\n    -------\n    Point\n\n    See Also\n    --------\n    geopandas.GeoSeries.centroid\n    dtoolkit.geoaccessor.geoseries.geocentroid\n    dtoolkit.geoaccessor.geodataframe.geocentroid\n\n    Examples\n    --------\n    >>> import dtoolkit.geoaccessor\n    >>> import geopandas as gpd\n    >>> from shapely import Point\n    >>> df = gpd.GeoDataFrame(\n    ...     {\n    ...         \"weights\": [1, 2, 3],\n    ...         \"geometry\": [Point(100, 32), Point(120, 50), Point(122, 55)],\n    ...     },\n    ...     crs=4326,\n    ... )\n    >>> df\n       weights                    geometry\n    0        1  POINT (100.00000 32.00000)\n    1        2  POINT (120.00000 50.00000)\n    2        3  POINT (122.00000 55.00000)\n    >>> df.geocentroid()\n    <POINT (120 50)>\n\n    Set weights for each point.\n\n    >>> df.geocentroid(\"weights\")\n    <POINT (121.999 54.998)>\n    >>> df.geocentroid([1, 2, 3])\n    <POINT (121.999 54.998)>\n    \"\"\"\n\n    weights = np.asarray(weights) if weights is not None else 1\n    coord = xy(s)\n    X = coord.mean()\n    for _ in range(max_iter):\n        dis = geodistance(s, Point(*X.tolist())).rdiv(1).mul(weights, axis=0)\n        Xt = coord.mul(dis, axis=0).sum() / dis.sum()\n\n        if ((X - Xt).abs() <= tol).all():\n            X = Xt\n            break\n\n        X = Xt\n\n    return Point(*X.tolist())\n", "path": "dtoolkit/geoaccessor/geoseries/geocentroid.py"}, {"content": "from __future__ import annotations\n\nfrom typing import Hashable\n\nimport geopandas as gpd\nimport pandas as pd\nfrom pandas.util._decorators import doc\nfrom shapely import Point\n\nfrom dtoolkit.geoaccessor.geoseries import geocentroid as s_geocentroid\nfrom dtoolkit.geoaccessor.register import register_geodataframe_method\n\n\n@register_geodataframe_method\n@doc(s_geocentroid)\ndef geocentroid(\n    df: gpd.GeoDataFrame,\n    /,\n    weights: Hashable | pd.Series = None,\n    max_iter: int = 300,\n    tol: float = 1e-5,\n) -> Point:\n    if weights is not None and isinstance(weights, Hashable):\n        weights = df[weights]\n\n    return s_geocentroid(df.geometry, weights=weights, max_iter=max_iter, tol=tol)\n", "path": "dtoolkit/geoaccessor/geodataframe/geocentroid.py"}]}