Skip to content

Some cartopy features are missing when using set_box_aspect without set_extent #2599

@carstrb

Description

@carstrb

While I don't think this is necessarily a bug, I'm having trouble finding a simple way to enforce a matplotlib Axes box aspect ratio without losing certain cartopy features from the map, depending on what data I'm plotting. An example is below:

import cartopy.crs as ccrs
import cartopy.feature as cfeature
import matplotlib.pyplot as plot
import pandas as pd

MAP_FIXED_WIDTH = 8
MAP_FIXED_HEIGHT = 6

df = pd.DataFrame(
    {
        "timestamp": 
        [
            pd.Timestamp('2025-01-01 00:00:00 UTC'), 
            pd.Timestamp('2025-01-01 00:30:00 UTC'), 
            pd.Timestamp('2025-01-01 01:00:00 UTC'), 
            pd.Timestamp('2025-01-01 01:30:00 UTC'), 
            pd.Timestamp('2025-01-01 02:00:00 UTC'),
         ],
        "latitude": [-10, -12, -14, -16, -18],
        "longitude": [40, 50, 60, 70, 80],
    },
)

def create_map_with_scatter_points(df: pd.DataFrame) -> None:
    plot.figure(figsize=(MAP_FIXED_WIDTH, MAP_FIXED_HEIGHT))
    axes = plot.axes(
        projection=ccrs.PlateCarree(central_longitude=df["longitude"].median())
    )

    axes.set_box_aspect(MAP_FIXED_HEIGHT / MAP_FIXED_WIDTH)

    axes.scatter(df["longitude"], df["latitude"], color='green')

    axes.set_facecolor(cfeature.COLORS["water"])
    axes.add_feature(cfeature.LAND, color="lightgray")
    axes.add_feature(cfeature.LAKES)
    axes.add_feature(cfeature.RIVERS)
    axes.add_feature(cfeature.COASTLINE)
    axes.add_feature(cfeature.BORDERS, linestyle=":")

    axes.gridlines(
        draw_labels=True, linewidth=1, color="gray", alpha=0.5, linestyle="--"
    )

    plot.show()

create_map_with_scatter_points(df)

Output is as follows:

Image

From the output, you'll see that certain COASTLINE features are not being rendered. Simply setting edgecolor of LAND to "black" would resolve the missing coastlines in this case, however there are other cases where landmasses don't get rendered based on the data extent and area of the world that we're plotting. My understanding is that Cartopy is unaware that it needs to render map features outside of the explicit range of the data being plotted.

I'm aware that axes.set_box_aspect() only controls the physical dimensions of the Axes box, not the limits of data being displayed. I've also tried using axes.set_aspect(adjustable='datalim'), though it comes with the caveat that set_adjustable method "may ignore explicitly defined axis limits" (link)

I'm explicitly trying to avoid having to set Axes extent manually, as the logic required for choosing the correct central longitude for the map when data crosses the 180th meridian is very cumbersome.

It would be great if there was an easier way to adjust the data limits based on the aspect ratio set with set_box_aspect(). Has anyone run into this quirk before and found a workaround?

Dependency versions:

matplotlib==3.10.7
pandas==2.3.3
cartopy==0.25.0

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions