0

After making a code which creates a window with a figure and some (ii) checkboxes loading some data (one data per checkbox), I would like to export them by a pushbutton only if the checkbox matching a set of data is ticked.

First, I have created (with the help of "il_raffa") a number of checkbox which does need to be flexible (ii: input of a loop for) which out of my code can be summarized in principle by something like that:

GUI window

N=500;
M=300;

handles.fig=figure('Units', 'Pixels','Position',[100 100 N M]);

handles.axes=axes('Units', 'Pixels','tag','axes_tag','Position',[25 25 N-200     M-50]);

for ii=1:4; %input exemple

   handles.check{ii}=uicontrol('style','checkbox','string', ...
      ['Display_file_' num2str(ii)],'tag',['c_b_' num2str(ii)], ...
      'position',[N-150 M/2-ii*20 100 25],'callback','plot_sel_cb(handles.axes)');
end

checkbox callback

function plot_sel_cb(ax_h)
cb_id=get(gcbo,'string')
cb_pos=get(gcbo,'position')
val=get(gcbo,'value')
path=get(gcbo,'userdata');
axes(ax_h)
hold on

if val

   x=1:10;
   y=[1:10].*cb_pos(2)/100;
   plot(x,y,'color,[rand(1) rand(1) rand(1)])
   legend(cb_id)

    set(h,'tag',cb_id)


else 
    delete(findobj('tag',cb_id))
end

From this code I would like to create a pushbutton which takes only the [x,y] from the ticked checkboxes to create for example a variable with all these data inside.

The second issue is, I haven't managed to create a legend to "plot(x,y,'color,[rand(1) rand(1) rand(1)])" which add the name "cb_id" when the checkbox matching the data is ticked.

HELP

Thanks

1 Answers1

1

Let me start from your second issue: add a the legend.

In the checkbox callback you add / remove the lines according to the status (checked / unchecked) of the checkbox.

To add an item in the legend is quite easy, you just have to insert the desired string (in you case cb_id) into a cellarray and set it as input parameter to the legend function.

To remove an item from the legend when you unckeck a checkbox while leaving the other could be a little bit more difficult.

Considering the you seem not having so many lines to plot, the easiest (even if not the "optimal") approach coul be to change the way the checkbox callbak works.

Yuo can code it so that each time it is called, it:

  • delete all the previously plotted lines
  • delete the current legend
  • plot (in a loop) all the lines according to the checkbox status
  • create the proper legend

in the following, you can find an updated version of that callback uin which this approach has been implented.

In order to exchange the data (e. g. the handles of the checkbox) you can assign them to the figure's userdata property.

It might be used, for example, as a struct, so you can assign the data to its fields.

As an example, you have in the main function, ii checkbox handles; with the following code, you can assign the number of checkbox and their handles:

figure_data.n_cb=ii;
figure_data.cb_handles=handles.check;
set(handles.fig,'userdata',figure_data)

I've used this aprroach across all the function you can find below.

With respect to the first issue: a pushbutton to extract the (x,y) values.

You can add the pushbutton uicontrol in the main function (as per the checkboxes).

The pushbutton is:

  • disabled at the beginning (in main GUI function)
  • enabled when at leat one checkbox is checked (in the checkbox callback)
  • disabled otherwise (in the checkbox callback)

There are several way to get the (x,y) values, two of then are: - you can assign them to a variable in the checkbox callback (in this case you do not actually need to have a pushbutton) - you can exploit the fact that the data of each line plotted in the axes are also stored in the properties xdata and ydata in the plot's handle.

From the axes uicontrol you can access to them through the children property: it returs the handles of each element plotted in the axes therefore you can write a loop going through these handles and get the data.

Since, in principle, your data might not have the same size (the plot associated to checkbox_1 might have more data than the one of checkbox_2) you should not use a matrix to hold all of them.

It would be better to use a cellarray or an array of struct

In the following you can find the updated version of the main function in which the pushbuton ha been added and the pushbutton callback.

Main GUI function

N=500;
M=300;
% Added ",'toolbar','figure'" to show the figure toolbar (zoom, rotate,
% ...)
handles.fig=figure('Units', 'Pixels','Position',[100 100 N M],'toolbar','figure');


handles.axes=axes('Units', 'Pixels','tag','axes_tag','Position',[25 25 N-200 M-50]);

for ii=1:4; %input exemple

% Changed definition of "handles.check" from "cellarray" to "array"
% Added setting of each checkbox "userdata" to the value of loop index (a
% way to automatically identify the checkboxes)
%
%    handles.check{ii}=uicontrol('style','checkbox','string', ...
   handles.check(ii)=uicontrol('style','checkbox','string', ...
      ['Display_file_' num2str(ii)],'tag',['c_b_' num2str(ii)], ...
      'position',[N-150 M/2-ii*20 100 25],'userdata',ii, ...
      'callback','plot_sel_cb(handles.axes)');

end
% Add the pushbutton (it is disabled at creation), it will be enabled by
% the checkbox callback if any checkbox set
handles.button=uicontrol('style','pushbutton','string','Export data', ...
   'enable','off','position',[N-150 M/2+50 100 25], ...
   'callback','export_data');
%
% Store info into figure "userdata"
%    number of checkboxes
%    status of the checkboxes (all unchecked at the beginning)
%    pushbuton handle
figure_data.n_cb=ii;
figure_data.selected_cb=zeros(1,ii);
figure_data.cb_handles=handles.check;
figure_data.button=handles.button;
%
set(handles.fig,'userdata',figure_data)

Updated checkbox callback

function plot_sel_cb(ax_h)
% Get the checkbox id
cb_id=get(gcbo,'userdata');
% Check if current checkbox has been checked (val=1) or unchecked (val=0)
val=get(gcbo,'value');
% Get the number of checkbox in the GUI
figure_data=get(gcf,'userdata');
n_cb=figure_data.n_cb;
cb_handles=figure_data.cb_handles;

% path=get(gcbo,'userdata');
axes(ax_h);

% Clear axes (delete plot) and delete the legend
p_h=get(gca,'children');
if(~isempty(p_h))
   delete(p_h);
   delete(figure_data.leg_h)
end

hold on

% Update current checkbox status in the checkbox info
figure_data.selected_cb(cb_id)=val;
% Initialize legend string, counter and plot handles array
legend_str={};
cnt=0;
p_h=[];
% Loop throught the checkbox to plot
for i=1:n_cb
   if(figure_data.selected_cb(i))
      cnt=cnt+1;
      x=1:10;
      % Get checkbox position (to generate exmple data to plot)
      cb_pos=get(cb_handles(i),'position');
      % Get checkbox id
      curr_cb=get(cb_handles(i),'userdata');
      y=[1:10].*cb_pos(2)/100;
      % Plot and store plot handle
      p_h(cnt)=plot(x,y,'color',[rand(1) rand(1) rand(1)],'linewidth',2);
      % Set the plot tag to the index of the checkbox (it will be used in
      % the pushbutton callback as index of the cellarray in which to store
      % the data plottd
      set(p_h(cnt),'userdata',curr_cb)
      % Get the string of the current chceckbox
      cb_string=get(cb_handles(i),'string');
      % Replace "_" with "_-" for the correct visualization
      cb_string=strrep(cb_string,'_','_-');
      % Build the legend's string
      legend_str{cnt}=cb_string;
   end
end
% Add the updated legend and store its handle in figure_data
if(~isempty(legend_str))
   figure_data.leg_h=legend(p_h,legend_str);
end
% Manage "Export data" pushbutton enabling
if(any(figure_data.selected_cb))
   set(figure_data.button,'enable','on')
else
   set(figure_data.button,'enable','off')
end
% Update figure data
set(gcf,'userdata',figure_data);

Pushbutton callback

function export_data
% Get plotted data and set store them into a variable
%    the vaaible can be either a "cellarray" or an array of "struct"
% The data of each line plotted are stored in the "xdata" and "ydata"
% property of each "children" of the axis
p_h=get(gca,'children');
n_plot=length(p_h);
% Loop through the children to retreive the data
for i=1:n_plot
   cb_id=get(p_h(i),'userdata');
   x_data=get(p_h(i),'xdata');
   y_data=get(p_h(i),'ydata');
   % Create the cellarray "exported_data_cell_array"
   exported_data_cell_array{cb_id}=[x_data;y_data];
   % Create the struct "exported_data_struct"
   exported_data_struct(cb_id).checkbox_id=cb_id;
   exported_data_struct(cb_id).x_data=y_data;
   exported_data_struct(cb_id).y_data=y_data;
end
% Store the extractged data into th e figure_data
figure_data=get(gcf,'userdata');
figure_data.exported_data_cell_array=exported_data_cell_array;
figure_data.exported_data_struct=exported_data_struct;
set(gcf,'userdata',figure_data);

enter image description here

Hope this helps.

il_raffa
  • 5,090
  • 129
  • 31
  • 36