Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

BUG: fix write of kml lon/lat transpose #421

Merged
merged 21 commits into from
Jun 14, 2024
Merged
Show file tree
Hide file tree
Changes from 19 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@
`write` and `write_dataframe` (#384).
- Fixed bug preventing reading from bytes or file-like in `read_arrow` /
`open_arrow` (#407).
- Fixed bug transposing longitude and latitude when writing files with
co-ordinate transfomration to EPSG:4326 (#421).
nicholas-ys-tan marked this conversation as resolved.
Show resolved Hide resolved

### Packaging

Expand Down
6 changes: 5 additions & 1 deletion pyogrio/_io.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -2134,6 +2134,10 @@ cdef create_ogr_dataset_layer(
if crs is not None:
try:
ogr_crs = create_crs(crs)
# force geographic CRS to use lon, lat order and ignore axis order specified by CRS, in order
# to correctly write KML and GeoJSON coordinates in correct order
OSRSetAxisMappingStrategy(ogr_crs, OAMS_TRADITIONAL_GIS_ORDER)


except Exception as exc:
if dataset_options != NULL:
Expand Down Expand Up @@ -2735,4 +2739,4 @@ cdef create_fields_from_arrow_schema(
f"Error while creating field from Arrow for field {i} with name "
f"'{get_string(child.name)}' and type {get_string(child.format)}"
f"{gdal_msg}."
)
)
5 changes: 4 additions & 1 deletion pyogrio/_ogr.pxd
Original file line number Diff line number Diff line change
Expand Up @@ -196,7 +196,10 @@ cdef extern from "ogr_srs_api.h":
const char* OSRGetAuthorityName(OGRSpatialReferenceH srs, const char *key)
const char* OSRGetAuthorityCode(OGRSpatialReferenceH srs, const char *key)
OGRErr OSRImportFromEPSG(OGRSpatialReferenceH srs, int code)

ctypedef enum OSRAxisMappingStrategy:
OAMS_TRADITIONAL_GIS_ORDER

void OSRSetAxisMappingStrategy(OGRSpatialReferenceH hSRS, OSRAxisMappingStrategy)
int OSRSetFromUserInput(OGRSpatialReferenceH srs, const char *pszDef)
void OSRSetPROJSearchPaths(const char *const *paths)
OGRSpatialReferenceH OSRNewSpatialReference(const char *wkt)
Expand Down
70 changes: 70 additions & 0 deletions pyogrio/tests/test_geopandas_io.py
Original file line number Diff line number Diff line change
Expand Up @@ -2067,3 +2067,73 @@ def test_non_utf8_encoding_shapefile_sql(tmp_path, use_arrow):
)
assert actual.columns[0] == mandarin
assert actual[mandarin].values[0] == mandarin


@pytest.mark.requires_arrow_write_api
def test_write_kml_file_coordinate_order(tmp_path, use_arrow):
nicholas-ys-tan marked this conversation as resolved.
Show resolved Hide resolved
# confirm KML coordinates are written in lon, lat order even if CRS axis specifies otherwise
points = [Point(10, 20), Point(30, 40), Point(50, 60)]
gdf = gp.GeoDataFrame(geometry=points, crs="EPSG:4326")
output_path = tmp_path / "test.kml"
write_dataframe(
gdf, output_path, layer="tmp_layer", driver="KML", use_arrow=use_arrow
)

gdf_in = read_dataframe(output_path, use_arrow=use_arrow)

assert np.array_equal(gdf_in.geometry.values, points)

# test appending to the existing file
points_append = [Point(70, 80), Point(90, 100), Point(110, 120)]
gdf_append = gp.GeoDataFrame(geometry=points_append, crs="EPSG:4326")

write_dataframe(
gdf_append,
output_path,
layer="tmp_layer",
driver="KML",
use_arrow=use_arrow,
append=True,
)
# force_2d used to only compare xy geometry as z-dimension is undesirably
# introduced when the kml file is over-written.
gdf_in_appended = read_dataframe(output_path, use_arrow=use_arrow, force_2d=True)
nicholas-ys-tan marked this conversation as resolved.
Show resolved Hide resolved

assert np.array_equal(gdf_in_appended.geometry.values, points + points_append)


@pytest.mark.requires_arrow_write_api
def test_write_geojson_rfc7946_coordinates(tmp_path, use_arrow):
points = [Point(10, 20), Point(30, 40), Point(50, 60)]
gdf = gp.GeoDataFrame(geometry=points, crs="EPSG:4326")
output_path = tmp_path / "test.geojson"
write_dataframe(
gdf,
output_path,
layer="tmp_layer",
driver="GeoJSON",
RFC7946=True,
use_arrow=use_arrow,
)

gdf_in = read_dataframe(output_path, use_arrow=use_arrow)

assert np.array_equal(gdf_in.geometry.values, points)

# test appending to the existing file

points_append = [Point(70, 80), Point(90, 100), Point(110, 120)]
gdf_append = gp.GeoDataFrame(geometry=points_append, crs="EPSG:4326")

write_dataframe(
gdf_append,
output_path,
layer="tmp_layer",
driver="GeoJSON",
RFC7946=True,
use_arrow=use_arrow,
append=True,
)

gdf_in_appended = read_dataframe(output_path, use_arrow=use_arrow)
assert np.array_equal(gdf_in_appended.geometry.values, points + points_append)
Loading