本篇内容代码部分并非原创,引自ilovematlab,特此说明。
初衷
在进行文档写作的时候,我们往往会利用 matlab 绘制几张图片插入到文章中。所有 matlab 画出来的图千篇一律,以至于看文章的人一眼就看出来,你这张图使用 matlab 画的。
matlab 所画的图有个特色就是坐标刻度和标签在左边和下边,如下图所示的样子:
十分刻板。我们现在想要把 matlab 做的图坐标轴移到图形的中间部分去(与数学的做图习惯一致),也就是使用那种十字带箭头的那种坐标系,坐标原点位于(0,0)点。我们徒手画坐标系时,画出来的坐标系就是这种的。
目标
我们的目标就是要把图画成形如下面的这个样子:
实现
matlab 中并未自带相关的函数或者绘图参数使得它的坐标轴挪到了中间位置,我们需要编写函数实现。
写一个带网格参数的函数如下,基本的调用就是传入图像句柄以及是否画网格的标志。
function new_fig_handle = convert_to_std_coordinate_system( fig_handle,gridflag)
% 本函数目的是把 matlab 做的图的坐标轴在原点十字带箭头显示(与数学的做图习惯一致)
% 2019.2.2 in ucas
% author:LuSong
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
if nargin < 2
gridflag = 0;
end
figure('Name','std_coordinate_system','NumberTitle','off') % Create a new figure
new_fig_handle = copyobj( fig_handle , gcf );%拷贝图形到一个新的窗口
xL=xlim ;%取原来的x和y的范围
yL=ylim ;
xt=get(gca,'xtick') ;%取原来的tick
yt=get(gca,'ytick') ;
%set(gca,'YColor','w') ;
%set(gca,'XColor','w') ;
%set(gca,'xticklabel','');
%set(gca,'yticklabel','');
if gridflag == 0
set(gca,'xtick',[]);
set(gca,'ytick',[]);
else
grid on;
set(gca,'xticklabel','');
set(gca,'yticklabel','');
end
% 把 x 和 y 坐标轴的两个方向各延长 10% (为了视觉上好看)
extend_x = ( xL(2)-xL(1) ) * 0.1 ;
extend_y = ( yL(2)-yL(1) ) * 0.1 ;
xxL = xL + [ -extend_x extend_x] ;
yyL = yL + [ -extend_y extend_y] ;
set(gca,'xlim', xxL) ;%设置Range增加10%
set(gca,'ylim', yyL) ;
pos = get(gca,'Position') ;%获取绘图区域,pos(1)指左下角点的x坐标,pos(2)指左下角点的y坐标,pos(3)指宽度,pos(4)指高度
box off;%不展示轴的边界
x_shift = abs( yyL(1)/(yyL(2)-yyL(1)) ) ;
y_shift = abs( xxL(1)/(xxL(2)-xxL(1)) ) ;
temp_1 = axes( 'Position', pos + [ 0 , pos(4) * x_shift , 0 , - pos(4)* x_shift*0.99999 ] ) ;%新建一个axes
xlim(xxL) ;
box off ;
set(temp_1,'XTick',xt,'Color','None','YTick',[]) ;%显示我想要的范围刻度
set(temp_1,'YColor','w') ;
temp_2 = axes( 'Position', pos + [ pos(3) * y_shift , 0 , -pos(3)* y_shift*0.99999 , 0 ] ) ;
ylim(yyL) ;
box off ;
set(temp_2,'YTick',yt,'Color','None','XTick',[]) ;
set(temp_2,'XColor','w') ;
Base_pos = get(new_fig_handle,'Position') ;
arrow_pos_in_x_dircetion = Base_pos(2) - Base_pos(4) * yyL(1)/(yyL(2)-yyL(1)) ;
arrow_pos_in_y_dircetion = Base_pos(1) - Base_pos(3) * xxL(1)/(xxL(2)-xxL(1)) ;
annotation('arrow',[Base_pos(1) , Base_pos(1)+Base_pos(3)] , [arrow_pos_in_x_dircetion , arrow_pos_in_x_dircetion ] , 'Color','k');
annotation('arrow',[arrow_pos_in_y_dircetion , arrow_pos_in_y_dircetion ] , [Base_pos(2) , Base_pos(2)+Base_pos(4)] , 'Color','k');
%下面的处理是为了处理边框
% temp_addition = axes( 'Position', pos) ;
% box on ;
% set(temp_addition,'Color','None') ;
% set(temp_addition,'xtick',[],'ytick',[]) ;
temp_addition = axes( 'Position', pos) ;
box off ;
set(temp_addition,'Color','None') ;
set(temp_addition,'xtick',[],'ytick',[]) ;
set(temp_addition,'XColor','w') ;
set(temp_addition,'YColor','w')
end
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
一个测试函数如下:
clc
clear
close all
x = -5:0.1:6;
y = sin(x+0.5);
plot(x,y,'linewidth',5);
xlabel('x');
ylabel('y');
new_fig_handle = convert_to_std_coordinate_system(gca,1) ;
一个更简单地,鲁棒性和泛化能力更差的实现如下:
function new_fig_handle = shift_axis_to_origin( fig_handle )
% 本函数目的是把 matlab 做的图坐标轴移到图形的中间部分去(与数学的做图习惯一致)
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
figure('Name','shift_axis_to_origin','NumberTitle','off') % Create a new figure
% 拷贝图形到一个新的窗口
new_fig_handle = copyobj( fig_handle , gcf );
xL=xlim ;
yL=ylim ;
xt=get(gca,'xtick') ;
yt=get(gca,'ytick') ;
set(gca,'XTick',[],'XColor','w') ;
set(gca,'YTick',[],'YColor','w') ;
% 把 x 和 y 坐标轴的两个方向各延长 10% (为了视觉上好看)
extend_x = ( xL(2)-xL(1) ) * 0.1 ;
extend_y = ( yL(2)-yL(1) ) * 0.1 ;
xxL = xL + [ -extend_x extend_x] ;
yyL = yL + [ -extend_y extend_y] ;
set(gca,'xlim', xxL) ;
set(gca,'ylim', yyL) ;
pos = get(gca,'Position') ;
box off;
x_shift = abs( yyL(1)/(yyL(2)-yyL(1)) ) ;
y_shift = abs( xxL(1)/(xxL(2)-xxL(1)) ) ;
temp_1 = axes( 'Position', pos + [ 0 , pos(4) * x_shift , 0 , - pos(4)* x_shift*0.99999 ] ) ;
xlim(xxL) ;
box off ;
set(temp_1,'XTick',xt,'Color','None','YTick',[]) ;
set(temp_1,'YColor','w') ;
temp_2 = axes( 'Position', pos + [ pos(3) * y_shift , 0 , -pos(3)* y_shift*0.99999 , 0 ] ) ;
ylim(yyL) ;
box off ;
set(temp_2,'YTick',yt,'Color','None','XTick',[]) ;
set(temp_2,'XColor','w') ;
Base_pos = get(new_fig_handle,'Position') ;
arrow_pos_in_x_dircetion = Base_pos(2) - Base_pos(4) * yyL(1)/(yyL(2)-yyL(1)) ;
arrow_pos_in_y_dircetion = Base_pos(1) - Base_pos(3) * xxL(1)/(xxL(2)-xxL(1)) ;
annotation('arrow',[Base_pos(1) , Base_pos(1)+Base_pos(3)] , [arrow_pos_in_x_dircetion , arrow_pos_in_x_dircetion ] , 'Color','k');
annotation('arrow',[arrow_pos_in_y_dircetion , arrow_pos_in_y_dircetion ] , [Base_pos(2) , Base_pos(2)+Base_pos(4)] , 'Color','k');
end
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
效果
不足
不足的地方有很多,比如说 x x x和 y y y的标签在通常情况下,是写在箭头附近,不过这个没有关系,可以直接在对应位置印上文本即可。
如采用如下处理:
clc
clear
close all
x = -5:0.1:6;
y = 3*sin(x+0.5);
plot(x,y,'linewidth',5,'color','k');
text(-0.5,3.5,'y','FontSize',15)
text(6.8,-0.3,'x','FontSize',15)
%xlabel('x');
%ylabel('y');
new_fig_handle = convert_to_std_coordinate_system(gca,0) ;
效果如下: