Add data tips to non-supported chart

12 visualizaciones (últimos 30 días)
Roger Breton
Roger Breton el 18 de En. de 2022
Editada: Walter Roberson el 3 de Dic. de 2024
I'm creating a 2D graph, element by element, using rectangles. This is my current code:
clc
fig=figure('Position', [600 300 1000 1000])
fig =
Figure (1) with properties: Number: 1 Name: '' Color: [1 1 1] Position: [600 300 1000 1000] Units: 'pixels' Use GET to show all properties
ax = axes
ax =
Axes with properties: XLim: [0 1] YLim: [0 1] XScale: 'linear' YScale: 'linear' GridLineStyle: '-' Position: [0.1300 0.1100 0.7750 0.8150] Units: 'normalized' Use GET to show all properties
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_A = 24×1
0 4.1739 8.3478 12.5217 16.6957 20.8696 25.0435 29.2174 33.3913 37.5652
<mw-icon class=""></mw-icon>
<mw-icon class=""></mw-icon>
Axe_L = transpose(linspace(50, 50, 24))
Axe_L = 24×1
50 50 50 50 50 50 50 50 50 50
<mw-icon class=""></mw-icon>
<mw-icon class=""></mw-icon>
Axe_B = transpose(linspace(0, 0, 24))
Axe_B = 24×1
0 0 0 0 0 0 0 0 0 0
<mw-icon class=""></mw-icon>
<mw-icon class=""></mw-icon>
InGamut = transpose(linspace(0, 0, 24))
InGamut = 24×1
0 0 0 0 0 0 0 0 0 0
<mw-icon class=""></mw-icon>
<mw-icon class=""></mw-icon>
Lab = [Axe_L, Axe_A, Axe_B];
RGB = lab2rgb(Lab)
RGB = 24×3
0.4663 0.4663 0.4663 0.4951 0.4573 0.4668 0.5226 0.4477 0.4674 0.5492 0.4376 0.4679 0.5749 0.4269 0.4685 0.5999 0.4156 0.4690 0.6242 0.4035 0.4696 0.6481 0.3906 0.4702 0.6714 0.3767 0.4708 0.6943 0.3619 0.4715
<mw-icon class=""></mw-icon>
<mw-icon class=""></mw-icon>
%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
Unrecognized function or variable 'row'.
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
  10 comentarios
Muhammad Anam
Muhammad Anam el 1 de Dic. de 2024
@Adam Danz: Why there is a need to use command 'plot'. Why data cannot directly be pinned to patch?
Adam Danz
Adam Danz el 2 de Dic. de 2024
@Muhammad Anam, good question. Rather than limiting data tips to the 4 vertices of a rectanlge, my solution allows you to click anywhere in the rectangle. But the datatip still has to be associated with an existing plotted cooredinate. So I'm using plot() to add a temporary point at the click location where the datatip should appear.

Iniciar sesión para comentar.

Categorías

Más información sobre Graphics Performance 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