Problem calling multiple files through for-loop

This is the for-loop function, named spike_analysis_wrapper:
function spike_analysis_wrapper()
filepairs = {
'spike1.mat', 'footsignal_spike1.mat';
'spike2.mat', 'footsignal_spike2.mat'};
% Loop through each row of filepairs
for i = 1:size(filepairs)
% Send the 2 files in row "i" into the analysis
spike_analysis(filepairs{i,1},filepairs{i,2});
end
end
And this is the main function, named spike_analysis:
function spike_analysis (file1,file2)
load(file1)
%Plot the spike with a corrected baseline
A=spike1(:,1);
B=spike1(:,2);
B1=B-(min(B)); %Baseline is 0 if the minimum value is diferent than 0.
figure(1)
plot(A,B1)
ylabel('Intensity (pA)')
xlabel('Time(s)')
title('1st spike')
% The paramenters of the foot signal
load(file2)
A_f=footsignal_spike1(:,1);
B_f=footsignal_spike1(:,2);
figure (2)
plot(A_f,B_f)
ylabel('Intensity (pA)')
xlabel('Time(s)')
title('1st foot signal')
end
The for-loop execute the first set of files (spike1 & footsignal_spike1) but I got this error when the loop tries to execute the second set of files (spike2 & footsignal_spike2).
Undefined function or variable 'spike1'.
Error in spike_analysis (line 5)
A=spike1(:,1);
Error in spike_analysis_wrapper (line 8)
spike_analysis(filepairs{i,1},filepairs{i,2});
According to the error, the problem lies on the main function (spike_analysis) because of the variable spike1.
How can I fix this problem?
Thanks in advance!

 Accepted Answer

The problem is caused by badly designed .mat files, where every .mat file contains variables with different names. Your code assumes that the second files contains variables of the same name/s as the first file, but clearly this is not the case.Parsing multiple .mat files in a loop is much simpler when every .mat file contains exactly the same variable names.
If your .mat files contain exactly one variable per file, then you can use struct2cell:
S = load(file1);
C = struct2cell(S);
A = C{1}(:,1);
B = C{1}(:,2);
And the same for file2.
If your .mat files contain multiple variables per file, then you can load into a structure and then use dynamic fieldnames:

10 Comments

Thanks! That was the point!
Let me ask you three more questions:
1) The for-loop function has 2 set of files. In a real scenario, there were more than 300 set of files. How can I change the below code in order to load from the first set of spike to the last one? Is sprintf expression suitable for this purpose? I tried but MatLab did not run anything (not even an error).
filepairs = {
'spike1.mat', 'footsignal_spike1.mat';
'spike2.mat', 'footsignal_spike2.mat'};
2) This question is regarding the plots and a table in the main function (spike_analysis). 2 plots and 1 table with data of the spike are created every set of files.
load(file1)
figure(1)
plot(A,B1)
ylabel('Intensity (pA)')
xlabel('Time(s)')
title('1st spike')
load(file2)
A_f=footsignal_spike1(:,1);
B_f=footsignal_spike1(:,2);
figure (2)
plot(A_f,B_f)
ylabel('Intensity (pA)')
xlabel('Time(s)')
title('1st foot signal')
Parameters_spike1=table(MaxI_f,Q_footsignal,Ti_f,Tf_f,AT_f,AT_HW,AT_RT,halfMax,index1_HW,index2_HW,index1_RT,index2_RT,Q_spike,RT_90)
writetable (Parameters_spike1,'Parameters spike1.xlsx')
savefig(figure(1),'1st spike.fig')
savefig(figure(2),'1st footsignal.fig')
Now, I want to title the figures as the name of the .mat file loaded (e.g. for the spike5, title('5th spike')) automatically. In other words, name the plot with the same name as the file.
3) Finally, I was wondering how can I save the plots and a table for every set files. In the previous thread, Adam Danz gave me this code to save every output of the for loop.
function = spike_analysis_wrapper()
filepairs = {
'spike1.mat', 'footsignal_spike1.mat';
'spike2.mat', 'footsignal_spike2.mat';
'spike3.mat', 'footsignal_spike3.mat';
'spike4.mat', 'footsignal_spike4.mat'};
% Loop through each row of filepairs
for i = 1:size(filepairs,1))
[Table_parameters_spike1, fig1, fig2] = spike_analysis(filepairs{i,1},filepairs{i,2});
writetable (Table_parameters_spike1,'Parameters 1 spike.xlsx')
savefig(fig1,'1st spike.fig')
savefig(fig2,'1st footsignal.fig')
end
end
But I got this error:
spike_analysis_wrapper
Error using spike_analysis
Too many output arguments.
Error in spike_analysis_wrapper2 (line 8)
[Table_parameters_spike1, fig1, fig2] = spike_analysis(filepairs{i,1},filepairs{i,2});
Thanks you for your time and your powerful tips!
I've tried this
myfolder= 'C:\Users\usuario\Desktop\Lab\Stackoverflow\Spikes from B2310\Spikes subtracted\spikes'
filePattern_spike = fullfile(myfolder, 'spike%d.mat');
for i = 1:size(filePattern_spike)
spike_analysis2(i,1);
end
function spike_analysis2 (file1)
S=load(file1)
C=struct2cell(S)
%Plot the spike with a corrected baseline
A=C{1}(:,1);
B=C{1}(:,2);
B1=B-(min(B)); %Baseline is 0 if the minimum value is diferent than 0.
figure(1)
plot(A,B1)
ylabel('Intensity (pA)')
xlabel('Time(s)')
title('1st spike')
end
And I got this
Error in spike_analysis_wrapper2 (line 12)
spike_analysis2(i,1);
1) "How can I change the below code in order to load from the first set of spike to the last one?"
Essentially there are two ways to process multiple files: 1. read the filenames from folder/s, or 2. generate the filenames (e.g. using sprintf). Both of these are shown in the documentation:
"Is sprintf expression suitable for this purpose?"
Most likely, yes.
2) "In other words, name the plot with the same name as the file."
Use fileparts and sprintf.
3) "But I got this error:.. Too many output arguments."
You did not define your function to have any output arguments. Then you tried calling it with output arguments. Thus the error.
If you want your function to have output arguments, then you need to specify them:
PS: "I've tried this"
Is that code is supposed to process multiple files? Nowhere do you actually read the filenames from a folder (e.g. using dir) or generate the filenames (e.g. using sprintf).
You also define spike_analysis2 with one input argument, and then call it with two input arguments (neither of which are a filename, which is what you wrote the function to require).
Try something like this instead:
D = 'C:\Users\usuario\Desktop\Lab\Stackoverflow\Spikes from B2310\Spikes subtracted\spikes'
S = dir(fullfile(D,'spike*.mat'));
for k = 1:numel(S)
F = fullfile(D,S(k).name);
spike_analysis2(F);
end
Hi Stephen,
The first question is solved. Thanks! I've copied your code and made this change:
D = 'C:\Users\physiol\Desktop\Jose\Lab\Data\Matlab_files_spikes_analysis\spikes'
S = dir(fullfile(D,'spike*.mat'));
for k = 1:numel(S)
F = fullfile(D,S(k).name);
fprintf(1, 'Now reading %s\n', F);
spike_analysis2(F);
end
However, I have still problems with the other two question.
Skip the second one and let's go fist to the third one.
Honestly, I don't know what I should type as output in the spike_analysis2 function for the loop. This is the code of this function.
function spike_analysis2(file1,file2)
S = load(file1);
C = struc2cell(S);
%Plot the spike with a corrected baseline
A = C{1}(:,1);
B = C{1}(:,2);
B1=B-(min(B)); %Baseline is 0 if the minimum value is different than 0.
figure(1)
plot(A,B1)
ylabel('Intensity (pA)')
xlabel('Time(s)')
title('1st spike')
format longG
% The parameters for the entire spike
% Charge of the entire spike
%The inmediate integration of the vector Intensity during the time is the
%charge (Q), i.e. the amount of molecules released per vesicle.
Q_spike=trapz(A,B1)*10^3
% The Increment of time of the Half Width of the spike
%Find the Time (second) when Intensity is maximum
%[a b]=max(Fst_spike(:,2));
%Time_maxI=Fst_spike(b,1)
% The Increment of time of Half Width.
%Find the half max value.
halfMax = max(B1) / 2;
index1_HW = find(B1 >= halfMax, 1, 'first'); %Gives the number of the row where data first drops below half the max.
index2_HW = find(B1 >= halfMax, 1, 'last'); %Gives the number of the row where data last rises above half the max.
Ti_HW=A(index1_HW,1)
Tf_HW=A(index2_HW,1)
AT_HW=(Tf_HW-Ti_HW)*10^6
%The Rise Time (the time span between the 50% and the 90% of the
%maxIntensty).
% Find the 90% of the maxIntensity.
RT_90 = max(B1) * 0.90;
index1_RT = find(B1 >= halfMax, 1, 'first'); %Gives the number of the row where data first rises above half the max.
index2_RT = find(B1 >= RT_90, 1, 'first'); %Gives the number of the row where data first drops below 90% of the max.
Ti_RT=A(index1_RT,1)
Tf_RT=A(index2_RT,1)
AT_RT=(Tf_RT-Ti_RT)*10^6
% The paramenters of the foot signal
S2 = load(file2);
C2 = struc2cell(S);
A = C2{1}(:,1);
B = C2{1}(:,2);
figure (2)
plot(A_f,B_f)
ylabel('Intensity (pA)')
xlabel('Time(s)')
title('1st foot signal')
% Charge of the foot signal
Q_footsignal=trapz(A_f,B_f)*10^3
% Max amplitude of the foot signal
MaxI_f=max(B_f)
% Foot signal duration
Ti_f=min(A_f)
Tf_f=max(A_f)
AT_f=(Tf_f-Ti_f)*10^6
%Save the parameters and the entire spike figure
Table_parameters_spike1=table(MaxI_f,Q_footsignal,Ti_f,Tf_f,AT_f,AT_HW,AT_RT,halfMax,index1_HW,index2_HW,index1_RT,index2_RT,Q_spike,RT_90)
writetable (Table_parameters_spike1,'Parameters 1 spike.xlsx')
savefig(figure(1),'1st spike.fig')
savefig(figure(2),'1st footsignal.fig')
end
I've tried with several alternatives but nothing works.
"Skip the second one and let's go fist to the third one."
fileparts is very simple:
[P,N,E] = fileparts(F)
or even just
[~,N,E] = fileparts(S(k).name)
I am sure you can handle the rest using sprintf.
"Honestly, I don't know what I should type as output in the spike_analysis2 function for the loop."
As you do not explain which variables you want to output from the function, I also have no idea what you should type as the output of the spike_analysis2 function.
But, for the sake of example, lets say you want to output Ti_f and Tf_f (in exactly that order), then you simply define your function with:
function [Ti_f,Tf_f] = spike_analysis2(file1,file2)
which is exactly what the documentation explains as well, which I why I gave you the link to read. Remember to then call the function with two output arguments, e.g.:
[X,Y] = spike_analysis2(...);
How to call functions (with multiple inputs/outputs) is covered in the introductory tutorials:
This way isn't working:
function [Q_spike,Ti_HW,Tf_HW,AT_HW,Ti_RT,Tf_RT,AT_RT] = spike_analysis_file1 (file1)
S = load(file1);
C = struct2cell(S);
A = C{1}(:,1);
B = C{1}(:,2);
B1=B-(min(B)); %Baseline is 0 if the minimum value is diferent than 0.
figure(1)
plot(A,B1)
% the script continues
end
I got this
Spike_analysis_wrapper_forloop
Now reading spike1.mat
Error using load
Argument must contain a character vector.
Error in spike_analysis_file1 (line 4)
S = load(file1);
Error in Spike_analysis_wrapper_forloop (line 13)
spike_analysis_file1(k)
The for loop is:
% Specify the folder where the files live.
myFolder = 'C:\Users\usuario\Desktop\Lab\amperometry\Spikes from B2310\Spikes subtracted\spikes';
% Get a list of all files in the folder with the desired file name pattern.
filePattern = fullfile(myFolder, '*.mat');
theFiles = dir(filePattern);
for k = 1 : length(theFiles)
baseFileName = theFiles(k).name;
fullFileName = fullfile(myFolder, baseFileName);
fprintf(1, 'Now reading %s\n', baseFileName)
%Call the main function
spike_analysis_file1(k)
end
I solved the output problem(thanks again!), but I got a new one...
You wrote spike_analysis_file1 to accept one input argument named file1, which should be a filename. Now look at how you call spike_analysis_file1: is the provided input argument a filename?:
spike_analysis_file1(k) % k is not a filename!
Most likely you want to call it something like this:
spike_analysis_file1(fullFileName)
Finally!!! Thanks!! Now I address the second question.
Oh my godness, it took long time to understand all of you guys! Thanks again for your enormous support and effort!!
Hi Stephen,
I have a question: How can I save a table for all files loaded in the loop's script that contains all the outputs of the function for each file loaded in one .xlsx file?
At the beginning I created a table containing the five outputs of the function in the function's script and then save the table in a .xlsx file. Obviusly, the file was overwriting everytime by the loop. Then, I include the table inside the loop, but the table only contains the first output of the function of the last file loaded.
Actually, the value of the function in the loop is only the first output of the function. It is abnormal because the function has 5 output and the loop should give all the outputs, right?
for k = 1 : length(theFiles)
baseFileName = theFiles(k).name;
fullFileName = fullfile(myFolder, baseFileName);
fprintf(1, 'Now reading %s\n', baseFileName)
%Call the function Spike_analysis
spike_analysis_file1(fullFileName)
end
function [T,Q_spike,I_max,halfMax,AT_HW,AT_RT] = spike_analysis_file1 (file1)
S = load(file1);
C = struct2cell(S);
A = C{1}(:,1);
B = C{1}(:,2);
%Save the parameters and the entire spike figure
Table_parameters_spike=table(T,Q_spike,I_max,AT_HW,AT_RT)
end
Now reading spike5.mat
Table_parameters_spike =
1×5 table
T Q_spike I_max AT_HW AT_RT
_______ ___________ ______ ________________ ________________
4.04856 368.0273714 79.834 920.000000000698 240.000000000684
ans =
4.04856
The ans of the loop is always the first output of the function (also the first column of the table).
in other words, how can I save the tables (in this case 5 tables, one per file) in one .xlsx file?
"How can I save a table for all files loaded in the loop's script that contains all the outputs of the function for each file loaded in one .xlsx file?"
Using writetable or xlswrite, both of which let you specify the destination worksheet and/or range to save the data to (thus easily avoiding overwriting data).
"Obviusly, the file was overwriting everytime by the loop."
You forgot to write the new data to different sheets and/or ranges, to ensure that the data was not overwritten.
"...but the table only contains the first output of the function of the last file loaded."
In fact what your code shows is that you did not call your function with any output arguments at all (something that has been thoroughly discussed in previous comments). The table Table_parameters_spike is being displayed in the command window, and you have not defined it as an output of your function. You appear to be confusing some data being displayed in the command window with the output arguments of your function (none of which appear to be tables).
"Actually, the value of the function in the loop is only the first output of the function."
Because you did not allocate the function outputs to any variables, MATLAB allocates the first ouput argument to the default ans:
"It is abnormal because the function has 5 output and the loop should give all the outputs, right?"
Nope, not abnormal at all... in fact because you did not allocate any of the outputs to variables, I would not expect "all the outputs", I would expect only the first one allocated to the default ans.
Very basic MATLAB concepts, such as how to call functions with multiple output arguments, are explained in the introductory tutorials:
You need to decide if you want to:
  1. return the table from the function (in which case it needs to be an output argument AND you need to call the function with an appropriate number of output arguments AND you need to decide if you also save the table inside the loop (see point 2) or somehow join/concatenate the data into one table and save it after the loop)
  2. save the table inside the loop (in which case you need to decide what destination worksheet/range to use to prevent data from being overwritten).
So what would you prefer?

Sign in to comment.

More Answers (0)

Categories

Find more on Interactive Control and Callbacks in Help Center and File Exchange

Community Treasure Hunt

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

Start Hunting!