Reputation: 315
Following the instructions on other pages, e.g.
http://blogs.mathworks.com/videos/2011/10/19/tutorial-how-to-make-a-custom-data-tip-in-matlab/ http://it.mathworks.com/help/matlab/ref/datacursormode.html http://it.mathworks.com/matlabcentral/answers/68079-how-to-add-additional-info-to-the-data-cursor
i've written a custom callback function for the datatip to show me the index of the points on a x-y graph as well as their x and y coordinates:
function output_txt = customCallback_DataTip(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');
output_txt = {['X: ',num2str(pos(1),4)],...
['Y: ',num2str(pos(2),4)]};
% 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),4)];
else % 2D plot: write index of current point
i = find(event_obj.Target.XData == pos(1), 1);
output_txt{end+1} = ['i: ',num2str(i)];
end
This code starts from the default callback suggested by MATLAB, and adds a z-coordinate info whenever the plot is a 3D one. Since I very often need to know the array index of a point on a graph, the custom callback function is enabled automatically at MATLAB startup.
Now, whenever I plot an image (e.g. via imagesc
) I would like to have the "normal" image datatip:
i.e. with Index/RGB information on it. How can I modify the callback function in order to obtain this behavior?
EDIT: i would like to modify my custom callback so that it automatically displays something similar to the default MATLAB default datatip when I'm using the datatip on an image.
Upvotes: 1
Views: 2349
Reputation: 65440
To accomplish this, you can check the type of the event_obj.Target
and respond accordingly.
get(event_obj.Target, 'type')
All images (whether imagesc
, image
, or imshow
) will have a Type
of image
.
isImage = strcmpi(get(event_obj.Target, 'type'), 'image')
You can then extract the image data. If you have an indexed image, you can also get the colormap to determine all the other information to go into the datatip.
cdata = get(event_obj.Target, 'cdata');
cmap = colormap(ancestor(event_obj.Target, 'axes'));
Bringing this all together, I would modify your custom data tip callback to be something like this.
function output_txt = callback(obj, event_obj, clims)
% Get the cursor location
pos = get(event_obj, 'Position');
output_txt = {sprintf('[X,Y]: [%i, %i]', pos(1), pos(2))};
if strcmpi(get(event_obj.Target, 'type'), 'image')
% Get the image data
cdata = get(event_obj.Target, 'CData');
% Check to ensure pos is in range
if pos(1) < 1 || pos(1) > size(cdata, 2) || ...
pos(2) < 1 || pos(2) > size(cdata, 1)
rgb = {NaN, NaN, NaN};
newline = sprintf('[R,G,B]: [%0.4f %0.4f %0.4f]', rgb{:});
output_txt = cat(1, output_txt, newline);
return
end
% If the image is RGB
if size(cdata, 3) == 3
rgb = num2cell(cdata(pos(2), pos(1), :));
% If this is an indexed image
else
index = cdata(pos(2), pos(1));
% Figure out the colormap
hax = ancestor(event_obj.Target, 'axes');
cmap = colormap(hax);
% If the CData is scaled, we need to scale to the colormap
if strcmpi(get(event_obj.Target, 'CDataMapping'), 'scaled')
value = (index - clims(1)) * size(cmap, 1) / diff(clims);
else
value = index;
end
% Determine RGB value from colormap
rgb = num2cell(ind2rgb(round(value), cmap));
if round(index) == index
newline = sprintf('Index: %d', index);
else
newline = sprintf('Index: %.4f', index);
end
% Generate datatip text
output_txt = cat(1, output_txt, newline);
end
output_txt = cat(1, output_txt, ...
sprintf('[R,G,B]: [%0.4f %0.4f %0.4f]', rgb{:}));
% Otherwise we use your custom datatip for plots
else
index = find(event_obj.Target.XData == pos(1), 1);
pos = get(event_obj, 'Position');
output_txt = { sprintf('X: %0.4f', pos(1));
sprintf('Y: %0.4f', pos(2))};
% If there is a Z-coordinate in the position, display it as well
if length(pos) > 2
output_txt{end+1} = sprintf('Z: %0.4f', pos(3));
else % 2D plot: write index of current point
output_txt{end+1} = sprintf('i: %d', index);
end
end
end
If you notice, I'm passing in an additional variable (clims
) to the callback function. This is because some versions won't actually allow me to query axes properties from within the datatip UpdateFcn
. So this means that you will have to change your UpdateFcn
anonymous function just a little bit.
h = datacursormode(fig);
set(h, 'Enable', 'on')
% Here I have to pass the `clims` because I can't fetch them inside
set(h, 'UpdateFcn', @(dt,e)callback(dt, e, caxis(ancestor(dt.Host, 'axes'))));
Using this, I was able to show the proper display for both plots and images (both indexed and RGB).
Upvotes: 4