python 绘图,绘制模型模拟与实测值对比图

模型模拟值一般为连续的值,实测值为点,且一般带有误差

# 导入必要的包,定义文件读取函数
import os
import datetime
import pandas as pd
import numpy as np
from pcse.fileinput import CABOFileReader  # 读取CABO文件(作物土壤文件)
from pcse.fileinput import YAMLAgroManagementReader  # 管理文件读取
from pcse.models import Wofost71_WLP_FD, Wofost71_PP  # 导入模型,Wofost71_PP潜在模型
from pcse.base import ParameterProvider  # 综合作物、土壤、位点参数
from pcse.fileinput import ExcelWeatherDataProvider  # 读取气象文件
%matplotlib inline
import matplotlib.pyplot as plt
import matplotlib.font_manager as fm
from pandas.plotting import register_matplotlib_converters
register_matplotlib_converters()
def soil_data(s, c, om, b=1.5):   
    s = s  # sand %
    c = c  # clay %
    om = om # organic matter %
    b = b  # bulk g/cm3
    # 永久萎蔫点 PWP
    pwp = 1.14*(-0.00024*s+0.00487*c+0.006*om+0.00005*s*om-0.00013*c*om+0.0000068*s*c+0.031)-0.02
    # 田间持水量 FC
    o33 = -0.00251*s+0.00195*c+0.011*om+0.00006*s*om-0.00027*c*om+0.0000452*s*c+0.299
    fc = o33+1.283*o33*o33-0.374*o33-0.015
    # 饱和含水量-FC
    s_33 = 1.636*(0.00278*s+0.00034*c+0.022*om-0.00018*s*om-0.00027*c*om-0.0000584*s*c+0.078)-0.107
    # 饱和含水量 容重矫正后
    sat = fc+s_33-0.00097*s+0.043
    # 校正后田间持水量
    pn = 2.65*(1-(fc+s_33-0.00097*s+0.043))
    df = b/1.5
    if df<0.9:
        df=0.9
    elif df>1.2:
        df=1.2
    pdf = pn*df
    fc_v = fc-0.2*(fc+s_33-0.00097*s+0.043-(1-pdf/2.65))
    # 校正后饱和含水量
    sat_v = 1-(pdf/2.65)
    return [pwp, fc_v, sat_v]


def st_loc(num):
    """
    选取气象数据的时候标准化输入为0.5的分辨率
    """
    import math
    if num-math.floor(num) <=0.25 or num-math.floor(num)>=0.75:
        result = round(num)
    elif 0.25 < num-math.floor(num) < 0.75:
        result = math.floor(num) + 0.5      
    return result

# 设置绘图地点
sites = ['内黄', '许昌', '洛宁', '罗山']
sites_e = ['NH', 'XC', 'LN', 'LS']
annote = ['a', 'b', 'c', 'd']
data_dir = r'C:\Users\Administrator\Desktop\model calibration'  # 模型校准文件夹
weather_dir = r'C:\Users\Administrator\Desktop\2020气象数据'  # 气象数据路径
variety = 207# 品种
data_obs = pd.read_excel('实测值.xlsx', sheet_name='实测值')  # 实测值
tagp_rmse = [] # bioass rmse
twso_sim = [] # yield simulation
twso = [] # yield observation
twso_std = [] # yield standard deviation
fig = plt.figure(figsize=(10,14))  # 建立图表
for i in range(4):
#     运行模型
    site = sites[i]
    cropdata = CABOFileReader(os.path.join(data_dir,'%s.CAB'%site))  # 读取作物文件
    soildata = CABOFileReader(os.path.join(data_dir,'EC3.NEW'))  # 土壤文件
    sitedata = {'SSMAX'  : 0.,
                'IFUNRN' : 0,
                'NOTINF' : 0,
                'SSI'    : 0,
                'WAV'    : 20,
                'SMLIM'  : 0.03,
               'RDMSOL'  : 120}
    parameters = ParameterProvider(cropdata=cropdata, soildata=soildata, sitedata=sitedata)  # 参数集合
    data_base_info = pd.read_excel('18县生物量LAI整理12.27.xlsx', sheet_name='基本情况')
    sub_data = data_base_info.loc[data_base_info['试验地']==site, 
                                  ['经度', '维度', '品种', '播量(计算)', '播种期', 
                                   'sa', 'cl', 'bd', 'som', '灌溉', 'WAV']]
    # 基本数据获取
    lon = sub_data.loc[sub_data['品种']==variety, ['经度']]  # 读取经度
    lat = sub_data.loc[sub_data['品种']==variety, ['维度']]  # 读取纬度 
    SAND = sub_data.loc[sub_data['品种']==variety, ['sa']].iloc[0,0]  # 砂粒
    CLAY = sub_data.loc[sub_data['品种']==variety, ['cl']].iloc[0,0]  # 黏粒
    OM = sub_data.loc[sub_data['品种']==variety, ['som']].iloc[0,0]  # 有机质
    BULK_DENSITY = sub_data.loc[sub_data['品种']==variety, ['bd']].iloc[0,0]  # 容重
    sow_date = sub_data.loc[sub_data['品种']==variety, ['播种期']].iloc[0,0]  # 播期
    irrigation = sub_data.loc[sub_data['品种']==variety, ['灌溉']].iloc[0,0]  # 灌溉条件
    
    # 数据替换
    parameters['TDWI'] = sub_data.loc[sub_data['品种']==variety, ['播量(计算)']].iloc[0,0]  # 播量
    parameters['SMW'] = soil_data(SAND, CLAY, OM, BULK_DENSITY)[0]  # 萎蔫点
    parameters['SMFCF'] = soil_data(SAND, CLAY, OM, BULK_DENSITY)[1]  # 田间持水量
    parameters['SM0'] = soil_data(SAND, CLAY, OM, BULK_DENSITY)[2]  # 饱和含水量
    parameters['WAV'] = sub_data.loc[sub_data['品种']==variety, ['WAV']].iloc[0,0]
    # 气象数据
    weatherdataprovider = ExcelWeatherDataProvider(os.path.join(weather_dir,'NASA天气文件lat={0:.1f},lon={1:.1f}.xlsx'.
                                                                format(st_loc(lat.iloc[0,0]), st_loc(lon.iloc[0,0]))))
    agromanagement = YAMLAgroManagementReader(os.path.join(data_dir,'%s.agro'%site))  # 管理文件读取

    wf = Wofost71_WLP_FD(parameters, weatherdataprovider, agromanagement)  # 定义模型
    wf.run_till_terminate()  # 运行模型直到终止
    output=pd.DataFrame(wf.get_output()).set_index('day')
    # 实测值
    sub_obs = data_obs.loc[data_obs['试验地']==site, ['品种', 'day', 'LAI', '生物量kg/ha', 
                                                   '穗生物量kg/ha', '生物量标准差', '穗标准差']]
    sub_obs_103 = sub_obs.loc[sub_obs['品种']==variety].set_index('day')
    
# -----------------  绘图  ---------------------------------------------------- 
#     建子图
    axes = plt.subplot(3,2,i+1)  # 建立子图坐标域 三行两列 画前四个图
#     单位转换 Kg-Mg
    sub_obs_103['生物量kg/ha'] = sub_obs_103['生物量kg/ha']/1000
    sub_obs_103['穗生物量kg/ha'] = sub_obs_103['穗生物量kg/ha']/1000
    sub_obs_103['生物量标准差'] = sub_obs_103['生物量标准差']/1000
    # 绘制误差图errorbar
    axes.errorbar(sub_obs_103.index, sub_obs_103['生物量kg/ha'], yerr=sub_obs_103['生物量标准差'], fmt=".", ms=10,capsize=5, label = 'Observation')
    output['TAGP'] = output['TAGP']/1000
    output['TWSO'] = output['TWSO']/1000
    # 生物量模拟图Simulation
    output.TAGP.plot(ax=axes, label = 'Simulation', lw=3)   
    output['TAGP'].dropna(inplace=True)
    output['TWSO'].fillna(method='pad', inplace=True)   # 填充后面的空值为最后一个非空值,即最终产量
#     计算模拟与实测值的差与RMSE
    df_differences_tagp = sub_obs_103['生物量kg/ha'] - output['TAGP']
    tagp_rmse.append(np.sqrt(np.mean(df_differences_tagp**2)))
    # yield obs
    twso.append(sub_obs_103['穗生物量kg/ha'][-1])
    # yield sim
    twso_sim.append(output['TWSO'][-1])
    twso_std.append(sub_obs_103['穗标准差'][-1]/1000)
#     计算R方
    r2 = 1 - np.sum((df_differences_tagp)**2) / np.sum((sub_obs_103['生物量kg/ha'] - np.mean(sub_obs_103['生物量kg/ha']))**2)
#     设置字体格式
    font = {'family' : 'Helvetica',
    'weight' : 'normal',
    'size'   : 16,
    }
    axes.set_xlabel('') # 去除x轴标题
#     融合坐标轴 (下次考虑使用subplots的sharex,sharey)
    if i == 1 or i == 3:
        axes.set_ylabel('')  # 去除y轴标题
#         去除坐标轴标签
        plt.tick_params(axis='y', which='both', labelleft=False,top=False, left=False, labelbottom=False)
    else:
        axes.set_ylabel('Aboveground biomass (Mg/ha)', font)
    if i == 0 or i == 1:
        plt.tick_params(axis='x',which='both', top=False, bottom=False, labelbottom=False)
    else:
        plt.xticks(fontproperties = 'Helvetica' ,size = 14,rotation = 30)
#     标注R和RMSE,\it表示斜体
    axes.annotate("$\it{RMSE}$ = %.2f Mg/ha" % tagp_rmse[i], xy=('2019-10-20', 10),  family='Helvetica', weight='normal', fontsize=16)
    plt.text('2019-10-20', 17.8, annote[i], family='Helvetica', weight='normal', fontsize=17)
    axes.annotate("$\it{R^2}$ = %.2f" % r2, xy=('2019-10-20', 12),  family='Helvetica', weight='normal', fontsize=16)
    # 设置坐标轴字体格式
    plt.tick_params(axis='y', labelsize=15)
    labels = axes.get_xticklabels() + axes.get_yticklabels()
    [label.set_fontname('Helvetica') for label in labels]
    
    plt.ylim(0, 19)
    plt.legend(loc=(0.02, 0.72), prop=font)
#     fig.subplots_adjust(wspace=0.05,hspace=0.05)
axes = plt.subplot(3,1,3) # 绘制第三列大图
df = pd.DataFrame({'Observation': twso, 'Simulation': twso_sim})
df.plot(kind='bar', ax=axes,  yerr = [twso_std, [0,0,0,0]], error_kw = {'capsize' :4}, alpha=1)
plt.xticks([0,1,2,3],sites_e,fontproperties = 'Helvetica',rotation = 0, size=18)
axes.set_ylabel('Yield (Mg/ha)', font)
plt.text(-0.4, 7.8, 'e', family='Helvetica', weight='normal', fontsize=17)
labels = axes.get_xticklabels() + axes.get_yticklabels()
[label.set_fontname('Helvetica') for label in labels]
plt.tick_params(axis='y',labelsize=15)  # 可以指定是x或y坐标轴参数
plt.legend(prop=font)
plt.tight_layout()
plt.savefig('simulation.tif',bbox_inches='tight', dpi=600)  # bbox_inches防止保存丢失信息

结果
在这里插入图片描述

  • 1
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值