python利用cartopy绘制带有经纬度的地图

参考:
https://makersportal.com/blog/2020/4/24/geographic-visualizations-in-python-with-cartopy

https://scitools.org.uk/cartopy/docs/latest/

https://stackoverflow.com/questions/69465435/cartopy-show-tick-marks-of-axes
1、python利用cartopy绘制带有经纬度的地图
具体实现方式:

import csv
import numpy as np
import cartopy.crs as ccrs
import matplotlib.pyplot as plt
import cartopy.io.img_tiles as cimgt
from cartopy.mpl.ticker import LongitudeFormatter, LatitudeFormatter
import io
from urllib.request import urlopen, Request
from PIL import Image

def image_spoof(self, tile): # this function pretends not to be a Python script
    url = self._image_url(tile) # get the url of the street map API
    req = Request(url) # start request
    req.add_header('User-agent','Anaconda 3') # add user agent to request
    fh = urlopen(req) 
    im_data = io.BytesIO(fh.read()) # get image
    fh.close() # close url
    img = Image.open(im_data) # open image with PIL
    img = img.convert(self.desired_tile_form) # set image format
    return img, self.tileextent(tile), 'lower' # reformat for cartopy

################################
# parsing the ASOS coordinates
################################
#
asos_data = []
with open('asos-stations.txt','r') as dat_file:
    reader = csv.reader(dat_file)
    for row in reader:
        asos_data.append(row)

row_delin = asos_data[3][0].split(' ')[:-1]
col_sizes = [len(ii) for ii in row_delin]

col_header = []; iter_ii = 0
for ii,jj in enumerate(col_sizes):
    col_header.append(asos_data[2][0][iter_ii:iter_ii+col_sizes[ii]].replace(' ',''))
    iter_ii+=col_sizes[ii]+1
    
call,names,lats,lons,elevs = [],[],[],[],[]
for row in asos_data[4:]:
    data = []; iter_cc = 0
    for cc in range(0,len(col_header)):
        data.append(row[0][iter_cc:iter_cc+col_sizes[cc]].replace('  ',''))
        iter_cc+=col_sizes[cc]+1
    call.append(data[3])
    names.append(data[4])
    lats.append(float(data[9]))
    lons.append(float(data[10]))
    elevs.append(float(data[11]))

#######################################
# Formatting the Cartopy plot
#######################################
#
cimgt.Stamen.get_image = image_spoof # reformat web request for street map spoofing
osm_img = cimgt.Stamen('terrain-background') # spoofed, downloaded street map

fig = plt.figure(figsize=(12,9)) # open matplotlib figure
ax1 = plt.axes(projection=osm_img.crs) # project using coordinate reference system (CRS) of street map
ax1.set_title('ASOS Station Map',fontsize=16)
extent = [-124.7844079,-66.9513812, 24.7433195, 49.3457868] # Contiguous US bounds
# extent = [-74.257159,-73.699215,40.495992,40.915568] # NYC bounds
ax1.set_extent(extent) # set extents
ax1.set_xticks(np.linspace(extent[0],extent[1],7),crs=ccrs.PlateCarree()) # set longitude indicators
ax1.set_yticks(np.linspace(extent[2],extent[3],7)[1:],crs=ccrs.PlateCarree()) # set latitude indicators
lon_formatter = LongitudeFormatter(number_format='0.1f',degree_symbol='',dateline_direction_label=True) # format lons
lat_formatter = LatitudeFormatter(number_format='0.1f',degree_symbol='') # format lats
ax1.xaxis.set_major_formatter(lon_formatter) # set lons
ax1.yaxis.set_major_formatter(lat_formatter) # set lats
ax1.xaxis.set_tick_params(labelsize=14)
ax1.yaxis.set_tick_params(labelsize=14)

scale = np.ceil(-np.sqrt(2)*np.log(np.divide((extent[1]-extent[0])/2.0,350.0))) # empirical solve for scale based on zoom
scale = (scale<20) and scale or 19 # scale cannot be larger than 19
ax1.add_image(osm_img, int(scale)) # add OSM with zoom specification

#######################################
# Plot the ASOS stations as points
#######################################
#
ax1.plot(lons, lats, markersize=5,marker='o',linestyle='',color='#3b3b3b',transform=ccrs.PlateCarree())

plt.show()

代码来源:https://makersportal.com/blog/2020/4/24/geographic-visualizations-in-python-with-cartopy

属性设置:
(1)自定义显示经纬度label:ax1.set_xticks([100,110,120], crs=ccrs.PlateCarree()) ax1.set_yticks([20, 25,30,35, 40,45], crs=ccrs.PlateCarree())
(2)经纬度label保留整数,并显示小圆圈:lon_formatter = LongitudeFormatter(number_format='0.0f',degree_symbol='°',dateline_direction_label=True) # format lons lat_formatter = LatitudeFormatter(number_format='0.0f',degree_symbol='°') # format lats
显示效果:
在这里插入图片描述
(3)显示副刻度尺:ax.set_xticks(np.arange(-180, 180 + 30, 30), minor=True, crs=tick_proj)

完整代码:

import matplotlib.pyplot as plt
import cartopy.crs as ccrs

from cartopy.mpl.ticker import (LongitudeFormatter, LatitudeFormatter,
                                LatitudeLocator, LongitudeLocator)

fig, ax = plt.subplots(figsize=(10, 5), subplot_kw={"projection":ccrs.PlateCarree()})

ax.coastlines()

ax.yaxis.tick_right()
ax.set_xticks([-180,-120, -60, 0, 60, 120, 180], crs=ccrs.PlateCarree())
ax.set_yticks([-90, -60, -30, 0, 30, 60, 90], crs=ccrs.PlateCarree())
lon_formatter = LongitudeFormatter(zero_direction_label=True)
lat_formatter = LatitudeFormatter()
ax.xaxis.set_major_formatter(lon_formatter)
ax.yaxis.set_major_formatter(lat_formatter)

gl = ax.gridlines(crs=ccrs.PlateCarree(), draw_labels=False,
                  linewidth=2, color='gray', alpha=0.5, linestyle='--')

代码来源:https://stackoverflow.com/questions/69465435/cartopy-show-tick-marks-of-axes
显示结果:
在这里插入图片描述
设置刻度尺关键代码:

from cartopy.mpl.ticker import LongitudeFormatter, LatitudeFormatter
# 设置大刻度和小刻度
tick_proj = ccrs.PlateCarree()
ax.set_xticks(np.arange(-180, 180 + 60, 60), crs=tick_proj)
ax.set_xticks(np.arange(-180, 180 + 30, 30), minor=True, crs=tick_proj)
ax.set_yticks(np.arange(-90, 90 + 30, 30), crs=tick_proj)
ax.set_yticks(np.arange(-90, 90 + 15, 15), minor=True, crs=tick_proj)

# 利用Formatter格式化刻度标签
ax.xaxis.set_major_formatter(LongitudeFormatter())
ax.yaxis.set_major_formatter(LatitudeFormatter())

结果:
在这里插入图片描述
(4)隐藏label,只显示刻度线

# Hide the lat tick labels
for label in ax2.get_yticklabels():
    label.set_visible(False)

效果展示:
在这里插入图片描述

2、cartopy自带的底图
参考:http://earthpy.org/cartopy_backgroung.html

ax.background_img(name='pop', resolution='high')
ax.background_img(name='BM', resolution='high')
ax.stock_img();#Add a standard image to the map.Currently, the only (and default) option is a downsampled version of the Natural Earth shaded relief raster.
#等价于:
# get the path to an image (in this case, a stock image which ships with cartopy)
fname = os.path.join(config["repo_data_dir"],
                     'raster', 'natural_earth', '50-natural-earth-1-downsampled.png')
img = imread(fname)
ax.imshow(img, origin='upper', transform=ccrs.PlateCarree(), extent=[-180, 180, -90, 90])

如果想手动下载地图,可以到 Natural Earth (https://www.naturalearthdata.com/)网站上下载所需的地图数据。
在这里插入图片描述
如果想设置海岸线属性(如内陆设置为灰色,海洋设置为浅蓝色),可参考:
https://blog.youkuaiyun.com/weixin_43750300/article/details/129022005
具体实现方式:

ax1.add_feature(cfeature.COASTLINE)
ax1.add_feature(cfeature.OCEAN)
ax1.add_feature(cfeature.LAND)

想要设置其属性:

# 添加海岸线,并设置颜色和线宽
ax1.add_feature(cfeature.COASTLINE, edgecolor='black', linewidth=1.5)

# 添加海洋,并设置颜色
ax1.add_feature(cfeature.OCEAN, facecolor='lightblue')

# 添加陆地,并设置颜色
ax1.add_feature(cfeature.LAND, facecolor='lightgreen')

3、Cartopy 自带的 Natural Earth 的地图有三档分辨率:1:10m、1:50m、1:110m(默认分辨率为 1:110m)

ax.coastlines(resolution='50m')
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值