[GUIDE] Save plots in handles in a loop. When a new plot is saved, the previous one is deleted without a reason.

7 views (last 30 days)
This is the Fourth question of a serie of questions to help me complete a project. You can see the Third question here .
This is at the moment the Last Question. (I will update it if I'll ask something else).
You can see the gui in the attached file .png and test it by opening the compressed archive. The code is commented enough (I hope) to easily understand what I am doing.
I am trying to save the plots to handles.plots every time that PB2 is pressed (Plot!). If the checkbox was already checked on a previous interaction with PB2, the plot is already in the handles, hence it doesn't re-do all the actions taken before.
The code works properly except for one detail, let's say we press the checkboxes 1 and 3. If we enter debug mode, the plot saved after the first loop (i=1) is accessible as get(handles.plots{1}). For i = 2 nothing happens and for i = 3 (True checkbox) it saves the new plot to the handles.plots{3}, which becomes accessible as get(handles.plots{3}). The problem is that the plot saved in handles.plots{1} is deleted in the process without a logical reason (for me at least).
Why am I doing this? Because I want to find a way to assign the color to a plot, in a way that if I uncheck it and re-checks it it will reappears with the same properties on the graph. Right now I got to a point were each time you press PB2, each graph changes color, even if it was already plotted.
Don't forget that the code is attached if you want to see the entire code. I will be enourmosly greatful if you'd take 5 mins to check it.
Here is the code for PB2. Tell me if I can improve my code by vectorizing some of the loops in PB2.
% --- Executes on button press in PB2.
function PB2_Callback(hObject, eventdata, handles)
% Recover the handles
handles = guidata(hObject);
files = handles.files;
X = handles.plots;
% Save in table the logical value of the checkboxes and convert to mat
table = get(handles.uitable2, 'Data');
CB_answer = cell2mat(table(1:end,1));
% clear the plot and make it invisible
cla;
set(handles.axes1, 'Visible', 'off')
% This will be skipped the first time we press PB2. If we have already
% pressed it, in handles.plots there will be stored some plots,
% we have to convert them to 1 to use the next part of the code
for z = 1:length(X)
if find(X{z} ~= 0)
X{z} = 1;
end
end
% Convert X to mat to further use
X1 = cell2mat(X);
% The first time we press the button PB2, X1 will be empty, hence we
% preallocate the memory by creatintg an empty cell of the right size
if all(X1(:)==0)
handles.plots(1:length(files)) = {0};
X = handles.plots;
X1 = cell2mat(X);
end
% Check the status of the pushbutton, if they are true their value is == 1
for i = 1:length(CB_answer)
if CB_answer(i) == 1
% If the value of X1(i) == 0 it could mean that we pressed PB2 for
% the first time or the last time we pressed it, the checkbox(i)
% wasn't selected, hence it's not saved in handles.plots{i}.
if X1(i) == 0
f1 = cell2mat(files{i,1});
f2 = cell2mat(files{i,2});
handles.plots{i} = plot(f1,f2);
end
end
end
set(handles.axes1, 'Visible', 'on')
guidata(hObject, handles);
end

Accepted Answer

Geoff Hayes
Geoff Hayes on 3 Nov 2017
Michael - I'm not really sure what you mean by The problem is that the plot saved in handles.plots{1} is deleted in the process without a logical reason (for me at least). When I step through the code, I still see that handles.plots{1} is non-empty, so perhaps you mean that it is deleted from the plot or axes. If that is the case, then one problem is that you are missing a call to hold which will retain the current plot when adding new plots. Without this, each time you create a new plot, the previous one is deleted.
I would do the following in the code that supposedly only happens once
% The first time we press the button PB2, X1 will be empty, hence we
% preallocate the memory by creatintg an empty cell of the right size
if all(X1(:)==0)
handles.plots(1:length(files)) = {0};
X = handles.plots;
X1 = cell2mat(X);
hold(handles.axes1,'on');
end
Note the call to hold(handles.axes1,'on'); and so all plots will be retained. (You could put this same line in the GUI's OpeningFcn too.
I'm also not sure why you clear the axes with cla. Why not just show and hide your plots based on whether the checkboxes have been checked or not?
% --- Executes on button press in PB2.
function PB2_Callback(hObject, eventdata, handles)
% Recover the handles
handles = guidata(hObject);
files = handles.files;
X = handles.plots;
% Save in table the logical value of the checkboxes and convert to mat
table = get(handles.uitable2, 'Data');
CB_answer = cell2mat(table(1:end,1));
% This will be skipped the first time we press PB2. If we have already
% pressed it, in handles.plots there will be stored some plots,
% we have to convert them to 1 to use the next part of the code
for z = 1:length(X)
if X{z} > 0 && ishandle(X{z})
X{z} = 1;
end
end
% Convert X to mat to further use
X1 = cell2mat(X);
% The first time we press the button PB2, X1 will be empty, hence we
% preallocate the memory by creatintg an empty cell of the right size
if all(X1(:)==0)
handles.plots(1:length(files)) = {0};
X = handles.plots;
X1 = cell2mat(X);
hold(handles.axes1,'on');
end
% Check the status of the pushbutton, if they are true their value is == 1
for i = 1:length(CB_answer)
if CB_answer(i) == 1
% If the value of X1(i) == 0 it could mean that we pressed PB2 for
% the first time or the last time we pressed it, the checkbox(i)
% wasn't selected, hence it's not saved in handles.plots{i}.
if X1(i) == 0
f1 = cell2mat(files{i,1});
f2 = cell2mat(files{i,2});
handles.plots{i} = plot(f1,f2);
else
set(handles.plots{i}, 'Visible','on');
end
elseif ~isempty(X1) && X1(i) == 1
set(handles.plots{i}, 'Visible','off');
end
end
guidata(hObject, handles);
end
Note how we use ishandle to check to see if the values in handles.plots are valid handles to graphics objects, and how we hide and show the plots as checked
set(handles.plots{i}, 'Visible','on');
or
set(handles.plots{i}, 'Visible','off');
  1 Comment
Michael Daldini
Michael Daldini on 6 Nov 2017
Maybe you will be able to give me a last hint. I want to update the legend at each iteration but I cannot... It shows the first plot and then it never moves. Obviously I would love to be able to take them off is the plot is not shown anymore.
Do you have any suggestion?
if X1(i) == 0
f1 = cell2mat(files{i,1});
f2 = cell2mat(files{i,2});
handles.plots{i} = plot(f1,f2,'color',rand(1,3),'DisplayName', names{i});
else
set(handles.plots{i}, 'Visible', 'on', 'DisplayName', names{i});
end
elseif ~isempty(X1) && X1(i) == 1
set(handles.plots{i}, 'Visible', 'off');
end
end
legend('show');
I was trying to modify the last part of my code like this, it is still not working.

Sign in to comment.

More Answers (1)

Michael Daldini
Michael Daldini on 4 Nov 2017
Thank you very much, I only had to change the condition to inequal instead of bigger than:
% This will be skipped the first time we press PB2. If we have already
% pressed it, in handles.plots there will be stored some plots,
% we have to convert them to 1 to use the next part of the code
for z = 1:length(X)
if X{z} ~= 0 && ishandle(X{z})
X{z} = 1;
end
end
Except for that, everything works perfectly, THANK YOU.
Now I want that if i prss again PB1 the plot clears, I will find a way and post it down here.

Community Treasure Hunt

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

Start Hunting!