【问题标题】:Save cropped figure in Matlab在 Matlab 中保存裁剪后的图形
【发布时间】:2014-11-24 09:28:07
【问题描述】:

我用openfig 从matlab 文件中打开了一个高度复杂的.fig 图。

在此之后,我用

裁剪了图形

axis([X1, X2, Y1, Y2])

我现在想保存裁剪后的图形,以便在保存时缩小尺寸。问题是savefig 将保存缩放到指定轴的完整图像。如何保存图形,永久裁剪到我指定的轴?例如打开新图片时应该不能缩小。

【问题讨论】:

  • 那么,你需要它作为 .fig 还是 .png 就足够了?
  • @natan 我更喜欢它作为无花果,这就是问题所在。
  • 所以你只需要从中获取数据。缩放\裁剪不会省略其中包含的数据...
  • @natan 嗯好的。那么就没有别的办法了吗?问题是它是一个复杂的图形,矩形绘制在图像c 的顶部。
  • 好的,这对我有用。我加载了一个带有一些图(子图)和一个矩形的图。我选择(鼠标单击)其中一个图、矩形和图的边界框(在按下 SHIFT 键的同时),然后执行 CTRL+C(复制)。然后我打开一个新图形,单击它以选择 balnk 轴并粘贴 CTRL+V。看看这是否适合你。

标签: matlab crop figure


【解决方案1】:

我面前没有 MATLAB,也没有你的数据来测试这个,所以这是一个大概的答案,但正如 @natan 在上面的 cmets 中提到的那样,你可以从该图形存储在“XData”和“YData”中。然后,您可以将数据裁剪为您想要的部分,然后用裁剪的数据替换现有数据。它最终会看起来像这样:

kids = findobj(gca,'Type','line');
K = length(kids);

Xrange = get(gca,'XLim');
Yrange = get(gca,'YLim');

for k = 1:K
    X = get(kids(k),'XData');
    Y = get(kids(k),'YData');

    idx = X >= min(Xrange) & X <= max(Xrange) & Y >= min(Yrange) & Y <= max(Yrange);

    set(kids(k),'XDATA',X(idx),'YDATA',Y(idx));
end

如果你的地块有补丁对象、条对象等,你必须修改它,但想法就在那里。

边缘情况:

正如@Jan 正确指出的那样,有一些边缘情况需要考虑。首先,上述方法假设即使在扩展的尺度中也有相当高的点密度,并且会在线的末端和轴之间留下一个小的间隙。对于低点密度线,您需要扩展idx 变量以在任一方向捕获轴外的下一个点:

idx_center = X >= min(Xrange) & X <= max(Xrange) & Y >= min(Yrange) & Y <= max(Yrange);
idx_plus = [false idx(1:end-1)];
idx_minus = [idx(2:end) false];

idx = idx_center | idx_plus | idx_minus;

如果窗口内至少有一个点,那只会扩大点数。另一种边缘情况是线穿过窗口但不包含窗口内的任何点,如果idx 全部为假,就会出现这种情况。在这种情况下,您需要左轴外的最大点和右轴外的最小点。如果这些搜索中的任何一个为空,则该行不会通过窗口并且可以被丢弃。

if ~any(idx)
   idx_low = find(X < min(Xrange),1,'last');
   idx_high = find(X > max(Xrange),1,'first');

   if isempty(idx_low) | isempty(idx_high)
       % if there aren't points outside either side of the axes then the line doesn't pass through
       idx = false(size(X));
   else
       idx = idx_low:idx_high;
   end
end

这不会测试线是否在 y 边界内,因此线可能会通过窗口上方或下方而不相交。如果这很重要,您将需要测试连接找到的点的线。内存中额外的 2 点应该没什么大不了的。如果这是一个问题,那么我把它作为一个练习留给学生来测试一条线是否穿过轴。

把它们放在一起:

kids = findobj(gca,'Type','line'); % find children of the axes that are lines
K = length(kids); % count them

Xrange = get(gca,'XLim'); % get the axis limits
Yrange = get(gca,'YLim');

for k = 1:K
    X = get(kids(k),'XData'); % pull the x-y data for the line
    Y = get(kids(k),'YData');

    % find the points inside the window and then dilate the window by one in
    % each direction
    idx_center = X >= min(Xrange) & X <= max(Xrange) & Y >= min(Yrange) & Y <= max(Yrange);
    idx_plus = [false idx(1:end-1)];
    idx_minus = [idx(2:end) false];

    idx = idx_center | idx_plus | idx_minus;

    % handle the edge case where there are no points in the window but the line still passes through
    if ~any(idx)
       idx_low = find(X < min(Xrange),1,'last');
       idx_high = find(X > max(Xrange),1,'first');

       if isempty(idx_low) | isempty(idx_high)
           % if there aren't points outside either side of the axes then the line doesn't pass     
           % through
           idx = false(size(X));
       else
           % numerical indexing instead of logical, but it all works the same
           idx = idx_low:idx_high;
       end
    end

    if any(idx)
        % reset the line with just the desired data
        set(kids(k),'XDATA',X(idx),'YDATA',Y(idx));
    else
        % if there still aren't points in the window, remove the object from the figure
        delete(kids(k));
    end
end

【讨论】:

  • 您可能还必须将 XLimModeYLimMode 设置为手动,以防止在每次数据更新后重新调整坐标轴。
  • 这是一个很好的方法,但可能会出现一个问题,即不能保存在框内具有起点和在框外的终点的线。这可以相对容易地解决,但以下情况不那么简单:两个连接的点都在框外,导致在框内可见一条线。使用上面的代码将删除这些点,因此该行也会消失。
  • 在最初的化身中,您所描述的情况将离开情节的起点,但您是正确的,轴外没有可绘制的点。我认为上面的修改处理了这种情况和窗口内没有点的情况。
  • 感谢您的全面回答。
  • 很高兴为您提供帮助。不过,请注意第一句话。很有可能在这里的某个地方我尝试将行向量和列向量连接在一起,或者堆叠两个向量而不是将它们串在一起。如果您发现严重错误,请告诉我,我会对其进行编辑以确保完整性。
猜你喜欢
  • 2014-11-03
  • 2013-03-08
  • 2019-02-07
  • 2014-08-03
  • 2016-12-05
  • 1970-01-01
  • 1970-01-01
  • 2015-03-02
相关资源
最近更新 更多