Shade and calculate specific area - matlab

I tried to change the code in a way so that only the first area is shaded grey. How can I set the horizontal line in a way that it only appears under the area I want to shade?
Furthermore I want to calculate the area of ONE region. How do I achieve that? I know it is trapz but I am not sure how to set the boundaries. Thanks!
x = 0:.01:4*pi; %// x data
y = sin(x); %// y data
level = 0.5; %// level
plot(x, y)
hold on
area(x, max(y, level), level, 'EdgeColor', 'none', 'FaceColor', [.7 .7 .7])
Curve:-

you can try also this simple option:
x = 0:.01:4*pi; %// x data
y = sin(x); %// y data
level = 0.5; %// level
lineStart = find(y>=level,1);
lineEnd = find(y(lineStart:end)<=level,1)+lineStart;
plot(x,y)
hold all
area(x(lineStart:lineEnd),y(lineStart:lineEnd),...
level,'EdgeColor', 'none', 'FaceColor', [.7 .7 .7],'ShowBaseLine','off')
line([x(lineStart),x(lineEnd)],[level level ])
hold off
without defining areas of interest a-priory:
And don't forget to hold off...
To calaulate the area:
A = trapz(x(lineStart:lineEnd),y(lineStart:lineEnd))

You can limit the range of your x axis in the area plot to the range of interest, e.g. from 0 to 4 and then calculate the resulting values of the function in this range. For the base line: you can hide it in the area command and add it manually using the line command.
x = 0:.01:4*pi; %// x data
y = sin(x); %// y data
level = 0.5; %// level
plot(x, y)
hold on
x_interest = 0:.01:4;
y_interest = sin(x_interest);
area(x_interest, max(y_interest, level), level, ...
'EdgeColor', 'none', 'FaceColor', [.7 .7 .7], ...
'ShowBaseLine', 'off');
line( [ min(x_interest) max(x_interest) ], [ level level ] )

Related

Calculate the shaded area under the curve above and below a threshold using trapz and MATLAB

Im trying to find the area of the shaded parts of the curve. Blue for above the threshold and grey for below it. In the script you can change the ratio of blue to grey by adjusting the level value. When level is set to 2 (pic 1) the areas should be equal. When level is set to 1.6 (pic 2) the blue should have greater area than the grey, etc... Any thoughts on how to find the areas under the curve below and above the threshold?
pic 1:
pic 2:
My code:
%% Example
x = 0:.01:4*pi;% x data
y = sin(x)+2;% y data
level = 2;% level
plot(x, y)
hold on
x_interest = 0:.01:x(length(y));
y_interest = sin(x_interest)+2;
xlim ([0 x(length(y))])
% Shaded area above level
area(x_interest, max(y_interest, level), level, ...
'EdgeColor', 'none', 'FaceColor', [.6 .7 .8], ...
'ShowBaseLine', 'off');
% Shaded area below level
area(x_interest, min(y_interest, level), level, ...
'EdgeColor', 'none', 'FaceColor', [.5 .5 .5], ...
'ShowBaseLine', 'off');
%%== This did not work ==%%
above = find(y_interest >= level);
below = find(y_interest <= level);
A_above = trapz(above)
A_below = trapz(below)
%% Integrate
plot(x, sin(x)+2)
fun = #(x) sin(x)+2;
integral(fun, 0, x(length(y)))
A = trapz(x,y)
In the general sense, the function trapz(x,y) (where x and y are vectors of same length) estimates the area under the curve f(x) = y. This area is sandwiched by the function f(x) and the x-axis.
For A_above, you want to estimate the area between curves f1(x_interest) = max(y_interest, level) and f2(x_interest) = level. That is same as the area under curve f1(x_interest) shifted down by level. So this can be evaluated by:
A_above = trapz(x_interest, max(y_interest, level)-level)
Similarly, for A_below:
A_below = -trapz(x_interest, min(y_interest, level)-level)

How to create three Y-axis in one graph? [duplicate]

I have 4 sets of values: y1, y2, y3, y4 and one set x. The y values are of different ranges, and I need to plot them as separate curves with separate sets of values on the y-axis.
To put it simple, I need 3 y-axes with different values (scales) for plotting on the same figure.
Any help appreciated, or tips on where to look.
This is a great chance to introduce you to the File Exchange. Though the organization of late has suffered from some very unfortunately interface design choices, it is still a great resource for pre-packaged solutions to common problems. Though many here have given you the gory details of how to achieve this (#prm!), I had a similar need a few years ago and found that addaxis worked very well. (It was a File Exchange pick of the week at one point!) It has inspired later, probably better mods. Here is some example output:
(source: mathworks.com)
I just searched for "plotyy" at File Exchange.
Though understanding what's going on in important, sometimes you just need to get things done, not do them yourself. Matlab Central is great for that.
One possibility you can try is to create 3 axes stacked one on top of the other with the 'Color' properties of the top two set to 'none' so that all the plots are visible. You would have to adjust the axes width, position, and x-axis limits so that the 3 y axes are side-by-side instead of on top of one another. You would also want to remove the x-axis tick marks and labels from 2 of the axes since they will lie on top of one another.
Here's a general implementation that computes the proper positions for the axes and offsets for the x-axis limits to keep the plots lined up properly:
%# Some sample data:
x = 0:20;
N = numel(x);
y1 = rand(1,N);
y2 = 5.*rand(1,N)+5;
y3 = 50.*rand(1,N)-50;
%# Some initial computations:
axesPosition = [110 40 200 200]; %# Axes position, in pixels
yWidth = 30; %# y axes spacing, in pixels
xLimit = [min(x) max(x)]; %# Range of x values
xOffset = -yWidth*diff(xLimit)/axesPosition(3);
%# Create the figure and axes:
figure('Units','pixels','Position',[200 200 330 260]);
h1 = axes('Units','pixels','Position',axesPosition,...
'Color','w','XColor','k','YColor','r',...
'XLim',xLimit,'YLim',[0 1],'NextPlot','add');
h2 = axes('Units','pixels','Position',axesPosition+yWidth.*[-1 0 1 0],...
'Color','none','XColor','k','YColor','m',...
'XLim',xLimit+[xOffset 0],'YLim',[0 10],...
'XTick',[],'XTickLabel',[],'NextPlot','add');
h3 = axes('Units','pixels','Position',axesPosition+yWidth.*[-2 0 2 0],...
'Color','none','XColor','k','YColor','b',...
'XLim',xLimit+[2*xOffset 0],'YLim',[-50 50],...
'XTick',[],'XTickLabel',[],'NextPlot','add');
xlabel(h1,'time');
ylabel(h3,'values');
%# Plot the data:
plot(h1,x,y1,'r');
plot(h2,x,y2,'m');
plot(h3,x,y3,'b');
and here's the resulting figure:
I know of plotyy that allows you to have two y-axes, but no "plotyyy"!
Perhaps you can normalize the y values to have the same scale (min/max normalization, zscore standardization, etc..), then you can just easily plot them using normal plot, hold sequence.
Here's an example:
%# random data
x=1:20;
y = [randn(20,1)*1 + 0 , randn(20,1)*5 + 10 , randn(20,1)*0.3 + 50];
%# plotyy
plotyy(x,y(:,1), x,y(:,3))
%# orginial
figure
subplot(221), plot(x,y(:,1), x,y(:,2), x,y(:,3))
title('original'), legend({'y1' 'y2' 'y3'})
%# normalize: (y-min)/(max-min) ==> [0,1]
yy = bsxfun(#times, bsxfun(#minus,y,min(y)), 1./range(y));
subplot(222), plot(x,yy(:,1), x,yy(:,2), x,yy(:,3))
title('minmax')
%# standarize: (y - mean) / std ==> N(0,1)
yy = zscore(y);
subplot(223), plot(x,yy(:,1), x,yy(:,2), x,yy(:,3))
title('zscore')
%# softmax normalization with logistic sigmoid ==> [0,1]
yy = 1 ./ ( 1 + exp( -zscore(y) ) );
subplot(224), plot(x,yy(:,1), x,yy(:,2), x,yy(:,3))
title('softmax')
Multi-scale plots are rare to find beyond two axes... Luckily in Matlab it is possible, but you have to fully overlap axes and play with tickmarks so as not to hide info.
Below is a nice working sample. I hope this is what you are looking for (although colors could be much nicer)!
close all
clear all
display('Generating data');
x = 0:10;
y1 = rand(1,11);
y2 = 10.*rand(1,11);
y3 = 100.*rand(1,11);
y4 = 100.*rand(1,11);
display('Plotting');
figure;
ax1 = gca;
get(ax1,'Position')
set(ax1,'XColor','k',...
'YColor','b',...
'YLim',[0,1],...
'YTick',[0, 0.2, 0.4, 0.6, 0.8, 1.0]);
line(x, y1, 'Color', 'b', 'LineStyle', '-', 'Marker', '.', 'Parent', ax1)
ax2 = axes('Position',get(ax1,'Position'),...
'XAxisLocation','bottom',...
'YAxisLocation','left',...
'Color','none',...
'XColor','k',...
'YColor','r',...
'YLim',[0,10],...
'YTick',[1, 3, 5, 7, 9],...
'XTick',[],'XTickLabel',[]);
line(x, y2, 'Color', 'r', 'LineStyle', '-', 'Marker', '.', 'Parent', ax2)
ax3 = axes('Position',get(ax1,'Position'),...
'XAxisLocation','bottom',...
'YAxisLocation','right',...
'Color','none',...
'XColor','k',...
'YColor','g',...
'YLim',[0,100],...
'YTick',[0, 20, 40, 60, 80, 100],...
'XTick',[],'XTickLabel',[]);
line(x, y3, 'Color', 'g', 'LineStyle', '-', 'Marker', '.', 'Parent', ax3)
ax4 = axes('Position',get(ax1,'Position'),...
'XAxisLocation','bottom',...
'YAxisLocation','right',...
'Color','none',...
'XColor','k',...
'YColor','c',...
'YLim',[0,100],...
'YTick',[10, 30, 50, 70, 90],...
'XTick',[],'XTickLabel',[]);
line(x, y4, 'Color', 'c', 'LineStyle', '-', 'Marker', '.', 'Parent', ax4)
(source: pablorodriguez.info)
PLOTYY allows two different y-axes. Or you might look into LayerPlot from the File Exchange. I guess I should ask if you've considered using HOLD or just rescaling the data and using regular old plot?
OLD, not what the OP was looking for:
SUBPLOT allows you to break a figure window into multiple axes. Then if you want to have only one x-axis showing, or some other customization, you can manipulate each axis independently.
In your case there are 3 extra y axis (4 in total) and the best code that could be used to achieve what you want and deal with other cases is illustrated above:
clear
clc
x = linspace(0,1,10);
N = numel(x);
y = rand(1,N);
y_extra_1 = 5.*rand(1,N)+5;
y_extra_2 = 50.*rand(1,N)+20;
Y = [y;y_extra_1;y_extra_2];
xLimit = [min(x) max(x)];
xWidth = xLimit(2)-xLimit(1);
numberOfExtraPlots = 2;
a = 0.05;
N_ = numberOfExtraPlots+1;
for i=1:N_
L=1-(numberOfExtraPlots*a)-0.2;
axesPosition = [(0.1+(numberOfExtraPlots*a)) 0.1 L 0.8];
if(i==1)
color = [rand(1),rand(1),rand(1)];
figure('Units','pixels','Position',[200 200 1200 600])
axes('Units','normalized','Position',axesPosition,...
'Color','w','XColor','k','YColor',color,...
'XLim',xLimit,'YLim',[min(Y(i,:)) max(Y(i,:))],...
'NextPlot','add');
plot(x,Y(i,:),'Color',color);
xlabel('Time (s)');
ylab = strcat('Values of dataset 0',num2str(i));
ylabel(ylab)
numberOfExtraPlots = numberOfExtraPlots - 1;
else
color = [rand(1),rand(1),rand(1)];
axes('Units','normalized','Position',axesPosition,...
'Color','none','XColor','k','YColor',color,...
'XLim',xLimit,'YLim',[min(Y(i,:)) max(Y(i,:))],...
'XTick',[],'XTickLabel',[],'NextPlot','add');
V = (xWidth*a*(i-1))/L;
b=xLimit+[V 0];
x_=linspace(b(1),b(2),10);
plot(x_,Y(i,:),'Color',color);
ylab = strcat('Values of dataset 0',num2str(i));
ylabel(ylab)
numberOfExtraPlots = numberOfExtraPlots - 1;
end
end
The code above will produce something like this:

how to add markers at limits of fplot matlab?

I want to add markers at the limits of a function in matlab. I am plotting the function using fplot this is what I tried:
user_func = '2*x-3';
user_limits = '-2,2';
user_limits = regexp(user_limits, '\,', 'split');
user_limit(1) = str2num(user_limits{1});
user_limit(2) = str2num(user_limits{2});
h = fplot(func,limits);
I am trying to add markers at the limits only (size 10 color 'r'). any idea on how to do that?
thank you
Not sure if this is exactly what you are trying to accomplish but I modified your code slightly so I could plot the function (using an anonymous function):
user_func = #(x) 2*x-3;
user_limits = '-2,2';
user_limits = regexp(user_limits, '\,', 'split')
user_limit(1) = str2num(user_limits{1})
user_limit(2) = str2num(user_limits{2})
figure;fplot(user_func,[user_limit(1) user_limit(2)]);
Next, set the ticks at your locations and change the font size to 10 pt:
set(gca,'XTick',[user_limit(1) user_limit(2)],'FontSize',10);
Change the color of your labels to red:
set(gca, 'XColor', [1 0 0]);
set(gca, 'YColor', [1 0 0]);
Just so you can see the ticks, stretch the x-range a bit:
axis([-2.1 2.1 0 1]); axis 'auto y'
EDIT: After some additional input from the OP, the red tick markers can be plotted as shown below.
First let the x-position at the first limit be given by:
x1 = user_limit(1);
The y-value for first marker is then obtained from the anonymous function like this:
y1 = user_func(x1);
y2 = y1;
We have, y2 = y1, since you want the y-value where where your function first crosses the x-axis to be the same. Now make your plot like this (with x2 = user_limit(2)):
hold on;
plot(x1, y1, 'ro', x2, y2,'ro');
hold off;
giving a plot like:

MATLAB contourf plot for an irregular domain

I am stuck with this problem for a long time now. I have a polygonal region (lets say, a hexagon). I can calculate the values of certain function at any point inside the polygon. Now I need to create a filled contour (using contourf in MATLAB) of this data. How do I go about it. I found some discussion on this topic at the link below (page 121)
http://www-personal.umich.edu/~jpboyd/eng403_chap4_contourplts.pdf
This works somewhat ok but it still produces jagged edges which I don't want. Anyone has any suggestion on this problem? Thanks. Here is my code
close all
Node = [ 1.0 0
0.5 0.8660
-0.5 0.8660
-1.0 0
-0.5 -0.8660
0.5 -0.8660];
[x,y] = meshgrid(-1:0.1:1,-1:0.1:1);
N = zeros(size(x));
for i=1:size(x,2)
for j=1:size(y,2)
p = [x(i,j) y(i,j)];
IN = inpolygon(p(1),p(2),Node(:,1),Node(:,2));
if IN
N(i,j)= rand;
else
N(i,j)= NaN;
end
end
end
figure
contourf(x,y,N,'LineStyle','none'), hold on;
xlabel('X'), ylabel('Y'), axis equal; axis off; colorbar;
line([Node(:,1);Node(1,1)],[Node(:,2);Node(1,2)],'Color',[1 1 1],'LineWidth',2.0)
clear IN i j p x y
You're using a square grid to sample a hexagonal area. This will indeed lead to boundary problems.
A better solution (but still not quite optimal) is to use a hexagonal grid:
%# define hexagon
Node = [ 1.0 0
0.5 0.8660
-0.5 0.8660
-1.0 0
-0.5 -0.8660
0.5 -0.8660];
%# Generate hexagonal grid
Rad3Over2 = sqrt(3) / 2;
[x, y] = meshgrid(0:51);
n = size(y,1);
x = Rad3Over2 * x;
y = y + repmat([0 0.5],[n,n/2]);
%# re-scale to -1..1
x = 2*x/max(x(:))-1;
y = 2*y/max(y(:))-1;
%# insode-polygon check
N = zeros(size(x));
for i=1:size(x,2)
for j=1:size(y,2)
p = [x(i,j) y(i,j)];
IN = inpolygon(p(1),p(2),Node(:,1),Node(:,2));
if IN
N(i,j)= rand;
else
N(i,j)= NaN;
end
end
end
%# make contour plot
figure(1)
contourf(x,y,N,'LineStyle','none'), hold on;
xlabel('X'), ylabel('Y'), axis equal; axis off; colorbar;
line([Node(:,1);Node(1,1)],[Node(:,2);Node(1,2)],'Color',[1 1 1],'LineWidth',2.0)
If you want even better coverage, you'll have to devise a grid that better covers your area and/or up the number of sample points.
For arbitrary irregular areas, you might want to experiment with irregular/random grids, distributed such that there are more points close to the boundaries, than there are in the middle of the area.
Suppose you have a function defined on a hexagon. Then take some square that contains the hexagon.
A simple first test could be to extend your function on the square to take the value = 0 for points outside of the hexagon.
Depending on the range of your function this may, or may not, give you a good answer.
If this doesn't work, then find the min of the function on the hexagon using min(min(A))) for an nxn matrix A. Then define the function to be min(min(A)) - 1.0 outside of the hexagon but in the square.
Then use contourf(x, y, z, v) where v is a vector of values for the output, so take v(1) = min(min(A)) - 1.0, and v(2:n) = linspace(min(min(A)), max(max(A)), n) for some integer n. You can probably specify the color of the level set min(min(A)) - 1.0 to be white, but I've never done this. I've had to do something like this before, and setting the function = 0 outside of he hexagon was enough.
If your function can only be evaluated inside the polygonal region, then my hexagonal grid answer still stands. However, if your function can be (or modified to be) evaluated outside the polygon, you might want to use a cheat:
figure(1), clf, hold on
%# External contour, square.
x1 = [-3 -3 +3 +3 -3]/2;
y1 = [-3 +3 +3 -3 -3]/2;
%# internal contour, some polygon
x2 = [1.0 0.5 -0.5 -1.0 -0.5 0.5];
y2 = [0 0.8660 0.8660 0 -0.8660 -0.8660];
%# convert to patches
[f, v] = poly2fv({x1, x2}, {y1, y2});
patch(...
'Faces' , f,...
'Vertices' , v,...
'FaceColor', get(0, 'defaultuicontrolbackgroundcolor'), ...
'EdgeColor', 'none'...
);
%# Generate function for contourplot
[x, y] = meshgrid(-2.8/2:0.1:2.8/2);
N = rand(size(x));
%# make contour plot
contourf(x,y,N,'LineStyle','none'), hold on;
xlabel('X'), ylabel('Y'), axis equal;
axis off; colorbar;
It basically creates your contour plot on a square region, and overlays a mask with a hexagonal hole in it, so it looks like it's only a contour of the hexagonal. I suspect it is a lot easier to tweak your function to allow function evaluations outside the region, then it is to (re-)invent some sort of grid that contains the boundaries.

Plot outside axis in Matlab

How to plot something outside the axis with MATLAB? I had like to plot something similar to this figure;
Thank you.
Here is one possible trick by using two axes:
%# plot data as usual
x = randn(1000,1);
[count bin] = hist(x,50);
figure, bar(bin,count,'hist')
hAx1 = gca;
%# create a second axis as copy of first (without its content),
%# reduce its size, and set limits accordingly
hAx2 = copyobj(hAx1,gcf);
set(hAx2, 'Position',get(hAx1,'Position').*[1 1 1 0.9], ...
'XLimMode','manual', 'YLimMode','manual', ...
'YLim',get(hAx1,'YLim').*[1 0.9])
delete(get(hAx2,'Children'))
%# hide first axis, and adjust Z-order
axis(hAx1,'off')
uistack(hAx1,'top')
%# add title and labels
title(hAx2,'Title')
xlabel(hAx2, 'Frequency'), ylabel(hAx2, 'Mag')
and here is the plot before and after:
You can display one axis with the scale you want, then plot your data on another axis which is invisible and large enough to hold the data you need:
f = figure;
% some fake data
x = 0:20;
y = 23-x;
a_max = 20;
b_max = 23;
a_height = .7;
%% axes you'll see
a = axes('Position', [.1 .1 .8 a_height]);
xlim([0 20]);
ylim([0 20]);
%% axes you'll use
scale = b_max/a_max;
a2 = axes('Position', [.1 .1 .8 scale*a_height]);
p = plot(x, y);
xlim([0 20]);
ylim([0 b_max]);
set(a2, 'Color', 'none', 'Visible', 'off');
I had similar problem and I've solved it thanks to this answer. In case of bar series the code is as follows:
[a,b] = hist(randn(1000,1)); % generate random data and histogram
h = bar(b,a); % plot bar series
ylim([0 70]) % set limits
set(get(h,'children'),'clipping','off')% turn off clippings