如何创建"skill-bias diagram"(气象学)?
How to create a "skill-bias diagram" (meteorology)?
在我的研究领域(气象学),通常会生成图内图。
有关它的更多信息可以found here。
每条线都连接了具有以下特征的数据点:
- 一个介于 0 和 1 之间的 x 值(图表中不应显示大于 1 的值)。
- 一个 y 值,介于 0 和 1 之间。
- PSS 值,介于 1 和 -1 之间。
- 频率偏移值,范围从0到+∞,但不显示大于4的值。
- 误报率 (FAR) 值,范围从 0.0 到 0.9。对于任何给定线上的每个数据点,误报率值保持在特定值不变。
编辑:为了让事情变得更具体,我在图表上画了一个粉红色的点。该点表示 x=0.81、y=0.61、PSS=-0.2、B=3.05、FAR=0.8 的数据点。
我正在尝试在 MATLAB 中重现类似的东西。谷歌搜索出现了很多答案,例如 this,其中包含插图而不是我正在寻找的内容。
我将数据组织成一个 3D 数组,其中每一页都指的是不同级别的误报率。 FAR 为 0.8 的页面(数据here)是这样开始的
然后 3D 阵列上还有其他页面专门介绍 FAR 0.7、0.6 等。
问题
1. 甚至可以在 MATLAB 中创建这样的图形吗?
2. 如果是,我应该使用什么功能,我应该采取什么方法?编辑:我有工作代码(下面)使用线性 plot
函数创建了一个有点相似的图形,但是这个函数的文档没有说明在另一个图形中插入图形的任何方法。我不确定这段代码有多大帮助,但已将其插入以回应反对者。
H = [0:0.01:1];
figure; hold on
fill([0 1 1],[0 0 1],[0 0.2 0.4]) % Deep blue
fill([0 1 0],[0 1 1],[0.4 0 0]) % Purple
low_colours = {[0 0.501 1],[0 0.8 0.4], [0.4 0.8 0], [0.8 0.8 0]};
high_colours = {[0.6 0 0],[0.8 0 0], [1 0.5019 0], [0.988 0.827 0.196]};
colour_counter = 0;
for ii = -0.8:0.2:0
colour_counter = colour_counter + 1;
if colour_counter < 5
colour_now = low_colours{colour_counter};
end
ORSS = ones(1,size(H,2))*ii;
F = (H .* (1-ORSS)) ./ ((1-2.*H) .* ORSS + 1);
plot(F,H)
fill(F,H,colour_now);
end
colour_counter = 0;
for ii = 0.8:-0.2:0
colour_counter = colour_counter + 1;
if colour_counter < 5
colour_now = high_colours{colour_counter};
end
ORSS = ones(1,size(H,2))*ii;
F = (H .* (1-ORSS)) ./ ((1-2.*H) .* ORSS + 1);
plot(F,H)
fill(F,H,colour_now);
end
我想我得到了你想要的,但在你转到下面的代码之前,请注意以下几点:
- 我不需要 link 中的任何功能(而且我不知道它们的作用)。
- 我也没有真正使用数据中的
x
和 y
列,它们是 PSS
和 B
的冗余坐标。
- 我将你数据中的所有 'pages' 连接成一个长 table(下面的
FAR
),有 5 列(FAR,x,y,PSS,FB
)。
如果您仔细查看数据,您会发现一些本应在图中着色的区域在其中没有表示(即没有值)。因此,为了将颜色插入到那里,我们需要添加角:
FAR{end+1,:} = [0.8 0 0 0 4];
FAR{end+1,:} = [0.9 0 0 -0.66 3.33];
FAR{end+1,:} = [1 0 0 0 0];
FAR{end+1,:} = [1 0 0 -1 3];
接下来,该过程分为 2 个部分。首先,我们为每个变量创建一个矩阵,按相应的 FAR
值在列中排序,例如,在 PSS
矩阵中,第一列是所有 PSS 值,其中 FAR 为 0,第二列是 FAR 为 0.1 的所有 PSS 值,依此类推。我们为 FAR(F
)、PSS 和 FreqBias(B
) 制作这样的矩阵,并用 NaN 初始化它们,这样我们就可以拥有具有不同数量值的列:
F = nan(max(histcounts(FAR.FAR,10)),10);
PSS = F;
B = F;
c = 1;
f = unique(FAR.FAR).';
for k = f
valid = FAR.FAR==k & FAR.x<=1;
B(1:sum(valid),c) = FAR.FB(valid);
B(sum(valid):end,c) = B(sum(valid),c);
PSS(1:sum(valid),c) = FAR.PSS(valid);
PSS(sum(valid):end,c) = PSS(sum(valid),c);
F(:,c) = k;
c = c+1;
end
然后我们设置颜色图的颜色(我部分取自您),并设置标签位置:
colors = [0 0.2 0.4
0 0.501 1;
0 0.8 0.4;
0.4 0.8 0;
0.8 0.8 0;
0.988 0.827 0.196;
1 0.5019 0;
0.8 0 0;
0.6 0 0.2;
0.4 0.1 0.5];
label_pos =[0.89 0.77
1.01 0.74
1.14 0.69
1.37 0.64
1.7 0.57
2.03 0.41
2.65 0.18
2.925 -0.195
2.75 -0.55];
然后我们使用 contourf
将所有内容绘制在一起,并设置各种属性以使其看起来不错:
[C,h] = contourf(B,PSS,F);
xlim([0 4])
ylim([-1 1])
colormap(colors)
caxis([0 1])
xlabel('Frequency Bias B')
ylabel('Pierce Skill Score PSS')
title('False Alarm Ratio')
ax = h.Parent;
ax.XTick = 0:4;
ax.YTick = -1:0.5:1;
ax.FontSize = 20;
for k = 1:numel(f)-2
text(label_pos(k,1),label_pos(k,2),num2str(f(k+1)),...
'FontSize',12+k)
end
结果如下:
获取标签位置:
如果您想知道获取变量 label_pos
的快速方法是什么,那么我是这样做的...
你 运行 上面的代码没有最后一个 for
循环。然后你运行下面的代码:
clabel(C,'manual')
f = gcf;
label_pos = zeros(numel(f.Children.Children)-1,2);
for k = 1:2:size(label_pos,1)
label_pos(k,:) = f.Children.Children(k).Position(1:2);
end
label_pos(2:2:size(label_pos,1),:) = [];
在第一行之后脚本将暂停,您将在命令 window:
中看到此消息
Carefully select contours for labeling.
When done, press RETURN while the Graph window is the active window.
单击要添加标签的图形,然后按 Enter。
而已!现在变量 label_pos
有了标签的位置,就像我在上面使用的那样。
在我的研究领域(气象学),通常会生成图内图。
有关它的更多信息可以found here。
每条线都连接了具有以下特征的数据点:
- 一个介于 0 和 1 之间的 x 值(图表中不应显示大于 1 的值)。
- 一个 y 值,介于 0 和 1 之间。
- PSS 值,介于 1 和 -1 之间。
- 频率偏移值,范围从0到+∞,但不显示大于4的值。
- 误报率 (FAR) 值,范围从 0.0 到 0.9。对于任何给定线上的每个数据点,误报率值保持在特定值不变。
编辑:为了让事情变得更具体,我在图表上画了一个粉红色的点。该点表示 x=0.81、y=0.61、PSS=-0.2、B=3.05、FAR=0.8 的数据点。
我正在尝试在 MATLAB 中重现类似的东西。谷歌搜索出现了很多答案,例如 this,其中包含插图而不是我正在寻找的内容。
我将数据组织成一个 3D 数组,其中每一页都指的是不同级别的误报率。 FAR 为 0.8 的页面(数据here)是这样开始的
然后 3D 阵列上还有其他页面专门介绍 FAR 0.7、0.6 等。
问题
1. 甚至可以在 MATLAB 中创建这样的图形吗?
2. 如果是,我应该使用什么功能,我应该采取什么方法?编辑:我有工作代码(下面)使用线性 plot
函数创建了一个有点相似的图形,但是这个函数的文档没有说明在另一个图形中插入图形的任何方法。我不确定这段代码有多大帮助,但已将其插入以回应反对者。
H = [0:0.01:1];
figure; hold on
fill([0 1 1],[0 0 1],[0 0.2 0.4]) % Deep blue
fill([0 1 0],[0 1 1],[0.4 0 0]) % Purple
low_colours = {[0 0.501 1],[0 0.8 0.4], [0.4 0.8 0], [0.8 0.8 0]};
high_colours = {[0.6 0 0],[0.8 0 0], [1 0.5019 0], [0.988 0.827 0.196]};
colour_counter = 0;
for ii = -0.8:0.2:0
colour_counter = colour_counter + 1;
if colour_counter < 5
colour_now = low_colours{colour_counter};
end
ORSS = ones(1,size(H,2))*ii;
F = (H .* (1-ORSS)) ./ ((1-2.*H) .* ORSS + 1);
plot(F,H)
fill(F,H,colour_now);
end
colour_counter = 0;
for ii = 0.8:-0.2:0
colour_counter = colour_counter + 1;
if colour_counter < 5
colour_now = high_colours{colour_counter};
end
ORSS = ones(1,size(H,2))*ii;
F = (H .* (1-ORSS)) ./ ((1-2.*H) .* ORSS + 1);
plot(F,H)
fill(F,H,colour_now);
end
我想我得到了你想要的,但在你转到下面的代码之前,请注意以下几点:
- 我不需要 link 中的任何功能(而且我不知道它们的作用)。
- 我也没有真正使用数据中的
x
和y
列,它们是PSS
和B
的冗余坐标。 - 我将你数据中的所有 'pages' 连接成一个长 table(下面的
FAR
),有 5 列(FAR,x,y,PSS,FB
)。
如果您仔细查看数据,您会发现一些本应在图中着色的区域在其中没有表示(即没有值)。因此,为了将颜色插入到那里,我们需要添加角:
FAR{end+1,:} = [0.8 0 0 0 4];
FAR{end+1,:} = [0.9 0 0 -0.66 3.33];
FAR{end+1,:} = [1 0 0 0 0];
FAR{end+1,:} = [1 0 0 -1 3];
接下来,该过程分为 2 个部分。首先,我们为每个变量创建一个矩阵,按相应的 FAR
值在列中排序,例如,在 PSS
矩阵中,第一列是所有 PSS 值,其中 FAR 为 0,第二列是 FAR 为 0.1 的所有 PSS 值,依此类推。我们为 FAR(F
)、PSS 和 FreqBias(B
) 制作这样的矩阵,并用 NaN 初始化它们,这样我们就可以拥有具有不同数量值的列:
F = nan(max(histcounts(FAR.FAR,10)),10);
PSS = F;
B = F;
c = 1;
f = unique(FAR.FAR).';
for k = f
valid = FAR.FAR==k & FAR.x<=1;
B(1:sum(valid),c) = FAR.FB(valid);
B(sum(valid):end,c) = B(sum(valid),c);
PSS(1:sum(valid),c) = FAR.PSS(valid);
PSS(sum(valid):end,c) = PSS(sum(valid),c);
F(:,c) = k;
c = c+1;
end
然后我们设置颜色图的颜色(我部分取自您),并设置标签位置:
colors = [0 0.2 0.4
0 0.501 1;
0 0.8 0.4;
0.4 0.8 0;
0.8 0.8 0;
0.988 0.827 0.196;
1 0.5019 0;
0.8 0 0;
0.6 0 0.2;
0.4 0.1 0.5];
label_pos =[0.89 0.77
1.01 0.74
1.14 0.69
1.37 0.64
1.7 0.57
2.03 0.41
2.65 0.18
2.925 -0.195
2.75 -0.55];
然后我们使用 contourf
将所有内容绘制在一起,并设置各种属性以使其看起来不错:
[C,h] = contourf(B,PSS,F);
xlim([0 4])
ylim([-1 1])
colormap(colors)
caxis([0 1])
xlabel('Frequency Bias B')
ylabel('Pierce Skill Score PSS')
title('False Alarm Ratio')
ax = h.Parent;
ax.XTick = 0:4;
ax.YTick = -1:0.5:1;
ax.FontSize = 20;
for k = 1:numel(f)-2
text(label_pos(k,1),label_pos(k,2),num2str(f(k+1)),...
'FontSize',12+k)
end
结果如下:
获取标签位置:
如果您想知道获取变量 label_pos
的快速方法是什么,那么我是这样做的...
你 运行 上面的代码没有最后一个 for
循环。然后你运行下面的代码:
clabel(C,'manual')
f = gcf;
label_pos = zeros(numel(f.Children.Children)-1,2);
for k = 1:2:size(label_pos,1)
label_pos(k,:) = f.Children.Children(k).Position(1:2);
end
label_pos(2:2:size(label_pos,1),:) = [];
在第一行之后脚本将暂停,您将在命令 window:
中看到此消息Carefully select contours for labeling. When done, press RETURN while the Graph window is the active window.
单击要添加标签的图形,然后按 Enter。
而已!现在变量 label_pos
有了标签的位置,就像我在上面使用的那样。