How can I contour plot a custom function? - matlab

I have a custom function which returns either 0 or 1 depending on two given inputs:
function val = myFunction(val1, val2)
% logic to determine if val=1 or val=0
end
How can I create a contour plot of the function over the x,y coordinates generated by the following meshgrid?
meshgrid(0:.5:3, 0:.5:3);
This plot will just simply display where the function is 0 or 1 on the contour map.

If your function myFunction is not designed to handle matrix inputs, then you can use the function ARRAYFUN to apply it to all the corresponding entries of x and y:
[x,y] = meshgrid(0:0.5:3); %# Create a mesh of x and y points
z = arrayfun(#myFunction,x,y); %# Compute z (same size as x and y)
Then you could use the function CONTOUR to generate a contour plot for the above data. Since your z data only has 2 different values, it would probably make sense for you to only plot one contour level (which would be at a value of 0.5, halfway between your two values). You might also want to instead use the function CONTOURF, which produces color-filled contours that will clearly show where the ones and zeroes are:
contourf(x,y,z,1); %# Plots 1 contour level, filling the area on either
%# side with different color
NOTE: Since you are plotting data that only has ones and zeroes, plotting contours may not be the best way to visualize it. I would instead use something like the function IMAGESC, like so:
imagesc(x(1,:),y(:,1),z);
Keep in mind the y-axis in this plot will be reversed relative to the plot generated by CONTOURF.

The following will do it:
function bincontour
clear; clc;
xrange = 0:.5:3;
yrange = 1:.5:5;
[xmesh, ymesh] = meshgrid(xrange, yrange);
z = arrayfun(#myFunction, xmesh, ymesh);
contourf(xrange, yrange, z, 5)
end
function val = myFunction(val1, val2)
val = rand() > 0.5;
end

Related

MATLAB - scatter plot of a vector by a matrix?

I'm very new to Matlab. I'm trying to plot X, where X is an 100x1 vector, against Y, which is an 100x10 matrix. I want the result to be X vs 10 different Y values all in the same graph, different colors for each column. The only way I can think of plotting each column of this matrix is by using the hold command, but then I have to split it up so I get each column individually. Is there an easy way to do this?
Use repmat to expand X to be the same size as Y. Try plotting them with plot(X,Y) and if it looks strange, transpose each one (plot(X',Y')).
You can use linespec arguments to select linestyle, marker style, etc. For example, plot(X,Y,'.') would indicate a point at each vertex with no connecting lines.
You don't need to use repmat, just use plot instead of scatter:
plot(X,Y,'o')
Here's an example:
% some arbitrary data:
X = linspace(-2*pi,2*pi,100).'; % size(X) = 100 1
Y = bsxfun(#plus,sin(X),rand(100,10)); % size(Y) = 100 10
% you only need the next line:
plot(X,Y,'o')
legend('show')

Matlab: 1D array to RGB triplets with colormap

I'm trying to draw a set of rectangles, each with a fill color representing some value between 0 and 1. Ideally, I would like to use any standard colormap.
Note that the rectangles are not placed in a nice grid, so using imagesc, surf, or similar seems unpractical. Also, the scatter function does not seem to allow me to assign a custom marker shape. Hence, I'm stuck to plotting a bunch of Rectangles in a for-loop and assigning a FillColor by hand.
What's the most efficient way to compute RGB triplets from the scalar values? I've been unable to find a function along the lines of [r,g,b] = val2rgb(value,colormap). Right now, I've built a function which computes 'jet' values, after inspecting rgbplot(jet). This seems a bit silly. I could, of course, obtain values from an arbitrary colormap by interpolation, but this would be slow for large datasets.
So, what would an efficient [r,g,b] = val2rgb(value,colormap) look like?
You have another way to handle it: Draw your rectangles using patch or fill specifying the color scale value, C, as the third parameter. Then you can add and adjust the colorbar:
x = [1,3,3,1,1];
y = [1,1,2,2,1];
figure
for ii = 1:10
patch(x + 4 * rand(1), y + 2 * rand(1), rand(1), 'EdgeColor', 'none')
end
colorbar
With this output:
I think erfan's patch solution is much more elegant and flexible than my rectangle approach.
Anyway, for those who seek to convert scalars to RGB triplets, I'll add my final thoughts on the issue. My approach to the problem was wrong: colors should be drawn from the closest match in the colormap without interpolation. The solution becomes trivial; I've added some code for those who stumble upon this issue in the future.
% generate some data
x = randn(1,1000);
% pick a range of values that should map to full color scale
c_range = [-1 1];
% pick a colormap
colormap('jet');
% get colormap data
cmap = colormap;
% get the number of rows in the colormap
cmap_size = size(cmap,1);
% translate x values to colormap indices
x_index = ceil( (x - c_range(1)) .* cmap_size ./ (c_range(2) - c_range(1)) );
% limit indices to array bounds
x_index = max(x_index,1);
x_index = min(x_index,cmap_size);
% read rgb values from colormap
x_rgb = cmap(x_index,:);
% plot rgb breakdown of x values; this should fall onto rgbplot(colormap)
hold on;
plot(x,x_rgb(:,1),'ro');
plot(x,x_rgb(:,2),'go');
plot(x,x_rgb(:,3),'bo');
axis([c_range 0 1]);
xlabel('Value');
ylabel('RGB component');
With the following result:

Extract trajectory at a contour level from streamline in MATLAB

When plotting streamlines in MATLAB using quiver, streamslice or similar, is it possible to extract the contour line at given contour level?
Take this example (I have numerical data in my case, but I will use analytical functions in the example):
[X,Y] = meshgrid(0:.02:1);
Z = X.*exp(-X.^2 - Y.^2);
[DX,DY] = gradient(Z,.2,.2);
figure
imagesc([0 1], [0 1], Z)
hold on
streamslice(X,Y,DX,DY) %how to extract a trajectory at a given contour level C?
hold off
colorbar
If not, is it possible to obtain them otherwise? I was thinking of using contour in this way,
contour(X,Y,sqrt(DX.*DX+DY.*DY), [1 1]*0.07)
but this is clearly wrong when I compare to the streamlines above.
hs = streamslice(X,Y,DX,DY); as result you obtain a vector with handles to the traject lines. For example, you can get the coordinates of the first traject line:
N_trajects = length(hs); % the number of all trajectories
n = 1; % the chosen trajectory
X_traject = get(hs(n),'XData');
Y_traject = get(hs(n),'YData');
or using new version of MATLAB:
X_traject = hs(n).XData;
Y_traject = hs(n).YData;
To extract countour lines data:
C = contour(X,Y,sqrt(DX.*DX+DY.*DY), [1 1]*0.07);
where C consits data with the contour lines. In your case there is one contour line only (X_contour = C(1,:), Y_contour = C(2,:)). In the case of many contour levels, to extract them see here or here or using this.
Now we know the coordinates of the trajectory and contour level. Thus you can find the point(s) of intersection between the trajectory and the contour level.

multiple matlab contour plots with one level

I have a number of 2d probability mass functions from 2 categories. I am trying to plot the contours to visualise them (for example at their half height, but doesn't really matter).
I don't want to use contourf to plot directly because I want to control the fill colour and opacity. So I am using contourc to generate xy coordinates, and am then using fill with these xy coordinates.
The problem is that the xy coordinates from the contourc function have strange numbers in them which cause the following strange vertices to be plotted.
At first I thought it was the odd contourmatrix format, but I don't think it is this as I am only asking for one value from contourc. For example...
contourmatrix = contourc(x, y, Z, [val, val]);
h = fill(contourmatrix(1,:), contourmatrix(2,:), 'r');
Does anyone know why the contourmatrix has these odd values in them when I am only asking for one contour?
UPDATE:
My problem seems might be a failure mode of contourc when the input 2D matrix is not 'smooth'. My source data is a large set of (x,y) points. Then I create a 2D matrix with some hist2d function. But when this is noisy the problem is exaggerated...
But when I use a 2d kernel density function to result in a much smoother 2D function, the problem is lessened...
The full process is
a) I have a set of (x,y) points which form samples from a distribution
b) I convert this into a 2D pmf
c) create a contourmatrix using contourc
d) plot using fill
Your graphic glitches are because of the way you use the data from the ContourMatrix. Even if you specify only one isolevel, this can result in several distinct filled area. So the ContourMatrix may contain data for several shapes.
simple example:
isolevel = 2 ;
[X,Y,Z] = peaks ;
[C,h] = contourf(X,Y,Z,[isolevel,isolevel]);
Produces:
Note that even if you specified only one isolevel to be drawn, this will result in 2 patches (2 shapes). Each has its own definition but they are both embedded in the ContourMatrix, so you have to parse it if you want to extract each shape coordinates individually.
To prove the point, if I simply throw the full contour matrix to the patch function (the fill function will create patch objects anyway so I prefer to use the low level function when practical). I get the same glitch lines as you do:
xc = X(1,:) ;
yc = Y(:,1) ;
c = contourc(xc,yc,Z,[isolevel,isolevel]);
hold on
hp = patch(c(1,1:end),c(2,1:end),'r','LineWidth',2) ;
produces the same kind of glitches that you have:
Now if you properly extract each shape coordinates without including the definition column, you get the proper shapes. The example below is one way to extract and draw each shape for inspiration but they are many ways to do it differently. You can certainly compact the code a lot but here I detailed the operations for clarity.
The key is to read and understand how the ContourMatrix is build.
parsed = false ;
iShape = 1 ;
while ~parsed
%// get coordinates for each isolevel profile
level = c(1,1) ; %// current isolevel
nPoints = c(2,1) ; %// number of coordinate points for this shape
idx = 2:nPoints+1 ; %// prepare the column indices of this shape coordinates
xp = c(1,idx) ; %// retrieve shape x-values
yp = c(2,idx) ; %// retrieve shape y-values
hp(iShape) = patch(xp,yp,'y','FaceAlpha',0.5) ; %// generate path object and save handle for future shape control.
if size(c,2) > (nPoints+1)
%// There is another shape to draw
c(:,1:nPoints+1) = [] ; %// remove processed points from the contour matrix
iShape = iShape+1 ; %// increment shape counter
else
%// we are done => exit while loop
parsed = true ;
end
end
grid on
This will produce:

maybe matrix plot!

for an implicit equation(name it "y") of lambda and beta-bar which is plotted with "ezplot" command, i know it is possible that by a root finding algorithm like "bisection method", i can find solutions of beta-bar for each increment of lambda. but how to build such an algorithm to obtain the lines correctly.
(i think solutions of beta-bar should lie in an n*m matrix)
would you in general show the methods of plotting such problem? thanks.
one of my reasons is discontinuity of "ezplot" command for my equation.
ok here is my pic:
alt text http://www.mojoimage.com/free-image-hosting-view-05.php?id=5039TE-beta-bar-L-n2-.png
or
http://www.mojoimage.com/free-image-hosting-05/5039TE-beta-bar-L-n2-.pngFree Image Hosting
and my code (in short):
h=ezplot('f1',[0.8,1.8,0.7,1.0]);
and in another m.file
function y=f1(lambda,betab)
n1=1.5; n2=1; z0=120*pi;
d1=1; d2=1; a=1;
k0=2*pi/lambda;
u= sqrt(n1^2-betab^2);
wb= sqrt(n2^2-betab^2);
uu=k0*u*d1;
wwb=k0*wb*d2 ;
z1=z0/u; z1_b=z1/z0;
a0_b=tan(wwb)/u+tan(uu)/wb;
b0_b=(1/u^2-1/wb^2)*tan(uu)*tan(wwb);
c0_b=1/(u*wb)*(tan(uu)/u+tan(wwb)/wb);
uu0= k0*u*a; m=0;
y=(a0_b*z1_b^2+c0_b)+(a0_b*z1_b^2-c0_b)*...
cos(2*uu0+m*pi)+b0_b*z1_b*sin(2*uu0+m*pi);
end
fzero cant find roots; it says "Function value must be real and finite".
anyway, is it possible to eliminate discontinuity and only plot real zeros of y?
heretofore,for another function (namely fTE), which is :
function y=fTE(lambda,betab,s)
m=s;
n1=1.5; n2=1;
d1=1; d2=1; a=1;
z0=120*pi;
k0=2*pi/lambda;
u = sqrt(n1^2-betab^2);
w = sqrt(betab^2-n2^2);
U = k0*u*d1;
W = k0*w*d2 ;
z1 = z0/u; z1_b = z1/z0;
a0_b = tanh(W)/u-tan(U)/w;
b0_b = (1/u^2+1/w^2)*tan(U)*tanh(W);
c0_b = -(tan(U)/u+tanh(W)/w)/(u*w);
U0 = k0*u*a;
y = (a0_b*z1_b^2+c0_b)+(a0_b*z1_b^2-c0_b)*cos(2*U0+m*pi)...
+ b0_b*z1_b*sin(2*U0+m*pi);
end
i'd plotted real zeros of "y" by these codes:
s=0; % s=0 for even modes and s=1 for odd modes.
lmin=0.8; lmax=1.8;
bmin=1; bmax=1.5;
lam=linspace(lmin,lmax,1000);
for n=1:length(lam)
increment=0.001; tolerence=1e-14; xstart=bmax-increment;
x=xstart;
dx=increment;
m=0;
while x > bmin
while dx/x >= tolerence
if fTE(lam(n),x,s)*fTE(lam(n),x-dx,s)<0
dx=dx/2;
else
x=x-dx;
end
end
if abs(real(fTE(lam(n),x,s))) < 1e-6 %because of discontinuity some answers are not correct.%
m=m+1;
r(n,m)=x;
end
dx=increment;
x=0.99*x;
end
end
figure
hold on,plot(lam,r(:,1),'k'),plot(lam,r(:,2),'c'),plot(lam,r(:,3),'m'),
xlim([lmin,lmax]);ylim([1,1.5]),
xlabel('\lambda(\mum)'),ylabel('\beta-bar')
you see i use matrix to save data for this plot.
![alt text][2]
because here lines start from left(axis) to rigth. but if the first line(upper) starts someplace from up to rigth(for the first figure and f1 function), then i dont know how to use matrix. lets improve this method.
[2]: http://www.mojoimage.com/free-image-hosting-05/2812untitled.pngFree Image Hosting
Sometimes EZPLOT will display discontinuities because there really are discontinuities or some form of complicated behavior of the function occurring there. You can see this by generating your plot in an alternative way using the CONTOUR function.
You should first modify your f1 function by replacing the arithmetic operators (*, /, and ^) with their element-wise equivalents (.*, ./, and .^) so that f1 can accept matrix inputs for lambda and betab. Then, run the code below:
lambda = linspace(0.8,1.8,500); %# Create a vector of 500 lambda values
betab = linspace(0.7,1,500); %# Create a vector of 500 betab values
[L,B] = meshgrid(lambda,betab); %# Create 2-D grids of values
y = f1(L,B); %# Evaluate f1 at every point in the grid
[c,h] = contour(L,B,y,[0 0]); %# Plot contour lines for the value 0
set(h,'Color','b'); %# Change the lines to blue
xlabel('\lambda'); %# Add an x label
ylabel('$\overline{\beta}$','Interpreter','latex'); %# Add a y label
title('y = 0'); %# Add a title
And you should see the following plot:
Notice that there are now additional lines in the plot that did not appear when using EZPLOT, and these lines are very jagged. You can zoom in on the crossing at the top left and make a plot using SURF to get an idea of what's going on:
lambda = linspace(0.85,0.95,100); %# Some new lambda values
betab = linspace(0.95,1,100); %# Some new betab values
[L,B] = meshgrid(lambda,betab); %# Create 2-D grids of values
y = f1(L,B); %# Evaluate f1 at every point in the grid
surf(L,B,y); %# Make a 3-D surface plot of y
axis([0.85 0.95 0.95 1 -5000 5000]); %# Change the axes limits
xlabel('\lambda'); %# Add an x label
ylabel('$\overline{\beta}$','Interpreter','latex'); %# Add a y label
zlabel('y'); %# Add a z label
Notice that there is a lot of high-frequency periodic activity going on along those additional lines, which is why they look so jagged in the contour plot. This is also why a very general utility like EZPLOT was displaying a break in the lines there, since it really isn't designed to handle specific cases of complicated and poorly behaved functions.
EDIT: (response to comments)
These additional lines may not be true zero crossings, although it is difficult to tell from the SURF plot. There may be a discontinuity at those lines, where the function shoots off to -Inf on one side of the line and Inf on the other side of the line. When rendering the surface or computing the contour, these points on either side of the line may be mistakenly connected, giving the false appearance of a zero crossing along the line.
If you want to find a zero crossing given a value of lambda, you can try using the function FZERO along with an anonymous function to turn your function of two variables f1 into a function of one variable fcn:
lambda_zero = 1.5; %# The value of lambda at the zero crossing
fcn = #(x) f1(lambda_zero,x); %# A function of one variable (lambda is fixed)
betab_zero = fzero(fcn,0.94); %# Find the value of betab at the zero crossing,
%# using 0.94 as an initial guess