linkaxes has a second input that allows you to link the x,y,or both axes. However, since your y-axes have different scales, the linkaxes function will not be useful to you.
Linking axes with different scales is demonstrated in this answer but since that answer uses overlaid axes and "links" both x and y axies, I've made some adjustments to that demo which is shown below which links the y-axes between two plots. The only "input" in the entire code is ax which is a 1x2 vector of axis handles [ax1,ax2] where ax1 is the left axes and ax2 is the right-axes handles.
The process is not straight-forward since you have to manually scale the axes, use a listener, and adjust the behavior of the "restore view" toolbar button. If needed, see the answer mentioned above for a detailed description and comments. Tested in R2020b and R2021a.
Attachments
- linkedYAxesDiffScale.m - Full demo of this answer.
- linkedYAxesDiffScale_UI.m - Full demo of this answer modified to use UIFigure and UIAxes.
0. Set up demo figure
The goal will be to link the y-axes which have different scales .
histogram(y-mean(y),20,'Orientation','Horizontal')
Important: before proceeding, the yscales should be set using ylim() in both axes (not shown). The y-limits are already ideally set in the simple demo using auto Y-limit-mode.
1. Turn off interactions for axes #2 (right)
All zooming / panning should be done in axes #1 on the left.
ax(2).Toolbar.Visible = 'off';
2. Set up a listener that will respond to y-axis limit changes in axes #1 (left)
xyscale = range(ax(2).YLim) / range(ax(1).YLim);
axBaseLim = [ax(1).YLim; ax(2).YLim];
ax(1).UserData.Listener = addlistener(ax(1),{'YLim'}, 'PostSet', ...
@(~,~)axisLimitListener([], [], [ax(1),ax(2)], xyscale, axBaseLim));
3. Address the "restore view" button problem
When you press the "restore view" button in the axis #1 toolbar, this listener will not respond. To address that, this block below and the "myRestoreButtonCallbackFcn" block below will update axes #2 when the "restore view" button is pressed in axes #1.
axTB = axtoolbar(ax(1),'default');
isRestoreButton = strcmpi({axTB.Children.Icon},'restoreview');
restoreButtonHandle = axTB.Children(isRestoreButton);
originalRestoreFcn = restoreButtonHandle.ButtonPushedFcn;
restoreButtonHandle.ButtonPushedFcn = ...
{@myRestoreButtonCallbackFcn, ax(2), originalRestoreFcn, xyscale, axBaseLim};
4. Define listener that responds to changes to y-axis limits in axes #1
function axisLimitListener(~,~,ax,scalingFactor,axBaseLim)
normLowerLimit = (ax(1).YLim(1) - axBaseLim(1,1))./range(axBaseLim(1,:));
newLimits = normLowerLimit.*range(axBaseLim(2,:)) + axBaseLim(2,1);
newLimits(:,2) = newLimits + range(ax(1).YLim).*scalingFactor;
set(ax(2), 'YLim', newLimits)
5. Define the "restore view" callback that responds to axis #1 toolbar > Restore View
function myRestoreButtonCallbackFcn(hobj, event, ax2, originalCallback, xyscale, axBaseLim)
originalCallback(hobj,event)
axisLimitListener([],[],[event.Axes,ax2],xyscale,axBaseLim)