Thomas
Thomas

Reputation: 1245

Link different data sources in Matlab subplots

I want to plot latitude and longitude data together with another type of data (speed), recorded at every latitude-longitude-point. This is basically equivalent to

figure()
subplot(1,2,1); plot(lat,lon);
subplot(1,2,2); plot(t,y);

Where all vectors have the same length and t is the timestamp in seconds for every recording. I'd love to be able to link the data such that when I highlight data in the first subplot, the corresponding data gets highlighted in the second subplot (and vice versa).

However, because the two subplots don't have a common data source (at least not by name), I struggle to get linkdata working.

Here's what I tried (without linkdata)

function linkedexasmple()
close all

t = linspace(-2,2,100);
lat = sin(t);
lon = cos(t);
x = t;
y = exp(t);
M = [lat',lon',x',y'];

figure()
whos

subplot(1,2,1)
plot(M(:,1),M(:,2),'-x','XDataSource','M(:,1)','YDataSource','M(:,2)');
subplot(1,2,2)
plot(M(:,3),M(:,4),'-x','XDataSource','M(:,3)','YDataSource','M(:,4)');

%linkdata on
%linkdata showdialog
end

enter image description here

However, if I toggle linkdata on, the plot completely changes to this. enter image description here

How can I preserve the original plot while enabling linking them?

As a last remark: I would obviously want to call that function with arguments (lat, lon, x, y) later on. But for this MWE, I thought it would be easier this way.

Upvotes: 2

Views: 283

Answers (2)

Miscellaneous
Miscellaneous

Reputation: 398

You can use the undocumented BrushData property with brush's ActionPostCallback. The BrushData property is a uint8 array of 0s and 1s, with 1s indicating data points that are selected. In the callback function, set the BrushData of both subplots simultaneously when either of them is "brushed".

function linkedexample()
    t = linspace(-2,2,100);
    lat = sin(t);
    lon = cos(t);
    x = t;
    y = exp(t);

    fig = figure();
    subplot(1,2,1)
    p1 = plot(lat,lon);
    subplot(1,2,2)
    p2 = plot(x,y);

    % Bind callback function with the brush
    b = brush(fig);
    b.ActionPostCallback = {@onBrushAction};

    % callback function
    function onBrushAction(~, eventdata)
        set(p1, 'BrushData', eventdata.Axes.Children.BrushData)
        set(p2, 'BrushData', eventdata.Axes.Children.BrushData)
    end
end

The result: Sync brush highlight of subplots

These two articles, "Accessing plot brushed data" on Undocumented Matlab and this Mathwork post by its staff, provide more information about BrushData and ActionPostCallback.

Upvotes: 2

Luk
Luk

Reputation: 46

Interesting question. Rather than linkdata, a callback function that responds to a click input would be more natural to me.

The solution below is a quick hack -- you'd always need to select a point in subplot 1. It can be made more fancy by using MATLAB's ButtonDownFcn function and by defining a callback that understands which subplot has been selected.

close all
clearvars

t = linspace(-2,2,100);
lat = sin(t);
lon = cos(t);
x = t;
y = exp(t);
M = [lat',lon',x',y'];

figure(1);

subplot(1,2,1)
plot(M(:,1),M(:,2),'-x','XDataSource','M(:,1)','YDataSource','M(:,2)');
subplot(1,2,2)
plot(M(:,3),M(:,4),'-x','XDataSource','M(:,3)','YDataSource','M(:,4)');

% Quick hack
while 1
    
    % Get coordinates of clicked point
    waitforbuttonpress;
    CP = get(gca,'CurrentPoint');
    x1 = CP(2,1);  % X-point
    y1 = CP(2,2);  % Y-point

    % Find index of closest point
    dists = (M(:,1)-x1).^2 + (M(:,2)-y1).^2; 
    [~,idx] = min(dists);

    % Replot base-figure to remove previously selected points
    figure(1);
    subplot(1,2,1)
    plot(M(:,1),M(:,2),'-x','XDataSource','M(:,1)','YDataSource','M(:,2)');
    subplot(1,2,2)
    plot(M(:,3),M(:,4),'-x','XDataSource','M(:,3)','YDataSource','M(:,4)');


    % Update both subplots
    subplot(1,2,1)
    hold on
    plot(M(idx,1),M(idx,2),'ro');
    hold off
    subplot(1,2,2)
    hold on
    plot(M(idx,3),M(idx,4),'ro');
    hold off
end

Upvotes: 1

Related Questions