Accessing the value of other sliders from within a ValueChangingFcn - matlab

I have multiple sliders inside a figure, and I would like to publish their values (using the robotics toolbox) when one of them changes. I'm unable to access the value of more than one slider - an attempt to access the slider values gives me the following error in the sliderMoving function:
Undefined variable "event1" or class "event1.Value".
The code is as follows:
function sliderchanging
%rosinit('129.78.214.177');
first_val = 0;
euler_v = rossubscriber('/Euler_values');
slider_v = rospublisher('/Slider_values', 'std_msgs/Float64MultiArray');
slidermsg = rosmessage(slider_v);
eulermsg = rostopic('echo', '/Euler_values');
ypr = eulermsg.Data;
y = ypr(1);
p = ypr(2);
r = ypr(3);
fig = uifigure;
sld = uislider(fig,'Position',[20 50 260 20],'ValueChangingFcn',#(sld,event) sliderMoving(event, slidermsg, slider_v, y, p, r));
sld1 = uislider(fig,'Position',[20 80 260 20],'ValueChangingFcn',#(sld1,event1) sliderMoving(event1, slidermsg, slider_v, y, p, r));
if first_val == 0
send(slider_v, eulermsg);
end
sld.Limits = [y-2 y+2];
sld.Value = y;
sld.Position = [20 50 260 20];
sld1.Limits = [p-2 p+2];
sld1.Value = p;
sld1.Position = [20 80 260 20];
end
function sliderMoving(event, slidermsg, slider_v, y, p, r)
first_val = 1;
disp(event.Value)
disp(event1.Value)
slidermsg.Data = [event.Value, p, r];
send(slider_v, slidermsg)
end
What is wrong with this code? How can I access the values of all available sliders from within the sliderMoving callback?

Your problem is because the sliderMoving function does not know the name of the variable in the calling workspace. In other words,
function out = func(in)
% do something with in
end
won't behave differently if we call it like func(in1) or func(in2).
In your case, the event will always be known inside the callback as event.
If you want different behavior based on which slider was used, you should decide based on the first two inputs to the callback (commonly: src and eventData), or via some additional input parameter (as you already do). If you need to access the value of the other slider, you can do this using event.Source.Parent.otherSld.
You should also note that the statement first_val = 1; that is found inside the callback has no effect on the value outside the callback. You should read about nested functions.
I think this is what you meant to do:
function sliderchanging
...
fig = uifigure;
...
function sliderMoving(...)
end
end

As the error message says event1 is not a variable or class. You can't copy the slider code and put a 1 after every entry.
I suggest you look at the MATLAB documentation on events. You will have to use event
in both slider definitions and either use a different callback for each slider or if you use the same call back then you will need to find someway of identifying which slider triggered the callback.

Related

matlab append different values of the same variable on button click

So I am doing this in matlab app designer, I have a variable x which changes on every button click, I would like to add every value of x to an array to find the average. Say on the first click, x is 10, on the second, x is 2 and on the 3rd x is 9, I would like an array, values, to be equal to [10 2 9]. Every time I have tried, it just ends up containing the most recent x value. Below is what I have tried.
function GenerateButtonPushed(app, event)
x = (randi[1 30]);
values = [];
values(end+1) = x;
average = mean(values)
I can see what the problem is, every time I press the button, it resets the array to be empty, but I do not know how to get around this. Suggestions are appreciated, thanks!
You need to store your values somehwere other than the callback function.
One way is to use setappdata and getappdata.
function GenerateButtonPushed(app, event)
x = (randi[1 30]);
values = getappdata(app.Parent, 'myvalues'); % Get values from the app
values(end+1) = x;
setappdata(app.Parent, 'myvalues', values); % Put the updated values back
average = mean(values)
Somewhere in your app startup you'll need to initialise the array with something like, setappdata(app_fig, 'myvalues', []).
See examples here
Note I'd suggest reading about the "scope" of variables within functions so you understand why they don't persist.
You can also do this with a persistent variable:
function GenerateButtonPushed(app, event)
x = (randi[1 30]);
persistent values % initialized to [] on first call
values(end+1) = x;
average = mean(values)
values will be reset every time you do clear all or clear functions or clear GenerateButtonPushed or anything else that removes the function from memory. You cannot modify the variable in any other way.

Body of this Matlab function works, but not the function itself (interp1 error)

I've written the following piece of subcode (with parameters commented) for an Euler policy iteration algorithm. When I try to run the body of the function (everything below global) for say, a1 = 1, it works, and returns a scalar. However, when I call the function as euler_diff_test(1), I get an error. (Pasted below)
function diff = euler_diff_test(a1)
%the following comments are example parameters. They are in the global line originally.
% r = 0.2, a = 0.5, y = 1.1, a_grid = linspace(0.5,7,100)
%policy_guess = zeros(2,N);
%policy_guess(1,:) = 0.3*a_grid;
%policy_guess(2,:) = 0.3*a_grid;
% M = zeros(2,2); %M for markov transition kernel
% M(1,1) = p;
% M(2,2) = p;
% M(2,1) = 1-p;
% M(1,2) = 1-p;
% j = 1
global r a y a_grid policy_guess M j;
c = (1+r)*a + y - a1; %consumption formula
if c<=1e-02 %don't care about consumption being negative
diff = 888888888888888888888;
else
policy_func = interp1(a_grid', policy_guess', a1, 'linear');
diff = 1/c - beta*(1+r)*(1 ./ policy_func)*M(j,:)';
end
end
Error Reads:
Any help is much appreciated!
The problem is that you dont understand globals nor how they work!
You seem to be doing something like:
N=100; p=0.1;
r = 0.2, a = 0.5, y = 1.1, a_grid = linspace(0.5,7,100)
policy_guess = zeros(2,N);
policy_guess(1,:) = 0.3*a_grid;
policy_guess(2,:) = 0.3*a_grid;
M = zeros(2,2); %M for markov transition kernel
M(1,1) = p;
M(2,2) = p;
M(2,1) = 1-p;
M(1,2) = 1-p;
euler_diff_test(1)
And this is causing the error you show. Of course it is!
First, you need to learn what a global is and what worskpaces are. Each fucntion has its own worskpace or "scope". That means that only variables defined within the workspace are visible by the function itself.
A global variable is one that exist for all workspaces, and everyone can modify it. You seem to want all those variables defined outside the function, inside your function. But realise! when the variables are defined, they are not global. The function starts, and in its first line, it does only know about the existence of a1. Then, later, you define a bunch of variables as global, that the function did not know about. So what does the function do? just create them empty, for you.
If you want your the variables that you create in the main script scope to be global, you need to declare them as global then, not inside the function. So cut your line global ... from the fucntion, and put it on top of the script where you declare all your variables, i.e. on top of
% here!
N=100; p=0.1;
...
in my example.
Now, the important stuff: Global variables are bad. When you have globals, you don't know who modifies, and its super easy to lost track of what is happening to them, because every function that uses a variable a will modify the global a, so its a pain to debug. Almost no one uses globals because of this. The best way is to pass them to the function as input, i.e. define your function as:
function diff = euler_diff_test(a1,r, a, y, a_grid, policy_guess, M, j)

How to update a uitable after creation from other functions?

I created a matfile in which I store data that are constantly overwritten by user behavior. This occurs in a function "test()".
n=1
while n < 5
myVal = double(Test704(1, 780, -1)) %Returns the user's behavior
if myVal == 1
n = n + 1 %"n" is the overwritten variable in the matfile
end
save('testSave1.mat') %The matfile
m = matfile('testSave1.mat')
end
Then, I want to display these data in another function (it is essential to have two separated functions) called "storageTest()". More particularly, storageTest() is a GUI function where I developped an uitable "t". So, I first call the function "test()" and give its output values as data of "t". Here is the code of the interesting part of "storageTest":
m = test()
d = [m.n]
t = uitable('Data',d, ...
'ColumnWidth',{50}, ...
'Position',[100 100 461 146]);
t.Position(3) = t.Extent(3);
t.Position(4) = t.Extent(4);
drawnow
This code executes only when "m = test()" running is over and displays me a tab in which I can see the final value of "n". However, I want my table to be displayed before and to see my value incrementing according to user's behavior.
I have searched on the web to solve my issue, but I cannot find any answer, is it possible to do such a thing?
Assuming I'm interpreting the question correctly, it should be fairly trivial to accomplish this if you initialize your table prior to calling test and then pass the handle to your table for test to update in the while loop:
For example:
function testGUI
% Initialize table
t = uitable('ColumnWidth',{50}, 'Position',[100 100 461 146]);
test(t)
function test(t)
n = 1;
while n < 5
n = n + 1;
t.Data = n;
pause(0.25); % Since we're just incrementing a number, a slight so we can actually see the change
end
When you run the above, you'll notice the data in your table iterating as expected.
excaza was a little faster in writing basically the same answer like me. As it looks a slightly different, I'll post it anyway.
function storagetest()
close all
f = figure;
data = [1];
t = uitable(f,'Data',data,'ColumnWidth',{50});
test()
end
function test()
% handle uitable
t = evalin('caller','t')
n = 1;
while n < 5
newVal = input('Enter a number:');
data = get(t,'Data');
set(t,'Data', [data; newVal]);
n = n + 1;
end
end
The "user behaviour" I imitated with the input function. The basic idea is to update your table from within test(). evalin you can use, if you don't want to pass parameters to test(), though passing the handle of the uitable directly is certainly the better option.
If you are working on a serious GUI project I highly recommend you reading this answer.

Variable persisting between function calls

Suppose I want to call a function twice, but I need the function to remember variables it initialized the first time it is called so execution can be changed in subsequent calls.
For example if I have a piece of code like this:
function random
if exist('a','var') == 0
fprintf('hello\n');
a = 1;
else
disp('goodbye\n');
end
end
How could I get MATLAB to remember that a equals 1 when when I call the code again? Specifically, I'm hoping to use this for a push button callback function in a program I'm writing.
MATLAB supports the keyword persistent, which you would use as follows:
function toggleval_persist
% Set up the persistent variable and initialize it.
persistent a;
if isempty(a)
a = 0;
end
if ( a == 0 )
disp('hello');
a = 1;
else
a = 0;
disp('goodbye');
end
end
Also, I wouldn't recommend using a persistent variable for toggling a button state. The button's state is usually available in the object structure for the GUI if you're using MATLAB's UI system.
What you could do (in the optics of using this code in a GUI) is set up a flag telling whether a has been initialized or not and pass it as an argument to the function random. Storing the flag (let's call it a_flag) in the handles structure of the GUI, for instance, would allow you to keep track of its value (actually stored in handles.a_flag) for example.
So in other words,you could set the flag to 0 during the creation of the GUI (or in its Opening_Fcn if you are using GUIDE) as follows:
handles.a_flag = false;
and then in the function called random, which you could call with: random(handles.a_flag):
function random(a_flag)
if ~a_flag
%// Update the flag
a_flag = true;
fprintf('hello\n');
a = 1;
else
fprintf('goodbye\n');
end
end
Even simpler would be to use global variables...but I like that idea better :)
EDIT
The point of my code is to demonstrate that we can use the handles structure of a GUI (as asked by the OP) to store the value of the flag. Since the structure is accessible from every callback pressing the pushbutton will update it the same way a persistent variable would.
Please try this code to see what I mean:
function TestGUI
clear
clc
hFigure = figure('Position',[200 200 200 150]);
handles.Disp_a_title = uicontrol('Style','text','String','a','Position',[20 100 60 20]);
handles.Disp_aflag = uicontrol('Style','text','String','0','Position',[100 100 60 20]);
handles.Button = uicontrol('Style','Push','Position',[50 50 60 20],'String','Update a','Callback',#(s,e) PushCb);
a = 0;
handles.a_flag = false;
guidata(hFigure,handles)
function PushCb(~,~)
handles = guidata(hFigure);
fprintf('Flag is %i\n',handles.a_flag)
if handles.a_flag == false;
disp('hello\n');
a = 1;
handles.a_flag = true;
else
disp('goodbye\n');
end
guidata(hFigure,handles)
end
end
Pressing the button twice results in the following output in the Command Window:
Flag is 0
hello\n
Flag is 1
goodbye\n
Which from what I understood is the expected behaviour the OP is looking for.

Pass function as argument to function

So I have these two made up .m files. This is an example of the problem I'm having and the math is pseudo-math
rectangle.m:
function [vol, surfArea] = rectangle(side1, side2, side3)
vol = ...;
surfArea = ...;
end
ratio.m:
function r = ratio(f,constant)
% r should return a scaled value of the volume to surface area ratio
% based on the constant provided.
% This line doesn't work but shows what I'm intending to do.
[vol,surfArea] = f
r = constant*vol*surfArea;
end
What I'm unsure how to do is pass the rectangle function as f and then access vol and surfArea from within the ratio function. I've read and the Mathworks page on function handles and function functions and have come up empty handed on figuring out how to do this. I'm new to MATLAB so that doesn't help either.
Let me know if you need anymore info.
Thanks!
The correct way of passing the function rectangle as and argument of ratio is
r = ratio( #recangle, constant )
You can then call [vol,surfArea] = f(s1,s2,s3) from within ratio, but it requires the sideX arguments to be known.
If ratio should not require to know these arguments, then you could create an object function and pass this as a reference argument. Or better, you could create a rectangle class altogether:
classdef Rectangle < handle
properties
side1, side2, side3;
end
methods
% Constructor
function self = Rectangle(s1,s2,s3)
if nargin == 3
self.set_sides(s1,s2,s3);
end
end
% Set sides in one call
function set_sides(self,s1,s2,s3)
self.side1 = s1;
self.side2 = s2;
self.side3 = s3;
end
function v = volume(self)
% compute volume
end
function s = surface_area(self)
% compute surface area
end
function r = ratio(self)
r = self.volume() / self.surface_area();
end
function r = scaled_ratio(self,constant)
r = constant * self.ratio();
end
end
end
While I didn't bring this up in my question above, this is what I was searching for.
So what I wanted to do was pass some of rectangles arguments to ratio while being able to manipulate any chosen number of rectangles arguments from within the ratio function. Given my .m files that above, a third .m would look something like this. This solution ended up using MATLAB's anonymous functions.
CalcRatio.m:
function cr = calcRatio(length)
% Calculates different volume to surface area ratios given
% given different lengths of side2 of the rectangle.
cr = ratio(#(x) rectangle(4,x,7); %<-- allows the 2nd argument to be
% manipulated by ratio function
end
ratio.m:
function r = ratio(f,constant)
% r should return a scaled value of the volume to surface area ratio
% based on the constant provided.
% Uses constant as length for side2 -
% again, math doesnt make any sense, just showing what I wanted to do.
[vol,surfArea] = f(constant);
r = constant*vol*surfArea;
end