I am attempting to edit the boundaries of a map using the EuroPP() projection in cartopy. I have written the following code, but hope to zoom in on the Scandinavia region. Any suggestions? Thanks!
import matplotlib.pyplot as plt
%matplotlib inline
import cartopy
import cartopy.crs as ccrs
import cartopy.io.img_tiles as cimgt
plt.figure(figsize=(5, 6))
ax = plt.axes(projection=ccrs.EuroPP())
ax.coastlines(resolution='50m', linewidth = 0.5)
ax.gridlines()
ax.add_feature(cartopy.feature.BORDERS, linestyle='-', alpha=.5)
ax.add_feature(cartopy.feature.OCEAN)
tile = cimgt.StamenTerrain()
ax.add_image(tile,5)
plt.show()
The code produces the following image:
You can use set_extent to "zoom" into the desired region, in your case, just create a bounding box around Scandinavia. Add the following code right before plt.show():
ax.set_extent([0, 43, 54, 75])
Output:
Related
I'm plotting an orthographic projection of the north pole next to one of the south pole. However, I want to crop the images so that I only see latitudes within maybe 10 or degrees of the poles, rather than all the way down to the equator. Here is my code so far:
# %% Import packages
import os
import matplotlib.pyplot as plt
import sys
import pandas as pd
import numpy as np
from geopack import geopack
import cartopy.crs as ccrs
import cartopy.feature as cfeature
fig = plt.figure(figsize=(20,10))
# North
ax = fig.add_subplot(1,2,1, projection=ccrs.Orthographic(central_latitude=90))
ax.stock_img()
ax.coastlines()
ax.add_feature(cfeature.BORDERS, linestyle="--")
# South
ax = fig.add_subplot(1,2,2, projection=ccrs.Orthographic(central_latitude=-90))
ax.stock_img()
ax.coastlines()
ax.add_feature(cfeature.BORDERS, linestyle="--")
plt.show()
The plot that my code currently generates
Any help would be appreciated. Thanks!
Map zooming may not be supported by the Orthographic projection in Cartopy.
I try the South[North]PolarStereo() projection, using set_extent to limit the map region, and clipping the plot by a circular path. The output figrure may meet your requirements.
Here is the code.
# %% Import packages
#import os
import matplotlib.pyplot as plt
#import sys
#import pandas as pd
import numpy as np
#from geopack import geopack
import cartopy.crs as ccrs
import cartopy.feature as cfeature
import matplotlib.path as mpath
# ref: https://scitools.org.uk/cartopy/docs/latest/gallery/lines_and_polygons/always_circular_stereo.html#sphx-glr-gallery-lines-and-polygons-always-circular-stereo-py
def add_circle_boundary(ax):
# Compute a circle in axes coordinates, which we can use as a boundary
# for the map. We can pan/zoom as much as we like - the boundary will be
# permanently circular.
theta = np.linspace(0, 2*np.pi, 100)
center, radius = [0.5, 0.5], 0.5
verts = np.vstack([np.sin(theta), np.cos(theta)]).T
circle = mpath.Path(verts * radius + center)
ax.set_boundary(circle, transform=ax.transAxes)
fig = plt.figure(figsize=(20,10))
# South
#ax = fig.add_subplot(1,2,1, projection=ccrs.Orthographic(central_latitude=90))
#ax = fig.add_subplot(1,2,1, projection=ccrs.NorthPolarStereo())
ax = fig.add_subplot(1,2,1, projection=ccrs.SouthPolarStereo())
ax.stock_img()
ax.coastlines()
ax.gridlines()
ax.set_title('Original',fontsize = 24)
#ax.add_feature(cfeature.BORDERS, linestyle="--")
ax.set_extent([-180, 180, -90, 0], crs=ccrs.PlateCarree())
add_circle_boundary(ax)
# South zoomed
ax1 = fig.add_subplot(1,2,2, projection=ccrs.SouthPolarStereo())
ax1.stock_img()
ax1.coastlines()
ax1.gridlines()
#ax1.add_feature(cfeature.BORDERS, linestyle="--")
ax1.set_extent([-180, 180, -90, -60], crs=ccrs.PlateCarree())
ax1.set_title('Zoomed',fontsize = 24)
add_circle_boundary(ax1)
#plt.show()
plt.savefig("out.png")
I'm trying to figure out how to generate a map that crosses the dateline with Cartopy and a terrain from img_tiles. Here is what I have so far:
import cartopy.crs as ccrs
import matplotlib.pyplot as plt
import cartopy.feature as cfeature
import cartopy.io.img_tiles as cimgt
import shapely.geometry as sgeom
my_dpi = 96
plt.figure(figsize=(1530/my_dpi, 900/my_dpi), dpi=my_dpi, frameon=False)
plt.subplots_adjust(left=0.0, right=1.0, top=1.0, bottom=0)
ax = plt.axes(projection=ccrs.Mercator(central_longitude=180))
terrain = cimgt.Stamen('terrain-background')
ax.add_image(terrain, 4)
states = cfeature.NaturalEarthFeature('cultural', 'admin_1_states_provinces', '10m', edgecolor='darkblue',facecolor='none')
ax.add_feature(states, linewidth = 0.1, linestyle='-')
# draw box
box = sgeom.box(minx=69, maxx=210, miny=-57, maxy=13.5)
ax.add_geometries([box], ccrs.PlateCarree(), facecolor='coral',
edgecolor='black', alpha=0.5)
# Set extent
ax.set_extent(oceania_coords, crs=ccrs.PlateCarree())
plt.show()
When I draw a box around the region I want to zoom in on, it looks correct.
When I try to ax.set_extent on this range, it seems to set all of the cfeatures correctly but screws up with the img_tiles features.
Is there any way to work around this? Thanks for the help!
I have a solution that is good enough for me, by abutting two subplots with the appropriate ratios and borders turned off. There is a tiny artifact on the seam, but I'm mostly slicing ocean in this frame so I'm ok with it. When I have Russia in the frame, it's more obvious.
import cartopy.crs as ccrs
import matplotlib.pyplot as plt
import cartopy.feature as cfeature
import cartopy.io.img_tiles as cimgt
import shapely.geometry as sgeom
import matplotlib.gridspec as gridspec
my_dpi=96
f = plt.figure(figsize=(1530/my_dpi, 900/my_dpi), dpi=my_dpi, frameon=False)
spec = gridspec.GridSpec(ncols=2, nrows=1,width_ratios=[111,30])
plt.subplots_adjust(left=0.0, right=1.0, top=1.0, bottom=0)
ax1 = f.add_subplot(spec[0],projection=ccrs.Mercator(central_longitude=180))
terrain = cimgt.Stamen('terrain-background')
ax1.add_image(terrain, 3)
states = cfeature.NaturalEarthFeature('cultural', 'admin_1_states_provinces', '10m', edgecolor='darkblue',facecolor='none')
ax1.add_feature(states, linewidth = 0.1, linestyle='-')
ax1.set_extent([69, 180, -57, 13.5], crs=ccrs.PlateCarree())
plt.gca().outline_patch.set_visible(False)
ax2 = f.add_subplot(spec[1],projection=ccrs.Mercator(central_longitude=180))
ax2.add_image(terrain, 3)
ax2.add_feature(states, linewidth = 0.1, linestyle='-')
ax2.set_extent([-180,-150, -57, 13.5], crs=ccrs.PlateCarree())
plt.gca().outline_patch.set_visible(False)
plt.subplots_adjust(wspace=0)
I am trying to make map lines always on top of data, but cannot find the right command/options to do so in cartopy. In the plot below, I want the thick blue line "under" the black state lines but on top of the beige states.
Code:
import matplotlib.pyplot as plt
import numpy as np
import cartopy.crs as ccrs
import cartopy.feature as cfeature
import os,sys
conus_proj = ccrs.LambertConformal(central_longitude=-96,central_latitude=39.0)
fig = plt.figure(figsize=(10,8))
ax = fig.add_subplot(1,1,1,projection=conus_proj)
ax.set_extent([-120,-70,22,50])
#ax.add_feature(cfeature.BORDERS)
ax.add_feature(cfeature.COASTLINE)
ax.add_feature(cfeature.OCEAN, facecolor='#CCFEFF')
ax.add_feature(cfeature.LAKES, facecolor='#CCFEFF')
ax.add_feature(cfeature.RIVERS, facecolor='#CCFEFF')
ax.add_feature(cfeature.LAND, facecolor='#FFE9B5')
state_borders = cfeature.NaturalEarthFeature(category='cultural', name='admin_1_states_provinces_lakes', scale='50m', facecolor='#FFE9B5')
ax.add_feature(state_borders, edgecolor='black')
plt.plot([-120,-70],[35,45],linewidth=8, transform=ccrs.PlateCarree())
plt.show()
I have tried changing the zorder of ax.add_feature(state_borders...) and plt.plot(...) but have received weird results. The state borders are on top by default with pcolormesh, but don't appear to be so with plt.plot
Here is the output of the above code:
The reason things turn out differently for pcolormesh vs. plot is that those have different default zorders. If I set the zorder for the state borders (note below that I use Cartopy's built-in support for states) to 10, I get them to appear on top of the plot:
import matplotlib.pyplot as plt
import numpy as np
import cartopy.crs as ccrs
import cartopy.feature as cfeature
import os,sys
conus_proj = ccrs.LambertConformal(central_longitude=-96,central_latitude=39.0)
fig = plt.figure(figsize=(10,8))
ax = fig.add_subplot(1,1,1,projection=conus_proj)
ax.set_extent([-120,-70,22,50])
ax.add_feature(cfeature.COASTLINE)
ax.add_feature(cfeature.OCEAN, facecolor='#CCFEFF')
ax.add_feature(cfeature.LAKES, facecolor='#CCFEFF')
ax.add_feature(cfeature.RIVERS, edgecolor='#CCFEFF')
ax.add_feature(cfeature.LAND, facecolor='#FFE9B5')
ax.add_feature(cfeature.STATES, edgecolor='black', zorder=10)
plt.plot([-120,-70],[35,45],linewidth=8, transform=ccrs.PlateCarree())
plt.show()
I also had to remove the face colors on some of the features.
I have need to plot point on the map, produce PNG image on that map and, output display coordinated of the plotted point.
Using cartopy I could get the map I wanted and plot a point in given lon/lat coordinates.
I cannot figure out how to get the pixel coordinates out. I tried to follow simple matplotlib tutorial https://matplotlib.org/users/transforms_tutorial.html But it does not work as expected in this situation
import cartopy.crs as ccrs
import cartopy.feature as cfeature
import matplotlib.pyplot as plt
# Create Mercator projection with dateline in the middle:
from matplotlib import lines
fig = plt.figure(figsize=(10, 10))
ax = plt.axes(projection=ccrs.Mercator(central_longitude=26,))
ax.set_extent([19, 33, 59.5, 70.5], crs=ccrs.PlateCarree())
LAND = cfeature.NaturalEarthFeature('physical', 'land', '50m',
edgecolor='face',
facecolor=cfeature.COLORS['land'], zorder=-1)
ax.add_feature(LAND)
ax.coastlines(resolution='50m')
ax.add_feature(cfeature.NaturalEarthFeature('cultural', 'admin_0_boundary_lines_land',
'50m', edgecolor='black', facecolor='none'))
plt.plot([26.7042], [60.8679], color='blue', linewidth=2, marker='o',
transform=ccrs.PlateCarree(),
)
fig.canvas.draw()
# print image x y coordinates of point 60.8679° N, 26.7042° E here
plt.show()
The texts on the right on this pyplot graph are clipped, how can I expand the plot area without changing the x-axis?
Minimal example code (similar to but not identical to example image)
import numpy as np
import matplotlib.pyplot as plt
import matplotlib as mp
n40=146-1.07*40
n90=146-1.07*90
ageAxis =np.array([10, 40, 90])
Normal=np.array([n40, n40, n90])
plt.plot(ageAxis,Normal)
plt.text(90.2,50,'long text here that will be clipped')
ax = plt.gca()
ax.set_ylim([0,165])
ax.set_xlim([0,90])
fig= plt.gcf()
# set size fig.set_size_inches(20, 10.5)
plt.show()
It seems that it can be done with a combination of set_size_inches and subplots_adjust
Not elegant, I think, but it works:
import numpy as np
import matplotlib.pyplot as plt
import matplotlib as mp
n40=146-1.07*40
n90=146-1.07*90
ageAxis =np.array([10, 40, 90])
Normal=np.array([n40, n40, n90])
plt.plot(ageAxis,Normal)
plt.text(90.2,50,'long text here that will be clipped')
ax = plt.gca()
ax.set_ylim([0,165])
ax.set_xlim([0,90])
fig= plt.gcf()
fig.set_size_inches(10, 5.5) # set a suitable size
plt.subplots_adjust(right=0.75) # adjust plot area
plt.show()