Reputation: 1245
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
However, if I toggle linkdata on
, the plot completely changes to this.
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
Reputation: 398
You can use the undocumented BrushData
property with brush's ActionPostCallback
. The BrushData
property is a uint8
array of 0
s and 1
s, with 1
s 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
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
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