Cartopy v0.18.0墨卡托投影下基于GoogleTiles绘制圆形的技术求助
I get it, deadlines are tight—let’s fix this quickly. The core issue here is mismatched coordinate systems and how Cartopy handles projection transforms for shapes. Here’s what’s going wrong and how to fix it:
Why Your Current Code Isn’t Working
- Using
transform=ccrs.PlateCarree(): Your circle’s radius is in degrees of latitude/longitude, but Mercator projection scales latitude distances differently than longitude (latitude degrees get stretched more near the poles). This turns your "degree-based circle" into an ellipse on the map. - Using
transform=ccrs.Mercator(): You’re passing geographic coordinates (lat/lon) to a projection that uses linear units (like meters), so the circle ends up way outside your map’s extent, hence invisible.
Quick Fix 1: Use Geodetic Transform (Best for Small Local Circles)
Since you’re working with a small area (looks like San Francisco!), using ccrs.Geodetic() as your transform will let Cartopy handle converting a geographic "great-circle" into the correct shape for the Mercator projection. Mercator is a conformal projection, so small circles will appear round on the map.
Modify your add_patch line to this:
from matplotlib.patches import Circle # You can use Circle directly instead of Patch.Circle # ... rest of your existing code ... ax.add_patch(Circle( xy=[-122.4015173428571, 37.78774634285715], radius=0.021709041989311614 + 0.005, alpha=0.3, zorder=30, transform=ccrs.Geodetic() # This is the key change! ))
Quick Fix 2: Use Projected Coordinates (For Meter-Based Radii)
If you want to define your circle in actual meters (instead of degrees), convert your geographic center to the Mercator projection’s coordinate system first, then use a meter-based radius:
import math from matplotlib.patches import Circle # ... rest of your existing code ... # Convert geographic center to Mercator projection coordinates center_proj = tiles.crs.transform_point( -122.4015173428571, 37.78774634285715, ccrs.PlateCarree() ) # Calculate meters per degree of longitude at your latitude (Mercator scales longitude uniformly) lat_rad = math.radians(37.787746) meters_per_deg_lon = 111319 * math.cos(lat_rad) # ~85390 meters/degree at 37N radius_meters = (0.021709041989311614 + 0.005) * meters_per_deg_lon # Draw the circle using projected coordinates and meter radius ax.add_patch(Circle( xy=center_proj, radius=radius_meters, alpha=0.3, zorder=30, transform=tiles.crs ))
Either of these methods will give you a perfect circle on your GoogleTiles map without distorting the underlying map tiles.
内容的提问来源于stack exchange,提问作者AxelEckenberger

