How to fill the area under the curve in Matlab - matlab

The user gives a function, and I make the graphic in an axis with syms(x) and ezplot(funcion). And in another case, the user gives the function and the interval for x. In the second example, I use plot() instead of ezplot(). Here are my codes=
syms x;
funcion=eval(get(handles.txtFuncion, 'String'));
ezplot(funcion);
The second code is this:
a=eval(get(handles.txtA, 'String'));
b=eval(get(handles.txtB, 'String'));
x=a:b;
funcion=eval(get(handles.txtFuncion, 'String'));
plot(x,funcion);

I don't have the symbolic math toolbox so I can only address the second code.
Given the sample data provided:
a = -10;
b = 10;
x = a:b;
h.areaplot = area(x, eval('x.^2'));
Produces:
Edit: Alternatively you can modify your function input syntax to work without needing eval:
a = str2double(get(handles.txtA, 'String'));
b = str2double(get(handles.txtB, 'String'));
x = a:b;
funcion = str2func(get(handles.txtFuncion, 'String'));
h.areaplot = area(x, funcion(x));
Where your text inputs now take the form '#(x) x.^2'

Related

Function handle as input to the function handle

Is it possible in Matlab to create function handle that will take as input another function handle and how?
e.g. I have h = #(x) x^2
I want to have h as parameter and get as output function that 4*x^2
function alpha = fun(h, type)
x= sym('x',[8,1]);
gamma = 16;
alpha_ = gamma*h(x);
alpha = matlabFunction(alpha_, 'vars', {x});
end
Is it possible to create something like that? I want to avoid creating alphas for multiple function handles.

How to force MATLAB function area to hold on in figure

I'm working on this function which gets axis handler and data, and is supposed to plot it correctly in the axis. The function is called in for loop. It's supposed to draw the multiple data in one figure. My resulted figure is shown below.
There are only two correctly plotted graphs (those with four colors). Others miss areas plotted before the final area (red area is the last plotted area in each graph). But the script is same for every axis. So where can be the mistake? The whole function is written below.
function [] = powerSpectrumSmooth(axis,signal,fs)
N= length(signal);
samplesPer1Hz = N/fs;
delta = int16(3.5*samplesPer1Hz); %last sample of delta frequncies
theta = int16(7.5*samplesPer1Hz); %last sample of theta frequncies
alpha = int16(13*samplesPer1Hz); %last sample of alpha frequncies
beta = int16(30*samplesPer1Hz); %last sample of beta frequncies
x=fft(double(signal));
powerSpectrum = 20*log10(abs(real(x)));
smoothPS=smooth(powerSpectrum,51);
PSmin=min(powerSpectrum(1:beta));
y1=[(smoothPS(1:delta)); zeros(beta-delta,1)+PSmin];
y2=[zeros(delta-1,1)+PSmin; (smoothPS(delta:theta)); zeros(beta-theta,1)+PSmin];
y3=[zeros(theta-1,1)+PSmin; (smoothPS(theta:alpha)); zeros(beta-alpha,1)+PSmin];
y4=[zeros(alpha-1,1)+PSmin; (smoothPS(alpha:beta))];
a1=area(axis,1:beta,y1);
set(a1,'FaceColor','yellow')
hold on
a2=area(axis,1:beta,y2);
set(a2,'FaceColor','blue')
a3=area(axis,1:beta,y3);
set(a3,'FaceColor','green')
a4=area(axis,1:beta,y4);
set(a4,'FaceColor','red')
ADDED
And here is the function which calls the function above.
function [] = drawPowerSpectrum(axesContainer,dataContainer,fs)
size = length(axesContainer);
for l=1:size
powerSpectrumSmooth(axesContainer{l},dataContainer{l},fs)
set(axesContainer{l},'XTickLabel','')
set(axesContainer{l},'YTickLabel','')
uistack(axesContainer{l}, 'top');
end
ADDED 29th July
Here is a script which reproduces the error, so you can run it in your computer. Before running it again you might need to clear variables.
len = 9;
axesContainer = cell(len,1);
x = [0.1,0.4,0.7,0.1,0.4,0.7,0.1,0.4,0.7];
y = [0.1,0.1,0.1,0.4,0.4,0.4,0.7,0.7,0.7];
figure(1)
for i=1:len
axesContainer{i} = axes('Position',[x(i),y(i),0.2,0.2]);
end
dataContainer = cell(len,1);
N = 1500;
for i=1:len
dataContainer{i} = rand(1,N)*100;
end
for l=1:len
y1=[(dataContainer{l}(1:N/4)) zeros(1,3*N/4)];
y2=[zeros(1,N/4) (dataContainer{l}(N/4+1:(2*N/4))) zeros(1,2*N/4)];
y3=[zeros(1,2*N/4) (dataContainer{l}(2*N/4+1:3*N/4)) zeros(1,N/4)];
y4=[zeros(1,3*N/4) (dataContainer{l}(3*N/4+1:N))];
axes=axesContainer{l};
a1=area(axes,1:N,y1);
set(a1,'FaceColor','yellow')
hold on
a2=area(axes,1:N,y2);
set(a2,'FaceColor','blue')
hold on
a3=area(axes,1:N,y3);
set(a3,'FaceColor','green')
hold on
a4=area(axes,1:N,y4);
set(a4,'FaceColor','red')
set(axes,'XTickLabel','')
set(axes,'YTickLabel','')
end
My result of this script is plotted below:
Again only one picture contains all areas.
It looks like that every call to plot(axes,data) deletes whatever was written in axes.
Important note: Do not use a variable name the same as a function. Do not call something sin ,plot or axes!! I changed it to axs.
To solve the problem I just used the classic subplot instead of creating the axes as you did:
len = 9;
axesContainer = cell(len,1);
x = [0.1,0.4,0.7,0.1,0.4,0.7,0.1,0.4,0.7];
y = [0.1,0.1,0.1,0.4,0.4,0.4,0.7,0.7,0.7];
figure(1)
dataContainer = cell(len,1);
N = 1500;
for i=1:len
dataContainer{i} = rand(1,N)*100;
end
for l=1:len
y1=[(dataContainer{l}(1:N/4)) zeros(1,3*N/4)];
y2=[zeros(1,N/4) (dataContainer{l}(N/4+1:(2*N/4))) zeros(1,2*N/4)];
y3=[zeros(1,2*N/4) (dataContainer{l}(2*N/4+1:3*N/4)) zeros(1,N/4)];
y4=[zeros(1,3*N/4) (dataContainer{l}(3*N/4+1:N))];
axs=subplot(3,3,l);
a1=area(axs,1:N,y1);
set(a1,'FaceColor','yellow')
hold on
a2=area(axs,1:N,y2);
set(a2,'FaceColor','blue')
hold on
a3=area(axs,1:N,y3);
set(a3,'FaceColor','green')
hold on
a4=area(axs,1:N,y4);
set(a4,'FaceColor','red')
set(axs,'XTickLabel','')
set(axs,'YTickLabel','')
axis tight % this is to beautify it.
end
As far as I know, you can still save the axs variable in an axescontainer and then modify the properties you want (like location).
I found out how to do what I needed.
len = 8;
axesContainer = cell(len,1);
x = [0.1,0.4,0.7,0.1,0.4,0.7,0.1,0.4];
y = [0.1,0.1,0.1,0.4,0.4,0.4,0.7,0.7];
figure(1)
for i=1:len
axesContainer{i} = axes('Position',[x(i),y(i),0.2,0.2]);
end
dataContainer = cell(len,1);
N = 1500;
for i=1:len
dataContainer{i} = rand(1,N)*100;
end
for l=1:len
y1=[(dataContainer{l}(1:N/4)) zeros(1,3*N/4)];
y2=[zeros(1,N/4) (dataContainer{l}(N/4+1:(2*N/4))) zeros(1,2*N/4)];
y3=[zeros(1,2*N/4) (dataContainer{l}(2*N/4+1:3*N/4)) zeros(1,N/4)];
y4=[zeros(1,3*N/4) (dataContainer{l}(3*N/4+1:N))];
axes=axesContainer{l};
Y=[y1',y2',y3',y4'];
a=area(axes,Y);
set(axes,'XTickLabel','')
set(axes,'YTickLabel','')
end
The area is supposed to work with matrices like this. The tricky part is, that the signal in every next column is not plotted absolutely, but relatively to the data in previous column. That means, if at time 1 the data in first column has value 1 and data in second column has value 4, the second column data is ploted at value 5. Source: http://www.mathworks.com/help/matlab/ref/area.html

plotting a graph by calling a function

M = round(csvread('noob.csv'))
save projectDAT.dat M -ascii
load projectDAT.dat
mat = (projectDAT)
sum_of_rows(mat)
plotthegraph
This is my main script. I have a excel file, which opens up a 20 x 20 matrix in matlab. Now I have to call a function in this mainscript, which would find the sum of elements in a row for me and put them in a column vector. Here is my function:
function sumRow = sum_of_rows(mat)
[m n] = size(mat);
sumRow = zeros(m,1);
for i = 1:m;
for j = 1:n;
sumRow(i) = sumRow(i) + mat(i,j);
end
end
vec = sumRow;
end
I am required to plot a line graph using this column vector. I am supposed to call a function from the mainscript. The function should be able to take the input from this sum_of_rows function. I tried doing this:
function plotthegraph(~)
% Application for plotting the height of students
choice = menu('Choose the type of graph', 'Plot the data using a line plot', 'Plot the data using a bar plot');
if choice == 1
plot_line(sum_of_rows)
y = sum_of_rows
x = 1:length(y)
plot(x,y)
title('Bar graph')
xlabel('Number of characters')
ylabel('Number of grades')
elseif choice == 2
plot_bar(sum_of_columns)
end
Its not working out though. Can someone please help me out, I would really appreciate it. Thank you.
You could do the following to get rid of the sum_of_rows function:
sumRow = sum(mat,2);
The second argument tells the sum to add all the columns in the matrix rowwise, giving you the sum of each row in mat.
To plot this vector you need to pass it as input to your function. Also matlab takes care of the x values for you if you do not specify variable along, doing exactly what you did manually while defining x. Your function would look like this:
function plotthegraph(sum_of_rows)
% Application for plotting the height of students
prompt='Type 1 for line plot, 2 for bar';
choice=input(prompt)
if choice == 1
plot(sum_of_rows)
title('Line graph')
xlabel('Number of characters')
ylabel('Number of grades')
elseif choice == 2
bar(sum_of_rows)
end
end
So you'd have to call this function passing the sum of rows:
plotthegraph(sumRow)

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

Use MATLAB's 'keyPressFcn' in a simple program

I am trying to use the 'KeyPressFcn' in a normal MATLAB script, but I am having problems. I can use it nicely WITHIN a function, (like here), but I would like to use it in a normal script like so.
My simple script is:
%Entry Point
clear all
N = 100;
x = randn(1,N);
figHandle = figure(1);
clf(figHandle);
set(figHandle, 'KeyPressFcn', myFunction(~, eventDat,x,N))
Here is the function 'myFunction' that sits in the same directory:
function myFunction(~, eventDat,x,N)
mean = sum(x)/N;
disp(mean);
key = eventDat.Key;
disp(key);
end
Now, if I run this, it does not work, because, (I suspect), something is wrong with the way I am calling myFunction, but I cannot figure out what the problem is exactly, since I am a noob at using KeyPressFcn. Help would be appreciated for this problem. Thanks!
You need to do it through anonymous functions:
In script file, for example called test.m:
%Entry Point
clear all
N = 100;
x = randn(1,N);
figHandle = figure(1);
clf(figHandle);
set(figHandle, 'KeyPressFcn', ...
#(fig_obj , eventDat) myFunction(fig_obj, eventDat, x, N));
In a file called myFunction.m in the same folder as test.m
function myFunction(~, eventDat, x, N)
mean = sum(x)/N;
disp(mean);
key = eventDat.Key;
disp(key);
How to return value from myFunction?
There are few ways of doing this. It depends on what u want to do. But quickly you could use mutable variables for this, such as, containers.Map. This is one example of ding this. The returned variable is newN.
In script file, for example called test.m:
%Entry Point
clear all
N = 100;
x = randn(1,N);
% this map will store everything u want to return from myFunction.
returnMap = containers.Map;
figHandle = figure(1);
clf(figHandle);
set(figHandle, 'KeyPressFcn', ...
#(fig_obj , eventDat) myFunction(fig_obj, eventDat, x, N, returnMap));
% wait till gui finishes in this example.
waitfor(figHandle);
newN = returnMap('newN');
% display newN
newN
In a file called myFunction.m:
function myFunction(handle, eventDat, x, N, returnMap)
mean = sum(x)/N;
disp(mean);
key = eventDat.Key;
disp(key);
newN = 435;
returnMap('newN') = newN;