matlab append different values of the same variable on button click - matlab

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.

Related

Matlab draw line with plot and dynamic values

I am trying to draw line with plot in matlab app designer. But i dont know how to create line. I am just redrawing point on new coordinates.
This is my code (functions runs each second) (format of plot is plot(PlotUI,X,Y))
function function2(app)
app.timeCounter = app.timeCounter + 1;
plot(app.UIAxes,app.timeCounter,app.newValDblPublic);
end
I will be thankful for any help.
At the moment you are just plotting the current set of values, if you want to plot the historic values too, you need to keep them in an array and plot the entire array.
%When the GUI is first created, start with one value in the array
app.time_values = [0];
app.y_values = [0];
%Inside your function
function function2(app)
app.time_values(end+1) = app.time_values(end)+1; % Add a new value to the array, 1 greater than the last value
app.y_values(end+1) = app.newValDblPublic;
plot(app.UIAxes,app.time_values,app.y_values);
end

Plotting brownian motion matlab

First of all, I just want to say that I'm not that used to using matlab, but I need for an assignment, I'm supposed to create a "brownian movement". My code is currently looking like this:
clf
hold on
prompt = 'Ge ett input';
size = input(prompt) ;
numParticles = input('Ange antal partiklar');
axis([-size size -size size]);
Part = [];
color = 'brkgmyco';
for i = drange(1:numParticles)
Part = [Part [0;0]];
end
for i = drange(1:200)
dxdy = randn(2,numParticles);
k = Part
Part = Part + dxdy;
My concern is how to print, I would even want like a small delay on every print, so you really can see what's happening for the assignment, is this possible to achieve from the code I've written for now or should anything be changed? Thanks in advance!
Here are some basic problems with your code, regardless of what you are trying to do:
You use size as a variable name. Doing so overrides MATLAB's function size.
The function zeros creates an array initialized by zeros, no need for a loop for that.
Instead of calculating randn for 200 times in a loop, you can do it once, with dxdy = randn(2,numParticles,200) and then simply refer to dxdy(:,:,i) within the loop.
The same holds for summation. Instead of summing within a loop to get the cumulative sum, use cumsum like Part = cumsum(randn(2,numParticles,200),3); and then refer to Part(:,:,i), within the loop.
Now to your task. You said you want to know how to print, but I believe you want to plot because you use some commands like axis, clf and hold, that refer to graphic objects. However, you never really do plot anything.
The basic and general function for plotting in 2D is plot, but there are many other more specific functions. One of them is scatter, and it has a sister function gscatter, that takes triples of x, y and groupand plot each (x(k),y(k)) colored by their group(k).
This code plots the particles on an axes, and animate their movement:
prompt = 'Ge ett input';
scope = input(prompt) ;
numParticles = input('Ange antal partiklar');
N = 500;
Part = cumsum(randn(2,numParticles,N)*scope/100,3);
h = gscatter(Part(1,:,1),Part(2,:,1),1:numParticles);
axis([-scope scope -scope scope]);
legend off
for k = 2:N
for p = 1:numParticles
h(p).XData = Part(1,p,k);
h(p).YData = Part(2,p,k);
end
drawnow
end
Is this what you look for?

Looping a Function in Matlab

total newbie here. I'm having problems looping a function that I've created. I'm having some problems copying the code over but I'll give a general idea of it:
function[X]=Test(A,B,C,D)
other parts of the code
.
.
.
X = linsolve(K,L)
end
where K,L are other matrices I derived from the 4 variables A,B,C,D
The problem is whenever I execute the function Test(1,2,3,4), I can only get one answer out. I'm trying to loop this process for one variable, keep the other 3 variables constant.
For example, I want to get answers for A = 1:10, while B = 2, C = 3, D = 4
I've tried the following method and they did not work:
Function[X] = Test(A,B,C,D)
for A = 1:10
other parts of the code...
X=linsolve(K,L)
end
Whenever I keyed in the command Test(1,2,3,4), it only gave me the output of Test(10,2,3,4)
Then I read somewhere that you have to call the function from somewhere else, so I edited the Test function to be Function[X] = Test(B,C,D) and left A out where it can be assigned in another script eg:
global A
for A = 1:10
Test(A,2,3,4)
end
But this gives an error as well, as Test function requires A to be defined. As such I'm a little lost and can't seem to find any information on how can this be done. Would appreciate all the help I can get.
Cheers guys
I think this is what you're looking for:
A=1:10; B=2; C=3; D=4;
%Do pre-allocation for X according to the dimensions of your output
for iter = 1:length(A)
X(:,:,iter)= Test(A(iter),B,C,D);
end
X
where
function [X]=Test(A,B,C,D)
%other parts of the code
X = linsolve(K,L)
end
Try this:
function X = Test(A,B,C,D)
% allocate output (it is faster than changing the size in every loop)
X = {};
% loop for each position in A
for i = 1:numel(A);
%in the other parts you have to use A(i) instead of just A
... other parts of code
%overwrite the value in X at position i
X{i} = linsolve(K,L);
end
end
and run it with Test(1:10,2,3,4)
To answer what went wrong before:
When you loop with 'for A=1:10' you overwrite the A that was passed to the function (so the function will ignore the A that you passed it) and in each loop you overwrite the X calculated in the previous loop (that is why you can only see the answer for A=10).
The second try should work if you have created a file named Test.m with the function X = (A,B,C,D) as the first code in the file. Although the global assignment is unnecessary. In fact I would strongly recommend you not to use global variables as it gets very messy very fast.

Run the for loop only once Matlab

total_Route = zeros(4,4);
tmp = evalin('base', 't'); % i initialise t in the Workspace with the value 1
if(tmp==5)
tmp=1;
end
total_Route(tmp,1) = Distance_Traveled_CM;
total_Route(tmp,2) = Hauptantrieb_Verbrauchte_Energie_CM;
total_Route(tmp,3) = Nebenaggregate_Verbrauch_Real_CM;
total_Route(tmp,4) = t;
Total_Distance_Traveled_CM = sum(total_Route(:,1));
set(handles.edit3, 'string',Total_Distance_Traveled_CM);
Total_Hauptantrieb_Verbrauchte_Energie_CM = sum(total_Route(:,2));
set(handles.edit4, 'string',Total_Hauptantrieb_Verbrauchte_Energie_CM);
Total_Nebenaggregate_Verbrauch_Real_CM = sum(total_Route(:,3));
set(handles.edit5, 'string',Total_Nebenaggregate_Verbrauch_Real_CM);
%% Index
set(handles.edit15, 'string',tmp);
assignin('base', 't', tmp + 1); % with this line i can increment "t" after each pass
guidata(hObject,handles);
Sorry that I did not explain my problem well.
#Sardar_Usama I want to run the loop only once but t should be incremented after each time I click on my Button.
# Sembei Norimaki end is at the end of my codes, have forgotten to write it in my question
#Patrik & #Dennis Jaheruddin let me explain my problem again
I created a Matrix with 4×4 Elements with the Goal to save the results of each my Variable (Total_Distance_Traveled_CM, Total_Hauptantrieb_Verbrauchte_Energie_CM etc...) after each Simulation in the element of my Matrix (See image below).
I want by pressing a button (on my GUI) to get always the sum of each Column.
Example
The first pass: t = 1--> Distance_Traveled(1,1) is 900 the GUI will take through clicking on the Button, the sum of the first column (which is 900+0+0+0) and write it in a static test.
The second pass t = 2--> Distance_traveled(2,1) is 800 the GUI will take the sum of the first column (which is 900+800+0+0) and write it in a static test and the same thing should happen with the other column.
This should continue until t = 4 i.e. until it does the same thing for each column, then it should reset.
I hope, I have explained my problem better this time and I apologize for my bad English.
I appreciate any help.
Based on your code fragment the for loop is only called once.
However, the contents of the for loop are ran for four times. (first for i=1 then for 1=2 etc..)
If you only want to run one of these options the solution is very simple:
i = 1
yourLoopContent
If i is always 0 the first time, and you always want to run it for the current i, it would also be simple:
yourLoopContent
i = i+1;
However if i may not be set properly the first time, things get messy. This is because i is by default defined as the square root of minus 1.
Therefore I would recommend you to use a different letter like t instead. Then you could do this:
if ~exists(t)
t=0;
end
yourLoopContent %Everywhere using t instead of i
t = t+1;
In general you may want to avoid i as an index to stay clear of complex number issues.
I'm not sure if I got your question correctly, but it seems to me that what you look for is a cumulative sum. This can be done either buy summing on 1:t or by using cumsum. I'm not sure why you use a loop, but if this is only for the summing then cumsum can replace that.
Here is some example in your code:
total_Route = zeros(4,4);
% I commented below what is not part of the question
for t = 1:4
total_Route(t,:) = [Distance_Traveled_CM,
Hauptantrieb_Verbrauchte_Energie_CM,
Nebenaggregate_Verbrauch_Real_CM,
t];
% the following line compute the comulative sum from the top of each
% column to every element in it, so cs_total_Route(3,2) is like
% sum(total_Route(1:3,2)):
cs_total_Route = cumsum(total_Route);
Total_Distance_Traveled_CM = cs_total_Route(t,1); % OR sum(total_Route(1:t,1))
% set(handles.edit3, 'string',Total_Distance_Traveled_CM);
Total_Hauptantrieb_Verbrauchte_Energie_CM = cs_total_Route(t,2); % OR sum(total_Route(1:t,2))
% set(handles.edit4, 'string',Total_Hauptantrieb_Verbrauchte_Energie_CM);
Total_Nebenaggregate_Verbrauch_Real_CM = cs_total_Route(t,3); % OR sum(total_Route(1:t,3))
% set(handles.edit5, 'string',Total_Nebenaggregate_Verbrauch_Real_CM);
% set(handles.edit15, 'string',t);
end
And here is a quick look on what cumsum does (with some random numbers for total_Route):
total_Route =
671 4.6012 1.0662 1
840 3.6475 0.58918 2
354 8.6056 2.1313 3
893 4.1362 2.0118 4
cs_total_Route =
671 4.6012 1.0662 1
1511 8.2487 1.6554 3
1865 16.854 3.7867 6
2758 20.991 5.7985 10
Is this what you looked for?

Customizing cursor in Matlab

In Matlab 2012a I have generated a figure from a previous code that is SSI as a function of age.
I want to customize datatip by updating my own function instead of the default one. I know how to change x and y and now I have Age and SSI for them. However, I have another piece of information -subjectID- which I want to add to the display text.
By clicking on each point, I want datatip to show Age, SSI and subject ID of corresponding data point.
This is what I have now:
matlab is a saved work place of my SSI-age.
function output_txt = myupdatefcn(obj,event_obj,...
matlab,labels,SubjectID)
pos = get(event_obj,'Position');
x = pos(1);
y = pos(2);
[~, ~, raw0_0] = xlsread('Data.xlsx','CONTROLS','A2:A106');
raw = [raw0_0];
SubjectID = cell2mat(raw);
output_txt = {['AGE: ',num2str(pos(1),4)],...
['SSI: ',num2str(pos(2),4)],...
['SubjectID: ',SubjectID]};
idx = find(matlab == x,1);
[row,col] = ind2sub(size(matlab),idx);
output_txt{end+1} = cell2mat(labels(row));
Obviously, this is not right. Can somebody please help me out here? Thank you.
If I read your code correctly, I make the following assumptions (which may be incorrect):
* the subjectID is a cell containing a vector of strings
* subjectID is X position of the clicked point
First, a quick digression: getting SubjectID into your plot
I noticed, in your function call, you have SubjectID as one of the input parameters. However, it appears that it would never be used, since the next line that uses it assigns it a value.
As written, this will read from the excel file each and every time that the update function is called. You might wish to move the load-from-excel portion into the same section of code where the data is first loaded. If I assume the SubjectID is text, you can store it in the UserData variable of the timeseries. That would make the following work:
Onward to the answer
So, if you include your SubjectID information in the userdata, when you first plot like so:
% ...not shown: get the ages, SSIs and SubjectIDs ....
plot(ages, SSIs, 'UserData', SubjectIDs); % Store SubjectIDs along with the line...
Then the following should work -- or at least put you on solid ground.
function output_txt = myupdatefcn(obj,event_obj)
pos = get(event_obj,'Position');
x = pos(1);
y = pos(2);
allIDs = get(event_obj.Target,'UserData');
thisSubject = event_obj.UserData{pos(1)};
output_txt = {['AGE: ',num2str(pos(1),4)],...
['SSI: ',num2str(pos(2),4)],...
['SubjectID: ',thisSubject]};
You can probably get rid of the last 3 lines of code, since you know a priori that all 3 values are accessible.
Hope that helps.