Мне нужно построить квадратную карту, используя Cartopy. В настоящее время я использую следующий код для своей карты:
plt.figure(figsize = (15, 15))
img = cimgt.GoogleTiles()
ax = plt.axes(projection = img.crs)
ax.set_extent((d['longitude'].min() - 0.05, d['longitude'].max() + 0.05,
d['latitude'].min() - 0.05, d['latitude'].max() + 0.05))
ax.add_image(img, 10, interpolation = 'bicubic')
plt.scatter(d['longitude'], d['latitude'], transform = ccrs.PlateCarree(),
c = '#E8175D', s = 14)
Это прекрасно работает, за исключением того, что карта не квадратная. Вместо этого он просто вписывается в квадрат (15, 15)
участка.
Я хотел бы добавить немного больше карты влево и вправо, чтобы сделать график идеально квадратным, не искажая его. Простое определение масштаба с той же разницей по широте и долготе не выполняет эту работу, потому что широта и долгота охватывают разные расстояния в прогнозах карты Google (и большинства других). Я также нашел этот пост, но из того, что я получаю, намерение здесь состоит в том, чтобы исказить карту.
Надеюсь, у кого-то есть идея, как это сделать. Кажется, что Cartopy не очень интуитивен в этом отношении.
Чтобы получить квадратную величину, вам нужно указать ее в координатах проекции карты. Это связано с некоторыми преобразованиями координат. Вот фрагмент кода, который вам нужен.
# crs of your choice
crg = cimgt.StamenTerrain().crs # or cimgt.GoogleTiles().crs
# set map limits, in degrees
lonmin, lonmax = -22, -15
latmin, latmax = 63, 65
# do coordinate transformation
LL = crg.transform_point(lonmin, latmin, ccrs.Geodetic())
UR = crg.transform_point(lonmax, latmax, ccrs.Geodetic())
EW = UR[0] - LL[0]
SN = UR[1] - LL[1]
# get side of the square extent (in map units, usually meters)
side = max(EW, SN) # larger value is in effect
mid_x, mid_y = LL[0]+EW/2.0, LL[1]+SN/2.0 # center location
# the extent preserves the center location
extent = [mid_x-side/2.0, mid_x+side/2.0, mid_y-side/2.0, mid_y+side/2.0]
# this sets square extent
# crs=crg signifies that projection coordinates is used in extent
ax.set_extent(extent, crs=crg)
Надеюсь, поможет.
редактировать
Вот полный рабочий код и его итоговая карта.
import matplotlib.pyplot as plt
import cartopy.crs as ccrs
from cartopy.mpl.gridliner import LONGITUDE_FORMATTER, LATITUDE_FORMATTER
import cartopy.io.img_tiles as cimgt
def make_map(projection=ccrs.PlateCarree()):
fig, ax = plt.subplots(figsize=(10, 10),
subplot_kw=dict(projection=projection))
gl = ax.gridlines(draw_labels=True)
gl.xlabels_top = gl.ylabels_right = False
gl.xformatter = LONGITUDE_FORMATTER
gl.yformatter = LATITUDE_FORMATTER
return fig, ax
request = cimgt.StamenTerrain() # very responsive
crg = request.crs #crs of the projection
fig, ax = make_map(projection = crg)
# specify map extent here
lonmin, lonmax = -22, -15
latmin, latmax = 63, 65
LL = crg.transform_point(lonmin, latmin, ccrs.Geodetic())
UR = crg.transform_point(lonmax, latmax, ccrs.Geodetic())
EW = UR[0] - LL[0]
SN = UR[1] - LL[1]
side = max(EW,SN)
mid_x, mid_y = LL[0]+EW/2.0, LL[1]+SN/2.0 #center location
extent = [mid_x-side/2.0, mid_x+side/2.0, mid_y-side/2.0, mid_y+side/2.0] # map coordinates, meters
ax.set_extent(extent, crs=crg)
ax.add_image(request, 8)
# add a marker at center of the map
plt.plot(mid_x, mid_y, marker='o', \
color='red', markersize=10, \
alpha=0.7, transform = crg)
plt.show()