How can I add automated "new line" within a xlabel (too long lable text shall not exceed the subplot width).

17 次查看(过去 30 天)
Hello,
I have to create figure including several subplots.
Due to the number of subplots the subplot size is reduced. Consequently, the length of the x-label is limited. Thus, in case of too long xlabel text the different labels are clashing and the text becomes not readable.
I tried to solve this by splitting the label text into several lines. I took the width (InnerPosition(3)) of the subplot (with characters as unit) and create several "lines" which will not exceed the width of the subplot (innerPosition).
This works fine.
My Issue is now: the measurement of the width is based on the size of an "x" with Font Size = 14, however my font settings are different and not ever letter has the same size as an "x".
My Question: Is there an option to adapt the size of the xlevel better to my font settings (or to make it independent from the font setting)?
Thank you for your support!
%%%%%%%%%%%%%%%%%%%%%
Just described by pictures...
My Problem is described by subplot(2,2,1) and subplot(2,2,2).
My wanted solution is shown by subplot(2,2,3) and subplot(2,2,4).
My current solution:
But the size measurement is not perfect, because it is based on the size of "x" with FontSize = 14, and my font is smaller.
My Code:
clear
clc
x = 0:0.1:10
y = sin(x)
f = figure(100)
for k=1:4
subplot(2,2,k)
plot(x,y)
f.Children(k).Units = 'characters'
max_lable_size = f.Children(k).InnerPosition(3) %get the width of the subplot
f.Children(k).Units = 'normalized'
lable_text = 'This text is to long it exceeds the horizontal size of the subplot'
if (length(lable_text)>max_lable_size)
count=0
offset = 0
splitted_label_text = split(lable_text)
string_skalar = []
loop = 1
while offset < length(splitted_label_text)
i=1
newstring = ''
while (length(newstring) + length(splitted_label_text{i})+1<max_lable_size) &&...
(offset+i-1<length(splitted_label_text))
if i==1
newstring = splitted_label_text{offset + i}
end
if i>1
newstring = join([newstring ' ' splitted_label_text{offset + i}])
end
i=i+1
lenght_of_string = length(newstring)
end
count = count+lenght_of_string
offset = offset + i-1
string_skalar{loop}=newstring
loop = loop+1
end
end
xlabel(string_skalar,fontsize = 14)
k=k+1
end

回答(2 个)

Vineet Kuruvilla
Vineet Kuruvilla 2022-2-26
quickly written script...this might help.
close all
clear all
% fig1 = figure; plot(1:5,1:5)
xlbl='testing testing testing testing testing testing testing ';
ylbl = 'test';
fig2 = figure;
sfig1 = subplot(1,2,1);
plot(1:5,1:5)
xlabel(xlbl);
ylabel(ylbl);
sfig2 = subplot(1,2,2);
plot(1:50,1:50)
xlabel(xlbl);
ylabel(ylbl);
%pos1 = get(fig1,'Position');
%size of parent figure of subplots
pos2 = get(fig2,'Position');
subplot_parent_width = pos2(3);
spos2_1 = get(sfig1,'Position');
spos2_2 = get(sfig2,'Position');
subplot1_width = spos2_1(3)*subplot_parent_width;
subplot2_width = spos2_2(3)*subplot_parent_width;
%set label length per line
label_len_limit = round(subplot1_width*0.1);
%close previous plots and recreate plot with adjusted labels
close all
parts_num = round(size(xlbl,2)/label_len_limit);
if parts_num <= 1
xlbl_adjusted = xlbl;
ylbl_adjusted = ylbl;
else
xlbl_adjusted = [];
ylbl_adjusted = [];
end
% insert new line if x axis label too long.
% same can be done foy y axis label
if(size(xlbl,2)>label_len_limit)
for i = 1 : parts_num
if i == 1
xlbl_adjusted = [xlbl_adjusted, xlbl(1:i*label_len_limit)];
elseif i < parts_num
xlbl_adjusted = [xlbl_adjusted, newline, xlbl((i-1)*label_len_limit+1:i*label_len_limit)];
else
xlbl_adjusted = [xlbl_adjusted, newline, xlbl((i-1)*label_len_limit+1:end)];
end
end
end
fig2 = figure;
sfig1 = subplot(1,2,1);
plot(1:5,1:5)
xlabel(xlbl_adjusted);
ylabel(ylbl);
sfig2 = subplot(1,2,2);
plot(1:50,1:50)
xlabel(xlbl_adjusted);
ylabel(ylbl);

Voss
Voss 2022-2-26
编辑:Voss 2022-2-26
You can try this method. The idea is very similar to what you had, but this approach sets the xlabel 'String' and keeps track of the actual width of the xlabel (using the 'Extent' property), so it works for fonts with variable-width characters and for any font size.
clear
clc
x = 0:0.1:10;
y = sin(x);
f = figure(100);
for k=1:4
ax = subplot(2,2,k);
plot(x,y);
axes_units = ax.Units;
ax.Units = 'pixels';
max_lable_size = ax.InnerPosition(3); %get the width of the subplot
ax.Units = axes_units;
lable_text = 'This text is to long it exceeds the horizontal size of the subplot';
xlabel(lable_text,fontsize = 14);
xlabel_object = ax.XLabel;
xlabel_object.Units = 'pixels';
label_size = xlabel_object.Extent(3); % width of the xlabel
if label_size > max_lable_size
% need to split the text into multiple lines
string_skalar = {}; % cell array of strings that will contain the final xlabel String
splitted_label_text = split(lable_text); % split the text into words
n_words = numel(splitted_label_text); % count the number of words
label_size = 0; % xlabel width in pixels
n_words_new = 0; % number of words on the current line of the label
word_idx = 1; % index of the next word to be added to the label
last_word_size = 0; % number of characters in the last word added to the label
while word_idx <= n_words
% while there are words to be added to the xlabel
if n_words_new == 0
% if there are no words on the current line of the xlabel,
% the next word becomes the current line
current_line = splitted_label_text{word_idx};
% store the length (number of characters) of the new word,
% in case we need to remove it later
last_word_size = numel(splitted_label_text{word_idx});
else
% if the current line contains some words already, add the
% next word with a space beforehand
current_line = [current_line ' ' splitted_label_text{word_idx}];
% store the length (number of characters, including the
% space) of the new word, in case we need to remove it later
last_word_size = numel(splitted_label_text{word_idx})+1;
end
% increment the word counters
n_words_new = n_words_new+1;
word_idx = word_idx+1;
% set the xlabel's String to the current line
xlabel_object.String = current_line;
% and get the xlabel's width in pixels
label_size = xlabel_object.Extent(3);
if label_size > max_lable_size
% the xlabel is too wide now, but maybe we can remove the
% last word added to the current line and make it the first
% word of the next line
if n_words_new == 1
% if the current line is only one word, it can't be removed,
% so leave the line alone (don't allow lines with zero
% words and don't split words, e.g., maxi-mum) and just
% add it to the end of the cell array
string_skalar{end+1} = current_line;
current_line = '';
n_words_new = 0;
else
% but if the last word can be moved to the next line,
% then add the current line (without the last word) to the
% end of the cell array, and then create a new line with
% that one last word
string_skalar{end+1} = current_line(1:end-last_word_size);
current_line = current_line(end-last_word_size+2:end);
n_words_new = 1;
end
end
% continue to the next word, if any
end
if ~isempty(current_line)
% add the current line to the end of the cell array, if it's
% not empty (i.e., the maximum width wasn't exceeded, so this
% remaining part wan't added yet: need to add it now)
string_skalar{end+1} = current_line;
end
% set the final String
xlabel_object.String = string_skalar;
end
% restore the Units
xlabel_object.Units = 'data';
end

类别

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

产品


版本

R2021b

Community Treasure Hunt

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

Start Hunting!

Translated by