8

I realized that the order of my geopandas dataframe is wrong, it has y, x instead of x, y.

This makes it difficult to use with other modules that needs exactly x, y type of coordinates. Is there any function in geopandas to interchange the coordinates without the need to enter in each geometry element, geometry type and change coordinates one by one? If not is there a shapely function to do it similarly instead of collecting all points one by one and change them?

More info: I have a geodataframe composed of a lineStrings (shapely object) in the geometry field for each row. If it's easier to do it in QGIS, I could also do it there.

1
  • 2
    Where did you get your original dataframe? I would switch the coordinates as early in the workflow as possible, i.e. before you create a geodataframe.
    – Jon
    Commented Jul 31, 2018 at 18:39

5 Answers 5

12

shapely.ops.transform module allows passing a function to operate on coordinates. Therefore if you want to swap x, y coordinates in a GeoDataFrame you can use :

import shapely

gdf.geometry.map(lambda polygon: shapely.ops.transform(lambda x, y: (y, x), polygon))

To account for 3D geometries (or as in my case, a mix of 2D and 3D), add the optional z=None parameter this way:

gdf.geometry.map(lambda myGeom: shapely.ops.transform(lambda x, y, z=None: (y, x, z), myGeom))

BTW, this should work for all kinds of geometries (lines, points, polygons)

6

To swap (x,y) for any Shapely geometry type, here is a general function. It also preserves z coordinates (if present):

def swap_xy(geom):
    if geom.is_empty:
        return geom

    if geom.has_z:
        def swap_xy_coords(coords):
            for x, y, z in coords:
                yield (y, x, z)
    else:
        def swap_xy_coords(coords):
            for x, y in coords:
                yield (y, x)

    # Process coordinates from each supported geometry type
    if geom.type in ('Point', 'LineString', 'LinearRing'):
        return type(geom)(list(swap_xy_coords(geom.coords)))
    elif geom.type == 'Polygon':
        ring = geom.exterior
        shell = type(ring)(list(swap_xy_coords(ring.coords)))
        holes = list(geom.interiors)
        for pos, ring in enumerate(holes):
            holes[pos] = type(ring)(list(swap_xy_coords(ring.coords)))
        return type(geom)(shell, holes)
    elif geom.type.startswith('Multi') or geom.type == 'GeometryCollection':
        # Recursive call
        return type(geom)([swap_xy(part) for part in geom.geoms])
    else:
        raise ValueError('Type %r not recognized' % geom.type)

For example:

from shapely.geometry import Point, Polygon, MultiPoint, MultiLineString

# POINT Z (1 2 3) -> POINT Z (2 1 3)
swap_xy(Point(1, 2, 3))

# MULTILINESTRING ((1 2, 3 4)) -> MULTILINESTRING ((2 1, 4 3))
swap_xy(MultiLineString([[(1, 2), (3, 4)]]))

# Map the function to a geopandas geometry column
table.geometry = table.geometry.map(swap_xy)
1
  • 2
    While this is done well, it's probably safer / quicker / more general to use the shapely.ops.transform function as in the answer by MCMZL.
    – Gijs
    Commented Aug 8, 2019 at 9:37
4

It's easier to interchange coordinates by means of Swap XY plugin in QGIS. Just select the layer and click the button.

enter image description here

Changes are carried out in place so that you may need to backup.

4

QGIS 3.2 has a native "Swap X and Y coordinates" algorithm in the Processing Toolbox. This may come in handy if you need a GUI solution which works with all geometry types.

4
from shapely.geometry import Point, LineString
import geopandas

def swap(x):
    coords = list(x.coords)
    coords = [Point(t[1], t[0]) for t in coords] #Swap each coordinate using list comprehension and create Points
    return LineString(coords)

df.geometry = df.geometry.map(swap) #Apply the function to the geometry of dataframe df

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.