Clear Filters
Clear Filters

Multi x plot, linked zoom and indipendent pan

11 views (last 30 days)
Hi guys, my goal is to have a plot with two x axes and at least two y axes and to be able to pan one indipentently from the other but with linked zoom on the X axis. Suppose to have two time signal, one shorter than the other, and you want to move one over the other to compare them at a precise moment. I have tried linkprop and linkaxes in some ways but the result is that I managed to link zoom and pan together but not to decouple them. To be clear, the aim is: plot 2 signal with different X and Y, zoom them at the same level, horizontal pan one indipendently from the other.
Thanks in advance guys

Answers (1)

Just Manuel
Just Manuel on 27 Jan 2021
Edited: Just Manuel on 27 Jan 2021
I've run into the same problem. There does not seem to be a convenient way to do this. I have worked around it using ActionPreCallback and ActionPostCallback on the zoom object.
As matlab only feeds those callbacks with the handle to the figure being zoomed and the handle to the axes being zoomed, you have to remember the original limits yourself.
Another issue is that you can not have a return value in the callbacks, so you have to implement some kind of out parameter. I created a handle wrapper for that.
Here's an example how i used it (tested in R2018a):
% generate some sample data
x1 = 1:0.1:20;
x2 = x1(20:80);
x3 = x1(30:120);
y1 = sin(x1);
y2 = sin(x2 + 1);
y3 = sin(x3 - 2);
% plot data using axes with transparent background on top on each other
% see
line(x1, y1);
ax(1) = gca;
ax(1).XColor = 'b';
ax(2) = axes('Position',ax(1).Position, 'XAxisLocation','top', 'Color','none');
ax(2).XColor = 'r';
line(x2, y2, 'Parent',ax(2), 'Color', 'r');
ax(3) = axes('Position',ax(1).Position, 'XAxisLocation','origin', 'Color','none');
ax(3).XColor = [0.5 0 0.1];
line(x3, y3, 'Parent',ax(3), 'Color',[0.5 0 0.1]);
linkaxes(ax, 'y');
% synchronize limits
xlim(ax(2), xlim(ax(1)));
xlim(ax(3), xlim(ax(1)));
% instatniate a handle containing a cell array with the current limits
originalLimitsHandle = HandleWrapper({xlim(ax(1)), xlim(ax(2)), xlim(ax(3))});
z = zoom;
% update current limits before the zoom happens
z.ActionPreCallback = {@updateLimits, ax, originalLimitsHandle};
% update the limits of the other axes after the zoom has happened
z.ActionPostCallback = {@linkXZoom, ax, originalLimitsHandle};
function updateLimits(fig, ax, linkedAxes, originalLimitsHandle)
for n = 1:length(linkedAxes)
originalLimitsHandle.Property{n} = xlim(linkedAxes(n));
function linkXZoom(fig, ax, linkedAxes, originalLimitsHandle)
% determine which axes was zoomed (source)
zoomedIndex = find(eq(ax.Axes, linkedAxes));
originalSourceLimits = originalLimitsHandle.Property{zoomedIndex};
newSourceLimits = xlim(ax.Axes);
% determine offsets to calculate new limits
offset = newSourceLimits(1) - originalSourceLimits(1);
limitWidth = newSourceLimits(2) - newSourceLimits(1);
for n = 1:length(linkedAxes)
% only update the non-zoomed axes (targets)
if n ~= zoomedIndex
% calculate new limits
originalTargetLimits = xlim(linkedAxes(n));
newTargetLimits = [originalTargetLimits(1) + offset, ...
originalTargetLimits(1) + offset + limitWidth];
% do the zooming by setting the calculated x limits
xlim(linkedAxes(n), newTargetLimits);
And that's the handle wrapper class:
classdef HandleWrapper < handle
%HANDLEWRAPPER wraps a property within a handle
% can be used as an pointer parameter in functions
function obj = HandleWrapper(property)
if nargin ~= 0
obj.Property = property;
Hope that hepls you (and any other poor soul encountering the same problem)
Cheers Manuel
  1 Comment
Just Manuel
Just Manuel on 27 Jan 2021
This vexed me. I extended the functionality and packed it into a single class. It now behaves similarly to linkaxes.

Sign in to comment.


Find more on Visual Exploration 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!