# annotation with both "doublearrow" and "textblock", with same data units

18 views (last 30 days)
Sim on 28 Dec 2023
Commented: Hassaan on 28 Dec 2023
I am employing the solution proposed by @Jorg Woehl in "Specify annotation position with respect to x- and y-axes values?" to use data units inside
annotation('doublearrow',...)
Now, I would like to add the "annotation('textbox',..)" in the same position of the "annotation('doublearrow',...)", by using the same data units. Something like this:
my_position = [x_begin y_begin dx dy];
annotation('doublearrow','dim',my_position);
annotation('textbox','dim',my_position);
However, my attempt does not work:
% From: Jorg Woehl in "Specify annotation position with respect to x- and y-axes values?"
hf = figure;
x = 0:180; f = @(x) 0.09*exp(-x/18);
plot(x, f(x));
ha = annotation('doublearrow');
ha.Parent = hf.CurrentAxes; % associate annotation with current axes
% now you can use data units
ha.X = [50 20];
ha.Y = [f(20) f(20)];
% From: https://ch.mathworks.com/help/matlab/ref/annotation.html
dim = [ha.X ha.Y];
str = {'Straight Line Plot','from 1 to 10'};
annotation('textbox',dim,'String',str,'FitBoxToText','on');
Error using annotation
Position values must be between 0 and 1.
Any suggestion?

Hassaan on 28 Dec 2023
Edited: Hassaan on 28 Dec 2023
Same solution as pointed by @Voss [credit and special thanks goes to him] , I Just created some functions for easier access and modification.
x = 0:200;
f = @(x) 0.09*exp(-x/18);
y = f(x);
figure;
ax = gca;
plot(ax, x, y);
xStart = 20;
xEnd = 50;
txtHorizontaloffset = 1;
txtBoxXstart = (xEnd + txtHorizontaloffset);
createDoubleArrow(ax, [xStart xEnd], [f(xStart) f(xStart)]);
% Add a text box annotation
createTextBox(ax, txtBoxXstart, f(xStart), 'Straight Line Plot from 1 to 10');
function createDoubleArrow(ax, xData, yData)
% Creates a double-arrow annotation on the given axes
% ax: Axes handle where the plot is drawn
% xData: The x-coordinates for the annotation (start and end point)
% yData: The y-coordinates for the annotation (start and end point)
% Ensure that xData and yData have two points for the double-arrow
if length(xData) ~= 2 || length(yData) ~= 2
error('xData and yData must contain exactly 2 elements each.');
end
% Draw a double-arrow annotation
doubleArrow = annotation(ax.Parent, 'doublearrow');
doubleArrow.Parent = ax; % Associate with the correct axes
doubleArrow.X = xData;
doubleArrow.Y = yData;
end
function createTextBox(ax, xPos, yPos, annotationText)
% Creates a text box annotation on the given axes
% ax: Axes handle where the plot is drawn
% xPos, yPos: The position for the annotation text box
% annotationText: The text to be displayed in the text box
% Add text at the specified location
textAnnotation = text(ax, xPos, yPos, annotationText, ...
'HorizontalAlignment', 'left', 'EdgeColor', 'k', ...
'BackgroundColor', 'white', 'Margin', 5);
end
Sim on 28 Dec 2023
Edited: Sim on 28 Dec 2023
I accepted your answer for the efforts and encouragement, but I think I will use the @Voss solution because easy to use and modify according to my needs (indeed, when possible, I prefer minimal solutions).... If you both think this is not correct, I will accept the @Voss answer :-) However, many thanks to both of you for providing nice solutions and for your time spent on this issue! :-)
Hassaan on 28 Dec 2023
I am Ok with both. I personally liked the @Voss answers as well. Thanks.

Voss on 28 Dec 2023
% From: Jorg Woehl in "Specify annotation position with respect to x- and y-axes values?"
hf = figure;
x = 0:180; f = @(x) 0.09*exp(-x/18);
plot(x, f(x));
ha = annotation('doublearrow');
ha.Parent = hf.CurrentAxes; % associate annotation with current axes
% now you can use data units
ha.X = [50 20];
ha.Y = [f(20) f(20)];
One way is to use the text() function:
str = {'Straight Line Plot','from 1 to 10'};
text(ha.X(1),ha.Y(1),join(str,newline()), ...
'Parent',ha.Parent,'EdgeColor','k','HorizontalAlignment','left');

Hassaan on 28 Dec 2023
Edited: Hassaan on 28 Dec 2023
Each function will take care of positioning based on the given x values and will place the textbox above the double arrow. You can tinker with the values and functionality as per your needs.
% Example usage
hf = figure;
x = 0:0.1:200;
f = @(x) 0.09*exp(-x/18);
plot(x, f(x));
ax = gca;
% Call the functions to create annotations
createDoubleArrowAnnotation(ax, f, [50, 100]);
createTextboxAnnotation(ax, f, [50, 100], 'Straight Line Plot, from 50 to 100');
% Function to create a double arrow annotation
function createDoubleArrowAnnotation(ax, f, x_range)
y_start = f(x_range(1));
y_end = f(x_range(2));
% Normalize the coordinates
norm_x = normalizeCoordinate(ax, x_range);
norm_y = normalizeCoordinate(ax, [y_start, y_end], 'y');
% Create the double arrow annotation
annotation('doublearrow', norm_x, norm_y);
end
% Function to create a textbox annotation
function createTextboxAnnotation(ax, f, x_range, str)
% Calculate the midpoint of the double arrow in data units for the textbox
mid_x = mean(x_range);
mid_y = f(mid_x) + 0.1 * range(ax.YLim); % Adjust y to place the textbox above the arrow
% Normalize the coordinates
norm_mid_x = normalizeCoordinate(ax, mid_x);
norm_mid_y = normalizeCoordinate(ax, mid_y, 'y');
% Create the textbox annotation
ht = annotation('textbox', [norm_mid_x, norm_mid_y, 0.1, 0.05], 'String', str, 'FitBoxToText', 'on', 'BackgroundColor', 'white');
% Adjust the position of the textbox to center it above the arrow
ht.Position(1) = ht.Position(1) - ht.Position(3) / 2;
end
% Helper function to normalize x or y coordinates
function norm_coord = normalizeCoordinate(ax, data_coord, coord_type)
if nargin < 3
coord_type = 'x';
end
ax_lim = get(ax, [upper(coord_type) 'Lim']);
ax_pos = get(ax, 'Position');
norm_coord = (data_coord - ax_lim(1)) / diff(ax_lim);
if strcmpi(coord_type, 'x')
norm_coord = norm_coord * ax_pos(3) + ax_pos(1);
else
norm_coord = norm_coord * ax_pos(4) + ax_pos(2);
end
end
Make sure to place the createDoubleArrowAnnotation and createTextboxAnnotation functions, along with the normalizeCoordinate helper function, in the same file or in your MATLAB path. Then, you can call these functions as shown in the example usage to create your annotations. The normalizeCoordinate function is a utility to convert data coordinates to normalized figure coordinates, which is used by both annotation-creating functions.
------------------------------------------------------------------------------------------------------------------------------------------------
If you find the solution helpful and it resolves your issue, it would be greatly appreciated if you could accept the answer. Also, leaving an upvote and a comment are also wonderful ways to provide feedback.

Hassaan on 28 Dec 2023
% Example usage
hf = figure;
x = 0:0.1:200;
f = @(x) 0.09*exp(-x/18);
plot(x, f(x));
ax = gca;
% Define the y values for the annotations
y_values = [f(20), f(20)];
% Call the functions to create annotations
createDoubleArrowAnnotation(ax, [50, 20], y_values);
createTextboxAnnotation(ax, [50, 20], y_values, 'Straight Line Plot, from 50 to 100');
% Function to create a double arrow annotation with specified x and y values
function createDoubleArrowAnnotation(ax, x_range, y_range)
% Normalize the coordinates
norm_x = normalizeCoordinate(ax, x_range, 'x');
norm_y = normalizeCoordinate(ax, y_range, 'y');
% Create the double arrow annotation
annotation('doublearrow', norm_x, norm_y);
end
% Function to create a textbox annotation with specified x and y values
function createTextboxAnnotation(ax, x_range, y_range, str)
% Calculate the midpoint of the double arrow in data units for the textbox
mid_x = mean(x_range);
mid_y = mean(y_range) + 0.1 * range(ax.YLim); % Adjust y to place the textbox above the arrow
% Normalize the coordinates
norm_mid_x = normalizeCoordinate(ax, mid_x, 'x');
norm_mid_y = normalizeCoordinate(ax, mid_y, 'y') + 0.002; % Adjust this value as needed to offset above the arrow
% Create the textbox annotation
ht = annotation('textbox', [norm_mid_x - 0.002, norm_mid_y, 0.1, 0.002], 'String', str, 'FitBoxToText', 'on', 'BackgroundColor', 'white');
% Adjust the position of the textbox to center it above the arrow
ht.Position(1) = ht.Position(1) - ht.Position(3) / 2;
ht.Position(2) = norm_mid_y; % Align top of textbox with midpoint y
end
% Helper function to normalize x or y coordinates
function norm_coord = normalizeCoordinate(ax, data_coord, coord_type)
ax_lim = get(ax, [upper(coord_type) 'Lim']);
ax_pos = get(ax, 'Position');
if strcmpi(coord_type, 'x')
norm_coord = (data_coord - ax_lim(1)) / diff(ax_lim) * ax_pos(3) + ax_pos(1);
else
norm_coord = (data_coord - ax_lim(1)) / diff(ax_lim) * ax_pos(4) + ax_pos(2);
end
end
------------------------------------------------------------------------------------------------------------------------------------------------
If you find the solution helpful and it resolves your issue, it would be greatly appreciated if you could accept the answer. Also, leaving an upvote and a comment are also wonderful ways to provide feedback.