Search code examples
matlabsignalsuicontrol

MATLAB uicontrol callback return matrix


Original post: MATLAB scrolling plot

I got a second part in my problem now. As before, I have a 19*1000*134 matrix that I'm plotting thanks to the nicely answer from Aero Engy on the last post.

I would like to create in my workspace a vector called clean that will have a 134 length.

By default, the value for clean(i) (with i between 1 and 134) will be 1 -- but, if I press a button on the UI interface, the value must get to 0.

My code bellow, just don't give me any ouput. The button seems to work, but when I close the figure, I don't get the vector clean.

function cleanData(data);
% data = rand(19,1000,134);
global clean
clean = ones(1,size(data,3));
f = figure('Units','Normalized','Position',[0.25 0.25 0.5 0.5]);
a =   axes('Units','Normalized','Position',[0.05 0.15, 0.75 0.75]);
s =   uicontrol(f, 'Style','Slider', 'Units','Normalized','Position',[0.05 0.025, 0.75 0.05],...
                   'Min',1,'Max',size(data,3),'Value',1, 'Callback',{@sliderChange,a});
l =   uicontrol(f, 'Style','listbox','Units','Normalized','Position',[0.85 0.15, 0.1, 0.75],...
                   'String',cellstr(num2str([1:size(data,1)]')),'Callback',{@changeChannel,a,s,data});
c = uicontrol(f, 'Style','pushbutton','Units','Normalized','String','Not clean',...
                   'Position',[0.85 0.025 0.1 0.05],'Callback',{@notClean,clean,s});

stepSize = 1/(s.Max - s.Min);
s.SliderStep = [stepSize 2*stepSize];               
changeChannel(l,[],a,s,data)

function changeChannel(l,evtData,a,s,data)
cla(a);
chanNum = str2double(l.String{l.Value});
sR = 500;  %500Hz
tempData = reshape(data(chanNum,:,:),[],size(data,3)); %Reshape each epoch into a column
tempTime = [0:1/sR:(size(data,2)-1)/sR]' + (0:1:size(data,3)-1)*2; %Build time array
plot(a,tempTime,tempData) %plot all the lines
s.Value = 1; %Rest Slider Position

function sliderChange(s,evtData,a)
viewI = round(s.Value);
disp(['Current Epoch: ' num2str(viewI)]) %console print
xlim(a,[(viewI-1)*2 viewI*2] + [-.1 .1])

function notClean(c,evtData,clean,s)
num = round(s.Value);
clean(num) = 0;
disp(['Epoch ' num2str(num) ' not clean']) %console print

What am I doing wrong ?

Bonus: It would be nice if

  • When I press the button "Not clean", the slider change values and increment aswell (Currently, I have to press the button, then the right Arrow of the slider to go to the next 2 secs of data).
  • Once I check "Clean" or "not clean" for one channel (one of the 19 rows of the matrix), for the next one, it will skip the "not clean" data (i.e. with a 0 in the clean matrix corresponding to the epoch number).

Thanks for the help, I'm quite new at MATLAB, and even if I improve quickly, I'm far from fully understanding this code.


Solution

  • In the notClean callback I called clean out as a global. I also removed it as an input ... since it is a global it is not necessary to pass it in.

    Also I added the code to advance the slider 1 each time you pressed the button.

    In your workspace after closing the GUI to see what you marked you just need to do the following at the command line to access your clean array. (Numbers are random things I marked as not clean.

    I have to leave right now so I can't address the second bullet about changing channels and skipping the ~clean elementr ... but it shouldn't be very hard. I will get back here in a couple of hours.

    >> global clean
    >> find(~clean)
    ans =
      3  4  11 19
    

    MODIFIED CODE: EDIT: Added code protection at the edges for skipping channels.

    function cleanData(data)
    % data = rand(19,1000,134);
    global clean
    clean = ones(1,size(data,3));
    f = figure('Units','Normalized','Position',[0.25 0.25 0.5 0.5]);
    a =   axes('Units','Normalized','Position',[0.05 0.15, 0.75 0.75]);
    s =   uicontrol(f, 'Style','Slider', 'Units','Normalized','Position',[0.05 0.025, 0.75 0.05],...
                       'Min',1,'Max',size(data,3),'Value',1, 'Callback',{@sliderChange,a});
    l =   uicontrol(f, 'Style','listbox','Units','Normalized','Position',[0.85 0.15, 0.1, 0.75],...
                       'String',cellstr(num2str([1:size(data,1)]')),'Callback',{@changeChannel,a,s,data});
    c = uicontrol(f, 'Style','pushbutton','Units','Normalized','String','Not clean',...
                       'Position',[0.85 0.025 0.1 0.05],'Callback',{@notClean,s,a});
    
    stepSize = 1/(s.Max - s.Min);
    s.SliderStep = [stepSize 2*stepSize];               
    changeChannel(l,[],a,s,data)
    
    function changeChannel(l,evtData,a,s,data)
    cla(a);
    chanNum = str2double(l.String{l.Value});
    sR = 500;  %500Hz
    tempData = reshape(data(chanNum,:,:),[],size(data,3)); %Reshape each epoch into a column
    tempTime = [0:1/sR:(size(data,2)-1)/sR]' + (0:1:size(data,3)-1)*2; %Build time array
    plot(a,tempTime,tempData) %plot all the lines
    s.Value = 1; %Rest Slider Position
    
    function sliderChange(s,evtData,a)
    global clean
    persistent prevI
    
    if isempty(prevI)
        prevI = 1;
    end
    
    viewI = round(s.Value);
    sDir = sign(viewI - prevI);  %-1 if going backwards +1 if going forward
    prevI = viewI;
    
    if clean(viewI) == 0
        newPos = viewI + sDir;
        if newPos < 1 || newPos > s.Max
            return
        end
        s.Value = newPos; 
        sliderChange(s,[],a)
    else
        disp(['Current Epoch: ' num2str(viewI)]) %console print
        xlim(a,[(viewI-1)*2 viewI*2] + [-.1 .1])  
    end
    
    
    function notClean(c,evtData,s,a)
    global clean %Call the global
    num = round(s.Value);
    clean(num) = 0;
    disp(['Epoch ' num2str(num) ' not clean']) %console print
    %Advance to the next slider position.
    if num+1 < s.Max
        s.Value = num+1;
        sliderChange(s,[],a)
    end