xnx
xnx

Reputation: 25478

Set centre of geopandas map

I can plot a world map with geopandas with:

world = geopandas.read_file(geopandas.datasets.get_path('naturalearth_lowres'))
fig, ax = plt.subplots()
world.plot(ax=ax, color=(0.8,0.5,0.5))

and it works fine, but I would like to center the map on a different longitude than the Prime Meridian. How do I do this?

Upvotes: 1

Views: 1517

Answers (3)

Florian Neukirchen
Florian Neukirchen

Reputation: 1

With Shapely >= 2.0 the answer of J. P. has to be adapted: you'll have to replace list(element) with list(element.geoms):

from shapely.geometry import LineString
from shapely.ops import split
from shapely.affinity import translate
from shapely.geometry import GeometryCollection

def shift_map(mymap, shift):
    shift -= 180
    moved_map = []
    splitted_map = []
    border = LineString([(shift,90),(shift,-90)])
    for row in mymap["geometry"]:
        splitted_map.append(split(row, border))
    for element in splitted_map:
        items = list(element.geoms)
        for item in items:
            minx, miny, maxx, maxy = item.bounds
            if minx >= shift:
                moved_map.append(translate(item, xoff=-180-shift))
            else:
                moved_map.append(translate(item, xoff=180-shift))
    mymap = gpd.GeoDataFrame({"geometry":moved_map})
    return mymap

Upvotes: 0

Russell Jarvis
Russell Jarvis

Reputation: 91

enter image description hereLike in this question I needed to reset the centre of the map, but I also needed to move scatter plot network node positions that where bound to (long,lat) coordinates too. I am hoping to save someone some time, as it's probably not obvious initially that to solve this problem you will have to wrangle some unfamiliar types.

Here is a method for shifting both the underlying map and some additional points:

import geopandas
world = 
    geopandas.read_file(geopandas.datasets.get_path('naturalearth_lowres'))
import matplotlib.pyplot as plt
import geopandas as gpd
from shapely.geometry import LineString
from shapely.ops import split
from shapely.affinity import translate

def shift_geom(shift, gdataframe,pos_all, plotQ=True):
    # this code is adapted from answer found in SO
    # will be credited here: ???
    shift -= 180
    moved_geom = []
    splitted_geom = []
    border = LineString([(shift,90),(shift,-90)])

    for row in gdataframe["geometry"]:
        splitted_geom.append(split(row, border))
    for element in splitted_geom:
        items = list(element)
        for item in items:
            minx, miny, maxx, maxy = item.bounds
            if minx >= shift:
                moved_geom.append(translate(item, xoff=-180-shift))
            else:
                moved_geom.append(translate(item, xoff=180-shift))

    # got `moved_geom` as the moved geometry            
    moved_geom_gdf = gpd.GeoDataFrame({"geometry": moved_geom})

    # can change crs here
    if plotQ:
        fig1, ax1 = plt.subplots(figsize=[8,6])
        moved_geom_gdf.plot(ax=ax1)
        plt.show()
        
    df = pd.DataFrame({'Latitude': [xy[1] for xy in pos_all.values()],
    'Longitude': [xy[0] for xy in pos_all.values()]})
    gdf = geopandas.GeoDataFrame(df, geometry=geopandas.points_from_xy(df.Longitude, df.Latitude))
    border2 = LineString([(shift,90),(shift,-90)])
    geom = gdf.geometry.values    
    moved_map_points = []
    moved_map_dict = {}

    for element,key in zip(geom,list(pos_all.keys())):
        if float(element.x) >= shift:        
            moved_map_points.append(translate(element, xoff=-180-shift))
        else:
            moved_map_points.append(translate(element, xoff=180-shift))
        moved_map_dict[key] = (moved_map_points[-1].x,moved_map_points[-1].y)

    return moved_geom_gdf,moved_map_dict

In this context pos_all are networkx node positions made of [(lat,long)]

shifted_world,moved_map_points = shift_geom(300, world,pos_all,plotQ= False)

Upvotes: 0

J. P.
J. P.

Reputation: 306

This is how you can do it:

from shapely.geometry import LineString
from shapely.ops import split
from shapely.affinity import translate
import geopandas

world = geopandas.read_file(geopandas.datasets.get_path('naturalearth_lowres'))

def shift_map(shift):
    shift -= 180
    moved_map = []
    splitted_map = []
    border = LineString([(shift,90),(shift,-90)])
    for row in world["geometry"]:
        splitted_map.append(split(row, border))
    for element in splitted_map:
        items = list(element)
        for item in items:
            minx, miny, maxx, maxy = item.bounds
            if minx >= shift:
                moved_map.append(translate(item, xoff=-180-shift))
            else:
                moved_map.append(translate(item, xoff=180-shift))
    gdf = geopandas.GeoDataFrame({"geometry":moved_map})
    fig, ax = plt.subplots()
    gdf.plot(ax=ax)
    plt.show()
   

In the first step, you create your world and split it on a pre defined border of yours. Then you get the bounds of all elements and check if the bounds match your desired shift. Afterwards you translate every element bigger than your border to the left side of the map and move all other elements to the right side, so that they aling with +180°.

This gives you for example: Shifted map by 120°

A map shifted by 120°

Upvotes: 1

Related Questions