Is there a better way to initialize the DataTipTemplate field in primitive objects?

37 views (last 30 days)
Problem:
Creating a Chart Object as in Plot() initializes a DataTipTemplate field in the resulting handle.
p = plot(0,0);
p.DataTipTemplate % Does not return error
But creating the primitive handle directly does not, resulting in an error
q = line(0,0);
q.DataTipTemplate % Returns: "Unrecognized...'DataTipTemplate' for '...primitive.Line'"
However, creating a datatip as in this example will initialize the field
mytip = datatip(q,1,1);
q.DataTipTemplate % Now is valid.
But this requires creating and deleting the datatip, which seems sub-optimal.
Ask:
Is there a better way to initialize the DataTipTemplate in primitive objects?
Context:
I'm trying to customize the datatip on a trisurf() plot, which returns a primitive "patch" handle with the same problem. Apparently trisurf() does not have the same initialization as something like plot() or scatter(). I'm also curious why this is...

Accepted Answer

Adam Danz
Adam Danz on 18 Nov 2021
Edited: Adam Danz on 19 Nov 2021
I've had this problem with patch objects in the past and I solved it by doing something similar to what you suggested, making a temporary invisible datatip, setting DataTipTemplate, and then deleting the invisible datatip. It's fast and you don't see the temp datatip.
[x,y] = meshgrid(1:15,1:15);
z = peaks(15);
T = delaunay(x,y);
h = trisurf(T,x,y,z);
mytip = datatip(h,x(1),y(1),z(1),'Visible','off');
h.DataTipTemplate
ans =
DataTipTemplate with properties: DataTipRows: [3×1 matlab.graphics.datatip.DataTipTextRow] Interpreter: 'tex' FontSize: 10 FontAngle: 'normal' FontName: 'Helvetica'
delete(mytip)
Although it's not very closely related to this question, I've also used a ButtonDownFcn to place a datatip anywhere on a patch object rather than just at its coordinates (see here).
For whatever reason, the DataTipTemplate property is either not accessible or not even present in some objects until a datatip is added. I haven't had access to those classdef files to dig any deeper.
Custom datatip demo with trisurf
Data tip values can be based on a property of the object or can be manually defined but either of the two methods must be consistent for all rows of the datatip. By default, datatips use property values. For example, the first row of trisurf data tips use "XData".
Starting in R2021b you can assign values to UserData and use the propert value definition of datat tip values as follows
% Create trisurf
figure()
[x,y] = meshgrid(1:15,1:15);
z = peaks(15);
T = delaunay(x,y);
h = trisurf(T,x,y,z);
% Create labels, one for each XData
n = 3; %number of random characters
m = numel(h.XData); % number of labels
v = [65:90, 97:122]; % ASCII letters
labels = arrayfun(@(i){char(v(randi(numel(v), 1, n)))},1:m); % 1xn char vector
% Create datatip
dt = datatip(h,x(1),y(1),z(1));
% Assign new row to datatip
h.UserData = labels;
row = dataTipTextRow('Label', 'UserData');
h.DataTipTemplate.DataTipRows(end+1) = row;
Prior to R2021b you'll have to redefine all rows of the datatip to use custom values in additional rows,
% Create trisurf
figure()
[x,y] = meshgrid(1:15,1:15);
z = peaks(15);
T = delaunay(x,y);
h = trisurf(T,x,y,z);
% Create labels, one for each XData
n = 3; %number of random characters
m = numel(h.XData); % number of labels
v = [65:90, 97:122]; % ASCII letters
labels = arrayfun(@(i){char(v(randi(numel(v), 1, n)))},1:m); % 1xn char vector
% Create datatip
dt = datatip(h,x(1),y(1),z(1));
% Recreate datatip and add new row
s.DataTipTemplate.DataTipRows = [];
row1 = dataTipTextRow('X', h.XData(:), '%g');
row2 = dataTipTextRow('Y', h.YData(:), '%g');
row3 = dataTipTextRow('Z', h.ZData(:), '%g');
row4 = dataTipTextRow('Label', labels(:));
h.DataTipTemplate.DataTipRows = [row1; row1; row3; row4];
  2 Comments
Joel Lynch
Joel Lynch on 19 Nov 2021
Thanks Adam! ~The streets of MATropolis feel much safer when experienced folks can respond to the occasional bat signal :)
The inviisble datatip works for what I need, though it is indeed counter-intuitive with patch. It looks like datatip may only accept x & y in your example:
[x,y] = meshgrid(1:15,1:15);
z = peaks(15);
T = delaunay(x,y);
h = trisurf(T,x,y,z);
%mytip = datatip(h,x(1),y(1),z(1),'Visible','off');
mytip = datatip(h,x(1),y(1),'Visible','off');
h.DataTipTemplate
It's also a bit counter-inutitive that setting a new datatip row, say Z*2, is not as easy as the MATLAB example:
row = dataTipTextRow('State',statelabel);
s.DataTipTemplate.DataTipRows(end+1) = row;
as the "Value" field in DataTipRows for trisurf->patch must match the size of the X/Y/ZData (3xN_tri), not the original x,y,z variables. I suppose that makes sense given delaunay is used, but even then, the X/Y/Z Data in the handle is actually transposed from the size of T (N_tris x 3).
I like your solution though, I'll give it a try. I actually didn't know about UserData in plot handles... That is a dream come true!
If you're curious, this is my application, ternary plots. It's my first real contribution, and I'm smoothing out rough edges at the moment. I haven't really recieved much feedback yet, but my goal is to get it as close to standard MATLAB as possible. I figure that means defining a new handle class, but that's a "part of the city" I haven't visited yet. Any tips there would also be appreciated.
Adam Danz
Adam Danz on 19 Nov 2021
Ha! I thought I recognized your name!
I wonder what problems you had with the datatip function. It looks like you're using R2021a and that release also supports the z-coordinate (R2021a datatip documentation). In fact, I get an error using the version without the z coordinate,
mytip = datatip(h,x(1),y(1),'Visible','off'); % R2021b
Error using datatip (line 162)
Unknown property: 'off'.
This is because datatip is expecting the z coordinate but receives "visible" instead so it interprets "off" as a property name rather than a property value.
To add a new row for the datatip, you need to provide the value for all points in the object which is what the Matlab example is doing. The trisurf datatips are based on the X|Y|ZData so the number of labels needs to equal the number of data points.
I'll update my answer to include a demo.
Very nice overview of your file exchange submission.

Sign in to comment.

More Answers (0)

Products


Release

R2021a

Community Treasure Hunt

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

Start Hunting!