【问题标题】:Matlab: patch area between two curves which depend on the curves valuesMatlab:两条曲线之间的补丁区域取决于曲线值
【发布时间】:2019-09-04 06:54:53
【问题描述】:

我正在尝试根据取决于曲线值的函数填充两条曲线之间的区域。

这是我到目前为止所做的代码

    i=50;
cc = @(xx,x,y) 1./(1+(exp(-xx)/(exp(-x)-exp(-y))));
n_vec = 2:0.1:10;
x_vec = linspace(2,10,length(n_vec));
y_vec = abs(sin(n_vec));
N=[n_vec,fliplr(n_vec)];  
X=[x_vec,fliplr(y_vec)];
figure(1)
subplot(2,1,1)
hold on
plot(n_vec,x_vec,n_vec,y_vec)
hp = patch(N,X,'b')
plot([n_vec(i) n_vec(i)],[x_vec(i),y_vec(i)],'linewidth',5)
xlabel('n'); ylabel('x')
subplot(2,1,2)

xx = linspace(y_vec(i),x_vec(i),100);
plot(xx,cc(xx,y_vec(i),x_vec(i)))
xlabel('x'); ylabel('c(x)')

此代码生成以下图表

我添加的颜色代码表示两条曲线之间区域的每条线(沿 x 轴上的一点处的 y 轴)应采用的颜色编码。

总的来说,整个区域应该用渐变色填充,这取决于曲线的值。

我已协助解决以下先前的问题,但无法解决解决方案

MATLAB fill area between lines

Patch circle by a color gradient

Filling between two curves, according to a colormap given by a function MATLAB

注意:曲线的函数形式并不重要,我更喜欢一个答案,它指的是两个由曲线组成的通用数组。

【问题讨论】:

    标签: matlab plot matlab-figure colormap


    【解决方案1】:

    冲浪绘图法

    1. 与散点图方法相同,即生成点网格。
    y = [x_vec(:); y_vec(:)];
    resolution = [500,500];
    px = linspace(min(n_vec), max(n_vec), resolution(1));
    py = linspace(min(y), max(y), resolution(2));
    [px, py] = meshgrid(px, py);
    
    1. 生成逻辑数组,指示点是否在多边形内,但无需提取点:
    in = inpolygon(px, py, N, X);
    
    1. 生成 Z。Z 的值指示用于曲面图的颜色。因此,它是使用您的函数cc 生成的。
    pz = 1./(1+(exp(-py_)/(exp(-y_vec(i))-exp(-x_vec(i)))));
    pz = repmat(pz',1,resolution(2));
    
    1. 将感兴趣区域之外的点的 Z 值设置为 NaN,这样 MATLAB 就不会绘制它们。
    pz(~in) = nan;
    
    1. 生成有界颜色图(如果要使用完整颜色范围,请删除)
    % generate colormap
    c = jet(100);
    [s,l] = bounds(pz,'all');
    s = round(s*100);
    l = round(l*100);
    if s ~= 0
        c(1:s,:) = [];
    end
    if l ~= 100
        c(l:100,:) = [];
    end
    
    1. 最后,情节。
    figure;
    colormap(jet)
    surf(px,py,pz,'edgecolor','none');
    view(2) % x-y view
    

    随意转动图像,看看它在 Z 维度上的样子 - 漂亮:)


    要测试的完整代码:

    i=50;
    cc = @(xx,x,y) 1./(1+(exp(-xx)/(exp(-x)-exp(-y))));
    n_vec = 2:0.1:10;
    x_vec = linspace(2,10,length(n_vec));
    y_vec = abs(sin(n_vec));
    
    % generate grid
    y = [x_vec(:); y_vec(:)];
    resolution = [500,500];
    px_ = linspace(min(n_vec), max(n_vec), resolution(1));
    py_ = linspace(min(y), max(y), resolution(2));
    [px, py] = meshgrid(px_, py_);
    
    % extract points
    in = inpolygon(px, py, N, X);
    
    % generate z
    pz = 1./(1+(exp(-py_)/(exp(-y_vec(i))-exp(-x_vec(i)))));
    pz = repmat(pz',1,resolution(2));
    pz(~in) = nan;
    
    % generate colormap
    c = jet(100);
    [s,l] = bounds(pz,'all');
    s = round(s*100);
    l = round(l*100);
    if s ~= 0
        c(1:s,:) = [];
    end
    if l ~= 100
        c(l:100,:) = [];
    end
    
    % plot
    figure;
    colormap(c)
    surf(px,py,pz,'edgecolor','none');
    view(2)
    

    【讨论】:

      【解决方案2】:

      您可以使用imagesc 和网格网格。查看代码中的 cmets 以了解发生了什么。

      对数据进行下采样

      % your initial upper and lower boundaries
      n_vec_long = linspace(2,10,1000000);
      
      f_ub_vec_long = linspace(2, 10, length(n_vec_long));
      f_lb_vec_long = abs(sin(n_vec_long));
      
      % downsample
      n_vec = linspace(n_vec_long(1), n_vec_long(end), 1000); % for example, only 1000 points
      
      % get upper and lower boundary values for n_vec
      f_ub_vec = interp1(n_vec_long, f_ub_vec_long, n_vec); 
      f_lb_vec = interp1(n_vec_long, f_lb_vec_long, n_vec); 
      
      % x_vec for the color function
      x_vec = 0:0.01:10;
      

      绘制数据

      % create a 2D matrix with N and X position
      [N, X] = meshgrid(n_vec, x_vec);
      
      % evaluate the upper and lower boundary functions at n_vec
      % can be any function at n you want (not tested for crossing boundaries though...)
      f_ub_vec = linspace(2, 10, length(n_vec));
      f_lb_vec = abs(sin(n_vec));
      
      % make these row vectors into matrices, to create a boolean mask
      F_UB = repmat(f_ub_vec, [size(N, 1) 1]);
      F_LB = repmat(f_lb_vec, [size(N, 1) 1]);
      
      % create a mask based on the upper and lower boundary functions
      mask = true(size(N));
      mask(X > F_UB | X < F_LB) = false;
      
      % create data matrix
      Z = NaN(size(N));
      
      % create function that evaluates the color profile for each defined value 
      % in the vectors with the lower and upper bounds
      zc = @(X, ub, lb) 1 ./ (1 + (exp(-X) ./ (exp(-ub) - exp(-lb))));
      CData = zc(X, f_lb_vec, f_ub_vec); % create the c(x) at all X
      
      % put the CData in Z, but only between the lower and upper bound.
      Z(mask) = CData(mask);
      
      % normalize Z along 1st dim
      Z = normalize(Z, 1, 'range'); % get all values between 0 and 1 for colorbar
      
      % draw a figure!
      figure(1); clf;
      ax = axes;                          % create some axes
      sc = imagesc(ax, n_vec, x_vec, Z);  % plot the data
      ax.YDir = 'normal' % set the YDir to normal again, imagesc reverses it by default;
      
      xlabel('n')
      ylabel('x')
      

      这看起来有点像你想要的,但让我们去掉边界外的蓝色区域。这可以通过创建一个“alpha 蒙版”来完成,即将之前定义的mask 之外的所有像素的 alpha 值设置为 0:

      figure(2); clf;
      ax = axes;                          % create some axes
      hold on;
      sc = imagesc(ax, n_vec, x_vec, Z);  % plot the data
      ax.YDir = 'normal' % set the YDir to normal again, imagesc reverses it by default;
      
      % set a colormap 
      colormap(flip(hsv(100)))
      
      % set alpha for points outside mask
      Calpha = ones(size(N));
      Calpha(~mask) = 0;
      sc.AlphaData = Calpha;
      
      % plot the other lines
      plot(n_vec, f_ub_vec, 'k', n_vec, f_lb_vec, 'k' ,'linewidth', 1)
      
      % set axis limits
      xlim([min(n_vec), max(n_vec)])
      ylim([min(x_vec), max(x_vec)])
      

      【讨论】:

      • 感谢您的回答,但这对我帮助不大。首先,代码不能应用于大型数据集。其次,也是最重要的一点,颜色渐变应该只在两条曲线之间的区域之间。这意味着两条曲线之间的距离定义了渐变的锐利程度。在您的结果中,所有 n 值都是相同的
      • @jarhead 我明白了,它目前只使用下边界。你能在你的问题中说明你想用什么样的数据集(维度,生成示例数据的代码......)。
      • @jarhead 看到更新,颜色值遵循曲线。如果这仍然不是您想要的,您能否更清楚地说明您想要实现的目标? c(x) 图中的颜色条表明您想要一个线性增加的颜色图,而曲线本身不是。
      • 这里可以上传MAT数据文件吗,我可以发个样本。
      • @jarhead 好吧,确实将其应用于该长度的向量是行不通的,但是您的屏幕上一个方向上也没有那么多像素,因此您将无法无论如何都要看到细节。您可以对数据进行插值/下采样,我会将其添加到答案中。
      【解决方案3】:

      曲线的函数形式并不重要,我更喜欢一个答案,它指的是由曲线组成的两个通用数组。

      使用patch 很难做到这一点。

      但是,您可以使用散点图用彩色点“填充”该区域。或者,可能更好的是,使用 surf 绘图并使用 cc 函数生成 z 坐标(请参阅我的单独解决方案)。

      散点图法

      1. 首先,在两条曲线边界的矩形空间内制作一个点网格(分辨率 500*500)。
      y = [x_vec(:); y_vec(:)];
      resolution = [500,500];
      px = linspace(min(n_vec), max(n_vec), resolution(1));
      py = linspace(min(y), max(y), resolution(2));
      [px, py] = meshgrid(px, py);
      
      figure; 
      scatter(px(:), py(:), 1, 'r');
      

      点网格的无趣图:

      1. 接下来,提取两条曲线定义的多边形内的点。
      in = inpolygon(px, py, N, X);
      px = px(in);
      py = py(in);
      
      hold on;
      scatter(px, py, 1, 'k');
      

      黑点在该区域内:

      1. 最后,创建颜色并绘制漂亮的渐变色图。
      % create color for the points
      cid = 1./(1+(exp(-py)/(exp(-y_vec(i))-exp(-x_vec(i)))));
      c = jet(101);
      c = c(round(cid*100)+1,:); % +1 to avoid zero indexing
      
      % plot
      figure;
      scatter(px,py,16,c,'filled','s'); % use size 16, filled square markers.
      

      请注意,您可能需要相当密集的点网格来确保不会出现白色背景。您也可以将磅值更改为更大的值(不会影响性能)。

      当然,您可以使用patch 替换scatter,但您需要计算出顶点和面ID,然后您可以使用patch('Faces',F,'Vertices',V) 分别修补每个面。以这种方式使用patch 可能会影响性能。


      要测试的完整代码:

      i=50;
      cc = @(xx,x,y) 1./(1+(exp(-xx)/(exp(-x)-exp(-y))));
      n_vec = 2:0.1:10;
      x_vec = linspace(2,10,length(n_vec));
      y_vec = abs(sin(n_vec));
      
      % generate point grid
      y = [x_vec(:); y_vec(:)];
      resolution = [500,500];
      px_ = linspace(min(n_vec), max(n_vec), resolution(1));
      py_ = linspace(min(y), max(y), resolution(2));
      [px, py] = meshgrid(px_, py_);
      
      % extract points
      in = inpolygon(px, py, N, X);
      px = px(in);
      py = py(in);
      
      
      % generate color
      cid = 1./(1+(exp(-py)/(exp(-y_vec(i))-exp(-x_vec(i)))));
      c = jet(101);
      c = c(round(cid*100)+1,:); % +1 to avoid zero indexing
      
      % plot
      figure;
      scatter(px,py,16,c,'filled','s');
      

      【讨论】: