MATLAB:通过m文件去除图片空白区域(plot、subplot),设置大小并保存清晰图片

原创文章,转载请注明出处,
(注:本人使用的malab版本为:Matlab 2018a。)

1.想法来源
1.1需求来源**
绘制图片时需要存储用于word文章编辑中,而存储的图片空白区域较大(相对图片实际内容而言占据太多空间),需要在word中手动裁剪。图片较多时需要重复,且不易保证每张图片大小调整得一致。
MATLAB:通过m文件去除图片空白区域(plot、subplot),设置大小并保存清晰图片_第1张图片
1.2期望结果

通过m文件自动设置图片大小,消除图片周围的空白区域,并保存成清晰的图片文件,全程不需要手动操作。

2.Figure和Axes的相关概念

为了调整图片大小及空白区域,有必要先了解一下figure图片及axes对象的一些关键属性。

figure对象:图片大小由属性Position确定。

Axes对象:其大小和显示由属性OuterPosition、TightInset、Position共同确定,其中TightInset属性由matlab自动确定,不可人工设置。

2.1 plot图片的特点

如下图matlab的help文档里介绍的plot图片及其坐标轴Axes的各属性定义,该介绍主要指plot绘制的图片的特点。

MATLAB:通过m文件去除图片空白区域(plot、subplot),设置大小并保存清晰图片_第2张图片

2.2 subplot图片的特点

而对于subplot得到的图像,其各边界有所差别。各子坐标轴Axes的OuterPosition一般与figure的Position不重合,且因为各个子图的数据范围不同,所以其标注所占的TightInset大小一般也不同。

MATLAB:通过m文件去除图片空白区域(plot、subplot),设置大小并保存清晰图片_第3张图片

3.参考前人的方法

为了消除图片四周的空白区域,在网上搜索到比较广泛使用的方法有两种,我分别进行了测试,发现这两种方法对于实际应用还存在一定问题。(因为上述种方法验证时所采用的subplot每个图的数据和曲线都相同,而实际绘图时各参数数据范围可能不同,因而会导致各个subplot子图的TightInset、标注不同,因而应用效果不能满意)。下面为我的测试结果:

参考方法1的网址:https://blog.csdn.net/shanchuan2012/article/details/53980288

MATLAB:通过m文件去除图片空白区域(plot、subplot),设置大小并保存清晰图片_第4张图片
MATLAB:通过m文件去除图片空白区域(plot、subplot),设置大小并保存清晰图片_第5张图片

可以看出虽然消除了空白,但是在改变坐标轴Position的位置和宽度、高度属性过程中,对于坐标轴xtick和ytick的宽度不同的情况下,造成了各图的坐标轴大小不一致(只是OuterPosition大小一致,但是由于TinghtInset不一样大,所以导致最后的Position大小不一致)。

参考方法2的网址:https://ww2.mathworks.cn/matlabcentral/fileexchange/27991-tight_subplot-nh-nw-gap-marg_h-marg_w
为了使得图片中各坐标轴及其标注可以正常实现,需要手动尝试调整该函数的输入参数(主要是各个坐标轴之间的边距和图片四周留白距离),该过程需反复尝试,使用不方便。
MATLAB:通过m文件去除图片空白区域(plot、subplot),设置大小并保存清晰图片_第6张图片
4.本人改进的方法
4.1 思路
经过对以上作者的经验的总结(十分感谢以上作者给我的启发),我觉得消除空白区域在于好好利用matlab已经绘制的图片和设置的内部参数,对其略作调整即可。本方法关键有以下几点:
(1) 找出图片的空白区域;
(2) 保持各个坐标轴的Position的宽度和高度大小变化一致;
(3) 保持各个坐标轴之间的相对位置不变;
(4) TightInset大小不变(确保坐标轴标注可见);
(5) 使每个图的TightInset的最大外界范围与figure.InnerPosition重合。
MATLAB:通过m文件去除图片空白区域(plot、subplot),设置大小并保存清晰图片_第7张图片
找到了空白区域,接下来就是通过算法实现移动坐标轴,并且增加坐标轴范围的宽度和高度讲空白区域填满即可实现空白区域的消除,主要为以下三步:
(1) 求出四边的空白区域的宽度/高度;
(2) 将空白区域宽度/高度的总和平均分配给每个坐标轴Axes.Position,增加其宽度和高度,使空白区域可以被填满。
(3)调整每个坐标轴Axes.Position的位置,使其移动适当距离,使所有坐标轴的蓝色虚线的公有最大边界TightInset的最大外边界)与figure的Position边界重合。

4.2 程序(必须分成两个m文件执行,第一个m文件绘图并设置图片大小,第二个m文件消除空白区域并保存图片,原因见第5节 遗留问题)
4.2.1消除空白区域的函数

function [] = FcnRemoveWhiteSpaceV5(Hgcf,Axes)
%***********************************************************************
%函数说明:通过调整figure中坐标轴大小和位置,消除figure的空白区域最小
%参数:   Hgcf   图片figure的句柄
%         Axes   图片中各子图subplot的坐标轴句柄,为Nrow*Ncol维的结构体矩阵阵
%                Axes(i,j)代表第i行,第j列的坐标轴对象
%***********************************************************************
%--------------自动获得subplot的行列数------------------------
    Dimensions=size(Axes);
    Nrow=Dimensions(1);
    Ncol=Dimensions(2);
%------------为避免最后图片显得太过拥挤,设置四周留白大小百分比------    
     WhiteSpaceLeftRatio=0.1;         %设置四周空白区域留下10%不去除
     Ratio=1-WhiteSpaceLeftRatio;   
%----------获得每个坐标轴的TightInset的位置向量---------    
     for i=1:Nrow   
        for j=1:Ncol
            left=Axes(i,j).Position(1)-Axes(i,j).TightInset(1);
            bottom=Axes(i,j).Position(2)-Axes(i,j).TightInset(2);
            width=Axes(i,j).Position(3)+Axes(i,j).TightInset(1)+Axes(i,j).TightInset(3);
            height=Axes(i,j).Position(4)+Axes(i,j).TightInset(2)+Axes(i,j).TightInset(4);
            AxesTightInsetPosition(i,j).TightInsetPosition=[left bottom width height]
        end 
     end   
     %-------计算图片四周的空白区域,获得需要填满的空白区域的宽度和高度----
    temp=AxesTightInsetPosition(1,1).TightInsetPosition(1);
 %求最左边空白
    for i=1:Nrow
        temp=min(temp,AxesTightInsetPosition(i,1).TightInsetPosition(1));
    end
     WhiteLeft=temp;
     
%求最下边空白
    temp=AxesTightInsetPosition(Nrow,1).TightInsetPosition(2);
    for j=1:Ncol
        temp=min(temp,AxesTightInsetPosition(Nrow,j).TightInsetPosition(2))
    end
    WhiteBottom=temp;
    
%求最右边空白   temp=AxesTightInsetPosition(1,Ncol).TightInsetPosition(1)+AxesTightInsetPosition(1,Ncol).TightInsetPosition(3);
    for i=1:Nrow  temp=max(temp,AxesTightInsetPosition(i,Ncol).TightInsetPosition(1)+AxesTightInsetPosition(i,Ncol).TightInsetPosition(3));
    end
     WhiteRight=1-temp;
     
%求最上边空白     temp=AxesTightInsetPosition(1,1).TightInsetPosition(2)+AxesTightInsetPosition(1,1).TightInsetPosition(4);
    for j=1:Ncol   temp=max(temp,AxesTightInsetPosition(1,j).TightInsetPosition(2)+AxesTightInsetPosition(1,j).TightInsetPosition(4));
    end
     WhiteTop=1-temp;
%求总的空白,并平均分配到每个坐标轴的高度和宽度增量 
     WhiteWidth=WhiteLeft+WhiteRight;
     WhiteHeight=WhiteBottom+WhiteTop;
     deltaW=WhiteWidth/Ncol*Ratio;
     deltaH=WhiteHeight/Nrow*Ratio;
       %----------调整坐标轴的位置和宽度高度,使空白区域被填满------------
%调整每个坐标轴的宽度和高度
    for i=1:Nrow   
        for j=1:Ncol
           Axes(i,j).Position(3)=Axes(i,j).Position(3)+deltaW; 
           Axes(i,j).Position(4)=Axes(i,j).Position(4)+deltaH;
        end 
    end
     
%调整每个坐标轴的水平位置   
     for i=1:Nrow   
        for j=1:Ncol
            if(j==1)   %第一列:往左移动WhiteLeft
               Axes(i,j).Position(1)=Axes(i,j).Position(1)-WhiteLeft*Ratio; 
            else      %其他列
               Axes(i,j).Position(1)=Axes(i,j).Position(1)-WhiteLeft*Ratio+(j-1)*deltaW; 
            end
        end 
     end
%调整每个坐标轴的垂直位置 
     for i=Nrow:-1:1   
        for j=1:Ncol
            if(i==Nrow)    %最后一行:往下移动WhiteBottom
               Axes(i,j).Position(2)=Axes(i,j).Position(2)-WhiteBottom*Ratio;
            else         %其他行
               Axes(i,j).Position(2)=Axes(i,j).Position(2)-WhiteBottom*Ratio+(Nrow-i)*deltaH; 
            end
        end 
     end

4.2.2脚本文件m1:

clc
close all
clear all
% ---------------------九图验证
Hgcf=figure('color','w');
subplot(331),plot(1:4,5000:5003),ylabel('αβμνλΨ');AX(1,1)=gca;
subplot(332),plot(1:4,50:53),ylabel('图2'),xlabel('t(s)'),AX(1,2)=gca
subplot(333),plot(1:4,5000:5003),ylabel('图2'),AX(1,3)=gca;
subplot(334),plot(1:4,5:8),ylabel('图2'),xlabel('t(s)'),AX(2,1)=gca;
subplot(335),plot(1:4,5000000:5000003),ylabel('图2'),AX(2,2)=gca;
subplot(336),plot(1:4,5:8),ylabel('图2'),xlabel('t(s)'),AX(2,3)=gca;
subplot(337),plot(1:4,5000:5003),ylabel('图2'),xlabel('t(s)'),AX(3,1)=gca;
subplot(338),plot(1:4,50:53),ylabel('图2'),AX(3,2)=gca;
subplot(339),plot(1:4,5:8),ylabel('图2'),xlabel('t(s)'),AX(3,3)=gca;

% ----------保存原始图片(为matlab自动调整图片间距消除重叠留够时间)--------
print(Hgcf,'-dtiff','-r300','原始图片.png');

%---------图片大小设置和保存的名字参数设置--------------------
SizeWidth=600;
SizeHeight=600;
PictureName='修改后的图片.png';

%----------重设图片大小-------------------------------------
set(Hgcf,'units','pixel');
set(Hgcf,'position',[200 50 SizeWidth SizeHeight])  %图片窗口显示大小设置

4.2.3脚本文件m2:

%--------------消除空白区域----------------------
FcnRemoveWhiteSpaceV5(Hgcf,AX);

%--------------保存图片----------------------
set(Hgcf, 'PaperPositionMode', 'auto');
print(Hgcf,'-dtiff','-r300',PictureName);

4.3 程序执行效果
进行了各种subplot的情况的验证,此处放上两种情况:
九图效果:
MATLAB:通过m文件去除图片空白区域(plot、subplot),设置大小并保存清晰图片_第8张图片二十五图效果:MATLAB:通过m文件去除图片空白区域(plot、subplot),设置大小并保存清晰图片_第9张图片

5.本人的方法的遗留问题

5.1问题1:必须分成两个m文件执行

原因分析:本人推测在图形比较多的情况下,在运行m文件绘subplot期间,一开始的坐标轴内容重合情况;而在m文件运行完毕之后,matlab会自动适应调整图片的坐标轴尺寸,其自动调整之后的各坐标轴边界不再重合。
如下图,M文件运行过程中获得的图形边界:M文件运行期间获得的的图片的边界,存在坐标轴边界重合现象
MATLAB:通过m文件去除图片空白区域(plot、subplot),设置大小并保存清晰图片_第10张图片
M文件运行完成后,Matlab进行了自适应调整,图片实际情况和图形边界如下,不再有subplot之间重合的现象。
MATLAB:通过m文件去除图片空白区域(plot、subplot),设置大小并保存清晰图片_第11张图片
通过在m文件运行期间和运行完成后输出数据验证了本人的推测:在这里插入图片描述

因此,只能在先运行完上一个m程序绘图后,,再运行下一个m文件进行坐标轴改变,进行图片的空白区域消除。
如果没有分两个m文件执行(且图片大小设置得较小),则可能会出现subplot之间重合情况。
MATLAB:通过m文件去除图片空白区域(plot、subplot),设置大小并保存清晰图片_第12张图片

我实在找不到办法解决这个问题,只能分两个m文件执行方能获得期望的结果,如果有大神找到了解决办法,还望不吝赐教!

5.2问题2:手动缩小图片造成显示不全
另外,手动拖动图片进行缩小会导致坐标轴标注边界显示不全以及subplot之间重合情况。这严格说来不是问题,因为我的初衷就是不需要手动改变图片大小,完全依靠m文件实现图片自动保存。
MATLAB:通过m文件去除图片空白区域(plot、subplot),设置大小并保存清晰图片_第13张图片

6.另一种思考:
有一种手动保存的方法如下:
(网址:https://blog.csdn.net/rookiew/article/details/51418661)

a) 首先Figure窗口"File"菜单,再点击“Export Setup”菜单项。
b) 首先进行导出图片大小的设置,包括长度单位,高和宽,这里一定记得点上“Expand axis to fill figure”以便导出的图像不含空白边框,
c) 再下一个“Rendering“是图片渲染设置。这里其他都可以不用管,主要是dpi需要设置,dpi越高图像越清晰,对于论文工作者而言,很多期刊是要求600dpi以上,这就已经很清楚了。
d) 最后所有设置好后点击右侧的“aplly to figure”。然后再点export选择要保存的路径及图片格式即可。

用这种方法可以很好地消除空白区域,但是需要手动调整,相对来说仍有些麻烦。所以我在思考,可不可以在m文件里调用Export setup菜单并将“Expand axis to fill figure”属性选中,再输出图像就可以获得没有白边的图片了。

你可能感兴趣的:(matlab)