Issue printing and saving some data in a file ID from excel in Guide

Hello everyone,
I am having an issue printing some data from an excel file. Basically, i would like to print out some data from an excel file and save them in a FileID.
I would like to print this:
handles.amplitude = data(:,5); The data are related to the amplitude and are on this format . ex: (1&1! )
handles.f_df = data(:,7); The data are all strings ex: A ,B...
I am having this as an error:
Unable to resolve the name handles.amplitude.
Error while evaluating TimerFcn for timer 'timer-2'
The code related to the issue is the last "paragraph" in the code.
function Hapticfinal_OpeningFcn(hObject, eventdata, handles, varargin)
% This function has no output args, see OutputFcn.
% hObject handle to figure
% eventdata reserved - to be defined in a future version of MATLAB
% handles structure with handles and user data (see GUIDATA)
% varargin command line arguments to Hapticfinal (see VARARGIN)
% Choose default command line output for Hapticfinal
handles.output = hObject;
data = xlsread('excel_data.xlsx');
% randomly permute the rows of data:
data = data(randperm(size(data,1)),:);
handles.v_thickness_1 = data(:,1);
handles.v_thickness_2 = data(:,2);
handles.h_thickness_1 = data(:,3);
handles.h_thickness_2 = data(:,4);
handles.amplitude = data(:,5);
handles.v_or_h_array = data(:,6);
handles.f_df = data(:,7);
handles.exp_counter = 1;
handles.region1 = [];
% Create the Arduino serial object
handles.arduinoObj = serialport('COM3', 38400);
configureTerminator(handles.arduinoObj,'CR/LF');
%
for i=1:8
handles.message = readline(handles.arduinoObj);
disp(handles.message)
end
create_patch(handles);
function create_patch(handles)
if ishandle(handles.region1)
delete(handles.region1);
end
v_or_h = handles.v_or_h_array(handles.exp_counter);
if v_or_h == 0 % Vertical line
v_thick1 = handles.v_thickness_1(handles.exp_counter);
v_thick2 = handles.v_thickness_2(handles.exp_counter);
handles.region1 = patch( ...
'Parent',handles.axes1, ...
'XData',[v_thick1 v_thick2 v_thick2 v_thick1], ...
'YData',[-10 -10 10 10], ...
'FaceColor','red');
set(handles.axes1,'XLim',[-5 0],'YLim',[-10 10]);
else % Horizontal line
h_thick1 = handles.h_thickness_1(handles.exp_counter);
h_thick2 = handles.h_thickness_2(handles.exp_counter);
handles.region1 = patch( ...
'Parent',handles.axes1, ...
'XData',[-10 10 10 -10], ...
'YData',[h_thick1 h_thick1 h_thick2 h_thick2], ...
'FaceColor','red');
set(handles.axes1,'YLim',[0 5],'XLim',[-10 10]);
end
set(handles.axes1,'XGrid','on','YGrid','on');
axis(handles.axes1,'equal');
% Update handles structure
guidata(handles.finger,handles);
% call the button motion fcn to update the new patch's color:
finger_WindowButtonMotionFcn(handles.finger);
function timerCallback(~,~,fileID)
%fprintf(fileID,'(X, Y, time) = (%g, %g, %s)\n', get(0, 'PointerLocation'), datetime('now'));
fprintf(fileID,'(X, Y, time) = (%g, %g, %s, %s,%s)\n', get(0, 'PointerLocation'), datetime('now'),...
handles.amplitude,handels.f_df );
%fprintf('calling timer callback\n

 Akzeptierte Antwort

Voss
Voss am 1 Mai 2022
Bearbeitet: Voss am 1 Mai 2022
I don't see the part of the code where the timer is created (actually the part where the timer's TimerFcn is specified, which may or may not be when the timer is created), but basically you have to pass some handle (e.g., the figure handles.finger) to the TimerFcn so that that function can get the handles structure.
For instance, if the part of the code where the timer's TimerFcn is specified looks like this:
fid = fopen('output.txt','w');
t = timer( ...
'TimerFcn',{@timerCallback,fid}, ...
);
It should be changed to this (this assumes handles is already defined in whatever function this part appears in):
fid = fopen('output.txt','w');
t = timer( ...
'TimerFcn',{@timerCallback,fid,handles.finger}, ... % pass the figure handle as well as the file handle
);
Then timerCallback would use guidata to get the figure's handles structure:
function timerCallback(~,~,fileID,f)
handles = guidata(f); % get the figure's handles struct
%fprintf(fileID,'(X, Y, time) = (%g, %g, %s)\n', get(0, 'PointerLocation'), datetime('now'));
fprintf(fileID,'(X, Y, time) = (%g, %g, %s, %s,%s)\n', get(0, 'PointerLocation'), datetime('now'),...
handles.amplitude,handles.f_df);%handels.f_df );
%fprintf('calling timer callback\n
Doing that will allow handles to be used by the timer.
[One thing not directly related to that is, you mention you want to write to an excel file. If you mean an xlsx file or similar, you wouldn't use fopen/fprintf. (If it's a csv file then fopen/fprintf is ok.) For xlsx or similar, you could use writematrix/writecell/writetable (or xlswrite). However, in this case, based on the data being written (i.e., '(X, Y, time) = (%g, %g, %s, %s,%s)\n'), I'd say a text file is appropriate, in which case fopen/fprintf is fine.]

16 Kommentare

@_ my bad. Let me post the code related to it. No i dont want to write from an excel file. I am reading From it.
function Start_button_Callback(hObject, eventdata, handles)
% hObject handle to Start_button (see GCBO)
% eventdata reserved - to be defined in a future version of MATLAB
% handles structure with handles and user data (see GUIDATA)
%clear
%clc
handles.fileID = fopen('exp.txt','w');
handles.t = timer('ExecutionMode', 'fixedRate', ...
'Period', 0.5, ...
'TasksToExecute', Inf, ...
'TimerFcn', {@timerCallback, handles.fileID});
start(handles.t);
set(handles.Start_button,'Enable','off'); % -> Disable the button
guidata(hObject,handles);% -----> do this to save the updated handles object
"No i dont want to write from an excel file. I am reading From it."
OK, that makes more sense.
Basically all you have to do is add the figure to the arguments for timerCallback:
function Start_button_Callback(hObject, eventdata, handles)
% hObject handle to Start_button (see GCBO)
% eventdata reserved - to be defined in a future version of MATLAB
% handles structure with handles and user data (see GUIDATA)
%clear
%clc
handles.fileID = fopen('exp.txt','w');
handles.t = timer('ExecutionMode', 'fixedRate', ...
'Period', 0.5, ...
'TasksToExecute', Inf, ... % figure included as argument
'TimerFcn', {@timerCallback, handles.fileID, handles.finger});
start(handles.t);
set(handles.Start_button,'Enable','off'); % -> Disable the button
guidata(hObject,handles);% -----> do this to save the updated handles object
And timerCallback can be as it was in my answer:
function timerCallback(~,~,fileID,f)
handles = guidata(f); % get the figure's handles struct
%fprintf(fileID,'(X, Y, time) = (%g, %g, %s)\n', get(0, 'PointerLocation'), datetime('now'));
fprintf(fileID,'(X, Y, time) = (%g, %g, %s, %s,%s)\n', get(0, 'PointerLocation'), datetime('now'),...
handles.amplitude,handles.f_df);%handels.f_df );
%fprintf('calling timer callback\n
However, since the file handle fileID is in the handles structure, it doesn't have to be a separate argument in timerCallback:
function Start_button_Callback(hObject, eventdata, handles)
% hObject handle to Start_button (see GCBO)
% eventdata reserved - to be defined in a future version of MATLAB
% handles structure with handles and user data (see GUIDATA)
%clear
%clc
handles.fileID = fopen('exp.txt','w');
handles.t = timer('ExecutionMode', 'fixedRate', ...
'Period', 0.5, ...
'TasksToExecute', Inf, ... % figure included as argument
'TimerFcn', {@timerCallback, handles.finger});
start(handles.t);
set(handles.Start_button,'Enable','off'); % -> Disable the button
guidata(hObject,handles);% -----> do this to save the updated handles object
in which case timerCallback will have only three input arguments and you'll use handles.fileID in that function:
function timerCallback(~,~,f)
handles = guidata(f); % get the figure's handles struct
%fprintf(fileID,'(X, Y, time) = (%g, %g, %s)\n', get(0, 'PointerLocation'), datetime('now'));
% using handles.fileID here instead of passing it in as an argument:
fprintf(handles.fileID,'(X, Y, time) = (%g, %g, %s, %s,%s)\n', get(0, 'PointerLocation'), datetime('now'),...
handles.amplitude,handles.f_df);%handels.f_df );
%fprintf('calling timer callback\n
and anything else you end up needing to use in timerCallback can also be put in the handles structure and accessed that way, by passing in just the figure handle to timerCallback.
[Also (and I don't know if this is already being done), you should be sure to fclose the text file when you're done writing to it (I don't know if there's a stop button callback or equivalent, but that would be a natural place to do it). Otherwise you might run into problems reading from or writing to a file that's still open from the previous run.]
1) Code tried
I am having another error.
Not enough inputs arguments
Error while evaluating Timerfcn for Timer 'Timer -5 '
2) Yes, i have fclose text file in stop button
function Stop_button_Callback(hObject, eventdata, handles)
% hObject handle to Stop_button (see GCBO)
% eventdata reserved - to be defined in a future version of MATLAB
% handles structure with handles and user data (see GUIDATA)
handles = guidata(hObject);
stop(handles.t) %whenever we want to stop.
fclose(handles.fileID);
set(handles.Start_button,'Enable','on'); % -> Enable the button
guidata(hObject,handles);
Timers can be hard to debug because: (1) they may persist and their TimerFcn may keep executing after the figure/app is closed, and (2) the error message doesn't tell you any function names or line numbers like a normal error message does.
So that error could be from an old timer still executing its TimerFcn, i.e., a timer from some previous stage of development when the arguments to timerCallback were different than they are now.
What I would do is close the figure and then do the following on the command line:
delete(timerfindall());
in order to delete all the timers that exist.
Then try running the program again and see if the error still happens.
@_ Thank you , i am learning along the way.
Yes, the error still continue
object must be a figure or one of its children
Error while evaluating TimerFcn for timer timer -1
That error sounds to me like handles.finger is incorrect (maybe empty or somehow has the wrong value) at the time it's specified to be an argument to the timer's TimerFcn.
guidata([])
Error using guidata
Object must be a figure or one of its child objects.
To know why that is, I'd have to see the whole code I think. (You can upload it if you want.)
However, as a workaround for now (just to get the file-writing working properly), you can change handles.finger to hObject (which refers to handles.Start_button in this case):
function Start_button_Callback(hObject, eventdata, handles)
% hObject handle to Start_button (see GCBO)
% eventdata reserved - to be defined in a future version of MATLAB
% handles structure with handles and user data (see GUIDATA)
%clear
%clc
handles.fileID = fopen('exp.txt','w');
handles.t = timer('ExecutionMode', 'fixedRate', ...
'Period', 0.5, ...
'TasksToExecute', Inf, ... % Start_button included as argument
'TimerFcn', {@timerCallback, hObject});
start(handles.t);
set(handles.Start_button,'Enable','off'); % -> Disable the button
guidata(hObject,handles);% -----> do this to save the updated handles object
because guidata (which is used in timerCallback to get the handles structure) returns the handles structure of the ancestor figure of the graphics object it's given - it doesn't have to be given a figure - so here we can give it the start button and it should work.
Make that change (and close the program, do delete(findalltimers()) again, and restart the program) and see if that works.
This is the initial code that works fine....
[ EDIT: long code removed because it has since been attached in a subsequent comment - _ ]
Can you just use the paperclip icon to attach the .fig file, the .m file, and the .xlsx file?
When you say "print" do you mean like bring up the printer dialog box to print to an actual laser printer? Or do you just mean you want to transfer some data from the XLSX file to a different file?
@Franck paulin Ludovig pehn Mayo Thanks for the code and everything.
I should've noticed this before: basically you don't want to start the timer until after the handles structure is updated to include the fileID and the timer t itself. In other words, Start_button_Callback should be like this:
function Start_button_Callback(hObject, eventdata, handles)
% hObject handle to Start_button (see GCBO)
% eventdata reserved - to be defined in a future version of MATLAB
% handles structure with handles and user data (see GUIDATA)
%clear
%clc
handles.fileID = fopen('exp.txt','w');
handles.t = timer('ExecutionMode', 'fixedRate', ...
'Period', 0.5, ...
'TasksToExecute', Inf, ...
'TimerFcn', {@timerCallback, handles.finger});
% start(handles.t); % don't start the timer yet
set(handles.Start_button,'Enable','off'); % -> Disable the button
guidata(hObject,handles);% -----> do this to save the updated handles object
start(handles.t); % now start the timer, after calling guidata to store handles
Because otherwise the first time timerCallback executes, the handles structure doesn't have everything it needs yet.
And then timerCallback should be this:
function timerCallback(~,~,f)
handles = guidata(f);
%fprintf(fileID,'(X, Y, time) = (%g, %g, %s)\n', get(0, 'PointerLocation'), datetime('now'));
fprintf(handles.fileID,'(X, Y, time) = (%g, %g, %s, %s, %s)\n', get(0, 'PointerLocation'), datetime('now'), ...
handles.amplitude{handles.exp_counter},handles.f_df{handles.exp_counter});
%fprintf('calling timer callback\n');
Where changes I made there were not related to the timer/handles update problem, but are due to wanting to write only the current amplitude and f_df values (based on exp_counter).
EDIT: When I ran your code with your data in my MATLAB (which is older than your MATLAB), I got an error in the OpeningFcn because data had only 6 columns instead of 7. So I modified it to use the 2nd output from xlsread as well as the first output, so handles.amplitude and handles.f_df became cell arrays, hence my use of curly-brace indexing of them in timerCallback. I don't know if they're string arrays for you or what (evidently you were able to get 7 columns of data with just the first output from xlsread, so I know something's different between your version of xlsread and mine), but handles.amplitude and handles.f_df are not referenced anywhere else in the code, so there was no way I could tell what class they are when you run the code in your version of MATLAB. I believe that curly brace indexing will work in either case, but if they are in fact string arrays, you could also use parentheses rather than curly braces:
fprintf(handles.fileID,'(X, Y, time) = (%g, %g, %s, %s, %s)\n', get(0, 'PointerLocation'), datetime('now'), ...
handles.amplitude(handles.exp_counter),handles.f_df(handles.exp_counter));
@_ Thank you . However, i am having two issues.
The first one is that it seems like it cannot print 7 columns . The error i am having is that , they are saying maximum 6
So i have reduced to 6 to see if it is working. Yes, it is working but it is printing NaN. Indeed , it is a mixed of numbers and symbols like 1&1! . So instead of "%s" what should i substitute with i have no clue.
Finally , is there anyway i can print out 7?
"%s" format is ok. Don't change that part. The problem is that the amplitudes really are NaNs because that's how xlsread has returned that column of data.
In fact, both of those problems (NaNs instead of "1&1!" for amplitude, and getting 6 columns instead of 7) can be fixed by modifying how xlsread is used. As I mentioned, I also ran into the problem of xlsread bringing in only 6 columns (I also had the problem of NaN amplitudes, but that one I did not mention). I assumed you were getting 7 somehow because otherwise you would've run into an error in the OpeningFcn.
Anyway, you can fix it by using the second output from xlsread, which contains the data from the cells in the spreadsheet that contain text, or the third output, which contains a cell array of all of the spreadsheet's data, numeric and text (the first output is numeric only, by the way). In this case, since the rows of data are randomly permuted, I'll use just the third output to keep it all together:
[~,~,data] = xlsread('excel_data.xlsx');
data(1,:) = []; % remove the header line
% randomly permute the rows of data:
data = data(randperm(size(data,1)),:);
numeric_data = cell2mat(data(:,[1 2 3 4 6]));
handles.v_thickness_1 = numeric_data(:,1); % numeric
handles.v_thickness_2 = numeric_data(:,2);
handles.h_thickness_1 = numeric_data(:,3);
handles.h_thickness_2 = numeric_data(:,4);
handles.amplitude = data(:,5); % cell array of char vectors
handles.v_or_h_array = numeric_data(:,5);
handles.f_df = data(:,7);
@_ Thank you , it is working perfectly
@_ I have another question related to it....
How can substitute the amplitude's handles (handles.amplitude = data(:,5);) in the code below knowing that the amplitudes are randomly read in he openingFcn. I want them to match each other when the line is called in the code below.
'4&1' is an example of the amplitude.
writeline(handles.arduinoObj, '4&1!')
I think that would be:
writeline(handles.arduinoObj, handles.amplitude{handles.exp_counter})
because (if I recall correctly) handles.exp_counter is the index of the current row of data (i.e., handles.exp_counter is the thing that's incremented by 1 in Next_button_Callback).
I'm glad it's working!
@_ yes, thank you. Workinf perfectly

Melden Sie sich an, um zu kommentieren.

Weitere Antworten (0)

Kategorien

Mehr zu Data Distribution Plots finden Sie in Hilfe-Center und File Exchange

Community Treasure Hunt

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

Start Hunting!

Translated by