[python] 画图:cartopy笔记(一)基础知识与误差分布图

参考链接:

基础知识理解:

摸鱼的气象&Python:绘图基础和地图投影_哔哩哔哩_bilibili

对应代码:摸鱼的气象&Python - Heywhale.com

《气py:Python气象资料处理与可视化》李开元、豆京华

​​​​​​Cartopy 系列:从入门到放弃 - 炸鸡人博客 (zhajiman.github.io)

画图实例:

​​​​​​(29条消息) 小白学习cartopy画地图的第一天(中国行政区域图,含南海)_野生的气象小流星的博客-CSDN博客_cartopy绘制中国省份图

​​​​​​(29条消息) 小白学习cartopy气象画地图的第二天(中国区域,陆地温度分布图)_野生的气象小流星的博客-CSDN博客_cartopy 气象

最终效果图如下:

目录

参考链接:

1.cartopy简介

2.画图流程及常用函数

2.1.创建画布、绘画区(figure、axes)

Figure:画布

Axes:绘图区

2.2 画地图

投影方式

3.画图实例:华南地区降水量mae分布图


1.cartopy简介

cartopy是一个为地理空间数据处理而设计的python包,用于生成地图和其他地理空间数据分析。本身不具有可视化功能,但可以为Matplotlib提供地理坐标系的转换,实现气象专业图形的绘制。

2.画图流程及常用函数

2.1.创建画布、绘画区(figure、axes)

import matplotlib.pyplot as plt

Figure:画布

Figure(figsize=None, dpi=None, facecolor=None, edgecolor=None, linewidth=0.0)

图像尺寸、像素点、背景颜色、边框颜色、边框宽度

import matplotlib.pyplot as plt

fig=plt.figure(figsize=(4,3),dpi=200,facecolor='blue',edgecolor='black',linewidth=2)

plt.show()

Axes:绘图区

figure对象有两种方法建立axes: plt.figure().add_axes()、 plt.figure().add_subplot()

其中,add_subplots属于axes的特殊情况

1).add_axes

import matplotlib.pyplot as plt
fig = plt.figure()
ax = fig.add_axes((0,0,3,2))#以(0,0)点为左下的起点坐标,选择一个长为3,宽为2的绘图区 
plt.show()

2).add_subplot

import matplotlib.pyplot as plt
fig = plt.figure()
ax = add_subplot(2,2,1)
plt.show()

3).GeoAxes:地图投影,把坐标投影为地理坐标

import matplotlib.pyplot as plt
import cartopy.crs as ccrs
fig = plt.figure()
ax = fig.add_axes([0,0,3,2],projection = ccrs.PlateCarree())
plt.show()

2.2 画地图

投影方式

有很多,最常用等距圆柱投影,对数据没有变形

可参考:摸鱼的气象&Python:绘图基础和地图投影_哔哩哔哩_bilibili

1).等距圆柱投影   ccrs.PlateCarree(central_longitude=0.0)

2).正形兰伯特投影   ccrs.LambertConformal( central_longitude=-96.0, central_latitude=39.0,
    standard_parallels=None, cutoff=-30,)

中心经度、中心维度、区间(内部数据为等比例投影)、截止纬度

填色(contour、contourf)

matplotlib.axes.Axes.contour:绘制等值线

matplotlib.axes.Axes.contourf:给等值线填色

ax.contourf(lon.lat,z,levels,cmap,transform,zorder)

levels:整数n或数组,n:画n条线,数组:按数组值画等值线

cmap:当color未被指定时,使用自己指定的cmap或官方默认的colormap方案。

fig = plt.figure(figsize=(12,8))
proj = ccrs.PlateCarree(central_longitude=180)
ax = fig.add_axes([0.1, 0.1, 0.8, 0.6],projection = proj)
c1 = ax.contour(lon,lat,z,levels=np.arange(5400,6000,50),
 cmap=plt.cm.bwr,transform=ccrs.PlateCarree())

c2 = ax.contourf(lon,lat,z,levels=np.arange(5400,6000,50),
extend='max' ,cmap=plt.cm.bwr,
transform=ccrs.PlateCarree(),zorder=0)

增加(刻度线、标题)等

可参考:摸鱼的气象&Python:几个必不可少的地理绘图函数_哔哩哔哩_bilibili

import cartopy.crs as ccrs
import cartopy.mpl.ticker as cticker
import matplotlib.pyplot as plt

fig = plt.figure(figsize=(12,8))
proj = ccrs.PlateCarree(central_longitude=180)
ax = fig.add_axes([0.1, 0.1, 0.8, 0.6],projection = proj)

ax.set_xticks(np.arange(leftlon,rightlon+60,60), crs=ccrs.PlateCarree())
ax.set_yticks(np.arange(lowerlat,upperlat+30,30), crs=ccrs.PlateCarree())
lon_formatter = cticker.LongitudeFormatter()
lat_formatter = cticker.LatitudeFormatter()
ax.xaxis.set_major_formatter(lon_formatter)
ax.yaxis.set_major_formatter(lat_formatter)

3.画图实例:华南地区降水量mae分布图

导入库

#参考链接:
# https://blog.csdn.net/weixin_42372313/article/details/113665724?spm=1001.2014.3001.5502
# https://zhajiman.github.io/post/cartopy_introduction/#%E7%AE%80%E4%BB%8B

import numpy as np
import matplotlib.pyplot as plt
import cartopy.crs as ccrs
from cartopy.mpl.ticker import LatitudeFormatter, LongitudeFormatter

一、加载数据mae、中国地图文件

plt.rcParams["font.sans-serif"] = ["DengXian"]  # 用来正常显示中文标签
plt.rc('axes', unicode_minus=False)  # 解决负号显示问题

# 加载mae mae(step,latitude,longitude),取超前0天对应的mae
correlation = mae.sel(step = '0 days')
lon = mae.longitude
lat = mae.latitude

#画地图底图(网址是:*https://gmt-china.org/data/*下载里面的CN-border-La.dat)
## 这一步是读取CN - border - La.da文件,目的是读取里面每个点的经纬度,用于给底图加上行政边界

 with open('CN-border-La.dat') as src:
        context = src.read()
        blocks = [cnt for cnt in context.split('>') if len(cnt) > 0]
        borders = [np.fromstring(block, dtype=float, sep=' ') for block in blocks]

二、画图

#1、创建画布
fig = plt.figure(figsize=[8, 8])#画布
ax = plt.axes(projection=ccrs.PlateCarree())#ax:绘图区,projection:投影方式为PlateCarree


#2、画底图

# 这里就用到了当时上面文件里面的坐标点了,其实就是用点画线,
# line[0::2]就是X,line[1::2]就是Y,就是用xy画平面图,一组是经度,一组是纬度。
    
 for line in borders:
        ax.plot(line[0::2], line[1::2], '-', lw=1.5, color='k',transform=ccrs.Geodetic())


# 咱们画出来的是世界地图,这个来框处要显示的区域
xmin, xmax = lon.min(), lon.max()
ymin, ymax = lat.min(), lat.max()
ax.set_extent([xmin, xmax, ymin,ymax],crs=ccrs.PlateCarree())


#3、画图填色
#使用contourf进行填色,下面先设置它的参数

#设置色标
import math
t_max = math.ceil(correlation.max().values)
t_min = math.floor(correlation.min().values)
n = (t_max - t_min)/10
cbar_kwargs = {
    'orientation': 'vertical',
    'label': '降水量误差(mm)',
    'shrink': 0.8,
    'ticks': np.arange(t_min, t_max, n),
    'pad': 0.05,
    'shrink': 0.65
}

# 设置画数据的精度,这里设置了从数据的最小值到最大值,按0.1mm画降水量
levels = np.arange(t_min, t_max, 0.1)

# 本质上是一个画等值线并填色的函数,被cartopy封装了一下,参数的含义可以去查#matplotlib.pyplot.contourf
# 参数含义:levels设置等值线密度,cmap颜色,cbar_kwargs色标,transform变换
correlation.plot.contourf(ax=ax, levels=levels, cmap='Spectral_r',
                        cbar_kwargs=cbar_kwargs, transform=ccrs.PlateCarree())


#4、画经纬度(即网格线)、刻度线、标题
#设置x、y刻度
#以5°为间隔计算x、y坐标刻度值,使用PlateCarree投影方式换算坐标,得到x、y的地理坐标
ax.set_xticks(
    np.arange(xmin, xmax + 1, np.round((xmax + 1 - xmin) / 5)),
    crs=ccrs.PlateCarree(),
)
ax.set_yticks(
    np.arange(ymin, ymax + 1, np.round((ymax + 1 - ymin) / 5)),
    crs=ccrs.PlateCarree(),
)    

# 设置刻度格式为经纬度格式
ax.xaxis.set_major_formatter(LongitudeFormatter())
ax.yaxis.set_major_formatter(LatitudeFormatter())


#设置标题
ax.set_title('华南地区总降水量mae分布图', color='blue', fontsize=20)


三、显示图形

plt.show()

四、完整代码

#参考链接:
# https://blog.csdn.net/weixin_42372313/article/details/113665724?spm=1001.2014.3001.5502
# https://zhajiman.github.io/post/cartopy_introduction/#%E7%AE%80%E4%BB%8B

import xarray as xr
import numpy as np
import matplotlib.pyplot as plt
import cartopy.crs as ccrs
from cartopy.mpl.ticker import LatitudeFormatter, LongitudeFormatter

class Error:
    def __init__(self,y_pred2,y_obs):
        self.y_pred2 = y_pred2
        self.y_obs = y_obs

    def Rmse(self):
        '''
        计算订正值与真实值之间的rmse
        :param self.y_pred2: 二次预测值(订正)
        :param self.y_obs: 观测值
        :return: rmse(i,j,l)、rmse_mean(l)
        '''
        err = self.y_pred2 - self.y_obs
        err = err**2
        err = err.mean(dim = 'time')
        rmse = err**0.5
        rmse_mean = rmse.mean(dim=['latitude','longitude'])
        return rmse,rmse_mean

    def Mae(self):
        '''
        计算订正值与真实值之间的rmse
        :param self.y_pred2: 二次预测值(订正)
        :param self.y_obs: 观测值
        :return: mae(i,j,l)、mae_mean(l)
        '''
        err = self.y_pred2 - self.y_obs
        err = abs(err)
        mae = err.mean(dim = 'time')
        mae_mean = mae.mean(dim=['latitude','longitude'])
        return mae,mae_mean

    def Tcc(self):
        obs = self.y_obs - self.y_obs.mean("step")
        pred = self.y_pred2 - self.y_pred2.mean("step")

        cov = (obs * pred).sum("step")
        var_var = np.sqrt((obs ** 2).sum("step") * (pred ** 2).sum("step"))
        tcc = cov / var_var
        tcc_mean = tcc.mean('time')
        return tcc,tcc_mean

    def Acc(self):
        self.y_obs = self.y_obs.stack(pos=("latitude", "longitude"))  # 拉成一个维度
        self.y_pred2 = self.y_pred2.stack(pos=("latitude", "longitude"))  # 拉成一个维度
        obs = self.y_obs - self.y_obs.mean("pos")
        pred = self.y_pred2 - self.y_pred2.mean("pos")

        cov = (obs * pred).sum("pos", skipna=True)
        var_var = np.sqrt((obs ** 2).sum("pos", skipna=True) * (pred ** 2).sum("pos", skipna=True))
        acc = cov / var_var
        acc_mean = acc.mean('time')
        return acc,acc_mean

plt.rcParams["font.sans-serif"] = ["DengXian"]  # 用来正常显示中文标签
plt.rc('axes', unicode_minus=False)  # 解决负号显示问题

if __name__ == '__main__':
    # 一、加载数据mae、中国地图文件
    path2 = '/home/gyy/gyy-project/model_set/pred2/source_pred2.nc'  # y_pred2
    path1 = '/home/gyy/gyy-project/model_set/pred2/source_test.nc'  # y_obs
    path0 = '/home/gyy/gyy-project/model_set/pred2/x_mean49.nc'  # y_pred1
    y_pred2 = xr.open_dataarray(path2)
    y_obs = xr.open_dataarray(path1)
    err = Error(y_pred2,y_obs)
    mae,mae_mean = err.Mae()

    # 加载mae mae(step,latitude,longitude),取超前0天对应的mae
    correlation = mae.sel(step='0 days')
    lon = mae.longitude
    lat = mae.latitude

    # 画地图底图(网址是:*https://gmt-china.org/data/*下载里面的CN-border-La.dat)
    ## 这一步是读取CN - border - La.da文件,目的是读取里面每个点的经纬度,用于给底图加上行政边界

    with open('CN-border-La.dat') as src:
        context = src.read()
        blocks = [cnt for cnt in context.split('>') if len(cnt) > 0]
        borders = [np.fromstring(block, dtype=float, sep=' ') for block in blocks]

    # 二、画图
    # 1、创建画布
    fig = plt.figure(figsize=[8, 8])  # 画布
    ax = plt.axes(projection=ccrs.PlateCarree())  # ax:绘图区,projection:投影方式为PlateCarree

    # 2、画底图

    # 这里就用到了当时上面文件里面的坐标点了,其实就是用点画线,
    # line[0::2]就是X,line[1::2]就是Y,就是用xy画平面图,一组是经度,一组是纬度。

    for line in borders:
        ax.plot(line[0::2], line[1::2], '-', lw=1.5, color='k', transform=ccrs.Geodetic())

    # 咱们画出来的是世界地图,这个来框处要显示的区域
    xmin, xmax = lon.min(), lon.max()
    ymin, ymax = lat.min(), lat.max()
    ax.set_extent([xmin, xmax, ymin, ymax], crs=ccrs.PlateCarree())

    # 3、画图填色
    # 使用contourf进行填色,下面先设置它的参数

    # 设置色标
    import math

    t_max = math.ceil(correlation.max().values)
    t_min = math.floor(correlation.min().values)
    n = (t_max - t_min) / 10
    cbar_kwargs = {
        'orientation': 'vertical',
        'label': '降水量误差(mm)',
        'shrink': 0.8,
        'ticks': np.arange(t_min, t_max, n),
        'pad': 0.05,
        'shrink': 0.65
    }

    # 设置画数据的精度,这里设置了从数据的最小值到最大值,按0.1mm画降水量
    levels = np.arange(t_min, t_max, 0.1)

    # 本质上是一个画等值线并填色的函数,被cartopy封装了一下,参数的含义可以去查#matplotlib.pyplot.contourf
    # 参数含义:levels设置等值线密度,cmap颜色,cbar_kwargs色标,transform变换
    correlation.plot.contourf(ax=ax, levels=levels, cmap='Spectral_r',
                              cbar_kwargs=cbar_kwargs, transform=ccrs.PlateCarree())

    # 4、画经纬度(即网格线)、刻度线、标题
    # 设置x、y刻度
    # 以5°为间隔计算x、y坐标刻度值,使用PlateCarree投影方式换算坐标,得到x、y的地理坐标
    ax.set_xticks(
        np.arange(xmin, xmax + 1, np.round((xmax + 1 - xmin) / 5)),
        crs=ccrs.PlateCarree(),
    )
    ax.set_yticks(
        np.arange(ymin, ymax + 1, np.round((ymax + 1 - ymin) / 5)),
        crs=ccrs.PlateCarree(),
    )

    # 设置刻度格式为经纬度格式
    ax.xaxis.set_major_formatter(LongitudeFormatter())
    ax.yaxis.set_major_formatter(LatitudeFormatter())

    # 设置标题
    ax.set_title('华南地区总降水量mae分布图', color='blue', fontsize=20)

    # 三、显示图形
    plt.show()
  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值