Reputation: 97
I want to plot some data in a LambertConformal projection and add labels to the axes. See the example code below. However, now the x-labels show up twice, and both times in the middle of the plot, instead of at its bottom. When instead I set gl.xlabels_bottom = False
and gl.xlabels_top = True
, no x-labels are plotted at all. With the y-labels, I do not get this problem; they are just nicely plotted either along the left or right boundary of the plot.
How can I get the x-labels at the right location (at the bottom of the figure)?
import numpy as np
import matplotlib.pyplot as plt
import cartopy.crs as ccrs
bounds_lon = [-45,-25]
bounds_lat = [55,65]
lon = np.arange(bounds_lon[0],bounds_lon[1]+0.1,0.1)
lat = np.arange(bounds_lat[0],bounds_lat[1]+0.1,0.1)
Lon, Lat = np.meshgrid(lon,lat)
data = np.ones(np.shape(Lon))
data_crs = ccrs.PlateCarree()
projection = ccrs.LambertConformal(central_longitude=np.mean(bounds_lon),central_latitude=np.mean(bounds_lat),cutoff=bounds_lat[0])
plt.figure(figsize=(4,4))
ax = plt.axes(projection=projection)
ax.coastlines()
ax.contourf(Lon, Lat, data, transform=data_crs)
gl = ax.gridlines(crs=ccrs.PlateCarree(), linewidth=2, color='gray', alpha=0.5, linestyle='--')
gl.xlabels_bottom = True
Upvotes: 1
Views: 874
Reputation: 18772
Manual repositioning of tick-labels are needed. To do that successfully, requires some other adjustments of the plot settings. Here is the code you can try.
import numpy as np
import matplotlib.pyplot as plt
import cartopy.crs as ccrs
bounds_lon = [-45,-25]
bounds_lat = [55,65]
# make-up data to plot on the map
inc = 0.5
lon = np.arange(bounds_lon[0],bounds_lon[1]+inc, inc)
lat = np.arange(bounds_lat[0],bounds_lat[1]+inc, inc)
Lon, Lat = np.meshgrid(lon,lat)
#data = np.ones(np.shape(Lon)) # original `boring` data
data = np.sin(Lon)+np.cos(Lat) # better data to use instead
data_crs = ccrs.PlateCarree()
projection = ccrs.LambertConformal(central_longitude=np.mean(bounds_lon), \
central_latitude=np.mean(bounds_lat), \
#cutoff=bounds_lat[0]
)
# Note: `cutoff` causes horizontal cut at lower edge
# init plot figure
plt.figure(figsize=(15,9))
ax = plt.axes(projection=projection)
ax.coastlines(lw=0.2)
ax.contourf(Lon, Lat, data, transform=data_crs, alpha=0.5)
# set gridlines specs
gl = ax.gridlines(crs=ccrs.PlateCarree(), linewidth=2, color='gray', alpha=0.5, linestyle='--')
gl.top_labels=True
gl.bottom_labels=True
gl.left_labels=True
gl.right_labels=True
plt.draw() #enable access to lables' positions
xs_ys = ax.get_extent() #(x0,x1, y0,y1)
#dx = xs_ys[1]-xs_ys[0]
dy = xs_ys[3]-xs_ys[2]
# The extent of `ax` must be adjusted
# Extents' below and above are increased
new_ext = [xs_ys[0], xs_ys[1], xs_ys[2]-dy/15., xs_ys[3]+dy/12.]
ax.set_extent(new_ext, crs=projection)
# find locations of the labels and reposition them as needed
xs, ys = [], []
for ix,ea in enumerate(gl.label_artists):
xy = ea[2].get_position()
xs.append(xy[0])
ys.append(xy[1])
# Targeted labels to manipulate has "W" in them
if "W" in ea[2].get_text():
x_y = ea[2].get_position()
# to check which are above/below mid latitude of the plot
# use 60 (valid only this special case)
if x_y[1]<60:
# labels at lower latitudes
curpos = ea[2].get_position()
newpos = (curpos[0], 54.7) # <- from inspection: 54.7
ea[2].set_position(newpos)
else:
curpos = ea[2].get_position()
newpos = (curpos[0], 65.3) # <- from inspection: 65.3
ea[2].set_position(newpos)
plt.show()
Edit1
If you want to move all the lat/long labels to the outside edges, try this code. It is much more concise than the above.
import numpy as np
import matplotlib.pyplot as plt
import cartopy.crs as ccrs
bounds_lon = [-45,-25]
bounds_lat = [55,65]
inc = 0.5
lon = np.arange(bounds_lon[0],bounds_lon[1]+inc, inc)
lat = np.arange(bounds_lat[0],bounds_lat[1]+inc, inc)
Lon, Lat = np.meshgrid(lon,lat)
#data = np.ones(np.shape(Lon)) # boring data
data = np.sin(Lon)+np.cos(Lat) # more interesting
data_crs = ccrs.PlateCarree()
projection = ccrs.LambertConformal(central_longitude=np.mean(bounds_lon), \
central_latitude=np.mean(bounds_lat), \
cutoff=bounds_lat[0]
)
# init plot
plt.figure(figsize=(15,9))
ax = plt.axes(projection=projection)
ax.coastlines(lw=0.2)
ax.contourf(Lon, Lat, data, transform=data_crs, alpha=0.3)
gl = ax.gridlines(draw_labels=True, x_inline=False, y_inline=False,
color='k', linestyle='dashed', linewidth=0.5)
gl.top_labels=True
gl.bottom_labels=True
gl.left_labels=True
gl.right_labels=True
plt.show()
If you want to get bottom edge as a straight line, you can achieve that by dropping the option cutoff=bounds_lat[0]
from this line of code:-
projection = ccrs.LambertConformal(central_longitude=np.mean(bounds_lon), \
central_latitude=np.mean(bounds_lat), \
cutoff=bounds_lat[0]
)
so that it becomes
projection = ccrs.LambertConformal(central_longitude=np.mean(bounds_lon),
central_latitude=np.mean(bounds_lat))
and you will get the plot like this:-
Upvotes: 1