Skip to content

Default values of area and projection for MapPanel objects are undocumented #4161

Open

Description

@sgdecker

What went wrong?

With the code below, I'm expecting to get a map showing the entire model grid, no more, no less. However, the map extends too far to the east and south:
Image

Is this a bug, or user error?

Operating System

Linux

Version

1.7.1

Python Version

3.13.16

Code to Reproduce

from datetime import datetime, timedelta
import pickle
import xarray as xr
import cartopy.crs as ccrs
from metpy.units import units
import metpy.calc as mpcalc
from metpy.plots import ContourPlot, FilledContourPlot, BarbPlot, MapPanel, PanelContainer

with open('isen_data.pkl', 'rb') as f:
    nam_isen = pickle.load(f)

nam_isen = nam_isen.metpy.assign_latitude_longitude()
proj = ccrs.LambertConformal(central_longitude=-95.0, central_latitude=25.0,
                             standard_parallels=(25, 25))

x0 = float(nam_isen.longitude[0,0].values)
x1 = float(nam_isen.longitude[-1,-1].values)
y0 = float(nam_isen.latitude[0,0].values)
y1 = float(nam_isen.latitude[-1,-1].values)

cp = ContourPlot()
cp.data = nam_isen
cp.field = 'pressure'
cp.contours = range(50, 1050, 50)
cp.linecolor = 'darkblue'
cp.clabels = True

barbs = BarbPlot()
barbs.data = nam_isen
barbs.field = ('ugrd', 'vgrd')
barbs.skip = (5, 4)

fcp = FilledContourPlot()
fcp.data = nam_isen
fcp.field = 'spfh'
fcp.plot_units = 'g/kg'
fcp.contours = range(1,10)
fcp.colormap = 'Greens'
fcp.colorbar = 'horizontal'

mp = MapPanel()
mp.area = [x0, x1, y0, y1]
mp.projection = proj
mp.layers = ['coastline', 'borders', 'states']
mp.plots = [fcp, cp, barbs]

pc = PanelContainer()
pc.size = (10,8)
pc.panels = [mp]
pc.show()

Errors, Traceback, and Logs

Activity

  1. dopplershift commented on Oct 17, 2026

    @dopplershift
    Member

    I'm not sure how to classify it, but it is expected behavior with Cartopy (which is used under the hood). The problem is that the extent that is set needs to be translated rectangle (x range and y range) in the plotted (projected) coordinate system. When you give it an extent in lat/lon, it's going to convert it to a rectangle with 4 points. This geometry is then projected to the destination projection; in this case the destination is Lambert Conformal (conic), so the rectangle becomes a curved conic section like:

    Image

    To turn this back into plot limits, the bounding box of this shape is taken (in projected coordinates). Essentially the problem is that once you're in projected coordinates, the e.g. right side of the plot is not defined by a single longitude value. That leaves you with the option of having a plot too big (which is what Cartopy does by default), or having a plot too small and clipping data.

  2. sgdecker commented on Oct 19, 2026

    @sgdecker
    ContributorAuthor

    Your figure nicely shows why it's the southern and eastern sides that are too large (and also indicates I've lost a few of the northern rows from the grid in my plot).

    In this case, I have intentionally set my map projection to match the projection of the grid, so it should be possible in principle to get a map that covers the grid precisely, no more, no less. I'm essentially trying to do what GEMPAK does with GAREA=GRID. However, it looks like I have to solve an inverse problem of sorts (I think I need to determine the lat/lon pairs for the red corners such that the green corners calculated by CartoPy match the corners I really want, i.e., the corners of the actual grid), so I'll do some playing around with using Cartopy/Matplotlib directly to generate the plot, and if I see a reasonable way forward, I'll see if I can come up with a feature/pull request to implement this GAREA=GRID-like functionality in MetPy.

  3. sgdecker commented on Oct 22, 2026

    @sgdecker
    ContributorAuthor

    D'oh! I get the plot I want simply by not specifying area and projection at all. The default values for these two traits are what I want. However, the defaults do not appear to be documented, so I am changing this issue to a request for improved docstrings.

  4. changed the title [-]Specifying grid corners for MapPanel area produces larger map than expected[/-] [+]Default values of area and projection for MapPanel objects are undocumented[/+] on Oct 22, 2026
  5. sgdecker commented on Nov 4, 2026

    @sgdecker
    ContributorAuthor

    Actually, based on #4192 it seems there might be some missing functionality here. Namely, there doesn't seem to be a way to force the map to match the grid exactly, like GAREA = grid does in GEMPAK. Thus, this issue has now evolved into a feature request to make such a MapPanel.area specification possible.

    I think this can be achieved with another elif around here, where in the new block the set_extent call would use the min and max map coordinates rather than geographic coords (and the reference to the PlateCarree CRS would be omitted), but I need to test this, for instance with the #4192 test case!

  6. dcamron commented on Nov 10, 2026

    @dcamron
    Member

    I've been playing around with this this week, and will put something together here. The main behavior decision in front of me: let's say in your example, your barb plot and your contours come from different grids. How does MapPanel.area = 'grid' behave?

    For comparison: currently MapPanel.projection = 'data' (the default) just looks at the first plot in the list and uses its CRS (if it exists.) I'm gonna clean that up a bit to at least search for a valid CRS among all plots.

    We could force some math to calculate an overlap or take any one (first, largest, whatever) grid of the bunch. Thoughts?

  7. sgdecker commented on Nov 10, 2026

    @sgdecker
    ContributorAuthor

    The main behavior decision in front of me: let's say in your example, your barb plot and your contours come from different grids. How does MapPanel.area = 'grid' behave?

    That's a good question! I don't have a strong opinion, but I favor something explicit rather than an automatic choice like first or largest, so I'd go with:

    1. It is an error to use MapPanel.area = 'grid' when not all of the grids on the MapPanel are the same, or
    2. Same as (1), but also allow MapPanel.area = (plotting object) where the plotting object is a specific instance of ContourPlot, etc., and it is that grid that is used to specify the area.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type: BugSomething is not working like it should

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions