MATLAB | 绘图复刻(十三) | 带NaN图例的地图绘制

有粉丝问我地图绘制如何添加NaN,大概像这样:

或者这样:

直接上干货:


原始绘图

假设我们有这样的一张图地图,注意运行本文代码需要去matlab官网下载Mapping Toolbox工具箱,但是其实原理都是相似的,如果M_map工具箱绘图也是类似的修改方法。

此外此处用到的nclCM函数如何获取请看这篇文章:https://slandarer.blog.csdn.net/article/details/127935365

或者去文末gitee仓库获取也行。

matlab 复制代码
% 需要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,首先将原始代码改成这样:

matlab 复制代码
% 需要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图例

在绘图区域外绘制个小方块并生成图例:

matlab 复制代码
% 绘制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 修改图例位置

将上一步的代码改成这样(可能大家绘图比例不同需要根据实际情况微调):

matlab 复制代码
% 修改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 方法一完整代码

matlab 复制代码
% 需要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。

matlab 复制代码
% 需要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前面续加上一段等长的灰色:

matlab 复制代码
CList=nclCM(15,100);
CList=[(CList(:,1).*0+1)*[240,240,240]./255;CList];
colormap(CList)
cbHdl=colorbar();

2.3 中心移动到NaN与数值交界处

使用我自己写的setPivot函数:

matlab 复制代码
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与数值交界处:

matlab 复制代码
% 调整配色范围
setPivot(minVal)

2.4 修改图例标签

matlab 复制代码
% 调整colorbar标签文字
cbHdl.TickLabels{cbHdl.Ticks<minVal}='';
cbHdl.TickLabels{1}='NaN';

2.5 方法二完整代码

matlab 复制代码
% 需要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工具包我也一块扔文件夹啦:

相关推荐
lly2024064 分钟前
Docker 安装 Node.js
开发语言
明天会有多晴朗10 分钟前
C语言入门教程(第6讲):函数——让程序学会“分工合作”的魔法
c语言·开发语言·算法
泽虞14 分钟前
《Qt应用开发》笔记p3
linux·开发语言·数据库·c++·笔记·qt·面试
晓风残月淡15 分钟前
JVM字节码与类的加载(一):类的加载过程详解
开发语言·jvm·python
XXYBMOOO18 分钟前
如何自定义 Qt 日志处理并记录日志到文件
开发语言·数据库·qt
知南x21 分钟前
【QT界面设计学习篇】qt快速开发技巧
开发语言·qt
hqyjzsb24 分钟前
2025 年项目管理转型白皮书:AI 驱动下的能力重构与跨域突破
开发语言·人工智能·重构·产品经理·编程语言·caie
奶茶树37 分钟前
【C++】12.多态(超详解)
开发语言·c++
草莓熊Lotso38 分钟前
《算法闯关指南:优选算法--二分查找》--17.二分查找(附二分查找算法简介),18. 在排序数组中查找元素的第一个和最后一个位置
开发语言·c++·算法
努力努力再努力wz43 分钟前
【C++进阶系列】:万字详解特殊类以及设计模式
java·linux·运维·开发语言·数据结构·c++·设计模式