Populating a Legend Dynamically

33 visualizaciones (últimos 30 días)
Kurtis McIntosh
Kurtis McIntosh el 7 de Mayo de 2018
Comentada: Kurtis McIntosh el 8 de Mayo de 2018
So I am currently working on a code that imports some excel data from any number of files as well as any number of sheets within the excel file. As such I have a for loop within a for loop to account for a random number of files as well as a random number of sheets. With the data I want to plot the data taken from the files, I want a legend to be dynamically populated with the information as it is going through the loop as it is running. Here is the portion of the code being described:
number_of_files = input('Please enter the number of files you would like to import. ');
xlRange = 'C2:K18';
total_materials = 0;
%For Loop to import the data
for i = 1:number_of_files
[filename, pathname] = uigetfile('*.xlsx');
number_of_materials = input('How many composites are you importing from this file? ');
for j = 1:number_of_materials
sheet = input(['Please input sheet for composite ' num2str(j) ': ']);
data(i,j,:,:) = xlsread(strcat(pathname,filename),sheet,xlRange);
%Declaration of each variable will be made here
temperature(i,j,:) = data(i,j,1,:);
FTU11(i,j,:) = data(i,j,8,:);
FTU33(i,j,:) = data(i,j,10,:);
E11t(i,j,:) = data(i,j,2,:);
loopcounter(i,j) = sheet; %Used Later to determine where the data is at.
end
total_materials = total_materials + number_of_materials; %Used later to establish plots
end
x = 1;
while x <= total_materials
for i = 1:number_of_files
for j = 1:length(loopcounter)
if loopcounter(i,j) == 0
continue
elseif loopcounter(i,j) ~= 0
%To plot, the variables need to be transformed into 1D
temperature_plot(:) = temperature(i,j,:);
FTU11_plot(:) = FTU11(i,j,:);
plot(temperature_plot, FTU11_plot,'o')
xlabel( 'Temperature (F)')
ylabel('FTU11 (Msi)')
title( 'In Plane Tensile Strength vs Temperature')
grid on
box on
xlim([0 4500])
ylim([ 0 80 ])
legendInfo{i,j} =['Composite ' num2str(i) '-' num2str(j)];
%saveas( gcf , 'default signal Y1.tif' , 'tif')
end
end
end
x = x + 1;
end
The error being spit out is:
Operands to the || and && operators must be convertible to logical scalar values.
Error in legend (line 162)
all(isgraphics(args{1})) % legend(children,strings,...)
Error in MaterialDataGraphs (line 65)
hl = legend(legendInfo);
In the particular case being tested, one file has 3 sheets, and the other file has only one sheet, resulting in a legendInfo matrix of:
'Composite 1-1' [] []
'Composite 2-1' 'Composite 2-2' 'Composite 2-3'
Is the error due to {1,2} and {1,3} not being populated? Is there another way of going about this or am I attempting something that MATLAB isn't necessarily capable of?
  2 comentarios
dpb
dpb el 7 de Mayo de 2018
I don't see the offending line in the code but you've built a 2D array of labels which doesn't meet the syntax requirements of legend; it expects a cell array of labels as a vector array, one cell per object in the plot (typically line) to be labelled.
It isn't clear what you expect plotted on each axes; as written with what is shown you're only going to get one line per axes; there's no hold on to add to an existing axes and the X,Y arguments to plot() are single vectors, not arrays so there's only one line per call.
Describing what you want the plot to contain might help, plus the complete code that created the error and the run that generated the error in context with the complete error message--context is key.
Kurtis McIntosh
Kurtis McIntosh el 8 de Mayo de 2018
I'm not sure why the entire code didn't copy. The hold on is actually right before the while loop. I've copied and pasted the entire code again so that it actually includes the hold. Again not sure what happened.
number_of_files = input('Please enter the number of files you would like to import. ');
xlRange = 'C2:K18';
total_materials = 0;
%For Loop to import the data
for i = 1:number_of_files
[filename, pathname] = uigetfile('*.xlsx');
number_of_materials = input('How many composites are you importing from this file? ');
for j = 1:number_of_materials
sheet = input(['Please input sheet for composite ' num2str(j) ': ']);
data(i,j,:,:) = xlsread(strcat(pathname,filename),sheet,xlRange);
%Declaration of each variable will be made here
temperature(i,j,:) = data(i,j,1,:);
FTU11(i,j,:) = data(i,j,8,:);
FTU33(i,j,:) = data(i,j,10,:);
E11t(i,j,:) = data(i,j,2,:);
loopcounter(i,j) = sheet; %Used Later to determine where the data is at.
end
total_materials = total_materials + number_of_materials; %Used later to establish plots
end
x = 1;
hold on
%Loop to Plot All Tensile Strengths
while x <= total_materials
for i = 1:number_of_files
for j = 1:length(loopcounter)
if loopcounter(i,j) == 0
continue
elseif loopcounter(i,j) ~= 0
%To plot, the variables need to be transformed into 1D
temperature_plot(:) = temperature(i,j,:);
FTU11_plot(:) = FTU11(i,j,:);
plot(temperature_plot, FTU11_plot,'o')
xlabel( 'Temperature (F)')
ylabel('FTU11 (Msi)')
title( 'In Plane Tensile Strength vs Temperature')
grid on
box on
xlim([0 4500])
ylim([ 0 80 ])
legendInfo{i,j} =['Composite ' num2str(i) '-' num2str(j)];
%saveas( gcf , 'Composite Comparison.tif' , 'tif')
end
end
end
x = x + 1;
end
hl = legend(legendInfo);
set( hl, 'location', 'southeast')
As far as what I am looking for, it is something similar to the image attached. I want to import data and have the legend show different data in the form of "Composite file_number - sheet_number
Please enter the number of files you would like to import. 2
How many composites are you importing from this file? 3
Please input sheet for composite 1: 1
Please input sheet for composite 2: 2
Please input sheet for composite 3: 3
How many composites are you importing from this file? 3
Please input sheet for composite 1: 1
Please input sheet for composite 2: 2
Please input sheet for composite 3: 3
Operands to the || and && operators must be convertible to logical scalar values.
Error in legend (line 162)
all(isgraphics(args{1})) % legend(children,strings,...)
Error in MaterialDataGraphs (line 65)
hl = legend(legendInfo);

Iniciar sesión para comentar.

Respuestas (1)

Steven Lord
Steven Lord el 8 de Mayo de 2018
Rather than building a large cell array of names that you pass into legend, I would instead use the DisplayName property of the line objects returned by the plot function.
% Sample data
x = 0:0.1:2*pi;
% Configure the axes
axis([0 2*pi -1 1]);
hold on
% Plot the first curve, y = sin(x), and give it a name to be displayed in the legend
plot(x, sin(x), 'DisplayName', 'sine of x');
% Show the legend
legend show
% Add a second curve, y = cos(x), and give it a name
% Depending on the release you're using, the legend may auto-update
plot(x, cos(x), 'DisplayName', 'cosine of x');
This has another benefit: the only time I even need to think about naming the line is exactly when I create the line. If I wanted to change one of those functions, say from cos(x) to (sin(x)+cos(x))/2, I only need to modify one line of code to change both what gets plotted and the name of what gets plotted. If I want to add a new function, I just have to add one line of code that both plots and names it.
plot(x, (sin(x)+cos(x))/2, 'DisplayName', 'average');
  1 comentario
Kurtis McIntosh
Kurtis McIntosh el 8 de Mayo de 2018
I ended up reading the name of each plot from excel and forming a character array of the cell's contents and using that to fill the legend.
for k = 1:length(property_names)
figure
hold on
for i = 1:number_of_files
for j = 1:n
if loopcounter(i,j) == 0
continue
elseif loopcounter(i,j) ~= 0
%To plot, the variables need to be transformed into 1D
temperature_plot(:) = temperature(i,j,:);
data_plot(:) = data(i,j,(k+1),:);
plot(temperature_plot, data_plot,'*')
xlabel('Temperature (F)')
ylabel([property_names(i,j,k) units(i,j,k)])
title([property_names(i,j,k) 'vs Temperature'])
grid on
box on
xlim([0 4500])
ylim([0 inf])
%saveas( gcf , 'default signal Y1.tif' , 'tif')
end
end
end
%Material matrix needs to have blank spaces eliminated to be
%incorporated into the legend
material2 = material(:);
material = material(~cellfun('isempty',material2'));
hl = legend(material);
set( hl, 'location', 'southeast')
hold off
end
Is there any benefit, whether speed or otherwise of using the DisplayName property vs the method that I have now? I used a similar method when labeling the y-axis and the plot titles.

Iniciar sesión para comentar.

Productos

Community Treasure Hunt

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

Start Hunting!

Translated by