Writing data into a text file - fprintf

Hello,
I'm beginner and I'm trying to program an experiment but I can not write data into a text file.
I am using functions in the main file. In main m file there are outputs such as ReactionTime but the Matlab gives this error: Unrecognized function or variable 'ReactionTime'.
I'm sharing here the savedata function. Where do I do wrong?
Thank you.
function savedata()
%openfile
clear all;
answer{1} = '02';
filename1 = sprintf('Posner_%s.txt', answer{1});
filename2 = sprintf('%s\\%s', cd, filename1);
fid = fopen(filename2, 'wt');
fclose(fid);
%savedata
fprintf(fid, 'Reaction Time: %d', ReactionTime) ;
fclose(fid);
end

 Accepted Answer

Note that just after ‘filename2’ is opened, it is immediately closed:
fid = fopen(filename2, 'wt');
fclose(fid);
That could cause problems here:
%savedata
fprintf(fid, 'Reaction Time: %d', ReactionTime) ;
So even if ‘ReactionTime’ is defined and passed to the ‘savedata’ function as an argument (as it should be, rather than as a global variable), the function will throw this error:
Error using fprintf
Invalid file identifier. Use fopen to generate a valid file identifier.
I did that experiment to verify it.
For what it’s worth, I agree with others that global variables are not to be used. It is always possible to avoid using them by passing the variables as arguments to the functions using them.
.

13 Comments

Thank you for your answer. Then how should I change the positions of the fopen and fclose functions?
My pleasure!
Eliminate the first fclose call and the clear all call. Keep the second fclose call where it is. Pass ‘answer’ and ‘ReactionTime’ as arguments to ‘savedata’. Another option would be to use the fullfile function to build the filename. It might also be worthwhile to create and return as an output some indicator that the file write was successful, and perhaps some details about the file.
Thank you. I did these and now it works. (except fullfile function. I will try to learn about this). Now I want to call another variable to savedata function and I got a different kind of error.
The source function is this:
function subject
%subject
prompt = {'Subject number:','Handedness:'};
name = 'Subject information';
numlines = 1;
defaultanswer = {'00','right'};
answer=inputdlg(prompt, name, numlines, defaultanswer);
end
I want to add Subject number to txt file's name. Also I want to save Handedness in the txt file just as ReactionTime.
I changed the savedata function as follows (just for the Subject number):
function [str2num(answer{1})] = savedata(ReactionTime, target_SOT)
%openfile
filename1 = sprintf('Posner_%s.txt', str2num(answer{1});
filename2 = sprintf('%s\\%s', cd, filename1);
fid = fopen(filename2, 'wt');
%savedata
fprintf(fid, 'Reaction Time: %d,\n target_SOT: %d,\n' , ReactionTime, target_SOT) ;
fclose(fid);
end
But I think { } brackets are not allowed to use like this. Because I got this error:
Error: File: savedata.m Line: 1 Column: 18
Invalid expression. When calling a function or indexing a variable, use parentheses. Otherwise, check for mismatched delimiters.
This may be the problem:
filename1 = sprintf('Posner_%s.txt', str2num(answer{1});
↑ ← MISSING PARENTHESIS
See if this works:
filename1 = sprintf('Posner_%s.txt', str2num(answer{1}));
.
Thank you I corrected this. However it says the problem is in the first line which is:
function [str2num(answer{1})] = savedata(ReactionTime, target_SOT, cue_condition, target_condition)
Error: File: savedata.m Line: 1 Column: 18
Invalid expression. When calling a function or indexing a variable, use parentheses. Otherwise, check for mismatched delimiters.
I think it says I should change ( symbol.
Adam Danz
Adam Danz on 14 Sep 2020
Edited: Adam Danz on 14 Sep 2020
Remove that output. "answer" still isn't defined in your function. Include it as an input variable. Even if it were defined, it's not proper syntax.
You should really review this page of the documentation,
The output should be a variable name. For example:
function [subj_nr] = savedata(ReactionTime, target_SOT, cue_condition, target_condition)
. . .
subj_nr = answer{1};
. . .
end
The square brackets [] around the output are not necessary for only one output. (I am not eliminating them here in the event you want to add other outputs.)
Sorry, yes, I should have added that variable as input. I fixed this as follows (I called Handedness from subject function here):
function savedata(answer{2}, ReactionTime, target_SOT, cue_condition, target_condition)
It still says it's an invalid expression.
Star Strider
Star Strider on 14 Sep 2020
Edited: Star Strider on 14 Sep 2020
My previous Comment (and the documentation for function) demonstrates how to use the function declaration line correctly.
EDIT — (14 Sep 2020 at 17:42)
If you want to append subsequent trials to the existing text file, use the 'a' or 'at' permission with fopen. See the documentation section on permission for more information.
Thank you! It fixed the problem immediately! May I ask one last question? The txt file looks like this now:
Subject number: 95
Handedness: right
Cue: 2,
Target: 2,
Reaction Time: 0.219418 seconds,
Subject number: 95
Handedness: right
Cue: 0,
Target: 1,
Reaction Time: 0.421627 seconds,
Is there any possibility that Subject number and Handedness will be shown one time, and other 3 variables will be shown for each trial (20 times)? Thank you in advance!
My pleasure!
I am a bit lost as to how your data are organised. It would likely be best for you to save the results of all the trials as a matrix in your calling script, then pass the Subject number and Handedness and the matrix of those trials to your ‘savedata’ function. Then you can write them the way you want, all at once.
Then do the same for all your other subjects, with subsequent calls to ‘savedata’.
As always, my pleasure!

Sign in to comment.

More Answers (2)

Adam Danz
Adam Danz on 13 Sep 2020
Edited: Adam Danz on 13 Sep 2020
You need to pass the ReactionTime variable in as an input.
function savedata(ReactionTime)
. . .
%savedata
fprintf(fid, 'Reaction Time: %d', ReactionTime) ;
fclose(fid);
end
Also, to create filenames, instead of sprintf() use fullfile().
As Asad pointed out, the first fclose(fid) should be removed.

17 Comments

Thank you. I tried this and got these errors:
Reference to a cleared variable ReactionTime.
Error in savedata (line 12)
fprintf(fid, 'Reaction Time: %d', ReactionTime) ;
Error in mainscript_6 (line 19)
savedata()
ReactionTime is from another function placed in the main script. Should I do anything in that function as well? That function's inputs and outputs are like this:
function [Response, ReactionTime] = response(target_SOT)
Yes, when you call the savedata function, you need to pass that variable, before it is cleared.
[Response, ReactionTime] = response(target_SOT)
savedata(ReactionTime)
I'm sorry, could you please tell me where should I pass that variable in the main script?
The main script:
PsychDebugWindowConfiguration
Screen('Preference', 'SkipSyncTests', 1);
subject()
[cue_condition, target_condition] = design;
[window, rect] = openWindow;
for i=1:length(cue_condition)
cue_trial = cue_condition(i);
target_trial = target_condition(i);
[target_SOT] = procedure(rect,window,cue_trial,target_trial);
[Key RT] = response(target_SOT);
blankScreen(window);
savedata()
end
Screen('CloseAll');
Also it is the other function which I tried to call output argument from:
function [Response, ReactionTime] = response(target_SOT)
KbName('UnifyKeyNames');
response_set = {'RightArrow','LeftArrow'};
keyIsDown = false;
while keyIsDown == false | ismember(KbName(keyCode), response_set) == 0
[keyIsDown, secs, keyCode, deltaSecs] = KbCheck;
end
Response = KbName(keyCode);
ReactionTime = secs-target_SOT;
end
Somewhere in your code the "ReactionTime" is produced. If you want the savedata function to have access to that variable, you have to pass that variable into that function.
It looks like this function produces the variable.
[Response, ReactionTime] = response(target_SOT)
Then you can send it to savedata by using
savedata(ReactionTime)
The Matlab Onramp may be helpful to learn the basics
Thank you! I did this when you first said "You need to pass the ReactionTime variable in as an input." However the error still continues. That's way I don't understand where's the problem.
"Reference to a cleared variable ReactionTime."
That tells me that somehwere in your workflow you are creating the variable "ReactionTime" and then you're clearing it before you can use it.
Maybe you're clearing it use "clear ReactionTime" or "clear all".
You'll need to explain what's going on: where is that var defined? What's happening between it's definition and when you call savedata()?
Thank you. As you said, savedata() function started with "clear all" before. I deleted this. Then I received this error:
Unrecognized function or variable 'ReactionTime'.
I guess it still can not find ReactionTime variable. I'm not sure what to do.
PsychDebugWindowConfiguration
Screen('Preference', 'SkipSyncTests', 1);
subject()
[cue_condition, target_condition] = design;
[window, rect] = openWindow;
for i=1:length(cue_condition)
cue_trial = cue_condition(i);
target_trial = target_condition(i);
[target_SOT] = procedure(rect,window,cue_trial,target_trial);
[Key RT] = response(target_SOT); %variable is defined here
blankScreen(window);
savedata() %savedata function is here
end
Screen('CloseAll');
Adam Danz
Adam Danz on 14 Sep 2020
Edited: Adam Danz on 14 Sep 2020
Are you saying that the "ReactionTime" variable doesn't exist anywhere, not even within the command window? Or are you saying you don't know where the ReactionTime variable is produced?
Have you spelled the the variable correctly, including case?
You can't save a variable that doesn't exist. If the variable exists, you just need to pass that variable into the savedata function as an input.
Also, as I mentioned in my answer above, you need to get rid of the first fclose(fid) and keep the second one.
Thank you. I did these and it's fixed. However when I used fullfile function it caused new errors so I decided not to use it for now.
Now I'm trying to call another variable but Matlab don't accept curly braces in input part of the function.
Source function is as follows:
function subject
%subject
prompt = {'Subject number:','Handedness:'};
name = 'Subject information';
numlines = 1;
defaultanswer = {'00','right'};
answer=inputdlg(prompt, name, numlines, defaultanswer);
end
I tried to call Handedness as follows:
function savedata(answer{2}, ReactionTime, target_SOT, cue_condition, target_condition)
It says:
Error: File: savedata.m Line: 1 Column: 25
Invalid expression. When calling a function or indexing a variable, use parentheses. Otherwise, check for mismatched delimiters.
You should really review this page of the documentation to understand the basics.
The input names to the function definition do not have to match the variable names and they cannot be indexed. Instead,
function savedata(answer, ReactionTime, target_SOT, cue_condition, target_condition)
When you call the function, then you can use
savedata(answer{2}, ReactionTime, target_SOT, cue_condition, target_condition)
assuming those are the actual variable names.
Please take a moment to make sense of this simple example:
function output = myFunction(input)
output = input + 1;
end
x = [0,5,10];
y = myFunction(x(2))
% ans = 6
Here, the input is 5 because x(2) == 5. The output is 5+1=6.
Thank you. I fixed the problem by using "answer" as the input and then I was able to use answer{1} and answer{2} in the function.
The experiment has 20 trials but the savedata function only could save the first trial's outputs. Do you have any ideas what can be the reason? (In early messages there is main script if you want to look at again).
Sila Dinc, I know what it's like to be lost in this.
One reason you're having these problems is because you're not understanding the problem. You're just trying things and sometimes they work, sometimes they don't work, and sometimes they cause new problems.
Take a moment to understand what the problem is. It's clear that you don't understand how inputs and outputs work and you don't understand where or when to call the savedata function. We've all been there so I know what that's like.
If you undersand these basics, the problem will be clear and the solution will be just as clear.
If "answer" holds the results from all 20 trials, why are you indexing it when you save those data? Why not just save all of it using,
savedata(answer, ReactionTime, target_SOT, cue_condition, target_condition)
Thank you. Yes, I'm here to understand things. I don't understand what you mean in the last sentence, I already used that code for the savedata function.
I just changed wt to a+ and then it was able to save the trials. I found this solution below the other answer, thank you.
"The experiment has 20 trials but the savedata function only could save the first trial's outputs. Do you have any ideas what can be the reason? "
And you're still having that problem?
No, as I said I changed wt to a+ and the problem solved.
fid = fopen(filename2, 'a+');
Ah, good!
So now you know about permissions with the fopen function.

Sign in to comment.

You should use variables like ReactionTime as global
Use this code after the function definition:
global ReactionTime cd
Use the same global command in the calling program
Also, the first fclose(fid); should not be used

2 Comments

Adam Danz
Adam Danz on 13 Sep 2020
Edited: Adam Danz on 13 Sep 2020
There is rarely a good reason to use global variables and they usually cause more problems than they solve.
See #2
'cd' is probably the current directory command in which case it doesn't need to be passed in as a variable.
Asad is correct that the first fclose(fid) should be removed.
Stephen23
Stephen23 on 13 Sep 2020
Edited: Stephen23 on 13 Sep 2020
You definitely should NOT use global variables.
Using global variables is bad advice in any programming language, and should be avoided in MATLAB too:
Using cd slows down code and makes debugging more difficult. The more efficient and recommended approach is to use absolute/relative filenames:

Sign in to comment.

Categories

Tags

Asked:

on 13 Sep 2020

Commented:

on 14 Sep 2020

Community Treasure Hunt

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

Start Hunting!