是否可以将一个MATLAB轴的'XLim'属性链接到另一个轴的'YLim'属性?我查看了linkaxes
和linkprop
但据我所知,他们只能链接相同的属性,例如一个轴'XLim'到另一个轴'XLim',依此类推。
使用MATLAB 2014b。谢谢!
答案 0 :(得分:2)
我想出了办法,虽然可以,但是仍然有些笨拙...
显然,此想法是将侦听器附加到要链接的两个属性,并在每次更改另一个属性时更新一个属性。
需要花些时间才能将侦听器附加到内置axes
对象的属性,您必须检索关联的meta.property
。我将此封装在外部子函数findPropertyHandle
中。
我使解决方案成为泛型,因此您可以将任何类型的属性链接在一起。现在,我没有对输入检查进行编程,因此,它当然只能在 compatible 属性上工作。 XLim
与YLim
显然兼容,但是如果您尝试将XLim
与PlotBoxAspectRatioMode
链接,则会在控制台中出现大量的红色和橙色文本。>
%% Demo data and figure
x = linspace(0,24*pi,1000) ;
y = cos(x) ;
hf = figure ;
hax1 = subplot(1,2,1) ; hp1 = plot(x,y) ;
hax2 = subplot(1,2,2) ; hp2 = plot(y,x) ;
%% Find (meta)property handle
prop1 = findPropertyHandle( hax1 , 'XLim' ) ;
prop2 = findPropertyHandle( hax2 , 'YLim' ) ;
%% Add a listener to each property
% no callback yet because we need the reference of both listeners to be part of the callback arguments
lh1 = addlistener( hax1, prop1 , 'PostSet', @() [] ) ;
lh2 = addlistener( hax2, prop2 , 'PostSet', @() [] ) ;
%% group a few things for convenience
pl.obj2link = [ hax1 ; hax2 ] ; % axes handles
pl.props2link = { 'XLim' ; 'YLim' } ; % name of properties to link
pl.listeners = [ lh1 ; lh2 ] ; % listener handle
pl.metaprops2link = [ prop1 ; prop2 ] ; % metaproperty handles
%% Set the callback of both listeners
% Have to use dot notation because the 'set' method is not defined for listener objects
lh1.Callback = @(h,e) LinkPropChangedFcn(h,e,pl) ;
lh2.Callback = @(h,e) LinkPropChangedFcn(h,e,pl) ;
LinkPropChangedFcn.m
function LinkPropChangedFcn( hobj, evt, plink )
%LinkPropChangedFcn Links 2 compatible properties
% find which property was triggered
changedPropIdx = find( hobj==plink.metaprops2link ) ;
prop2changeIdx = 3-changedPropIdx ; % because cumsum([1 2])=3
% disable the other listener to not trigger the property change on the
% target object
plink.listeners(prop2changeIdx).Enabled = false ;
% retrieve property value
val = get( plink.obj2link(changedPropIdx) , plink.props2link{changedPropIdx} ) ;
% aplpy the value to the target object property
set( plink.obj2link(prop2changeIdx) , plink.props2link{prop2changeIdx} , val ) ;
% re-enable target listener
plink.listeners(prop2changeIdx).Enabled = true ;
end
findPropertyHandle.m
function [ hprop ] = findPropertyHandle( hobj , propname )
%FINDPROPERTYHANDLE retrieve the handle of the meta.property object
mco = metaclass(hobj) ;
plist = mco.PropertyList;
for k=1:numel(plist)
if strcmpi(plist(k).Name,propname)
fprintf('[%s] property was found at index #%d\n',propname,k)
hprop = plist(k) ;
return
end
end
% no preperty was found if we are here
hprop = [] ;
fprintf('[%s] property was not found.\n',propname)
end
注意
我所说的笨拙是在使用“重置为原始视图”菜单而不是“缩小”时。该函数不会触发PostSet
属性的XLim
事件,因此更改并不总是传播到其他轴/属性。为了克服这个问题,在使用“重置为原始视图”之后,再次右键单击并“缩小”即可。这不会在单击的axes
中进一步缩小(如果您已经在“原始视图”中),但是它将触发侦听器并更新第二个目标轴。
答案 1 :(得分:1)
是的,有可能。不要相信文档。我只是有同样的需要:我有一个曲面z(x,y):
x=-10:10; y=-15:15;
[xx,yy]=meshgrid(x,y);
z=real( exp( -(xx.^2/9+yy.^2/4+xx.*yy/12)) .* exp( 1i * (xx/4+yy/9-xx.*yy/12+1)));
xz= sum(z,1);
zy= sum(z,2);
并且想要绘制这样的表面和部分和
figure;
zyy= subplot(2,2,1); plot(zy,y);
xyz= subplot(2,2,2); contour(x,y,z);
xxz = subplot(2,2,4); plot(x,xz);
我要链接的是xyz和xxz的x轴以及zyy和xyz的y轴。
如linkaxes
文档中所广告,这不起作用:
linkaxes([xyz xxz],'x');
linkaxes([xyz zyy],'y');
但是,至少在Matlab 2012b中,这种分解工作可以按预期进行:
set([xyz xxz],'XLimMode','manual');
set([xyz zyy],'YLimMode','manual');
hx=linkprop([xyz xxz],'XLim');
hy=linkprop([xyz zyy],'YLim');
setappdata(xxz,'graphics_linkaxes',hx);
setappdata(zyy,'graphics_linkaxes',hy);
如果查看链接轴的源代码,您会发现该代码正在尝试在链接的两端进行setappdata
,这实际上是行不通的,但似乎不必要。
答案 2 :(得分:0)
不,使用linkaxes
或linkplot
无法做到这一点。
我担心你必须创建自己的系统,大致复制内部linkprop
所做的事情,即在一个轴上监听事件,并通过相应的更改来回应它们到另一个。我害怕linkprop
只允许你为每个人的同一财产做这件事。
答案 3 :(得分:0)
您可以使用技巧:使用linkaxes
链接两个轴的'XLim'
属性。在第二个轴中,而不是
plot(x2,y2)
你使用
plot(y2,x2)
view(90,-90)
这样,第二轴中的 x - 坐标包含 y 数据(感谢plot
参数的反转),并且在< em> y 位置(感谢view
的更改);和其他坐标类似。
因此,您基本上链接了两个'XLim'
值,但让第二轴的 x - 坐标看起来就像是 y 坐标一样。< / p>
答案 4 :(得分:0)
这是我的解决方案,可在R2019a中使用 功能
function crosslinkaxes(ax,str)
%
% ax(1)=subplot(1,2,1);
% ax(2)=subplot(1,2,2);
% str='xy'; %link, x limits of ax(1) with ylimits of ax(2)
% crosslinkaxes(ax,str)
for k=1:numel(ax)
propListener(k) = addlistener(ax(k),expand(str(k)),'PostSet',@event);
end
function p=expand(str)
switch str
case 'x'
p='XLim';
case 'y'
p='YLim';
otherwise
error(str)
end
end
function event(src,evnt)
%src.Name
disp('lims')
L=evnt.AffectedObject.(src.Name);
for k=1:numel(ax)
ax(k).(expand(str(k)))=L;
end
% keyboard
end
end