Area between line and curve (no function) - matlab

I want to calculate the area beween the orange and the blue line. I managed to shade the area. But I do not know how to apply the trapz function in order to get the area. In this post: Area under surface between two curves I got some solutions but I do not have a specific equation for the curves just the plots per se.
The code for the orange line is:
x_1 = [0,M1_1];
y_1 = [c1,c1];
v = plot(x_1,y_1,'LineWidth',2)
The blue curve is a plot of arrays with the length of (10000x1)-abscissa and (1x10000)-ordinate.
If I use
%c0_1: Intersection blue curve with y-axis
%c1_1: Intersection orange curve with y-axis
A = trapz(ab1(0:c1_1),ab_y1(c1_1:c0_1))
I get the following error:
Warning: Integer operands are required for colon operator when used as
index Warning: Integer operands are required for colon operator when
used as index Error using trapz (line 58) LENGTH(X) must equal the
length of Y in dim 2.
How can I apply my trapz function easily on my problem?

Here is an answer, although I'm not sure what is the difference between the situation here and here, and therefore I'm not sure it truelly answers your question...
Anyway, you don't need to know y1 function explicitly, just to have its' series of data.
x = 0:0.1:12; % x data
y1 = 3*exp(-0.5*x); % y data
y2 = 0.5;
lineStart = find(x>=0,1);
lineEnd = find(y1<=y2,1);
f = plot(x,y1,'b',x,ones(1,length(x))*y2,'r','LineWidth',2);
ylim([0 4])
hold on
area(x(lineStart:lineEnd),y1(lineStart:lineEnd), y2,...
'EdgeColor', 'none', 'FaceColor', [0.5 0.5 1],'ShowBaseLine','off')
hold off
A = trapz(x(lineStart:lineEnd),y1(lineStart:lineEnd));
I added also the illustration of the integrated area:
Tell me is that solves the problem ;)

Related

How to plot my differential equation with quiver?

I want to solve my differential equation and plot velocity vectors but I am having some trouble with that. I tried this:
syms y(x);
ode = (1+exp(x))*y*diff(y,x)-2*exp(x) == 0;
ySol = dsolve(ode)
[X,Y] = meshgrid(-2:.2:2);
Z = 2*exp(X)/((1+exp(X)).*Y);
[DX,DY] = gradient(Z,.2,.2);
figure
contour(X,Y,Z)
hold on
quiver(X,Y,DX,DY)
hold off
and I get this error:
Warning: Matrix is singular to working precision.
Warning: Contour not rendered for non-finite ZData
It is probably something simple that I do not see but I am just starting using Matlab and I cold not find a right way to do my task. Please help me...
EDIT
As bconrad suggested, I changed my Z function like this:
Z = 2*exp(X)/((1+exp(X)).*Y);
and the previous errors are fixed. However, my prime goal, to plot velocity vectors is not accomplished yet because I get a graph like this:
Don’t have the ability to check at the moment, but I reckon you want an element by element division in that line. You’re missing a dot on the division, try
Z = 2*exp(X)./((1+exp(X)).*Y);
I took a closer look once at my station. The zero-division mentioned by Pablo forces inf's in Z, so quiver get's confused when scaling the vectors (understandably) and just doesn't show them. Try this (with the ode part removed):
[X,Y] = meshgrid(-2 : .2 : 2);
Z = 2 * exp(X) ./ ((1 + exp(X)) .* Y);
Z(isinf(Z)) = nan; % To avoid 0-division problems
[DX, DY] = gradient(Z, .2, .2);
figure
contour(X, Y, Z, 30, 'k')
hold on
quiver(X, Y, DX, DY, 6)
hold off
I've done 3 things here:
Added the line Z(isinf(Z)) = nan; forcing infinite values to be essentially ignored by quiver
Added the arguments 30, 'k' to the contour function to show 30 lines, and make them black (a bit more visible)
Added the argument 6 to the quiver function. This overrides the automatic length-scaling of the vectors.
You'll want to play with the arguments in the contour and quiver functions to make your figure appear as you'd like.
PS: There is a handy arrow function on the file exchange that I find gives better control when creating vector field plots. See https://www.mathworks.com/matlabcentral/fileexchange/278-arrow - the ratings do it justice.

How to find the intersection of two ellipses in MATLAB

I have two equations:
ellipseOne = '((x-1)^2)/6^2 + y^2/3^2 = 1';
and
ellipseTwo = '((x+2)^2)/2^2 + ((y-5)^2)/4^2 = 1';
and I plotted them:
ezplot(ellipseOne, [-10, 10, -10, 10])
hold on
ezplot(ellipseTwo, [-10, 10, -10, 10])
title('Ellipses')
hold off
Now I'm trying to find the intersection of the two ellipses. I tried:
intersection = solve(ellipseOne, ellipseTwo)
intersection.x
intersection.y
to find the points where they intersect, but MATLAB is giving me a matrix and an equation as an answer which I don't understand. Could anyone point me in the right direction to get the coordinates of intersection?
The solution is in symbolic form. The last step you need to take is to transform it into numeric. Simply convert the result using double. However, because this is a pair of quadratic equations, there are 4 possible solutions due to the sign ambiguity (i.e. +/-) and can possibly give imaginary roots. Therefore, isolate out the real solutions and what is left should be your answer.
Therefore:
% Your code
ellipseOne = '((x-1)^2)/6^2 + y^2/3^2 = 1';
ellipseTwo = '((x+2)^2)/2^2 + ((y-5)^2)/4^2 = 1';
intersection = solve(ellipseOne, ellipseTwo);
% Find the points of intersection
X = double(intersection.x);
Y = double(intersection.y);
mask = ~any(imag(X), 2) | ~any(imag(Y), 2);
X = X(mask); Y = Y(mask);
The first three lines of code are what you did. The next four lines extract out the roots in numeric form, then I create a logical mask that isolates out only the points that are real. This looks at the imaginary portion of both the X and Y coordinate of all of the roots and if there is such a component for any of the roots, we want to eliminate those. We finally remove the roots that are imaginary and we should be left with two real roots.
We thus get for our intersection points:
>> disp([X Y])
-3.3574 2.0623
-0.2886 2.9300
The first column is the X coordinate and the second column is the Y coordinate. This also seems to agree with the plot. I'll take your ellipse plotting code and also insert the intersection points as blue dots using the above solution:
ezplot(ellipseOne, [-10, 10, -10, 10])
hold on
ezplot(ellipseTwo, [-10, 10, -10, 10])
% New - place intersection points
plot(X, Y, 'b.');
title('Ellipses');
hold off;

How do you rescale the height of a histogram?

I am having trouble plotting a histogram of the x-values of my data points together with a line showing the relationship between x and y, mainly because the scale in the y direction of the histogram is not of the same magnitude as the scale in the line plot. For example:
% generate data
rng(1, 'twister')
x = randn(10000,1);
y = x.^2
% plot line, histogram, then histogram and line.
subplot(3,1,1)
scatter(x, y, 1, 'filled')
ax = gca;
maxlim = max(ax.XLim); % store maximum y-value to rescale histogram to this value
subplot(3,1,2)
h = histogram(x, 'FaceAlpha', 0.2)
subplot(3,1,3)
scatter(x, y, 1, 'filled')
hold on
h = histogram(x, 'FaceAlpha', 0.2)
Produces the following:
where the line chart is completely obscured by the histogram.
Now, one might naively try to rescale the histogram using:
h.Values = h.Values/max(h.Values) * maxlim;
which gives
You cannot set the read-only property 'Values' of Histogram.
Alternatively one can get the bin counts using histcounts, but as far as I can tell, the bar function does not allow one to set the face alpha or have other configurability as per the call to histogram.
As discussed in the comments there are several solutions that depend on the version of Matlab you are using. To restate the problem, the histogram function allows you to control many graphics properties like transparency, but only gives you a limited number of options to change the height of the bars. With histcounts you can get the bar heights and rescale them however you want, but you must plot the bars yourself.
First option: use histogram
As you cannot rescale the histogram heights, you must plot them on separate axis.
From release 2016a and onwards, you can use yyaxis left for the scatter plot and yyaxis right for the histogram, see Matlab documentation:
Prior to this one must manually create and set separate y-axis. Although I have not found a good simple example of this, this is perhaps the most relevant answer here: plot two histograms (using the same y-axis) and a line plot (using a different y-axis) on the same figure
Using histcounts and manually creating a bar chart
Using my example, we can get counts as follows:
[Values, Edges] = histcounts(x);
And rescaling:
Values = Values / max(Values) * maxlim;
and finding centres of bars:
bar_centres = 0.5*(Edges(1:end-1) + Edges(2:end));
Up to release 2014a, bar charts had a 'children' property for the patches that allows transparency to be controlled, e.g.:
% plot histogram
b1 = bar(bar_centres,Values);
% change transparency
set(get(b1,'Children'),'FaceAlpha',0.3)
After 2014a bar charts no longer have this property, and to get around it I plot the patches myself using the code from this mathworks q&a, replicated here:
function ptchs = createPatches(x,y,offset,c,FaceAlpha)
%createPatches.m
% This file will create a bar plot with the option for changing the
% FaceAlpha property. It is meant to be able to recreate the functionality
% of bar plots in versions prior to 2014b. It will create the rectangular
% patches with a base centered at the locations in x with a bar width of
% 2*offset and a height of y.
% Ensure x and y are numeric vectors
validateattributes(x,{'numeric'},{'vector'});
validateattributes(y,{'numeric'},{'vector'});
validateattributes(c,{'char'},{'scalar'});
%#TODO Allow use of vector c
% Check size(x) is same as size(y)
assert(all(size(x) == size(y)),'x and y must be same size');
% Default FaceAlpha = 1
if nargin < 5
FaceAlpha = 1;
end
if FaceAlpha > 1 || FaceAlpha <= 0
warning('FaceAlpha has been set to 1, valid range is (0,1]');
FaceAlpha = 1;
end
ptchs = cell(size(x)); % For storing the patch objects
for k = 1:length(x)
leftX = x(k) - offset; % Left Boundary of x
rightX = x(k) + offset; % Right Boundary of x
ptchs{k} = patch([leftX rightX rightX leftX],...
[0 0 y(k) y(k)],c,'FaceAlpha',FaceAlpha, ...
'EdgeColor', 'none');
end
end
I made one change: that is, imposed the no edge condition. Then, it is perfectly fine to use:
createPatches(bin_centres, Values, 1,'k', 0.2)
to create the bars.

Plot gradient in matlab and nothing but blank appears

I'm trying to plot the gradient of the real part of a complex function, however what I get is a blank figure. I do not understand what I am doing wrong since the code works with other functions (such as the imaginary part)
% Set up
x = -3:0.2:3;
y1 = (-3:0.2:3);
y = (-3:0.2:3)*1i;
[X, Y]= meshgrid(x,y);
% Complex variable s
s = X + Y;
% Complex function f(z)
z = s + 1./s;
figure
subplot(1,2,1);
[Dx, Dy] = gradient(real(z),.2,.5);
quiver(x,y1,Dx,Dy)
title('u(x,y) gradient, vector field');
%%Imaginary part
subplot(1,2,2)
contour(x,y1,imag(z),linspace(-10,10,100)); title('Contour of Im(f)');
xlabel('x'); ylabel('y'); %clabel(C3);
title('Imaginary part');
Here below is the image I get
I tried to rescale and resize the picture, the domain etc... but couldn't get the gradient to display (the arrows). What am I doing wrong here?
EDIT:
I found out it displays blank perhaps because there are some Inf and -Inf values in the Dy and Dx variables, is there an option to ignore these values or set them to 0?
It looks to me like it works, but the line width of your arrows is too small for you to see.
You can increase it by assigning a handle to the quiver plot like so:
hQuiver = quiver(x,y1,Dx,Dy);
And then, after the plot is created, change any of its many properties like so:
set(hQuiver,'LineWidth',4)
or do it all in the call to quiver:
hQuiver = quiver(x,y1,Dx,Dy,'LineWidth',4);
In this case it gives the following:
EDIT:
To answer your secondary question, you can set elements that are equal to +Inf or -Inf to any value you want using isinf:
Dx(isinf(Dx)) = 0;
and
Dy(isinf(Dy)) = 0;
It is not blank. You've plotted the quiver diagram (usually used in optical flow diagrams). It is giving an inward pointing arrow at each of the locations formed by the grid with points in x and y1.

Matlab partial area under the curve

I want to plot the area above and below a particular value in x axis.
The problem i am facing is with discrete values. The code below for instance has an explicit X=10 so i have written it in such a way that i can find the index and calculate the values above and below that particular value but if i want to find the area under the curve above and below 4 this program will now work.
Though in the plot matlab does a spline fitting(or some sort of fitting for connecting discrete values) there is a value for y corresponding to x=4 that matlab computes i cant seem to store or access it.
%Example for Area under the curve and partial area under the curve using Trapezoidal rule of integration
clc;
close all;
clear all;
x=[0,5,10,15,20];% domain
y=[0,25,50,25,0];% Values
LP=log2(y);
plot(x,y);
full = trapz(x,y);% plot of the total area
I=find(x==10);% in our case will be the distance value up to which we want
half = trapz(x(1:I),y(1:I));%Plot of the partial area
How can we find the area under the curve for a value of ie x = 2 or 3 or 4 or 6 or 7 or ...
This is an elaboration of patrik's comment, "first interpolate and then integrate".
For the purpose of this answer I'll assume that the area in question is the area that can be seen in the plot, and since plot connects points by straight lines I assume that linear interpolation is adequate. Moreover, since the trapezoidal rule itself is based on linear interpolation, we only need interpolated values at the beginning and end of the interval.
Starting from the given points
x = [0, 5, 10, 15, 20];
y = [0, 25, 50, 25, 0];
and the integration interval limits, say
xa = 4;
xb = 20;
we first select the data points within the limits
ind = (x > xa) & (x < xb);
xw = x(ind);
yw = y(ind);
and then complete them by interpolation values at the edges:
ya = interp1(x, y, xa);
yb = interp1(x, y, xb);
xw = [xa, xw, xb];
yw = [ya, yw, yb];
Now we can simply apply trapezoidal integration:
area = trapz(xw, yw);
I think that you either need more samples, or to interpolate the data. Another alternative is to use a function handle. Then you need to know the function though. Example using linear interpolation follows.
x0 = [0;5;10;15;20];
y0 = [0,25,50,25,0];
x1 = 0:20;
y1 = interp1(x0,y0,x1,'linear');
xMax = 4;
partInt = trapz(x1(x1<=xMax),y1(x1<=xMax));
Some other kind of interpolation may be suitable, but that is hard to say without more information. Also, this interpolates from the beginning to x. However, I guess figuring out how to change the limits should be easy from here. This solution is different than the former, since it is less depending on the pyramid shape of the data. So to say, it is more general.