绘图函数
-
绘图效果:
-
复制粘贴存好plot_scatter.m函数:
function coeff=plot_scatter(x_obs, y_sim, fit_degree,cal_metrics,plot_info)
% x_obs: 自变量数据
% y_sim: 因变量数据
% fit_degree: 多项式拟合的阶数
% cal_metrics: table,已计算好的拟合评价指标
% plot_info:table,已存储好的绘图信息
%% 输入数据预处理
% 检查输入的 x 和 y 是否具有相同的行列数
if ~isequal(size(x_obs), size(y_sim))
error('The sizes of input x_obs and y do not match.');
end
% 排除 NaN 值并计算有效元素个数
valid_indices = ~isnan(x_obs) & ~isnan(y_sim);
x_valid = x_obs(valid_indices);
y_valid = y_sim(valid_indices);
%% 基本绘图
[width, height] = deal(plot_info.size(1),plot_info.size(2));
figure('Units','centimeter','Position',[10 5 width height]);
%'Units', 'centimeter': 将图形窗口的单位设置为厘米。
%'Position', [17 11 8 8]: 设置图形窗口的位置和大小。
% [17 11 8 8] 表示 [left bottom width height],
%left = 17 cm;% 窗口左边缘离屏幕左边缘的距离
% bottom = 11 cm; % 窗口底边缘离屏幕底边缘的距离
% width = 8 cm; % 窗口的宽度
% height = 8 cm; % 窗口的高度
% 计算输入数据横纵坐标范围
x_range=[min(x_valid),max(x_valid)];
y_range=[min(y_valid),max(y_valid)];
% 绘制散点密度图
CData=density2C(x_valid, y_valid,x_range(1):10:x_range(2),y_range(1):10:y_range(2));
scatter(x_valid, y_valid,5,'filled','CData',CData);
cb=colorbar; % 显示colorbar
title(cb, 'ksdensity','FontSize',8,'Fontname','Times New Roman'); % 给颜色条添加标题
hold on;
% 普通散点图
% scatter(x_valid, y_valid,14,[0.1,0.5,0.8]) % 第三个是散点的大小,如果默认的话就写[],不写就会报错
% [0.8, 0.1, 0.2]: 散点的颜色,使用 RGB 三元组表示。
% 其中红色成分为 0.8,绿色成分为 0.1,蓝色成分为 0.2,这会生成一个深红色。
% bin散点密度图
% p1=binscatter(x_valid, y_valid, 250);
% colormap(gca, 'parula'); % 设置颜色映射为 'jet'
% hold on;
% 设置统一坐标轴范围
axis_range = [min(x_range(1),y_range(1)), max(x_range(2),y_range(2))];
% 向下取整最小值,向上取整最大值
axis_range_int = [floor(axis_range(1) / plot_info.ax_d) * ...
plot_info.ax_d,ceil(axis_range(2) / plot_info.ax_d) * plot_info.ax_d];
if ismember('range', plot_info.Properties.VariableNames) && ~isempty(plot_info.range)
axis_range_int=plot_info.range;
end
axis_set=axis_range_int(1):plot_info.ax_d:axis_range_int(2);
xlim(axis_range_int);
ylim(axis_range_int);
% 设置 x 轴和 y 轴的刻度间距
xticks(axis_set);
yticks(axis_set);
% 添加趋势线
coeff = polyfit(x_valid, y_valid, fit_degree);
y_fit = polyval(coeff, x_valid);
hold on;
plot(x_valid, y_fit, 'b-', 'LineWidth', 1);
%添加1:1回归虚线
x = axis_set;
y = x; % 1:1回归线
plot(x,y,'r--','linewidth',1)
%% 调试信息
fit_eq = strcat('\ity\rm=', num2str(coeff(1), '%.2f'), '\itx\rm+', num2str(coeff(2), '%.2f'));
idx_r2=strcat('\itR\rm^2=', num2str(cal_metrics.r_squared, '%.2f'));
idx_bias=strcat('BIAS=', num2str(cal_metrics.bias, '%.2f'),plot_info.units);
idx_rmse=strcat('RMSE=', num2str(cal_metrics.rmse, '%.2f'),plot_info.units);
idx_n=strcat('N=', num2str(cal_metrics.num_valid));
% 获取坐标范围
x_lim = xlim;
y_lim = ylim;
[x_frac, y_frac] = deal(plot_info.text1_pos(1),plot_info.text1_pos(2));
x_d= x_frac * (x_lim(2) - x_lim(1));
y_d= y_frac * (y_lim(2) - y_lim(1));
x_pos = x_lim(1) + x_d;
y_pos = y_lim(1) + y_d;
text(x_pos+y_d,y_pos+y_d*4,fit_eq,'FontSize',8,'Fontname','Times New Roman', 'Interpreter', 'tex');
text(x_pos+y_d,y_pos+y_d*3,idx_n,'FontSize',8,'Fontname','Times New Roman', 'Interpreter', 'tex');
text(x_pos+y_d,y_pos+y_d*2,idx_r2,'FontSize',8,'Fontname','Times New Roman', 'Interpreter', 'tex');%标记R
text(x_pos,y_pos+y_d,idx_bias,'FontSize',8,'Fontname','Times New Roman', 'Interpreter', 'tex');
text(x_pos,y_pos,idx_rmse,'FontSize',8,'Fontname','Times New Roman', 'Interpreter', 'tex');
[x_frac2, y_frac2] = deal(plot_info.text2_pos(1),plot_info.text2_pos(2));
x_d2= x_frac2 * (x_lim(2) - x_lim(1));
y_d2= y_frac2 * (y_lim(2) - y_lim(1));
x_pos2 = x_lim(1) + x_d2;
y_pos2 = y_lim(1) + y_d2;
text(x_pos2,y_pos2,plot_info.sitesID,...
'FontSize',8,'Fontname','Times New Roman');
set(gcf,'Color',[1,1,1]);%背景板设置为白色
set(gca,'FontName','Times New Roman','FontSize',8);
box on
%% 绘制辅助信息及图像保存
% 添加坐标轴标题
% 构建带有单位的标题字符串
xLabelStr = sprintf('%s (%s)', plot_info.xLabel, plot_info.units);
yLabelStr = sprintf('%s (%s)', plot_info.yLabel, plot_info.units);
% 设置坐标轴标签
xlabel(xLabelStr, 'FontName', 'Times New Roman', 'FontSize', 8);
ylabel(yLabelStr, 'FontName', 'Times New Roman', 'FontSize', 8);
% title([num2str(date),' Scatter plot of ', xLabel, ' vs. ', yLabel]);
% 检查表格中是否存在 'save' 列,并且其值为 0
if ismember('save', plot_info.Properties.VariableNames) && plot_info.save == 0
% 不保存图像
disp('图像未保存')
else
imageName = [plot_info.imageName, '.tiff']; % 默认使用png格式
fullPath = fullfile(plot_info.filePath, imageName);
% 设置要保存的分辨率
resolution = 300; % 例如,300 DPI
% 保存为指定分辨率的 JPEG 图像
print(gcf, fullPath, '-dtiff', ['-r' num2str(resolution)]);
end
% 关闭图形窗口
close(gcf);
end
注意:
以上散点密度图部分设置了3个可以实现的方法,可以任意选用看自己想用哪种效果,我用的是density2C.m函数,来自https://blog.csdn.net/slandarer/article/details/120242042?fromshare=blogdetail,很好用,感谢大佬的无私分享!
- 函数调用:
以下为多个变量的批量出图
% 提前设置好每个变量的参数,这里需要测试
range_all={[0,800],[-100,300],[-100,300],[0,800],[0,800],[0,1200],[0,300]};%轴域范围
text1_pos={[0.45,0.08], [0.45,0.08],[0.45,0.08], [0.45,0.08],...
[0.45,0.08], [0.45,0.08],[0.45,0.08]};%text1的定位
text2_pos={[0.08,0.9], [0.08,0.9],[0.08,0.9], [0.08,0.9],...
[0.08,0.9], [0.08,0.9],[0.08,0.9]};%text2的定位
ax_d=[200,100,100,200,200,300,100];%轴间距信息
plot_vars= fieldnames(flux_vars);
check_flux.(plot_vars{1})= flxdat.AAAA;
check_flux.(plot_vars{2})= flxdat.BBBB;
check_flux.(plot_vars{3})= flxdat.CCCC;
check_flux.(plot_vars{4})= flxdat.DDDD;
check_flux.(plot_vars{5})= flxdat.EEEE;
check_flux.(plot_vars{6})= flxdat.FFFF;
check_flux.(plot_vars{7})= flxdat.GGGG;
for j=1:length(plot_vars)
x_obs=check_flux.(plot_vars{j});
y_sim=flux_vars.(plot_vars{j});
[check_vars,valid_vars]= calculate_metrics(plot_vars{j},x_obs,y_sim);%与观测数据对比
% 绘制散点图
plot_info=table;
plot_info.size=[8,6];
plot_info.range=range_all{j};%先粗出图设置为[],测试好再确定统一范围
plot_info.ax_d=ax_d(j);%纵轴间距
plot_info.text1_pos=text1_pos{j};%[x_frac, y_frac]
plot_info.text2_pos=text2_pos{j};%[x_frac, y_frac]
plot_info.xLabel=strcat(plot_vars{j},'_o_b_s');
plot_info.yLabel=strcat(plot_vars{j},'_m_o_d');
plot_info.units='W/m^2';
plot_info.sitesID=sites(i);
plot_info.filePath=fullfile(wdir,'\data\data_check\4_AA_check\');
plot_info.imageName=strcat(sites{i},'_scatter_',plot_vars{j});
% plot_info.save=0;%0代表不保存,1代表保存,如果不设置这个,默认保存
coeff=plot_scatter(x_obs,y_sim,1,check_vars,plot_info);
check_vars.slope=coeff(1);
check_vars.intercept=coeff(2);
end
4.定位逻辑:
5.批量问题:
以上还只是1张1张批量出,不是subplot版本,我自己画的subplot版本还不够成熟好看,待继续摸索