How in Matlab do changes on figure 1 with slider on figure 2? - matlab

I have some sliders on figure 1, and I have some images on figure 2. I want to do the callbacks for the sliders in a way that, when I change the sliders in figure 1 , the threshold changes and images update automatically in figure 2.
I'm using addlistener to send values for callback function. The problem is when you move slider the active figure is figure 1, and you want to do changes on figure 2.
adding some code for clarification:
M.rgbImage = imread('euhedral-mag-on-po-edge-pseudo-sub-ophitic-rl-fov-4-8mm.jpg');
[rows, columns, numberOfColorBands] = size(M.rgbImage);
F.f = figure; % This is the figure which has the axes to be controlled.
% Now create the other GUI
S.fh = figure('units','pixels',...
'position',[400 400 500 100],...
'menubar','none',...
'name','Image control',...
'numbertitle','off',...
'resize','off');
S.sl = uicontrol('style','slide',...
'unit','pix',...
'position',[60 10 270 20],...
'min',0,'max',255,'val',100,...
'callback',{#sl_call2,S},'deletefcn',{#delete,F.f});
....
lis = addlistener(S.sl,'Value','PostSet',#(e,h) sl_call3(S,F,M));
function sl_call3(S,F,M)
v = get(S.sl,'value');
figure(F.f), subplot(4, 4, 13);
M.redMask = (M.redPlane > v);
imshow(M.redObjectsMask, []);
set(S.ed(2),'string',v);

Create reference to both your figures:
f1=figure(1);
f2=figure(2);
And then when doing the callback pass f2 as a parameter.

In the callback, you'll have get the handle to the second figure.
There's various ways to do that.
You can specify the handle to the second figure at the time of callback-definition:
figure2 = ...;
addlistener(hSlider, ..., #(a,b) changeStuffOn(figure2));
Or during the callback:
function callbackFunction(hObject, evt)
% get the handle to the second figure, e.g. by a tag, or its name
fig2 = findobj(0, 'type', 'figure', 'tag', 'figure2'); %
% do whatever you want with fig2
end
The latter might be somewhat worse in performance, but e.g. has the benefit of working reliably even if figure2 was deleted and recreated and some point.
To avoid the change of focus you'll have to get rid of this line your callback:
figure(F.f)
This explicitly moves the focus to the second figure.
You'll have to use e.g. the imshow(axes_handle, ...) syntax, in order to show the image not in the "current axes".

Related

How to plot a "moving" graph for real time values along the x-axis (using psychtoolbox)?

I am writing a code for a real time experiment using psychtoolbox to present the stimulus. In my experiment, I need to show the subject a graph that indicates his performance. I have plotted the graph using this simple code:
% Draw the graph
figure('visible','off','color',[0 0 0]);
pcolor([0 Num_timepoint+2],[-10 0],ones(2,2));
hold on;
pcolor([0 Num_timepoint+2],[0 10],2*ones(2,2));
colormap([79 167 255;255 187 221]/256);
plot(1:subloop,value0,'*-',...
'color',[0,0,0],...
'LineWidth',1,...
'MarkerSize',5,...
'MarkerEdgeColor','k',...
'MarkerFaceColor',[0.5,0.5,0.5]);
axis([0,Num_timepoint+2,-10,10]);
saveas(gcf,'line_chart.png'); %save it
close(figure);
line_chart=imread('line_chart.png'); %read it
resized_plot=imresize(line_chart,0.5);
imageSize = size(resized_plot);
[imageHeight,imageWidth,colorChannels]=size(resized_plot);
bottomRect = [xCenter-imageWidth/1.5, yCenter+gapdown, xCenter+imageWidth/1.5, yCenter+gapdown+imageHeight];
imageDisplay=Screen('MakeTexture', win0, resized_plot);
Screen('DrawTexture', win0, imageDisplay, [], bottomRect);
Unfortunately, this simple code is very slow. In addition, I couldn't make the graph moving along x axis, as soon as the new value comes.
Any help would be Awesome. Thanks in advance for your efforts.
Why are you saving the figure and redisplaying as an image? Maybe I'm missing something but you should be able to accomplish what you need by updating the existing plot with the fresh data using the handles properties of the plot:
.... First time through we need the initial plot ....
% Set up figure with colormaps and such but leave as 'visible','on'
hPlot = plot(plot(1:subloop,value0,'*-',...
'color',[0,0,0],...
'LineWidth',1,...
'MarkerSize',5,...
'MarkerEdgeColor','k',...
'MarkerFaceColor',[0.5,0.5,0.5]);
hAxes = gca;
.... Loop over your real time updates ....
% Assuming value0 has subject's results from t=0 to t=now
hPlot.XData = value0; hPlot.YData = [1:subloop];
hAxes.XLim = [0 numTimePoints+2];
hAxes.YLim = [-10 10]
.... Continue test and update value0 ....
I think that should keep your plots current without having to save the figure as image to file then reopen the image to display to subject.
If you want to move your data one sample, you can use the circshift function. For example, if you want your new values to appear on the left hand side, you can shift all values 1 sample rightward, then add your new value in the first position.
For converting a MATLAB figure to a Psychtoolbox texture, you don't need to save, then load the temporary images. You can instead use the getframe function to capture the MATLAB figure data, which can then be given to MakeTexture to turn it into a Psychtoolbox texture.
I'm not sure what values you're actually using for subloop, value0, etc. but there is an example that I think might be close to what you want. In this example, 30 frames of figures are plotted, with each figure being on screen for 1 second. New data points are generated randomly and appear from the left hand side of the figure.
Depending on the details of your experiment, you may find that this approach is still too slow. You could also create the figure directly via Psychtoolbox drawing methods like DrawLines, etc. though that would require more effort.
try
win0 = Screen('OpenWindow', 0, 0);
Num_timepoint = 100;
subloop = 100;
value0 = zeros(1,100);
num_demo_frames = 30;
% Draw the graph
fig_h = figure('visible','off','color',[0 0 0]);
pcolor([0 Num_timepoint+2],[-10 0],ones(2,2));
hold on;
pcolor([0 Num_timepoint+2],[0 10],2*ones(2,2));
colormap([79 167 255;255 187 221]/256);
plot_h = plot(1:subloop,value0,'*-',...
'color',[0,0,0],...
'LineWidth',1,...
'MarkerSize',5,...
'MarkerEdgeColor','k',...
'MarkerFaceColor',[0.5,0.5,0.5]);
axis([0,Num_timepoint+2,-10,10]);
for f = 1:num_demo_frames
new_value = randn(1,1);
data_values = plot_h.YData;
data_values = circshift(data_values, 1);
data_values(1) = new_value;
plot_h.YData = data_values;
plot_values = getframe(fig_h);
imageDisplay=Screen('MakeTexture', win0, plot_values.cdata);
Screen('DrawTexture', win0, imageDisplay);
Screen('Flip', win0);
WaitSecs(1);
end
sca;
catch e
sca;
rethrow(e);
end

How to reset the default values in a graphical user interface

I'm creating a graphic interface (manually) and I would like to have a reset button which reset the default values.
I already code this
H.but(3) = uicontrol('Units','normalized', ...
'BackgroundColor',[1 0.7 1], ...
'Callback','MyFunction(''Reset'');', ...
'FontSize',12, ...
'Position',[0.04 0.54 0.1 0.05 ], ...
'String','Reset');
case 'Reset'
clear all % Is not working and I think that isn't that I expect
set(findobj(H.fig,'style','edit', '-or','style','text'),'string','') % H is a global variable. This trial don't give the default value, it just clear certain boxes
I usually prefer to create a specific reset_gui function for my GUIs that resets all the relevant control properties (like checkbox states, strings in editable text boxes, etc.) to appropriate default values, as well as setting all relevant variable values to their defaults, clearing plots, etc..
If you'd prefer a generic option for resetting all UI control properties to their initial state, here's an example of one possible solution:
function example_reset_gui
% Initialize GUI:
hFigure = figure();
uicontrol('Style', 'edit', 'Position', [20 100 100 25]);
uicontrol('Style', 'edit', 'Position', [20 65 100 25]);
uicontrol('Style', 'push', 'Position', [20 20 60 30], ...
'String', 'Reset', 'Callback', #reset_fcn);
drawnow
% Collect default states:
[defaultState{1:3}] = get_default_state(hFigure);
% Nested reset function:
function reset_fcn(~, ~)
set(defaultState{:});
end
end
% Local function:
function [hArray, propArray, valueArray] = get_default_state(hFigure)
hArray = findall(hFigure, 'Type', 'uicontrol');
propArray = fieldnames(set(hArray(1)));
valueArray = get(hArray, propArray);
end
This creates a figure with 2 editable text boxes and a reset button. You can type whatever you want into the text boxes, and when you push the reset button it will clear them (i.e. set them to the default empty string they first contained).
The local function get_default_state will find all the uicontrol objects in the figure, then get all of their set-able properties (i.e. all properties that are not read-only), then get all the initial values for those properties. The three outputs are stored in the 1-by-3 cell array defaultState, which is accessible by the nested function reset_fcn. When the reset button is pressed, all of the set-able UI control properties are set to the values they had when first created.
It should be noted that any changes made to the Position property (such as due to resizing of the figure) could be undone by this approach. Using 'normalized' units would avoid this.
If you truly want to start your GUI over from scratch the easiest way would be to just close it open it again. You can do that from your button's callback. Which I pointed at a new function restartGUI. That could be a subfunction of your main gui or its own m-file, your choice.
Your question is pretty light on details so I can't help with some of the specifics but this should give you the general idea.
IF closing and opening isn't what your want then in the restartGUI function you would have to just manually reset the state of each of your uicontrols, etc. (whatever else is in your GUI that we can't see).
H.but(3) = uicontrol('Units','normalized', ...
'BackgroundColor',[1 0.7 1], ...
'Callback',#restartGUI, ...
'FontSize',12, ...
'Position',[0.04 0.54 0.1 0.05 ], ...
'String','Reset');
% <<<< THE rest of your code >>>
function restartGUI(hObject,varargin)
global H
close(H.fig) %Assuming H.fig the main GUI window.
%Call the GUI again which will restart it.
yourGUIFunction
Edit: added the use of the global H to close.

Selecting Axis inside a tab group with a programmatic GUI

When creating a GUI using OOP in MATLAB, I am having troubles understanding how to control which Axis of which Tab I want to plot my data in. I attach sample code to aid with my questions
First of all, when the GUI is loaded, only Axis 2 under Tab 2 is titled (Axis 2), the code title('Axis 1'); does not seem to get through. Why is this?
When the code is run, by default there are no plots in Tab1 or Tab2. If you click "Plot Data" while Tab1 is open, then switch to Tab2, you can see the sine curve is plot in Tab2. But according to my code, or at leaste what I am trying to do, is that the sine curve should appear in Axis1 of Tab1.
But when you click on Tab2, and click 'Plot Data', the curve changes to the exponential, which is what I am expecting.
I am still quite new at OOP GUI with MATLA so there might be some simple stuff I am missing. Thanks for any help and comments.
classdef example < handle
properties
Figure;
TabGroupAxis;
TabsAxis;
Axis1;
Axis2;
ButtonPlotData;
DataToPlot;
end
methods
function obj = example()
create(obj)
makeUpData(obj);
end
function create(obj)
obj.Figure = figure('Position',[300 300 640 640]);
obj.TabGroupAxis = uitabgroup(obj.Figure,'Units','pixels','Position',[100 20 600 600]);
obj.TabsAxis(1) = uitab(obj.TabGroupAxis,'Title','Tab1');
obj.TabsAxis(2) = uitab(obj.TabGroupAxis,'Title','Tab2');
obj.Axis1 = axes('Parent',obj.TabsAxis(1),'Units','pixels','Position',[30 20 500 500]);
obj.Axis2 = axes('Parent',obj.TabsAxis(2),'Units','pixels','Position',[30 20 500 500]);
obj.ButtonPlotData = uicontrol(obj.Figure,'Style','pushbutton','String','Plot Data',...
'Callback',#obj.buttonPlotDataCallback);
axis(obj.Axis1);
title('Axis 1');
axis(obj.Axis2);
title('Axis 2');
end
function makeUpData(obj)
obj.DataToPlot(1).x = linspace(0,2*pi);
obj.DataToPlot(1).y = sin(obj.DataToPlot(1).x);
obj.DataToPlot(2).x = linspace(0,2*pi);
obj.DataToPlot(2).y = exp(obj.DataToPlot(1).x);
end
function buttonPlotDataCallback(obj,hObject,eventdata)
activeTab = obj.TabGroupAxis.SelectedTab.Title;
switch activeTab
case 'Tab1'
axis(obj.Axis1);
plot(obj.DataToPlot(1).x,obj.DataToPlot(1).y);
case 'Tab2'
axis(obj.Axis2);
plot(obj.DataToPlot(2).x,obj.DataToPlot(2).y);
end
end
end
end
Long Answer
Excellent question, your example made it really easy for me to understand the problem. I put a break point in the buttonPlotDataCallback and saw that the switch case is operation correctly, the problem was that axis(obj.Axis1) didn't change the focus. Looking at the documentation, that's because that isn't the correct use of axis.
An alternative way to plot the function is to use an overloaded method of plot
case 'Tab1'
plot(obj.Axis1,obj.DataToPlot(1).x,obj.DataToPlot(1).y);
Now we realize that the reason that axis1 is not getting titled is that the call to axis on line 34 is not working either. This can also be fixed by overloading, this time title.
title(obj.Axis1,'Axis 1');
Shorter Answer
Turns out axes does exactly what you are using axis for. You have a typo that didn't get caught because axis is a valid function. change axis(< handle >) to axes(< handle >) and you'll be good to go.

Creating an unknown amount of uicontrols in matlab

So for a self project I'm creating a gui minesweeper like game in matlab and want to create an adjustable pushbutton grid however I'm not sure on how to do so. this is what I have got so far.
function createField()
xAmount = str2double(inputdlg('enter row length'));
yAmount = str2double(inputdlg('enter column length'));
for i = 1:xAmount
for j = 1:yAmount
%create buttons
end
end
end
One solution might be:
function create_field(hparent, nx, ny, width, padding)
% Test arguments
if ~test_parent_handle(hparent)
error('Parent must be a single valid graphic handle.');
elseif ~test_positive_integer(nx)
error('Number of buttons on X direction must be a scalar positive integer.');
elseif ~test_positive_integer(ny)
error('Number of buttons on Y direction must be a scalar positive integer.');
elseif ~test_positive_integer(width) ...
|| (width >= 100)
error('Button width must be a scalar positive integer smaller than 100.');
elseif ~test_positive_integer(padding) ...
|| (padding >= 20)
error('Button padding must be a scalar positive integer smaller than 20.');
end;
% Resize the parent to fit the button grid
set(hparent, 'Units', 'pixels');
ppos = get(hparent, 'Position');
ppos(3) = nx*width + (nx-1)*padding;
ppos(4) = ny*width + (ny-1)*padding;
set(hparent, 'Position', ppos);
% Create button grid
for p = 1:nx
for q = 1:ny
bpos = [ % Button spec:
(p-1)*(width+padding) % - X
(q-1)*(width+padding) % - Y
width % - W
width % - H
];
uicontrol( ...
'Units', 'pixels', ...
'Tag', sprintf('X%dY%d',p,q), ...
'Style', 'pushbutton', ...
'Parent', hparent, ...
'Position', bpos ...
);
end;
end;
% ----- NESTED FUNCTIONS -----
function tf = test_parent_handle(value)
tf = isscalar(value) ...
&& ishandle(value);
end
function tf = test_positive_integer(value)
tf = isscalar(value) ...
&& isreal(value) ...
&& isfinite(value) ...
&& (value > 0) ...
&& (fix(value) == value);
end
end
For a figure with 15 x 10 square buttons, each having the side 25 pixels with a padding of 3 pixels between the buttons, call:
create_field(figure(), 15, 10, 20, 3);
As with most problems there are many different approaches, having written something similar I'll give you the same prompts that I used when writing my helper function.
Your code is going to act based on what button is pressed so each button will need its own unique ID and properties. Depending on the MATLAB version used, each of your graphics elements will have a handle. Starting in R2014b, graphics objects can be addressed directly as objects rather than needing to utilize a numeric ID as a pointer.
Start with the figure window and check out the figure properties:
h.mainfig = figure; % Arbitrary figure window
get(h.mainfig); % Dump properties to command window
Right now we're probably most interested in the Units and Position properties of the main figure window, which you can use in a helper function to figure out how to size and space the buttons as you create them.
If we create a pushbutton graphics object with uicontrol() we're going to get mostly the same properties.
h.randombutton = uicontrol('Parent', h.mainfig, 'Style', 'pushbutton');
get(h.randombutton);
Again, we're interested in the Units and Position properties. We're also going to be interested in the Callback property, which is the function that executes when we interact with the button. Another good one is the Tag property, which can be used to set a unique string tag for each button for use with later logic.
You've probably noticed I'm using a structure array to store my graphics handles. This is similar to how MATLAB generates its object data when creating a GUI with GUIDE and has the huge advantage of a tidy data package to pass around our function. A great thing about structure arrays is that you can nest data structures, allowing us to easily generate and address graphics objects without needing to get clever with dynamic field references or eval() (yuck). Instead of having to do something like button_1, button_2, etc, we can do:
h.button(1) = uicontrol('Parent', h.mainfig, 'Style', 'pushbutton');
h.button(2) = uicontrol('Parent', h.mainfig, 'Style', 'pushbutton');
...
h.button(n) = uicontrol('Parent', h.mainfig, 'Style', 'pushbutton');
Now we know how to generate an arbitrary number of buttons programmatically and easily address them later on.
Other than the button generation we have another key function that I mentioned earlier, the button callback. Callback functions follow a slightly different syntax in that they natively pass along two arguments, the handle of the object whose callback is executing and the event data structure (see the documentation for more info). Because the function knows what UI object invoked it, we can make a pretty generic function.
Hopefully this helps!
Have you considered creating the ui in Java - undocumented matlab has some examples. Java would provide you nice LayoutManagers that will take care about resizing and more.

matlab GUIDE: storing data from loop in vector

I am new to matlab and i need some help. I am trying to make some program, where you can by 2 clicks on picture get a lenght of something. Basicly it works well, but got a problem when trying to algorytmize it. I use ginput to get coordinates and then pythagorean theorem to work with them and make important variable z2. And those variables I want to store in vector so basicly: I pressed push_button1 click twice on a picture and get some z2,now when i do the procedure again i want to store the new one with the old one in the same vector
[z2_old z2_new]. But basicly every time i tried to make something like this the old ones value is rewritten.
This is the code of my push button:
function pushbutton1_Callback(hObject, EventData, handles)
%counter - number of press (working right)
counter = get(hObject, 'UserData') + 1;
set(hObject, 'UserData', counter);
set(handles.text1, 'String', sprintf('%d', counter));
% - ginput part (working right)
c2 = ginput(2);
q3 = text(c2(1,1),c2(1,2),'X', ...
'HorizontalAlignment','center', ...
'Color', [1 1 0], ...
'FontSize',10);
q4 = text(c2(2,1),c2(2,2),'X', ...
'HorizontalAlignment','center', ...
'Color', [1 1 0], ...
'FontSize',10);
%creating the z2 variable(working right)
x2=c2(1,1)-c2(2,1);
y2=c2(1,2)-c2(2,2);
z2=sqrt(x2*x2+y2*y2);
% - loop for getting a vector (not ok)
for i=1:counter
z(i,1)=z2
end
So, basicly when I run the button first time and z2 got for example 130, second time 60, third time 210m I want to get z=[130 60 210], now I am still getting something like 1st press:z=[130], 2nd press: z=[60 60], 3rd press: z=[210 210 210], the old values are every time lost. I tried to fix it many ways but its still not working. Its only a small part of my work and i almost run out of time.
Can someone please tell me how should that loop look like? I tried z(end+1)=z2 , z=[z z2] , but the result is always the same.
Thanks for your help a lot. I really Appreciate it.
The issue is that with each click on pushbutton, it creates new values for z2. Even though the counter increments, but z2 is always the new value. So, you need to save z2 between clicks on the pushbutton. For that you have handles structure available for data storage between GUI callbacks. You need to make two changes -
Add this line inside the guiname__OpeningFcn before the handles structure is updated in guidata(hObject, handles); -
handles.z2 =[];
Edit the pushbutton callback to this -
x2=c2(1,1)-c2(2,1)
y2=c2(1,2)-c2(2,2)
z2=sqrt(x2*x2+y2*y2)
z = [handles.z2 z2]
handles.z2 = z;
guidata(hObject,handles);
Hope this works out for you, let us know!
Try this
Remove the for loop
Just write
z[z,z2]
This should add z2 to the end of the existing z every time.
In case it throws an error just first give z(0)=0; an initial garbage value to start with.