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

63 次查看(过去 30 天)
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
Hassaan 2023-12-28
编辑:Hassaan 2023-12-28
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);
% Add a double-arrow annotation
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
  3 个评论
Richard
Richard 2024-11-13,15:48
编辑:Richard 2024-11-13,15:53
Thanks for this. It helped me a lot.
Is there a way to turn the text sideways, so it would be readable from the right?
I'm using R2024a right now.
Update: Just added a this to the createTextBox-Function, just after the 'Margin',5 setting: 'Rotation',90

请先登录,再进行评论。

更多回答(3 个)

Voss
Voss 2023-12-28
% 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
Hassaan 2023-12-28
编辑:Hassaan 2023-12-28
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
Hassaan 2023-12-28
% 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.

类别

Help CenterFile Exchange 中查找有关 Annotations 的更多信息

Community Treasure Hunt

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

Start Hunting!

Translated by