转载请注明本文链接
及文章作者:slandarer
有粉丝问我地图绘制如何添加NaN,大概像这样:
或者这样:
直接上干货:
原始绘图
假设我们有这样的一张图地图,注意运行本文代码需要去matlab官网下载Mapping Toolbox工具箱,但是其实原理都是相似的,如果M_map工具箱绘图也是类似的修改方法。
此外此处用到的nclCM函数如何获取请看这篇推送:MATLAB | MATLAB海洋、气象数据colormap配色补充包(NCL color tables)
或者去文末gitee仓库获取也行。
% 需要mapping toolbox
[Z,R]=readgeoraster('n39_w106_3arc_v2.dt1','OutputType','double');
key.GTModelTypeGeoKey=2;
key.GTRasterTypeGeoKey=2;
key.GeographicTypeGeoKey=4326;
filename='southboulder.tif';
geotiffwrite(filename,Z,R,'GeoKeyDirectoryTag',key)
usamap([39 40],[-106 -105])
g=geoshow(filename,'DisplayType','mesh');
% 190 300 363
colormap(nclCM(15,100))
cbHdl=colorbar();
1 方法一
1.1 添加NaN
对于这个工具箱的这种绘图方式,比如我们想将数值低于2100的数值改成NaN,首先将原始代码改成这样:
% 需要mapping toolbox
[Z,R]=readgeoraster('n39_w106_3arc_v2.dt1','OutputType','double');
key.GTModelTypeGeoKey=2;
key.GTRasterTypeGeoKey=2;
key.GeographicTypeGeoKey=4326;
filename='southboulder.tif';
% 设置NaN值
Z(Z<2100)=nan;
geotiffwrite(filename,Z,R,'GeoKeyDirectoryTag',key)
usamap([39 40],[-106 -105])
g=geoshow(filename,'DisplayType','mesh');
% 190 300 363
colormap(nclCM(15,100))
cbHdl=colorbar();
1.2 生成NaN图例
在绘图区域外绘制个小方块并生成图例:
% 绘制nan图例
nanHdl=fill([0,1,1,0]-1000,[0,0,1,1]-1000,[240,240,240]./255,...
'EdgeColor','none','EdgeColor',[160,160,160]./255,'LineWidth',1.2,...
'DisplayName',' NaN');
lgdHdl=legend(nanHdl);
1.3 修改图例位置
将上一步的代码改成这样(可能大家绘图比例不同需要根据实际情况微调):
% 修改colorbar位置
tPosition=cbHdl.Position;
cbHdl.Position(1)=cbHdl.Position(1)+tPosition(3).*1.5;
cbHdl.Position(2)=cbHdl.Position(2)+tPosition(4)./10;
cbHdl.Position(4)=cbHdl.Position(4)-tPosition(4)./10;
% 绘制nan图例
nanHdl=fill([0,1,1,0]-1000,[0,0,1,1]-1000,[240,240,240]./255,...
'EdgeColor','none','EdgeColor',[160,160,160]./255,'LineWidth',1.2,...
'DisplayName',' NaN');
lgdHdl=legend(nanHdl);
lgdHdl.Box='off';
lgdHdl.ItemTokenSize=[16,16];
lgdHdl.Position(1)=tPosition(1)+tPosition(3).*1.3;
lgdHdl.Position(2)=tPosition(2);
1.4 方法一完整代码
% 需要mapping toolbox
[Z,R]=readgeoraster('n39_w106_3arc_v2.dt1','OutputType','double');
key.GTModelTypeGeoKey=2;
key.GTRasterTypeGeoKey=2;
key.GeographicTypeGeoKey=4326;
filename='southboulder.tif';
% 设置NaN值
Z(Z<2100)=nan;
geotiffwrite(filename,Z,R,'GeoKeyDirectoryTag',key)
usamap([39 40],[-106 -105])
g=geoshow(filename,'DisplayType','mesh');
% 190 300 363
colormap(nclCM(15,100))
cbHdl=colorbar();
% 修改colorbar位置
tPosition=cbHdl.Position;
cbHdl.Position(1)=cbHdl.Position(1)+tPosition(3).*1.5;
cbHdl.Position(2)=cbHdl.Position(2)+tPosition(4)./10;
cbHdl.Position(4)=cbHdl.Position(4)-tPosition(4)./10;
% 绘制nan图例
nanHdl=fill([0,1,1,0]-1000,[0,0,1,1]-1000,[240,240,240]./255,...
'EdgeColor','none','EdgeColor',[160,160,160]./255,'LineWidth',1.2,...
'DisplayName',' NaN');
lgdHdl=legend(nanHdl);
lgdHdl.Box='off';
lgdHdl.ItemTokenSize=[16,16];
lgdHdl.Position(1)=tPosition(1)+tPosition(3).*1.3;
lgdHdl.Position(2)=tPosition(2);
2 方法二
2.1 重设范围
这里假设NaN值被存为了-999,我们将将NaN部分数值设置为非NaN值最小值-1/10的非NaN值数值范围,这样colorbar灰色部分的长度就会是不是灰色的部分长度的1/10。
% 需要mapping toolbox
[Z,R]=readgeoraster('n39_w106_3arc_v2.dt1','OutputType','double');
key.GTModelTypeGeoKey=2;
key.GTRasterTypeGeoKey=2;
key.GeographicTypeGeoKey=4326;
filename='southboulder.tif';
% 假设NaN值被存为-999
Z(Z<2100)=-999;
% 将其数值设置为非NaN值最小值-1/10的非NaN值数值范围
% 这样colorbar灰色部分的长度就会是不是灰色的部分长度的1/10;
Z(Z==-999)=nan;minVal=min(min(Z));
Z(isnan(Z))=min(min(Z))-(max(max(Z))-min(min(Z)))./10;
geotiffwrite(filename,Z,R,'GeoKeyDirectoryTag',key)
usamap([39 40],[-106 -105])
g=geoshow(filename,'DisplayType','mesh');
2.2 修改配色
往colormap前面续加上一段等长的灰色:
CList=nclCM(15,100);
CList=[(CList(:,1).*0+1)*[240,240,240]./255;CList];
colormap(CList)
cbHdl=colorbar();
2.3 中心移动到NaN与数值交界处
使用我自己写的setPivot
函数:
function setPivot(varargin)
% @author:slandarer
if nargin==0
ax=gca;pivot=0;
else
if isa(varargin{1},'matlab.graphics.axis.Axes')
ax=varargin{1};
if nargin>1
pivot=varargin{2};
else
pivot=0;
end
else
ax=gca;pivot=varargin{1};
end
end
try
CLimit=get(ax,'CLim');
catch
end
try
CLimit=get(ax,'ColorLimits');
catch
end
% CMap=get(ax,'Colormap');
CMap=colormap(ax);
CLen=[pivot-CLimit(1),CLimit(2)-pivot];
if all(CLen>0)
[CV,CInd]=sort(CLen);
CRatio=round(CV(1)/CV(2).*300)./300;
CRatioCell=split(rats(CRatio),'/');
if length(CRatioCell)>1
Ratio=[str2double(CRatioCell{1}),str2double(CRatioCell{2})];
Ratio=Ratio(CInd);
N=size(CMap,1);
CList1=CMap(1:floor(N/2),:);
CList2=CMap((floor(N/2)+1):end,:);
if mod(N,2)~=0
CList3=CList2(1,:);CList2(1,:)=[];
CInd1=kron((1:size(CList1,1))',ones(Ratio(1)*2,1));
CInd2=kron((1:size(CList2,1))',ones(Ratio(2)*2,1));
CMap=[CList1(CInd1,:);repmat(CList3,[Ratio(1)+Ratio(2),1]);CList2(CInd2,:)];
else
CInd1=kron((1:size(CList1,1))',ones(Ratio(1),1));
CInd2=kron((1:size(CList2,1))',ones(Ratio(2),1));
CMap=[CList1(CInd1,:);CList2(CInd2,:)];
end
% set(ax,'Colormap',CMap)
colormap(ax,CMap);
end
end
end
中心移动到NaN与数值交界处:
% 调整配色范围
setPivot(minVal)
2.4 修改图例标签
% 调整colorbar标签文字
cbHdl.TickLabels{cbHdl.Ticks<minVal}='';
cbHdl.TickLabels{1}='NaN';
2.5 方法二完整代码
% 需要mapping toolbox
[Z,R]=readgeoraster('n39_w106_3arc_v2.dt1','OutputType','double');
key.GTModelTypeGeoKey=2;
key.GTRasterTypeGeoKey=2;
key.GeographicTypeGeoKey=4326;
filename='southboulder.tif';
% 假设NaN值被存为-999
Z(Z<2100)=-999;
% 将其数值设置为非NaN值最小值-1/10的非NaN值数值范围
% 这样colorbar灰色部分的长度就会是不是灰色的部分长度的1/10;
Z(Z==-999)=nan;minVal=min(min(Z));
Z(isnan(Z))=min(min(Z))-(max(max(Z))-min(min(Z)))./10;
geotiffwrite(filename,Z,R,'GeoKeyDirectoryTag',key)
usamap([39 40],[-106 -105])
g=geoshow(filename,'DisplayType','mesh');
% 往colormap前面续加上一段等长的灰色
CList=nclCM(15,100);
CList=[(CList(:,1).*0+1)*[240,240,240]./255;CList];
colormap(CList)
cbHdl=colorbar();
% 调整配色范围
setPivot(minVal)
% 调整colorbar标签文字
cbHdl.TickLabels{cbHdl.Ticks<minVal}='';
cbHdl.TickLabels{1}='NaN';
完
以上已经是完整代码,懒得一一搜集文件可以从以下Gitee仓库获取,setPivot函数和nclCM工具包我也一块扔文件夹啦:
https://gitee.com/slandarer/PLTreprint/