How can I display Index of a data point on the Data Cursor?

74 views (last 30 days)
When I use the Data Cursor option on a plot, I am able to view the X and Y-coordinates on the tool tip. However I wish to see the index of that point. I have tried editing the textUpdate function as follows:
function output_txt = myfunction(obj,event_obj)
% Display the position of the data cursor
% obj Currently not used (empty)
% event_obj Handle to event object
% output_txt Data cursor text string (string or cell array of strings).
pos = get(event_obj,'Position');
x = pos(1);
y = pos(2);
idx = find(xydata == x,y);
[row,~] = ind2sub(size(xydata),idx);
output_txt{end+1} = cell2mat(labels(row));
However this gives an error. Does anyone have any suggestions?
Thanks in advance
Deepa
  2 Comments
Adam
Adam on 7 Jul 2017
Edited: Adam on 7 Jul 2017
You haven't shown what you are doing with that function (how you are calling it) or what the error is so you can't really expect to get too much help if you don't give all relevant information.
dcm = datacursormode( hFig );
dcm.UpdateFcn = @updateDataCursor;
is the kind of thing to use to create a custom data cursor if you put the relevant code in updateDataCursor which may be what your 'myFunction' is, but that would just be a guess since you haven't shown that part of the code.
Deepa T
Deepa T on 8 Jul 2017
Edited: Walter Roberson on 9 Jul 2017
You are correct. The updateDataCursor is myFunction. I simply edited the default MATLAB function for data cursor.
By default, the data cursor displays x coordinate and y coordinate on the tooltip when a data point is clicked. I wish to display the index of the data point that is being plotted instead.
I have since made some modifications to the code. Code in main pgm:
dcm_obj = datacursormode(fig);
set(dcm_obj,'UpdateFcn',@myupdatefcn);
The updatefunction code is:
function txt = myupdatefcn(obj,event_obj)
pos = get(event_obj,'Position');
x = pos(1); y = pos(2); I = get(event_obj, 'DataIndex');
txt = {['X: ',num2str(x)],...
['Y: ',num2str(y)],...
['I: ',num2str(I)]};
Currently the DataIndex displays the same value as X.
X:8 Y:0.6 .DataIndex:8
I need it to display the index of the Yth variable. For example, if the point I have selected (8,0.6) is at index [8,59], I need it to display:
X:8 Y:0.6 DataIndex:59
Hope this clarifies the confusion.
Deepa

Sign in to comment.

Accepted Answer

Deepa T
Deepa T on 12 Jul 2017
Edited: Deepa T on 12 Jul 2017
I've received the desired output with the following code:
function txt = myupdatefcn(~,event_obj,myarray)
pos = get(event_obj,'Position');
ind = find(myarray(:,pos(1))== pos(2));
txt = {['X: ',num2str(pos(1))],...
['Y: ',num2str(pos(2))],...
['Index: ',num2str(ind')]};
end
as well as the following code in the main function.
dcm_obj = datacursormode(fig);
set(dcm_obj,'UpdateFcn',{@myupdatefcn,myarray})
Many thanks to everyone who helped.
  3 Comments
Deepa T
Deepa T on 15 Jan 2020
myarray is the name of the dataset I'm using. It's not a function.
Samuli Karvinen
Samuli Karvinen on 15 Jan 2020
Hey,
Oh I see, what data have put in there? The data tip objects?
Thanks in advance!
Samuli

Sign in to comment.

More Answers (3)

Les Beckham
Les Beckham on 8 Jul 2017
Try this (modify the num2str calls as you wish to get the number of digits you desire):
function output_txt = datatip_cb15digits(obj,event_obj)
% datatip_cb15digits.m - datatip callback function - modified to display 15 digits
% Display the position of the data cursor
% obj Currently not used (empty)
% event_obj Handle to event object
% output_txt Data cursor text string (string or cell array of strings).
pos = get(event_obj,'Position');
handles = get(gca, 'Children');
h=handles((handles == event_obj.Target));
dim = 2; % initially assume this is a 2d plot
output_txt = {['X: ',num2str(pos(1),15)],...
['Y: ',num2str(pos(2),15)]};
% If there is a Z-coordinate in the position, display it as well
if length(pos) > 2
output_txt{end+1} = ['Z: ',num2str(pos(3),15)];
dim = 3;
end
% display the index of the currently selected datapoint
if (dim == 2)
i = find(get(h, 'XData') == pos(1) & get(h, 'YData') == pos(2));
else
i = find(get(h, 'XData') == pos(1) & get(h, 'YData') == pos(2) ...
& get(h, 'ZData') == pos(3));
end
output_txt{end+1} = ['i: ', num2str(i)];
  5 Comments
Walter Roberson
Walter Roberson on 9 Jul 2017
Correct, the data index is specific to the line that was clicked on, and indicates the relative offset into the line, as in XData(index) YData(index) . This need not be sorted by x or y, and is completely independent of every other line or graphics object.
If you have access to all of the data to be plotted, you could always unique() the complete list of y values concatenated together, and request the third output of unique() so you know the index of each of the values relative the list of unique values, and then you could break that list up using mat2cell() according to the length of each original line, and then you could set() the UserData for each line to include the y indices for each point. Then your update handler can use the data index to index the UserData to get the information to display.
Deepa T
Deepa T on 9 Jul 2017
Thank you, Walter. That sounds like what I want to do. I'm trying to implement the code for this. Afraid I'm a newbie to MATLAB :(
Thank you
Deepa

Sign in to comment.


Walter Roberson
Walter Roberson on 9 Jul 2017
Suppose you have a cell, Xs, of all of the X values, and a cell Ys, of the corresponding Y values, such as might be plotted with
XYs = [Xs(:).'; Ys(:).'];
plot(XYs{:})
Then,
%create a giant column vector of all of the Y values
%and find the unique Y values and the indices of each
%original value into the unique list.
%this code does not assume anything about the orientation
%of the vectors
[uY, ~, uYidx] = unique( cell2mat( cellfun(@(V) V(:), Ys(:), 'Uniform', 0) ) );
Ylens = cellfun(@length, Ys);
Yidxcell = mat2cell(uYidx, Ylens, 1);
XYs = [Xs(:).'; Ys(:).'];
linehandles = plot(XYs{:});
for K = 1 : length(linehandles)
set(linehandles(K), 'UserData', Yidxcell{K});
end
Together with
function txt = myupdatefcn(obj, event_obj)
pos = get(event_obj,'Position');
x = pos(1); y = pos(2);
I = get(event_obj, 'DataIndex');
Yidxs = get(obj, 'UserData');
if isempty(Yidxs) || length(Yidxs) < I;
Yidx = '?';
else
Yidx = Yidxs(I);
end
txt = {['X: ',num2str(x)],...
['Y: ',num2str(y)],...
['I: ', Yidx]};
  2 Comments
Les Beckham
Les Beckham on 9 Jul 2017
There are definitely some very clever Matlab tricks and manipulations going on here, but in what legitimate use case would anyone ever create a plot this way? Since the OP never gave us an example of how the data is being plotted or what they are really trying to achieve, I'm skeptical that your very creative answer will really solve the poorly defined problem. OP did comment that "That sounds like what I want to do," so, hopefully I'm wrong.
I would definitely be interested in some sort of real world example where this approach would apply.

Sign in to comment.


Seyhan Özen
Seyhan Özen on 18 Jul 2022

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!