how to zoom on a figure with multiple axes
127 views (last 30 days)
Show older comments
hello guys
i am trying to creat a plot with 4 axes, but wen i try to zoom on the following plot, only 2 axes are modifed " the top and right axes"
is there a way to make all the axes change value wen i zoom?
thank you for your support
the following code and plot are :
clear all
clc
x1 = 0:0.1:40;
y1 = 4.*cos(x1)./(x1+2);
x2 = 1:0.2:20;
y2 = x2.^2./x2.^3;
ax1 = axes();
plot(ax1,x1,y1,'-r')
ax1.XColor = 'r';
ax1.YColor = 'r';
ax2 = axes();
plot(ax2,x2,y2,'-k')
ax2.XAxisLocation = 'top';
ax2.YAxisLocation = 'right';
ax2.Color = 'none';
ax1.Box = 'off';
ax2.Box = 'off';
1 Comment
Sree
on 13 Apr 2021
Hope this helps
clear all
clc
x1 = 0:0.1:40;
y1 = 4.*cos(x1)./(x1+2);
x2 = 1:0.2:20;
y2 = x2.^2./x2.^3;
plot(x1,y1)
hold on;
plot(x2,y2)
Accepted Answer
Adam Danz
on 13 Apr 2021
Edited: Adam Danz
on 23 Jan 2024
Multiple axes with same axis limits
If the xlim and ylim properties are the same between both axes, use linkaxes or linkprop to link the axis properties so changes to one pair of axes will affect the other pair of axes.
See this demo that links two overlaying axes, one that hosts a contour map and another that hosts an image.
Multiple axes with different scales or axis limits
This is more complicated. One solution is to assign a listener that responds to changes to xlim and ylim in one pair of axes and updates the other pair of axes while maintaining axis limit scales. For Matlab r2021a and later, you could use the LimitsChangedFcn instead of a listener (see this demo).
Follow this demo below to understand critical steps to make this work. This demo is designed for linearly scaled axes (it requires significant modification for log scale axes).
Demo code is attached as an m-file: YokedAxesDemo_DifferentScales.m
1. Create two overlaying axes with different x and y limits
A recommended step that this demo does not include is linking the axis position properties so a figure resize or the addition of a legend, colorbar, or axis lables does not shift one axis position relative to the other. For demos on using linkprop see linkprop demo 1 and linkprop demo 2.
ax1 and ax2 are the two axes handles.
x1 = 0:0.1:40;
y1 = 4.*cos(x1)./(x1+2);
x2 = 1:0.2:20;
y2 = x2.^2./x2.^3;
ax1 = axes();
plot(ax1,x1,y1,'-r')
ax1.XColor = 'r';
ax1.YColor = 'r';
ax2 = axes();
plot(ax2,x2,y2,'-k')
ax2.XAxisLocation = 'top';
ax2.YAxisLocation = 'right';
ax2.Color = 'none';
ax1.Box = 'off';
ax2.Box = 'off';
% Add an intersection marker to visually confirm correct scaling
hold on
plot(ax2, 2.526596, 0.396379, 'bx')
2. Turn off interation to ax1
ax2 is on top and will be the main axis the user interacts with.
Axis interaction is turned off for ax1 to simplify the problem.
ax1.Interactions = [];
ax1.Toolbar.Visible = 'off';
3. Set up a listener that responds to changes to ax2 limits
Any time the XLim or YLim changes in ax2, the listener responds (listener function defined later). See inline comments for more detail.
% Compute scaling factor to convert ax1 scale from ax2 scale
% xyscale is 2x1 factors of [x;y] axes
% range = @(ab)max(ab)-min(ab); % if you don't have access to stats TB
xyscale = [range(ax1.XLim) / range(ax2.XLim); range(ax1.YLim) / range(ax2.YLim)];
% Store original axis limits for both axes
% axBaseLim is 2x2x2 axis limits of [x;y] axes, [min,max] limits; and
% [ax1,ax2] along the 3rd dimension
axBaseLim = [ax1.XLim; ax1.YLim]; % ax1
axBaseLim(:,:,2) = [ax2.XLim; ax2.YLim]; % ax2
% Assign listener
ax2.UserData.Listener = addlistener(ax2,{'XLim','YLim'}, 'PostSet', ...
@(~,~)axisLimitListener([], [], [ax1,ax2], xyscale, axBaseLim));
4. Fix problem with axis Restore button
The listener responds to user interaction (zoom/pan) as well as programmatically setting the ax2 limits but the restore button in the axis toolbar only restores ax2! That's not cool. Here we customize the restore button callback function so that it updates ax1 after ax2 is restored. If your axes have a custom toolbar, this will replace it with the default toolbar.
% Fix restoreview button
axTB = axtoolbar(ax2,'default');
isRestoreButton = strcmpi({axTB.Children.Icon},'restoreview');
if any(isRestoreButton)
restoreButtonHandle = axTB.Children(isRestoreButton);
originalRestoreFcn = restoreButtonHandle.ButtonPushedFcn;
restoreButtonHandle.ButtonPushedFcn = ...
{@myRestoreButtonCallbackFcn, ax1, originalRestoreFcn, xyscale, axBaseLim};
end
5. Define the listener function
function axisLimitListener(~,~,ax,scalingFactor,axBaseLim)
% Listener callback that responds to x/y axis limit changes to ax2 and
% updates the axis limits to ax1.
% INPUTS
% ax: 1x2 array of axis handles to [ax1,ax2]
% scalingFactor: (see description of xyscale above)
% axBaseLim: (see description of axBaseLim above)
% Convert the lower axis limits from ax2 to values normalized
% by the original axis range. Example: for an axis range of [10,20]
% that was changed to [12,20], the lower limit of 12 is normalized to 0.2;
% range = @(ab)max(ab)-min(ab); % if you don't have access to stats TB
normLowerLimit = ([ax(2).XLim(1);ax(2).YLim(1)] - axBaseLim(:,1,2))./range(axBaseLim(:,:,2),2);
% Compute the new lower limits to ax1.
newLimits = normLowerLimit.*range(axBaseLim(:,:,1),2) + axBaseLim(:,1,1);
% Compute the new upper limits ax1.
newLimits(:,2) = newLimits(:,1) + [range(ax(2).XLim);range(ax(2).YLim)].*scalingFactor;
% Update ax1 limits
set(ax(1), 'XLim', newLimits(1,:), 'YLim', newLimits(2,:))
end
6. Define the restoration button callback function
This uses resetplotview which is undocumented and may change in future releases.
function myRestoreButtonCallbackFcn(hobj, event, ax1, originalCallback, xyscale, axBaseLim)
% Responds to pressing the restore button in the ax2 toolbar.
% originalCallback is a function handle to the original callback
% function for this button.
% xyscale and axBaseLim are defined elsewhere.
originalCallback(hobj,event) % reset ax2
axisLimitListener([],[],[ax1,event.Axes],xyscale,axBaseLim) % update ax1
end
10 Comments
Adam Danz
on 15 Apr 2021
Note that perhaps an easier alternative is to plot everything on the first axis and to merely set the appropriate tick values for the second axis.
Brandon
on 21 Jul 2023
I can think of no reason linkprop shouldn't work on axis that are of different scales. If I scale my secondary set of data to fit on the first axis, I lose the values upon inspection of data points, so the easy alternative isn't really an option.
More Answers (1)
Peter Seibold
on 23 Jan 2024
Great code from Adam Danz! Unfortunately the "range" function is part of a toolbox.
Attached is a modified file that works without toolboxes and works also with older Matlab releases (before R2018b).
0 Comments
See Also
Categories
Find more on Lighting, Transparency, and Shading in Help Center and File Exchange
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!