在MATLAB中,当涉及到两个图和一个阈值线时,如何对一个不重叠的小区域进行着色,如图所示

In MATLAB, how to shade a small non overlapping area when two plots and a threshold line involved, as shown in figure attached

我需要对 Matlab 图中的区域进行阴影处理,高于阈值,突出显示的小区域,在蓝色曲线 (DC) 下方但在红色曲线 (PV) 之外,高于阈值;第 120

load('LP_DCHEMS_PV.mat','DC'); % DCCHEMS loaded
load('FifteenPercentHotDay.mat','PV') % Hot Day Case I, 15%
th=120;

plot(DC);
hold on
plot(PV);
yline(th);

当我使用以下命令时,它会遮蔽如图2所示的区域。必须在此行中更正某些内容:h2=area([y1(:) , (PV(:)-DC(:)).* (DC(:)>th )]); 如果有人可以指导,

y1=zeros(1,144);
y1(1,:)=th;
x=1:144;

    h2=area([y1(:) ,  (PV(:)-DC(:)).* (DC(:)>th )]);

    h2(1).FaceColor=[1 1 1];  % white
    h2(2).FaceColor=[0 0 1 ]; % blue
    hold on;
    plot(x,DC,'b',x,PV,'r');
    title('overlapped area ');
    
    xlim([1 144]);

考虑以下脚本:

clear; close all; clc;

% Generate dummy data
x  = 1:150;
y1 = exp(-(x(:)-35).^2/750)+1.4*exp(-(x(:)-100).^2/1000)+0.1*rand(150,1);
y2 = -1e-3*(x(:)-75).^2 + 1.85 + 0.1*rand(150,1); y2(y2<0) = 0;

% Set some threshold
threshold = 0.85;

% Create the plot
fig = figure(1); hold on; box on;

plot(x, y1, 'LineWidth', 1.5);
plot(x, y2, 'LineWidth', 1.5);
plot([x(1) x(end)], threshold*ones(1,2), 'k:', 'LineWidth', 1.5);

% Mark the areas and customise them (by changing FaceAlpha, as an example)
areas = MarkAreasInPlot(x, y1, y2, threshold, 'g');
for i = 1:length(areas)
    areas{i}.FaceAlpha = 0.5;
end

legend('y_1', 'y_2', 'threshold', 'Location', 'NorthWest');

在顶部,我生成了一些虚拟数据。 y1 值的生成大致基于 bla did in ,而 y2 只是一个抛物线函数(有一些失真),其中所有低于零的值都被过滤掉了。接下来我们做的是定义一些 threshold,它表示可能的最低边界。在此之后,我们简单地绘制数据和阈值。

然后,我调用 MarkAreasInPlot 函数:

function areas = MarkAreasInPlot(x, y1, y2, threshold, color)
% This function fills the areas for which the following two statements
% are true:
%   (1) y1 > y2
%   (2) y1 > threshold

    % Reshape arrays (to column vectors) if necessary
    x  = reshape(x, 1, []);
    y1 = reshape(y1, 1, []);
    y2 = reshape(y2, 1, []);
    
    % Create filter and find indices
    filter = (y1 > y2) & (y1 > threshold);
    idx = find(filter==1);
    
    % If nothing was found, return empty array
    if isempty(idx)
        areas = {};
        return;
    end

    % Determine the number of areas by looping over the indices (idx) and
    % checking if the next index follows up the previous one. If this is
    % not the case, it means that we are dealing with separate areas
    num_areas = 0;
    idx_areas = idx(1);
    
    for i = 1:length(idx)-1
        if(idx(i+1) ~= idx(i)+1)
            num_areas = num_areas + 1;
            idx_areas = [idx_areas, idx(i), idx(i+1)];
        end
    end
    idx_areas = [idx_areas, idx(end)];
    
    % Draw all areas
    areas = cell(num_areas+1, 1);
    
    for i = 1:2:2*(num_areas+1)
        % Determine span of indices for area
        idx_span = idx_areas(i):idx_areas(i+1);
        
        % Determine x- and y-coordinates
        x_area = x(idx_span);
        x_area = [x_area, flip(x_area)];
        
        y_top = y1(idx_span);
        y_bot = y2(idx_span);
        y_bot(y_bot < threshold) = threshold;
        
        y_area = [y_top, flip(y_bot)];
        
        % Fill the area
        areas{i} = fill(x_area, y_area, color, 'EdgeColor', 'None');
    end
end

这个函数的工作原理如下。首先,我们确保所有数据数组(xy1y2)都是列向量(这是为了防止它们是行向量时可能出现的问题)。随后,我们确定数据数组 y1 > y2y1 > threshold 的索引。请注意,filter 是一个逻辑数组,其中只有当上述两个语句为真时,元素才为 1。然后,我们确定 filter 中元素的索引,我们的值为 1。在数据数组的这些索引处,我们知道这两个陈述是正确的。当然,我们会检查语句在所有位置都为假的情况,在这种情况下我们不会绘制任何区域并且 return 一个空元胞数组。找到索引后,我们遍历它们并检查下一个索引 处的元素是否 不等于当前索引处的值加 1 的情况。如果我们发现这种情况,我们现在正在处理两个不同的区域。每当发生这种情况时,我们将这两个索引处的两个值存储在 idx_areas 中,并将区域数 (num_areas) 的计数器增加 1。执行此操作后,idx_areas 包含一个甚至数量的元素。我们知道我们需要在 idx_areas(n):idx_areas(n+1) 范围给定的索引处填充 y1max(y2, threshold) 之间的区域 n = 1, 3, 5, 7, ... (当然 n 的值取决于 num_areas 的值)。这正是我们在函数末尾所做的,使用 fill 函数。请注意,我们对应该填充的区域数量使用 for 循环,并将每个 fill 调用的句柄存储在 areas 元胞数组中,即 returned.

如果我 运行 顶部的脚本,我会得到以下输出: 如您所见,它正确地检测并填充了这些区域。然而,由于数据的离散性,可能会发生在一个区域的一侧有一小部分最终没有被完全填充: 这是不是错误!相反,这是因为 y1 的下一个数据点位于 下方 threshold,这意味着 MarkAreasInPlot 的第二个要求] 功能不成立!您可以尝试 'solve' 使用插值程序(以找到 y1 值恰好等于 threshold 的 x 值),但我认为这是不值得的努力(因为它只是一个非常的小块,没有填充)。

为了向您展示更多结果,我现在将 threshold 设置为 1.6,这样就不会检测到任何区域:

作为最后一个例子,我在 MarkAreasInPlot:

的调用中交换了 y1y2
areas = MarkAreasInPlot(x, y2, y1, threshold, 'g');

正如预期的那样,它现在填充了 y2 > y1y2 > threshold 所在的区域: