How to use data cursor mode to display data tips for multiple plots in a tiled layout?

143 views (last 30 days)
Hello,
I am having some difficulty in using datacursormode to display some data tips for different subplots in a tiled layout.
In this example, I have a tiled layout with 6 scatter plots. I have collected some other useful information beforehand for each point that I would like to display in a datatip whenever a point is clicked on. I am trying to accomplish this by using datacursormode with a callback function. I am trying to pass the metadata I would like to display for each point in the data tip as an argument to a callback function.
I am struggling with how to accomplish this in a figure with mutliple plots. In my example code shown, the metadata is the same for every plot in the tiled layout (it is always shown as 70 in the datatip). It looks like it is just using the metadata accessed last in the loop. I expected the first plot to show 20, the next 30, then 40, and so on. Should I be specifying an axes instead of a figure for the datacursormode callback? If so, I could not figure out how to do this. Or is there a better approach?
Any help would be greatly appreciated.
Image of Plot
Code
fig = figure(); %create the tiled layout
set(gcf,'Name',"tiled");
t = tiledlayout('flow');
scatter_data = 10:20;
meta_data = [20,30,40,50,60,70]; %example useful metadata I would like to include in the data tip
for qq = 1:length(1:6) %creating the 6 subplots
a = nexttile;
scatter(1:10, ...
1:10, ...
36);
dcm = datacursormode;
dcm.Enable = 'on';
dcm.DisplayStyle = 'window';
dcm.UpdateFcn = {@displayCoordinates,meta_data(qq)}; %try to use a callback function to display the metadata
end
function txt = displayCoordinates(~,info, dat) %callback function I am using to display the metadata
x = info.Position(1);
y = info.Position(2);
txt = ['(' num2str(x) ', ' num2str(y) ')' ', ' num2str(dat)]; %the datatip on every subplot shows dat as 70
end

Answers (1)

Kevin Holly
Kevin Holly on 24 Apr 2023
If you are interested in the datatips information. You can acces the information from the Children subfield of the Scatter plot, which is a child of the axes. Note the last created datatip would be the first child. You could utilize this approach along with datacursormode with techniques shown in the example app attached.
figure
scatter(rand(10,1),rand(10,1))
% Select datatip
h = gca; %get current axes
h.Children.Children
Example app:
If you are trying to read the coordinates on the axes as your cursor moves, you can add listeners. In the attach example, I added listeners to my figure using WindowButtonMotionFcn and WindowButtonMotionFcn that tiggered the events 'WindowMouseMotion' and 'WindowMousePress' that pulled the CurrentPoint from an axes if the mouse was within the limits. I got the handles of the axes by setting a variablename = nexttile.
I hope this helps.
snippets from attached app:
app.tfig = figure('Name','Point');
tiledlayout(app.tfig,1,2);
app.ax1 = nexttile;
app.x1 = linspace(0,6);
app.y1 = sin(app.x1);
plot(app.ax1,app.x1,app.y1)
app.ax2 = nexttile;
app.x2 = linspace(0,6);
app.y2 = sin(app.x1);
plot(app.ax2,app.x2,app.y2)
linkaxes([app.ax1 app.ax2],'xy')
app.tfig.WindowButtonMotionFcn={@mouseMotionCB,app.ax1,app.ax2};
app.tfig.WindowButtonDownFcn={@mouseMotionCB,app.ax1,app.ax2};
function mouseMotionCB(fig,event,ax1,ax2)
% disp(event.EventName)
eventname = event.EventName;
switch eventname
case 'WindowMouseMotion'
currentPoint1 = ax1.CurrentPoint(1,1:3);
x1 = currentPoint1(1);
y1 = currentPoint1(2);
currentPoint2 = ax2.CurrentPoint(1,1:3);
x2 = currentPoint2(1);
y2 = currentPoint2(2);
if (ax1.XLim(1)<x1)&&(x1<ax1.XLim(2)) && (ax1.YLim(1)<y1)&&(y1<ax1.YLim(2))
title(ax1,'(X,Y)=', currentPoint1);
set(fig,'Pointer','crosshair');
elseif (ax2.XLim(1)<x2)&&(x2<ax2.XLim(2)) && (ax2.YLim(1)<y2)&&(y2<ax2.YLim(2))
title(ax2,'(X,Y)=', currentPoint2);
set(fig,'Pointer','crosshair');
else
set(fig,'Pointer','arrow');
end
case 'WindowMousePress'
currentPoint1 = ax1.CurrentPoint(1,1:3);
x1 = currentPoint1(1);
y1 = currentPoint1(2);
if (ax1.XLim(1)<x1)&&(x1<ax1.XLim(2)) && (ax1.YLim(1)<y1)&&(y1<ax1.YLim(2))
hold(ax1,"on")
scatter(ax1,x1,y1,'filled','b');
hold(ax1,"off")
end
currentPoint2 = ax2.CurrentPoint(1,1:3);
x2 = currentPoint2(1);
y2 = currentPoint2(2);
if (ax2.XLim(1)<x2)&&(x2<ax2.XLim(2)) && (ax2.YLim(1)<y2)&&(y2<ax2.YLim(2))
hold(ax2,"on")
scatter(ax2,x2,y2,'filled','g');
hold(ax2,"off")
end
end
end

Categories

Find more on Graphics Object Properties 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!