Repository: symerio/pgeocode

Issue:
incorrect centroid in query_postal_code for duplicate postal code entries
query_postal_code sums the longitude.

nomi.query_postal_code("41-800")

Thats from GEOName file:
41-800 will return you 2 locations: 
PL, 41-800, 50.2817, 18.6745
PL,41-800, 50.3055, 18.778

After running: nomi.query_postal_code("41-800")
postal_code                41-800
place_name        Gliwice, Zabrze
latitude                  50.2817
longitude                 18.7263


and the longitude = SUM of the locations from file / number of results.

Comments:

Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 683a3c0..088341d 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -4,6 +4,12 @@
 
  - The minimum supported Python version is updated to Python 3.8
    [#65](https://github.com/symerio/pgeocode/pull/65)
+ - Fix error in latitude grouping when creating a unique postcode index.
+   With this fix `Nominatim(.., unique=True)` correctly computes the average
+   latitude for each postcode (if multiple localities share the same postcode),
+   instead of taking the first latitude value.
+   [#62](https://github.com/symerio/pgeocode/pull/62)
+
  - The default folder to store downloaded data is changed to `~/.cache/pgeocode/`.
    This default can still be changed by setting the `PGEOCODE_DATA_DIR` environment variable.
    [#51](https://github.com/symerio/pgeocode/pull/51)
diff --git a/pgeocode.py b/pgeocode.py
index 65f8ffd..4f9aab3 100644
--- a/pgeocode.py
+++ b/pgeocode.py
@@ -252,7 +252,7 @@ class Nominatim:
             df_unique_cp_group = self._data.groupby("postal_code")
             data_unique = df_unique_cp_group[["latitude", "longitude"]].mean()
             valid_keys = set(DATA_FIELDS).difference(
-                ["place_name", "lattitude", "longitude", "postal_code"]
+                ["place_name", "latitude", "longitude", "postal_code"]
             )
             data_unique["place_name"] = df_unique_cp_group["place_name"].apply(
                 lambda x: ", ".join([str(el) for el in x])


Test patch:
diff --git a/test_pgeocode.py b/test_pgeocode.py
index b6fe453..1bfdcbf 100644
--- a/test_pgeocode.py
+++ b/test_pgeocode.py
@@ -261,3 +261,60 @@ def test_first_url_fails(httpserver, monkeypatch, temp_dir):
     with pytest.warns(UserWarning, match=msg):
         Nominatim("ie")
     httpserver.check_assertions()
+
+
+def test_unique_index_pcode(tmp_path):
+    """Check that a centroid is computed both for latitude and longitude
+
+    Regression test for https://github.com/symerio/pgeocode/pull/62
+    """
+
+    class MockNominatim(Nominatim):
+        def __init__(self):
+            pass
+
+    data = pd.DataFrame(
+        {
+            "postal_code": ["1", "1", "2", "2"],
+            "latitude": [1.0, 2.0, 3.0, 4],
+            "longitude": [5.0, 6.0, 7.0, 8],
+            "place_name": ["a", "b", "c", "d"],
+            "state_name": ["a", "b", "c", "d"],
+            "country_name": ["a", "b", "c", "d"],
+            "county_name": ["a", "b", "c", "d"],
+            "community_name": ["a", "b", "c", "d"],
+            "accuracy": [1, 2, 3, 4],
+            "country_code": [1, 2, 3, 4],
+            "county_code": [1, 2, 3, 4],
+            "state_code": [1, 2, 3, 4],
+            "community_code": [1, 2, 3, 4],
+        }
+    )
+
+    nominatim = MockNominatim()
+    data_path = tmp_path / "a.txt"
+    nominatim._data_path = str(data_path)
+    nominatim._data = data
+    data_unique = nominatim._index_postal_codes()
+
+    data_unique_expected = pd.DataFrame(
+        {
+            "postal_code": ["1", "2"],
+            "latitude": [1.5, 3.5],
+            "longitude": [5.5, 7.5],
+            "place_name": ["a, b", "c, d"],
+            "state_name": ["a", "c"],
+            # We don't include the country_name for some reason?
+            # 'country_name': ['a', 'c'],
+            "county_name": ["a", "c"],
+            "community_name": ["a", "c"],
+            "accuracy": [1, 3],
+            "country_code": [1, 3],
+            "county_code": [1, 3],
+            "state_code": [1, 3],
+            "community_code": [1, 3],
+        }
+    )
+    pd.testing.assert_frame_equal(
+        data_unique.sort_index(axis=1), data_unique_expected.sort_index(axis=1)
+    )