Add data tips to non-supported chart

15 visualizaciones (últimos 30 días)
Roger Breton
Roger Breton el 18 de En. de 2022
Editada: Adam Danz el 31 de En. de 2022
I'm creating a 2D graph, element by element, using rectangles. This is my current code:
clc
fig=figure('Position', [600 300 1000 1000])
ax = axes
axis([-128 128 -128 128])
xticks([-128 -112 -96 -80 -64 -48 -32 -16 0 16 32 48 64 80 96 112 128]);
yticks([-128 -112 -96 -80 -64 -48 -32 -16 0 16 32 48 64 80 96 112 128]);
grid on
grid minor
OffsetX=0;
OffsetY=0;
Axe_A = transpose(linspace(0, 96, 24))
Axe_L = transpose(linspace(50, 50, 24))
Axe_B = transpose(linspace(0, 0, 24))
InGamut = transpose(linspace(0, 0, 24))
Lab = [Axe_L, Axe_A, Axe_B];
RGB = lab2rgb(Lab)
%Add 4th column to flag out of gamut colors
RGBx = [RGB InGamut];
for ROW = 1:row
if RGB(ROW,1) < 0
RGBx(ROW,1) = 0;
RGBx(ROW,4) = 1;
end
if RGB(ROW,1) > 1
RGBx(ROW,1) = 1;
RGBx(ROW,4) = 1;
end
if RGB(ROW,2) < 0
RGBx(ROW,2) = 0;
RGBx(ROW,4) = 1;
end
if RGB(ROW,2) > 1
RGBx(ROW,2) = 1;
RGBx(ROW,4) = 1;
end
if RGB(ROW,3) < 0
RGBx(ROW,3) = 0;
RGBx(ROW,4) = 1;
end
if RGB(ROW,3) > 1
RGBx(ROW,3) = 1;
RGBx(ROW,4) = 1;
end
end
T = RGBx
[row,col] = size(RGB); % 16 x 3 double
for ROW = 1:row
if RGBx(ROW,4) == 0
rectangle(ax,'Position',[OffsetX OffsetY 4 4],'FaceColor',[RGBx(ROW,1) RGBx(ROW,2) RGBx(ROW,3)], 'LineStyle', 'none');
else
rectangle(ax,'Position',[OffsetX OffsetY 4 4],'FaceColor',[RGBx(ROW,1) RGBx(ROW,2) RGBx(ROW,3)]');
end
OffsetX=OffsetX+4
end
This is what the result looks like, so far :
Trouble is, there does not seem to be a way to add data tips to this graphics?
I wish I could display the Lab values when the mouse hover the graphic.

Respuestas (1)

Adam Danz
Adam Danz el 18 de En. de 2022
Editada: Adam Danz el 21 de En. de 2022
Demo 1: Click rectangle to show datatip using ButtonDownFcn
This demo is based on this answer using patches. A ButtonDownFcn is assigned to each rectangle. When clicked, a datatip appears. A 1x3 vector of RGB color values is added to the datatip.
% Define rectangle data
[xo,yo] = meshgrid(1:4,1:5); % rectangle (x,y) positions
rng('default') % for reproducibility of this demo
colors = rand(numel(xo),3) % mx3 color matrix for m rectangles (aka "Lab" in your code)
labels = compose('[%.2f %.2f %.2f]',colors) % Rectangle labels
% Draw rectangles
hFig = figure();
ax = axes(hFig);
hold(ax, 'on')
for i = 1:numel(xo)
rectangle(ax, 'Position', [xo(i), yo(i), .6, .6], ...
'FaceColor', colors(i,:), ...
'LineStyle','none', ...
'UserData', labels(i), ... % Assign label to each rectangle
'ButtonDownFcn', @rectButtonDownFcn); % Assign button-down-function
end
function rectButtonDownFcn(rectObj, hit)
% Responds to mouse clicks on rectangle objs.
% Add point at click location and adds a datatip representing
% the underlying patch.
% datatip() requires Matlab r2019b or later
% store mouse click coordinate
hitPoint = hit.IntersectionPoint;
% store original hold state and return at the end
ax = ancestor(rectObj,'axes');
holdStates = ["off","on"];
holdstate = ishold(ax);
cleanup = onCleanup(@()hold(holdStates(holdstate+1)));
hold(ax,'on')
% Search for and destroy previously existing datatips
% produced by this callback fuction.
preexisting = findobj(ax,'Tag','TempDataTipMarker');
delete(preexisting)
% detect 2D|3D axes
nAxes = numel(axis(ax))/2;
% Plot temp point at click location and add datatip
if nAxes==2 % 2D axes
hh=plot(ax,hitPoint(1),hitPoint(2),'k.','Tag','TempDataTipMarker');
dt = datatip(hh, hitPoint(1), hitPoint(2),'Tag','TempDataTipMarker');
else %3D axes
hh=plot(ax,hitPoint(1),hitPoint(2),hitPoint(3),'k.','Tag','TempDataTipMarker');
dt = datatip(hh, hitPoint(1), hitPoint(2), hitPoint(3),'Tag','TempDataTipMarker');
end
dt.DeleteFcn = @(~,~)delete(hh);
clear cleanup % return hold state
% Update datatip
% pos = hit.IntersectionPoint(1:2);
dtr = dataTipTextRow('Color:', repelem(rectObj.UserData,1,4));
hh.DataTipTemplate.DataTipRows(end+1) = dtr;
end
Demo 2: Move cursor over rectangles to show datatip using WindowButtonMotionFcn
A WindowButtonMotionFcn is assigned to the figure. When the mouse is within a rectangle, a datatip appears and follows the mouse until it leaves the rectangle. A 1x3 vector of RGB color values is added to the datatip. For simplicity, this demo assumes rectangles do not overlap and that their edges are parallel to the x and y axes. If any rectangle is deleted, the WindowButtonMotionFcn will be removed.
% Define rectangle data
[xo,yo] = meshgrid(1:4,1:5); % rectangle (x,y) positions
rng('default') % for reproducibility of this demo
colors = rand(numel(xo),3) % mx3 color matrix for m rectangles (aka "Lab" in your code)
labels = compose('[%.2f %.2f %.2f]',colors) % Rectangle labels
% Draw rectangles
hFig = figure();
ax = axes(hFig);
hold(ax, 'on') % required by WindowButtonMotionFcn
rectHandles = gobjects(size(xo));
for i = 1:numel(xo)
rectHandles(i) = rectangle(ax, ...
'Position', [xo(i), yo(i), .6, .6], ...
'FaceColor', colors(i,:), ...
'LineStyle','none', ...
'UserData', labels(i), ... % Assign label to each rectangle
'DeleteFc', @(h,~)set(ancestor(h,'figure'), 'WindowButtonMotionFcn',''));
% Remove WindowButtonMotionFcn if any rectangle is deleted
end
% Assign WindowButtonMotionFcn to figure
hFig.WindowButtonMotionFcn = {@rectButtonMoFcn, rectHandles(:), ax};
function rectButtonMoFcn(~, ~, rectObj, axHandle)
% Responds to mouse movement in figure (fig).
% Displays datatip if within rectangle (rectObj).
% This fcn should be as efficient and simple as possible.
% datatip() requires Matlab r2019b or later
persistent floatingMarkerHandle
% Create floating marker if it doesn't exist
if isempty(floatingMarkerHandle) || ~isvalid(floatingMarkerHandle)
floatingMarkerHandle = plot(axHandle,rectObj(1).Position(1),rectObj(1).Position(2),'k.','Visible','off');
datatip(floatingMarkerHandle, floatingMarkerHandle.XData, floatingMarkerHandle.YData);
dtr = dataTipTextRow('Color:', repelem({'[0 0 0]'},1,4));
floatingMarkerHandle.DataTipTemplate.DataTipRows(end+1) = dtr;
end
% get rectangle values
rectPos = cell2mat(get(rectObj,'position'));
rectX = [rectPos(:,1), rectPos(:,1)+rectPos(:,3)];
rectY = [rectPos(:,2), rectPos(:,2)+rectPos(:,4)];
% Determine which rectangle the mouse is in, if any.
% Assumes rectangle edges are vertical or horizontal (parallel to x,y axes)
cp = axHandle.CurrentPoint(1,1:2); % Current mouse point, data units, 2D axes.
rectIdx = cp(1) >= rectX(:,1) & ...
cp(1) <=rectX(:,2) & ...
cp(2) >= rectY(:,1) & ...
cp(2) <=rectY(:,2);
% Update floating marker and data tip if inside a rectangle; otherwise turnoff
if any(rectIdx)
set(floatingMarkerHandle,'XData',cp(1),'YData',cp(2),'Visible','on');
rectUserData = rectObj(rectIdx).UserData; % Assumes only 1 rectangle is selected (ie, no overlap)
floatingMarkerHandle.DataTipTemplate.DataTipRows(end).Value = rectUserData;
else
set(floatingMarkerHandle,'Visible','off');
end
end
  8 comentarios
Roger Breton
Roger Breton el 20 de En. de 2022
I take your suggestions very well, Adam! I experimented at some point with passing the axis handle in the callback function parameters but it did not solve my problem then? But I'll 'revisit' it -- promised.
I was thinking about using a fixed text box in the figure margin that displays the value but it's not as "live" or "interactive" as having a datatip exactly where the mouse points, which is the 'point' I want to nail with students...
Adam Danz
Adam Danz el 21 de En. de 2022
Editada: Adam Danz el 31 de En. de 2022
I've added a 2nd demo to my answer showing how to apply the same method as my first demo to a WindowButtonMotionFcn so that datatips show automatically when hovering over rectangels.
I believe this is what you were describing in this comment.

Iniciar sesión para comentar.

Categorías

Más información sobre Graphics Object Properties en Help Center y File Exchange.

Productos


Versión

R2021b

Community Treasure Hunt

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

Start Hunting!

Translated by