如何创建"skill-bias diagram"(气象学)?

How to create a "skill-bias diagram" (meteorology)?

在我的研究领域(气象学),通常会生成图内图。

有关它的更多信息可以found here

每条线都连接了具有以下特征的数据点:

  1. 一个介于 0 和 1 之间的 x 值(图表中不应显示大于 1 的值)。
  2. 一个 y 值,介于 0 和 1 之间。
  3. PSS 值,介于 1 和 -1 之间。
  4. 频率偏移值,范围从0到+∞,但不显示大于4的值。
  5. 误报率 (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

我想我得到了你想要的,但在你转到下面的代码之前,请注意以下几点:

  1. 我不需要 link 中的任何功能(而且我不知道它们的作用)。
  2. 我也没有真正使用数据中的 xy 列,它们是 PSSB 的冗余坐标。
  3. 我将你数据中的所有 '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 有了标签的位置,就像我在上面使用的那样。