66GPS_HARMONIZED_COLUMN_TYPES specification.
77"""
88
9+ import geoarrow .pyarrow as ga
910import numpy as np
1011import pandas as pd
1112
@@ -34,11 +35,15 @@ def harmonize_data(self, data):
3435 # First, apply standard column renaming
3536 data = super ().harmonize_data (data )
3637
37- # Then ensure all GPS harmonized columns exist with correct types
38+ # Ensure all GPS harmonized columns exist with correct types
3839 for harmonized_col in GPSHarmonizedColumn :
3940 col_name = harmonized_col .value
4041 pd_dtype = GPS_HARMONIZED_COLUMN_TYPES [harmonized_col ]
4142
43+ # Skip geometry column - we'll create it last from lat/lon
44+ if col_name == "geometry" :
45+ continue
46+
4247 if col_name not in data .columns :
4348 # Add column with null values and appropriate dtype
4449 if pd_dtype == "float64" :
@@ -65,6 +70,56 @@ def harmonize_data(self, data):
6570 elif pd_dtype == "datetime64[ns]" :
6671 data [col_name ] = pd .to_datetime (data [col_name ], errors = "coerce" )
6772
73+ # Create geometry column from latitude and longitude (WGS84)
74+ # Note: This creates geometry from current lat/lon values
75+ # If parsers modify lat/lon after calling super(), they should
76+ # call _create_geometry_column() again
77+ data = self ._create_geometry_column (data )
78+
79+ return data
80+
81+ def _create_geometry_column (self , data ):
82+ """
83+ Create or update geometry column from latitude and longitude.
84+
85+ This helper method can be called by subclasses after they've
86+ finished creating/modifying latitude and longitude columns.
87+
88+ Args:
89+ data: DataFrame with latitude and longitude columns
90+
91+ Returns:
92+ DataFrame with geometry column added/updated
93+ """
94+ # Only create if lat/lon columns exist and have valid (non-null) values
95+ if (
96+ "latitude" in data .columns
97+ and "longitude" in data .columns
98+ and not data ["latitude" ].isna ().all ()
99+ and not data ["longitude" ].isna ().all ()
100+ ):
101+ # Create point geometries from lat/lon coordinates
102+ # GeoArrow expects (x, y) which is (longitude, latitude)
103+ points = ga .make_point (
104+ data ["longitude" ].values ,
105+ data ["latitude" ].values ,
106+ crs = "EPSG:4326" ,
107+ )
108+ # Convert to pandas ArrowExtensionArray
109+ data ["geometry" ] = pd .array (
110+ points .to_pylist (), dtype = pd .ArrowDtype (points .type )
111+ )
112+ else :
113+ # Create empty geometry column if lat/lon don't exist or are all null
114+ empty_points = ga .make_point (
115+ np .full (len (data ), np .nan ),
116+ np .full (len (data ), np .nan ),
117+ crs = "EPSG:4326" ,
118+ )
119+ data ["geometry" ] = pd .array (
120+ empty_points .to_pylist (), dtype = pd .ArrowDtype (empty_points .type )
121+ )
122+
68123 return data
69124
70125 def get_harmonization_schema (self ):
0 commit comments