"Next trial" button in MATLAB - matlab

I have a script this MATLAB script:
function semjudge
clc;
name = input('Name: ','s');
snum = input('Subject #: ','s');
files = dir(fullfile('pictures','*.png'));
index = randperm(length(files));
picture1 = files(index(1)).name;
picture2 = files(index(2)).name;
image1 = fullfile('pictures',picture1);
image2 = fullfile('pictures',picture2);
subplot(1,2,1); imshow(image1); title(picture1);
subplot(1,2,2); imshow(image2); title(picture2);
uicontrol('Style', 'text',...
'Position', [200 45 200 20],...
'String','How related are these pictures?');
uicontrol('Style', 'text',...
'Position', [50 45 100 20],...
'String','Unrelated');
uicontrol('Style', 'text',...
'Position', [450 45 100 20],...
'String','Closely related');
uicontrol('Style','pushbutton','String','Next Trial',...
'Position', [250 350 100 20],...
'Callback','next');
h = uicontrol(gcf,...
'Style','slider',...
'Min' ,0,'Max',50, ...
'Position',[100 20 400 20], ...
'Value', 25,...
'SliderStep',[0.02 0.1], ...
'BackgroundColor',[0.8,0.8,0.8]);
set(gcf, 'WindowButtonMotionFcn', #cb);
lastVal = get(h, 'Value');
function cb(s,e)
if get(h, 'Value') ~= lastVal
lastVal = get(h, 'Value');
fprintf('Slider value: %f\n', lastVal);
end
end
end
This pulls up two random images from a directory onto the screen, with a scroll bar and instructions to determine the level of relatedness/similarity between the two pictures with a position on the scroll bar. That's all well and good.
What I want, though, is to set it so that when the "Next Trial" button is pressed, the screen will reset, with two NEW random pictures, and the scroll bar back in the middle. How do I do this? I can't find any instructions on how to do this online.

What about something like this:
uicontrol('Style','pushbutton','String','Next Trial','Position', [250 350 100 20],'Callback','clf; semjudge()');
clf to clear the figure window: http://www.mathworks.de/help/techdoc/ref/clf.html;
and afterwards your function is simply called again which will than plot into the SAME window!

Related

uicontrol callback for more than one function

I want to write a GUI program in Matlab and make 3 sliders on it with uicontrol and then write callbacks to use their 3 values in one command. I found a way to write a function for one slider as you can see in my program. Can you help me how use these 3 callbacks? (I use R2014a)
sld = uicontrol('Style', 'slider',...
'Min',0,'Max',255,'Value',0,...
'Position', [400 20 120 20],...
'Callback', #Blue);
sld = uicontrol('Style', 'slider',...
'Min',0,'Max',255,'Value',0,...
'Position', [400 60 120 20],...
'Callback', #Green);
sld = uicontrol('Style', 'slider',...
'Min',0,'Max',255,'Value',255,...
'Position', [400 100 120 20],...
'Callback', #Red);
function Red(source,~)
R = get(source,'Value');
end
function Green(source,~)
G = get(source,'Value');
end
function Blue(source,~)
B = get(source,'Value');
end
RGB = cat(3,R,G,B); %??????
Error: Undefined function or variable "R".
Persistent data must be stored somewhere that's accessible to the callback function. One common technique is to use the parent figure's UserData field. In the example above, once a slider has been moved, the current colour can be found in the RGB field of figure fh's UserData. Also, here only one callback is used, and the UI item is identified via its Tag.
fh = figure(1);
clf
%// Initialize figure's UserData
set(fh, 'UserData', struct('RGB', [0 0 0]));
sld_b = uicontrol('Style', 'slider',...
'Min',0,'Max',255,'Value',0,...
'Position', [400 20 120 20],...
'Callback', #colourHandler, 'Tag', 'blue');
sld_g = uicontrol('Style', 'slider',...
'Min',0,'Max',255,'Value',0,...
'Position', [400 60 120 20],...
'Callback', #colourHandler, 'Tag', 'green');
sld_r = uicontrol('Style', 'slider',...
'Min',0,'Max',255,'Value',255,...
'Position', [400 100 120 20],...
'Callback', #colourHandler, 'Tag', 'red');
%// This is in a separate file, colourHandler.m
function colourHandler(source, ~)
%// Find which slider triggered us
if strcmpi(get(source, 'Tag'), 'red')
ind = 1;
elseif strcmpi(get(source, 'Tag'), 'green')
ind = 2;
else
ind = 3;
end
%// update UserData
ud = get(get(source, 'Parent'), 'UserData');
ud.RGB(ind) = get(source, 'Value');
set(get(source, 'Parent'), 'UserData', ud);
end
Alternatively you can just store the handles of your graphics objects and use those to obtain the values in other functions.
For example:
function testcode
% Initialize sample GUI
h.fig = figure( 'MenuBar', 'none', 'ToolBar', 'none');
h.sld(1) = uicontrol( ...
'Parent', h.fig, ...
'Style', 'slider',...
'Min', 0, 'Max', 255, 'Value', 0, ...
'Units', 'Normalized', 'Position', [0.1 0.65 0.4 0.1], ...
'Tag', 'Red' ...
);
h.sld(2) = uicontrol( ...
'Parent', h.fig, ...
'Style', 'slider', ...
'Min', 0, 'Max', 255, 'Value', 0, ...
'Units', 'Normalized', 'Position', [0.1 0.45 0.4 0.1], ...
'Tag', 'Green' ...
);
h.sld(3) = uicontrol( ...
'Parent', h.fig, ...
'Style', 'slider', ...
'Min', 0, 'Max', 255, 'Value', 255, ...
'Units', 'Normalized', 'Position', [0.1 0.25 0.4 0.1], ...
'Tag', 'Blue' ...
);
% Use an axes object as a color display box
% Get starting RGB values for the color display, normalized so 0 <= x <= 1
startRGB = [get(h.sld(1), 'Value'), get(h.sld(2), 'Value'), get(h.sld(3), 'Value')]/255;
h.ax = axes( ...
'Parent', h.fig, ...
'Units', 'Normalized', 'Position', [0.6 0.36 0.3 0.3], ...
'XTickLabels', '', 'YTickLabels', '', ...
'Color', startRGB ...
);
% Need to set callback after all our elements are initialized
nsliders = length(h.sld);
set(h.sld, {'Callback'}, repmat({{#slidercallback, h}}, nsliders, 1));
end
function slidercallback(~, ~, h)
% Update background color of our axes object every time the slider is updated
RGB = [get(h.sld(1), 'Value'), get(h.sld(2), 'Value'), get(h.sld(3), 'Value')]/255;
set(h.ax, 'Color', RGB');
end
When callbacks execute they are passed 2 inputs by default, the invoking object and a structure of event data. As explained in the callback documentation, you can pass additional inputs to your callback by wrapping everything into a cell array. One thing to note is that the value of your variable being passed to the callback is its value as it exists when you define the callback. In other words, if we set the callback for our sliders at the same time we create them, when the callback for Red is fired h will only contain a handle to our figure, when the callback for Green is fired h will contain a handle to our figure and to the Red slider, and so on.
Because of this, you will see I have defined the callbacks once we have initialized all of our graphics objects. Using the curly brackets to set properties of multiple objects is explained in MATLAB's documentation for set. I use repmat so the size of the cell array is the same size as our array of slider objects.

Matlab, how to loop through a series of pushbuttons?

My program creates 5 pushbuttons, and I need to change their color according to the values in a matrix A. So I define A in the main, and then at the end of main I call the function create_maze(A).
The following is create_maze(A):
function create_maze(A)
A
% create 5X5 pushbuttons
scr = get(0, 'screensize');
f1 = figure(1);
set(f1, 'menubar', 'none');
set(f1, 'position', [scr(1) scr(2) scr(3) scr(4)]);
h1 = uicontrol('Style', 'pushbutton',...
'ForegroundColor', 'blue',...
'Position', [200 200 100 100],...
'Callback', pushbutton1_Callback);
h2 = uicontrol('Style', 'pushbutton',...
'ForegroundColor', 'blue',...
'Position', [300 200 100 100],...
'Callback', pushbutton1_Callback);
h3 = uicontrol('Style', 'pushbutton',...
'ForegroundColor', 'blue',...
'Position', [400 200 100 100],...
'Callback', pushbutton1_Callback);
h4 = uicontrol('Style', 'pushbutton',...
'ForegroundColor', 'blue',...
'Position', [500 200 100 100],...
'Callback', pushbutton1_Callback);
h5 = uicontrol('Style', 'pushbutton',...
'ForegroundColor', 'blue',...
'Position', [600 200 100 100],...
'Callback', pushbutton1_Callback);
function [L] = pushbutton1_Callback(h0object, A)
% here I put the pushbuttons together in an array
L=[h1, h2, h3, h4, h5];
for i = 1:size(A,1)
if i == 0
set(L{i},'Backgroundcolor','w');
elseif i == 1
set(L{i},'Backgroundcolor','b');
elseif i == 2
set(L{1},'Backgroundcolor','g');
elseif i == 2
set(L{i},'Backgroundcolor','y');
end
end
end
end
Unfortunately I get:
Error using create_maze/pushbutton1_Callback (line 164)
Not enough input arguments.
Could anybody help me with this loop?
Thank you!
You need to think about the scope of functions
Any variables defined within a function that aren't output by it will be cleaned up (deleted) when the function finishes executing.
In the case of graphics objects a link to the push button handles will still actually exist somewhere as a child of the main figure window, but it will be mush easier if you output the handles somehow from 'create_maze'
it is safer to define the line
L=[h1, h2, h3, h4, h5];
at the end of create_maze, rather than trying to be tricky with nested functions which will give you limited advantage here, and possibly slight overhead.
Check out the mathworks website for more info on the scope of variables in nested functions, but to be on the safe side, be sure that all of functions could run without relying on the other having defined variables.
Ie. make sure functions only need their input variables

Using editable boxes in a GUI to load part of an image in MATLAB

I have a displayable image which I load via uigetfile. I want to allow the user to choose which portion of the image he wants to load by keying in the pixel coordinates of the top-left pixel and the bottom-right pixel into editable boxes. The problem is that I'm having some serious issues with the handles structure used to store data and don't quite understand how to use it.
Here is my code. I can easily load the 4 pixels in the topleft corner of the image (that's the default setting), but I fail to load anything else when the editable box values are changed. Is there something I'm missing here?
function mygui
%%
%Initialise GUI and set up editable boxes and push buttons
f = figure('Visible', 'off', 'Position', [360 500 450 285]);
handles.data.topleft1 = 1; %x-axis position of topleft pixel
handles.data.topleft2 = 1; %y-axis position of topleft pixel
handles.data.botright1 = 2; %x-axis position of bottom right pixel
handles.data.botright2 = 2; %y-axis position of bottom right pixel
hloader = uicontrol('Style', 'pushbutton', 'String', 'Load File', 'Position', [8 5 50 20], 'Callback', {#loadbutton_Callback, handles});
htopleft1 = uicontrol('Style', 'edit', 'String', handles.data.topleft1, 'Position', [25 40 15 10], 'Callback', {#topleft1_Callback, handles});
htopleft2 = uicontrol('Style', 'edit', 'String', handles.data.topleft2, 'Position', [40 40 15 10], 'Callback', {#topleft2_Callback, handles});
hbotright1 = uicontrol('Style', 'edit', 'String', handles.data.botright1, 'Position', [25 30 15 10], 'Callback', {#botright1_Callback, handles});
hbotright2 = uicontrol('Style', 'edit', 'String', handles.data.botright2, 'Position', [40 30 15 10], 'Callback', {#botright2_Callback, handles});
set([f, hloader, htopleft1, htopleft2, hbotright1, hbotright2], 'Units', 'normalized');
movegui(f, 'center')
set(f, 'Visible', 'on', 'toolbar', 'figure');
%%
%Loader pushbutton
function loadbutton_Callback(source, eventdata, handles)
[filename, pathname, filterindex] = uigetfile('*.jpg'); %Choose mario picture here from the directory you downloaded it from
picture = imread(strcat(pathname,filename));
topleft1 = handles.data.topleft1;
topleft2 = handles.data.topleft2;
botright1 = handles.data.botright1;
botright2 = handles.data.botright2;
picture = picture([topleft1:botright1], [topleft2:botright2], :); %Trim picture dimensions according to editable box inputs
imagesc(picture)
end
%%
%Editable boxes
function topleft1_Callback(source, eventdata, handles)
%Get new input from editable box; Save it into guidata handles structure thingy
topleft1 = str2double(get(source, 'String'));
handles.data.topleft1 = topleft1;
guidata(source, handles)
end
%(Repeat 3 more times for topleft2, botright1 and botright2)
end
And as usual, here's the picture which I'm trying to trim:
(source: gawkerassets.com)
I can suggest a solution with some changes that might be not as efficient, bu they'll work. I would do this kind of passing data between callbacks simply using the fact that Your whole GUI is a nested function, so all the callbacks can acces handles without even running the guidata function:
Do achieve this just change the way boxes are calling their callbacks from
(... 'Callback', {#topleft1_Callback, handles})
to:
(... 'Callback', #topleft1_Callback)
Now adjust arguments taken by Your callbacks, so the don't take three but two:
function myCallback(source,eventdata)
although none of those will be used, so You could simply write:
function myCallback(~,~)
as You MATlab will probably suggest. And You don't need the
guidata(source, handles);
line in any of Your callbacks anymore, since handles can be accesed anyway just by its name.

MATLAB stop program after X repetitions?

I have this program, which as you can see is pulling random pictures out of a directory, and asking the user to compare them. After setting the value with the slider, the user presses a "Next Trial" button, which resets the slider and the random picture pair. How do I modify the code so that, after a certain number of repetitions (button presses), the program automatically ends (preferably with a "Experiment Ended" message)?
I can't find anything about how to do this in the MATLAB documentation. Do I need to set a variable, so that everytime the button is pressed "1" is added to the value of the variable, so that when it reaches a certain number (say "100") it terminates? Is that the easiest way to do this?
Here's the script:
function trials
files = dir(fullfile('samples','*.png'));
nFiles = numel(files);
combos = nchoosek(1:nFiles, 2);
index = combos(randperm(size(combos, 1)), :);
picture1 = files(index(1)).name;
picture2 = files(index(2)).name;
image1 = fullfile('samples',picture1);
image2 = fullfile('samples',picture2);
subplot(1,2,1); imshow(image1);
subplot(1,2,2); imshow(image2);
uicontrol('Style', 'text',...
'Position', [200 375 200 20],...
'String','How related are these pictures?');
uicontrol('Style', 'text',...
'Position', [50 375 100 20],...
'String','Unrelated');
uicontrol('Style', 'text',...
'Position', [450 375 100 20],...
'String','Closely related');
uicontrol('Style','pushbutton','String','Next Trial',...
'Position', [250 45 100 20],...
'Callback','clf; trials()');
h = uicontrol(gcf,...
'Style','slider',...
'Min' ,0,'Max',50, ...
'Position',[100 350 400 20], ...
'Value', 25,...
'SliderStep',[0.02 0.1], ...
'BackgroundColor',[0.8,0.8,0.8]);
set(gcf, 'WindowButtonMotionFcn', #cb);
lastVal = get(h, 'Value');
function cb(s,e)
if get(h, 'Value') ~= lastVal
lastVal = get(h, 'Value');
fprintf('Slider value: %f\n', lastVal);
end
end
end
One problem I see here is that the callback for your "Next Trial" button simply calls the function trials again. This is going to generate the combinations of images again, which you only want/need to do once. You should set the callback to be another nested function (like cb) so it can access the already-generated combinations.
Another problem is how you initialize picture1 and picture2. You should do your indexing like so:
picture1 = files(index(1,1)).name; %# Note that index is 2-dimensional!
picture2 = files(index(1,2)).name;
Now, you'll first want to initialize a variable to track the number of trials inside the function trials, as well as a maximum number of trials:
nReps = 1;
maxReps = 100;
Then your "Next Trial" button callback would look something like this:
function newTrial(s, e)
%# I assume you need the slider value for each trial, so fetch it
%# and save/store it here.
%# Check the number of trials:
if (nReps == maxReps)
close(gcf); %# Close the figure window
else
nReps = nReps + 1;
end
%# Get the new images:
picture1 = files(index(nReps, 1)).name;
picture2 = files(index(nReps, 2)).name;
image1 = fullfile('samples', picture1);
image2 = fullfile('samples', picture2);
%# Plot the new images:
subplot(1,2,1);
imshow(image1);
subplot(1,2,2);
imshow(image2);
%# Reset the slider to the default value:
set(h, 'Value', 25);
end
One additional suggestion... instead of displaying the slider value on the screen using FPRINTF, I would create a text object in your GUI and simply update its string value:
hText = uicontrol('Style', 'text', ...
'String', 'Slider value: 25', ... );
%# And in function cb...
set(hText, 'String', sprintf('Slider value: %f', lastVal));

MATLAB data file formatting

I am having a really hard time understanding the appropriate code/format for creating a datafile in MATLAB. For some reason this particular task just really confuses me.
So I have this script:
function semjudge
SubNum = ('Subject Number: ','s');
files = dir(fullfile('pictures','*.png'));
nFiles = numel(files);
combos = nchoosek(1:nFiles, 2);
index = combos(randperm(size(combos, 1)), :);
picture1 = files(index(1)).name;
picture2 = files(index(2)).name;
image1 = fullfile('pictures',picture1);
image2 = fullfile('pictures',picture2);
subplot(1,2,1); imshow(image1); title(picture1);
subplot(1,2,2); imshow(image2); title(picture2);
uicontrol('Style', 'text',...
'Position', [200 45 200 20],...
'String','How related are these pictures?');
uicontrol('Style', 'text',...
'Position', [50 45 100 20],...
'String','Unrelated');
uicontrol('Style', 'text',...
'Position', [450 45 100 20],...
'String','Closely related');
uicontrol('Style','pushbutton','String','Next Trial',...
'Position', [250 350 100 20],...
'Callback','clf; semjudge()');
h = uicontrol(gcf,...
'Style','slider',...
'Min' ,0,'Max',50, ...
'Position',[100 20 400 20], ...
'Value', 25,...
'SliderStep',[0.02 0.1], ...
'BackgroundColor',[0.8,0.8,0.8]);
set(gcf, 'WindowButtonMotionFcn', #cb);
lastVal = get(h, 'Value');
function cb(s,e)
if get(h, 'Value') ~= lastVal
lastVal = get(h, 'Value');
fprintf('Slider value: %f\n', lastVal);
end
end
end
Pretty simple little script. It pulls two random pictures from a folder, and the user is asked to compare them. All I want is a data file labelled by the Subject Number, something like:
fid = fopen(strcat('data','_',SubNum,'.txt'),'a');
The datafile itself I want to contain the title of each picture, and the values assigned to it by the slider. So, when the user presses the 'Next Trial' button, it saves title(picture1) and title(picture2) as well as lastVal.
I realize this is a very basic question, but the MathWorks documentation on datafiles I find to be very confusing, and I don't understand how to do it.
If I understand your problem correctly it should be something like this (check FPRINTF documentation for details):
fid = fopen(strcat('data','_',SubNum,'.txt'),'a');
fprintf(fid, '%s\t%s\t%f\n', picture1, picture2, lastVal)
fclose(fid);
Based on your code the file name will be ... a little weird. Like 'data_Subject Number: s.txt' (I hope s in 2nd line actually will be variable number), but it's up to you to change it.
If you want to print each variable as a single line, you can substitute \t with \n.