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.
ax2.XAxisLocation = 'top';
ax2.YAxisLocation = 'right';
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.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.
xyscale = [range(ax1.XLim) / range(ax2.XLim); range(ax1.YLim) / range(ax2.YLim)];
axBaseLim = [ax1.XLim; ax1.YLim];
axBaseLim(:,:,2) = [ax2.XLim; ax2.YLim];
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.
axTB = axtoolbar(ax2,'default');
isRestoreButton = strcmpi({axTB.Children.Icon},'restoreview');
restoreButtonHandle = axTB.Children(isRestoreButton);
originalRestoreFcn = restoreButtonHandle.ButtonPushedFcn;
restoreButtonHandle.ButtonPushedFcn = ...
{@myRestoreButtonCallbackFcn, ax1, originalRestoreFcn, xyscale, axBaseLim};
5. Define the listener function
function axisLimitListener(~,~,ax,scalingFactor,axBaseLim)
normLowerLimit = ([ax(2).XLim(1);ax(2).YLim(1)] - axBaseLim(:,1,2))./range(axBaseLim(:,:,2),2);
newLimits = normLowerLimit.*range(axBaseLim(:,:,1),2) + axBaseLim(:,1,1);
newLimits(:,2) = newLimits(:,1) + [range(ax(2).XLim);range(ax(2).YLim)].*scalingFactor;
set(ax(1), 'XLim', newLimits(1,:), 'YLim', newLimits(2,:))
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)
originalCallback(hobj,event)
axisLimitListener([],[],[ax1,event.Axes],xyscale,axBaseLim)