%1、数据预处理:
date_used=datevec(datenum(1979,1,1):1:datenum(2020,12,31));%构建时间向量,datevec把日期号datenum转化成向量形式
%date_used有六列,分别是年月日时分秒
sst_full=NaN(180,91,size(date_used,1));%预设空矩阵,三维:经纬度*时间
%批量读取mat文件:
for i=1979:2020;
index_here=ismember(date_used(:,1),i);%ismember判断数组元素是否为集数组成员,找date_used里第一列中i所在的位置index_here
load(['sst' num2str(i)]);%num2str将数字转化为字符数组
sst_full(:,:,index_here)=sst;
end
%2、时间格点,时间精度转换:把日精度的数据转化为月、年数据,也就是逐月平均sst_month和逐年平均sst_year
date_used=datevec(datenum(1979,1,1):1:datenum(2020,12,31));%构建时间向量,datevec把日期号datenum转化成向量形式
%unique数组中的唯一值
date_m=unique(date_used(:,1:2),'rows');%对1、2列沿行(rows)使用unique,提取出来年、月
date_y=unique(date_used(:,1),'rows');%对1列沿行使用unique,提取出来年
load('sst_full');
%先构建空数组用于之后储存月、年均值(每月、每年各自的均值,不是把所有月、年平均起来的一个二维数组)
sst_month=NaN(size(sst_full, 1), size(sst_full,2), size (date_m, 1));
sst_year=NaN(size(sst_full,1),size(sst_full,2),size(date_y,1));
for i=1: size(date_m, 1);
index_here=ismember(date_used(:,1:2), date_m(i,:), 'rows');%找到每个月份在date_used中的位置
sst_month (:,:,i)=nanmean(sst_full(:, :,index_here), 3) ;%将对应数据沿着第三维平均
end
for i=1:size(date_y, 1);
index_here=ismember(date_used(:, 1), date_y(i, :), 'rows');%找到每个年份在date_used中的位置
sst_year(:,:,i)=nanmean(sst_ful1(:,:,index_here),3);%将对应数据沿着第三维平均
end
%3、空间格点处理
%改图的中心位置:把中心是大西洋的改到太平洋,即西经180W-0-东经180E改为0-东经-180-西经-0,即-180~180改为0~360
lon (lon<0)=360+(lon (lon<0));
[lon_re,i]=sort (lon) ;%sort把lon从小到大排序。lon_re是重新排序后的经度,i是重排序后各数据的位置
%海温场的经度也重新排
sst_re=sst_full(i,:,:);
sst_re_m=sst_month(i,:, :);
sst_re_y=sst_year(i,:, :);
%4、基础的统计学参数:平均数Mean、中位数Median、标准差STD,5%、50%、95%的分位数Quantile
% only for sst_re here:
sst_mean=nanmean(sst_re ,3);%nan移除缺失值,3是指沿着时间维度计算
sst_med=nanmedian(sst_re,3);
sst_std=nanstd(sst_re,0,3);
sst_5q=quantile(sst_re,0.05,3);
sst_95q=quantile(sst_re,0.95,3);
sst_50q=quantile(sst_re,0.5,3);
%计算结果可以画成六张图,每个结果都是二维图
figure('pos', [10 10 1500 650], 'color', 'k');
t=tiledlayout (2,3, 'TileSpacing','Compact', 'Padding', 'Compact');%2行3列的拼图
date_name={'sst_mean','sst_med','sst_std','sst_5q','sst_50q','sst_95q'};%cell数据储存六个变量名
title_name={'a)mean','b)median','c)std','d)5%','e)50%','f) 95%'};%cell数据储存六个标题
for i=1:6
nexttile;
m_proj('miller', 'lon', [0 360], 'lat', [-90 90]);
if i~=3;
m_contourf(lon_re, lat,(eval(data_name{i}))', linspace(-2,30,200), 'linestyle', 'none');
% m_contourf绘制色块图,eval把字符串data_name{i}转化成程序语言
else %对第三张图特殊处理,std数据大小跟别的图不一样,用的色块范围不一样
m_contourf(lon_re, lat, (eval(data_name{i}))', linspace (0, 12,200), 'linestyle', 'none');
end
m_coast('patch', [0.7 0.7 0.7], 'linewidth',2);
m_grid('fontsiz', 12, 'linestyle','none' ,'color','w');
colormap (m_colmap('jet')) ;
s=colorbar ('color', 'w');
title(s, '^{o}C', 'color','w');
if i~=3
caxis([0 32]);
else %第三张图
caxis ([0 8]);
end
ttl = title(title_name{i});
ttl.Units = 'Normalize';
ttl.Position (1) = 0;
tt1.HorizontalAlignment = 'left';
ttl.Color= 'w'
end
%5、季节性,here通过计算对应月份的全时间月平均来看季节性
load ('sst_re');
date_used=datevec(datenum (1979, 1, 1) :1 : datenum (2020, 12, 31)) ;
sst_season=NaN(size(sst_re,1), size(sst_re,2), 12);%应该得到每个月一张图,每个月一个二维矩阵
for i=1:12;
sst_season (:,:,i)=nanmean(sst_re(:,:, date_used(:,2)==i) ,3) ;%对sst_re月份为i的部分沿着时间平均
%date_used(:,2)==i应该是返回一组数,这组数字是所有i月份在date_used中的位置,也就是date_used第二列为i的位置
end
%12张图画一起
figure('pos', [10 10 1500 1200], 'color', 'k');
t=tiledlayout (3,4, 'TileSpacing','Compact', 'Padding', 'Compact');
title_full={'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'};
for i=1:12
ax=nexttile;
m_proj('miller', 'lon', [0 360], 'lat', [-90 90]);
m_contourf(lon_re, lat, (sst_season(:,:,i)-sst_mean)',linspace(-12, 12,300), 'linestyle', 'none');
%这里画的是各个月的平均与全平均的差值
m_coast('patch',[0.7 0.7 0.7], 'linewidth' ,2);
m_grid('fontsiz',12, 'linestyle','none', 'color', 'w');
colormap (m_colmap ('diverging'));
caxis ([-4 4]);
ttl = title(title_full{i});
ttl.Units = 'Normalize';
tt1. Position (1) = 0;
tt1.HorizontalAlignment = 'left';
ttl.Color= 'w';
if ismember(i, [12 4 8]);
s=colorbar (ax, 'color', 'w');
end
end
%6、差异值anomaly
%以年为周期的多样性叫做气候态或者季节性气候态~计算方法很多
%here气候态:按照最小时间单位求取年内每个时间点的平均值。日精度数据,也就是365天中的每一天都求多年这一天的平均值。月精度数据,1月的气候态就是所有年份1月的平均值。年数据没有气候态可算
%移除了季节性气候态之后的是anomaly
date_daily=datevec(datenum(1979,1,1):datenum(2020,12,31));
date_month=unique(date_daily(:,1:2),'rows'); %用unique找出年和月
unique_d=unique(date_daily(:,2:3),'rows');%用unique找出月和日 得到366*2
unique_m=(1:12)';
sst_anom_d=NaN(size(sst_re));%size(sst_re)是三维海温场,日数据
sst_anom_m=NaN(size(sst_re_m));%
for i=1: size(unique_d, 1); %size(unique_d, 1)=366
index_here=ismember(date_daily(:,2:3),unique_d(i,:),'rows');%找到对应位置,同一个日期
sst_anom_d(:,:,index_here)=sst_re(:,:,index_here)-nanmean(sst_re(:,:,index_here),3);
end
for i=1: size(unique_m, 1) ;
index_here=ismember(date_month(:, 2) , unique_m(i, :), 'rows');%找到对应位置,同一个月份
sst_anom_m(:,:,index_here)=sst_re_m(:,:,index_here)-nanmean(sst_re_m(:,:,index_here),3);
end
%7、空间平均
%权重参数cos纬度
[lat,lon]=meshgrid(lat,lon_re);
data_name={'sst_anom_d','sst_anom_m','sst_re_y'};
output_name={'local_d','local_m','local_y'};
for i=1:length(data_name);
eval([data_name{i} '=' data_name{i} '.*repmat(cosd(lat),1,1,size(' data_name{i} ',3));']) ; %先将输入的数据乘上cos纬度来权重
eval([output_name{i} '=NaN(size(' data_name{i} ',3),6);'])
eval(['d3=' data_name{i} ';']);
%permute函数改变数据维度位置,指定的顺序重新排列数组的维度
d2=permute(d3,[3 1 2]);
d2=reshape(d2,size(d2,1),size(d2,2)*size(d2,3));
%permute和reshape将本来维度为经度、纬度、时间的三维数据转换化成时间*空间的二维数据
%然后根据区域范围
%1 Indian Ocean
ts_here=nanmean(d2(:,lon(:)>=20 & lon(:)<=110 & lat(:)>=-20 & lat(:)<=30), 2);
eval([output_name{i} '(:,1)=ts_here;'])
%2 North Pacific
ts_here=nanmean(d2(:,lon(:)>=120 & lon(:)<=240 & lat(:)>=0 & lat(:)<=66.5), 2);
eval([output_name{i} '(:,2)=ts_here;'])
%3 South Pacific
ts_here=nanmean(d2(:,lon(:)>=140 & lon(:)<=300 & lat(:)>=-66.5 & lat(:)<=0), 2);
eval([output_name{i} '(:,3)=ts_here;'])
%4 North Atlantic
ts_here=nanmean(d2(:,lon(:)<=5 & lon(:)>=110 & lat(:)>=0 & lat(:)<=66.5), 2);
eval([output_name{i} '(:,4)=ts_here;'])
%5 Eq Pacific
ts_here=nanmean(d2(:,lon(:)>=120 & lon(:)<=280 & lat(:)>=-20 & lat(:)<=20), 2);
eval([output_name{i} '(:,5)=ts_here;'])
%6 global
ts_there=nanmean(d2(:,abs(lat(:))<66.5),2);
eval([output_name{i} '(:,6)=ts_there;'])
%把结果分别存到了'local_d','local_m','local_r'
%每个数据都是一个行数对应时间点数,列数为6分别对应六个空间
end
%8、线性趋势 常用函数:polyfit不全, regress, fitlm太全计算量大
% b = regress(y,X) 或者 [b, bint] = regress(y,X)
%y是响应变量。 X是解释变量,不是向量,至少两列,第一列必须全部为1。
%得到的b是系数们,第一个是常数项,第二个是一次项系数
%bint是对应参数95%的置信区间上下限,如果区间范围不包含0就说明参数在95%置信区间内统计学显著
%以下用月SST来做个线性趋势分析。遍历空间点,对每个位置都做了时间序列的线性回归
sst_anom_d=sst_anom_m;
coef_sst=NaN(size(sst_anom_d, 1),size(sst_anom_d,2));
cint_sst=NaN(size(sst_anom_d, 1), size(sst_anom_d,2),2) ;
time_full=(1:size(sst_anom_d,3))';
for i=1:size(sst_anom_d, 1);
tic
for j=1: size (sst_anom_d, 2);
ts_here=squeeze(sst_anom_d(i,j,:));
if nansum(isnan(ts_here))~=length(ts_here);
[b,bint]=regress(ts_here, [ones(length(ts_here), 1) time_full]);
coef_sst(1,j)=b(2); %得到的参数都储存在这
cint_sst(i,j,:)=bint(2,:); %得到的置信区间上下限
end
end
toc
end
%结果用点图表示,scatter
%9、滑动线性趋势,相当于计算变化的瞬时速度,在较短的一定时间区域内计算其趋势。类似于滑动平均,把要平均的步骤换成求趋势
%形成的结果可以是一张折线图,每点的趋势还可以带上个置信区间
%画图:循环6次把6条线画到同一张图
figure('pos', [10 10 1200 800]);
load('sst_moving_trend.mat');
legend_used={'Indian Ocean', 'North Pacific', 'South Pacific', 'North Atlantic','Equatorial Pacific', 'Global'};
color= [0 0.4470 0.7410;...
[0.8500 0.3250 0.0980];
[0.9290 0.6940 0.1250];
[0.4940 0.1840 0.5560];
[0.4660 0.6740 0.1880];
[0 0 0]];
for i=1:6;
h=errorbar((1979:2020)',mtrend(:,i)*120, (mint(:,i,2)-mint(:,i,1))*120./2, '-s', 'Markersize', 10, 'linewidth' ,2, 'markeredgecolor', color (i,:), 'markerfacecolor' ,color(i,:),'color' ,color(i,:));
%errorbar,绘制每条线及其点上的置信区间。根据输入的前两个变量产生线图。第三个变量指定置信区间宽度,就是/2的那块。
hold on
eval(['h' num2str(i) '=h'])
end
yline(0, '--');
legend([h1 h2 h3 h4 h5 h6], legend_used, 'location', 'best', 'fontsize', 12);
set (gca, 'fontsize', 16) ;
ylabel('^{o}C/decade');