3

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
    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 Jul 31 '18 at 18:39
4

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
    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 Aug 8 '19 at 9:37
3
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
3

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))
2

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.

2

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.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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