Map to fit postersize using Cartopy

46 views Asked by At

My goal is to create a poster with a map of travel routs.

You should be able to set the poster size, i.e figure size.

Then you provide a list of long/lat points. Whether or not the poster should be horizontal or vertical should be up to the script, i.e what fits the lat/long provided.

It should then return the poster as a pdf, zoomed in on the relevant part of the map, while still filling the entire canvas. It’s been the last part I have struggled with for days. I guess the extend of the entire map needs to be changed to fit with the ratio of the poster size, but I haven’t been able to do so. Any suggestions would be much obliged ! PS. Im aware of (bbox_inches='tight'), but it ruins the total poster size.

Example script:

import matplotlib.pyplot as plt
import cartopy.crs as ccrs
import numpy as np

# Define the geographic locations (longitude, latitude)
points = np.array([
    (18.4241, -33.9249),
    (9.5375, 33.8869),  
    (-16.3151, 28.4682),
    (-9.1393, 38.7223),
    (-3.7038, 40.4168),
    (2.3522, 48.8566),
    (10.7522, 59.9139),
])

# Create figure and add a map in Mercator projection
fig, ax = plt.subplots(figsize=(10, 10), subplot_kw={'projection': ccrs.Mercator()})

# Calculate bounds
lon_min, lat_min = points.min(axis=0) - 1
lon_max, lat_max = points.max(axis=0) + 1

# Set extent based on points
ax.set_extent([lon_min, lon_max, lat_min, lat_max], crs=ccrs.PlateCarree())

# Plot points
ax.scatter(points[:, 0], points[:, 1], marker='o', color='red', transform=ccrs.Geodetic())

# Add coastlines for reference
ax.coastlines()

# Save the plot as a PDF
plt.savefig("map.pdf")
1

There are 1 answers

1
RuthC On BEST ANSWER

You can use constrained layout to make an axes fill the figure, and set_adjustable to make the data limits update so that the map is the right shape for the expanded axes:

import matplotlib.pyplot as plt
import cartopy.crs as ccrs
import numpy as np

# Define the geographic locations (longitude, latitude)
points = np.array([
    (18.4241, -33.9249),
    (9.5375, 33.8869),  
    (-16.3151, 28.4682),
    (-9.1393, 38.7223),
    (-3.7038, 40.4168),
    (2.3522, 48.8566),
    (10.7522, 59.9139),
])

# Create figure and add a map in Mercator projection
fig, ax = plt.subplots(figsize=(10, 10), subplot_kw={'projection': ccrs.Mercator()},
                       layout='constrained')

# Calculate bounds
lon_min, lat_min = points.min(axis=0) - 1
lon_max, lat_max = points.max(axis=0) + 1

# Set extent based on points
ax.set_extent([lon_min, lon_max, lat_min, lat_max], crs=ccrs.PlateCarree())

# Adjust the data limits so that the map fills the figure without stretching
ax.set_adjustable(adjustable='datalim')

# Plot points
ax.scatter(points[:, 0], points[:, 1], marker='o', color='red', transform=ccrs.Geodetic())

# Add coastlines for reference
ax.coastlines()

# Save the plot as a png (for StackOverflow example)
plt.savefig("map.png")

enter image description here