在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
这个函数的工作原理如下。首先,我们确保所有数据数组(x
、y1
和 y2
)都是列向量(这是为了防止它们是行向量时可能出现的问题)。随后,我们确定数据数组 y1 > y2
和 y1 > threshold
的索引。请注意,filter
是一个逻辑数组,其中只有当上述两个语句为真时,元素才为 1
。然后,我们确定 filter
中元素的索引,我们的值为 1
。在数据数组的这些索引处,我们知道这两个陈述是正确的。当然,我们会检查语句在所有位置都为假的情况,在这种情况下我们不会绘制任何区域并且 return 一个空元胞数组。找到索引后,我们遍历它们并检查下一个索引 处的元素是否 不等于当前索引处的值加 1 的情况。如果我们发现这种情况,我们现在正在处理两个不同的区域。每当发生这种情况时,我们将这两个索引处的两个值存储在 idx_areas
中,并将区域数 (num_areas
) 的计数器增加 1。执行此操作后,idx_areas
包含一个甚至数量的元素。我们知道我们需要在 idx_areas(n):idx_areas(n+1)
范围给定的索引处填充 y1
和 max(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
:
的调用中交换了 y1
和 y2
areas = MarkAreasInPlot(x, y2, y1, threshold, 'g');
正如预期的那样,它现在填充了 y2 > y1
和 y2 > threshold
所在的区域:
我需要对 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
这个函数的工作原理如下。首先,我们确保所有数据数组(x
、y1
和 y2
)都是列向量(这是为了防止它们是行向量时可能出现的问题)。随后,我们确定数据数组 y1 > y2
和 y1 > threshold
的索引。请注意,filter
是一个逻辑数组,其中只有当上述两个语句为真时,元素才为 1
。然后,我们确定 filter
中元素的索引,我们的值为 1
。在数据数组的这些索引处,我们知道这两个陈述是正确的。当然,我们会检查语句在所有位置都为假的情况,在这种情况下我们不会绘制任何区域并且 return 一个空元胞数组。找到索引后,我们遍历它们并检查下一个索引 处的元素是否 不等于当前索引处的值加 1 的情况。如果我们发现这种情况,我们现在正在处理两个不同的区域。每当发生这种情况时,我们将这两个索引处的两个值存储在 idx_areas
中,并将区域数 (num_areas
) 的计数器增加 1。执行此操作后,idx_areas
包含一个甚至数量的元素。我们知道我们需要在 idx_areas(n):idx_areas(n+1)
范围给定的索引处填充 y1
和 max(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
:
y1
和 y2
areas = MarkAreasInPlot(x, y2, y1, threshold, 'g');
正如预期的那样,它现在填充了 y2 > y1
和 y2 > threshold
所在的区域: