4D plot display variables with data cursor Matlab - matlab

I am having trouble figuring out how display 4 variables in my plot.
I want to vary the independent variables X,V, to produce the dependent variables Y and Z.
Y is a function of X AND V. And Z is a function of Y AND X.
This may be easier to see the dependencies: X, V, Y(X,V), Z(X,Y(X,V)).
I have used the surf function to plot X,Y,Z, but I also want to know the values of V, which I cannot currently ascertain.
Here is some test data to illustrate:
X = linspace(1,5,5)
V = linspace(1,5,5)
Capture = []
for j = 1:length(V)
Y = X.*V(j)
Capture = [Capture;Y]
end
[X,V] = meshgrid(X,V);
Z = Capture.*X
surf(X,Y,Z)
If I use the data cursor, I can see values of X,Y,Z, but I would also like to know the values of V. I know that the way I have it set up is correct because if I make two plots, say:
surf(X,Y,Z)
surf(X,V,Z)
and then use the data cursor to go on the same point of X and Z for both graphs the values for V and Y are what they should be for that point (X,Z).
Is there anyway to show the values for X,Y,V and Z without having to generate two separate graphs?
Thanks!

Using color as your 4th dimension is a possibility (whether it looks good to you is a matter of taste).
surf(X,Y,Z,V); #% 4th arg (V) is mapped onto the current colormap
You can change the colormap to suit your tastes.
colorbar #% displays a colorbar legend showing the value-color mapping
Edit: The questioner wants to see exactly the data in the not-shown array, rather than just a color. This is a job for custom data cursor function. Below I've implemented this using purely anonymous functions; doing it within a function file would be slightly more straightforward.
#% Step 0: create a function to index into an array...
#% returned by 'get' all in one step
#% The find(ismember... bit is so it returns an empty matrix...
#% if the index is out of bounds (if/else statements don't work...
#% in anonymous functions)
getel = #(x,i) x(find(ismember(1:numel(x),i)));
#% Step 1: create a custom data cursor function that takes...
#% the additional matrix as a parameter
myfunc = #(obj,event_obj,data) {...
['X: ' num2str(getel(get(event_obj,'position'),1))],...
['Y: ' num2str(getel(get(event_obj,'position'),2))],...
['Z: ' num2str(getel(get(event_obj,'position'),3))],...
['V: ' num2str(getel(data,get(event_obj,'dataindex')))] };
#% Step 2: get a handle to the datacursormode object for the figure
dcm_obj = datacursormode(gcf);
#% Step 3: enable the object
set(dcm_obj,'enable','on')
#% Step 4: set the custom function as the updatefcn, and give it the extra...
#% data to be displayed
set(dcm_obj,'UpdateFcn',{myfunc,V})
Now the tooltip should display the extra data. Note that if you change the data in the plot, you'll need to repeat Step 4 to pass the new data into the function.

Related

No visible points for plot in for loop

I'm struggling with a plot I want to make using a for-loop.
I know it works when I add it after the loop (just a simple plot). But I want to try it in this other way.
fib = ones(1:10);
for k=3:10
hold on
fib(k) = fib(k-1) + fib(k-2);
plot(k,fib(k))
end
hold off
The output is a plot, but there are no points visible.
You need to specify a marker. The documentation says:
If one of X or Y is a scalar and the other is either a scalar or a vector, then the plot function plots discrete points. However, to see the points you must specify a marker symbol, for example, plot(X,Y,'o')
So it will be:
plot(k,fib(k),'o');
Also note that you're creating a 10-dimensional array with fib = ones(1:10);. You most probably meant to write a comma instead of colon in between 1 and 10 to create a row vector. i.e.
fib = ones(1,10);
or a column vector as HansHirse suggested:
fib = ones(10,1);

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:

How to mark co-ordinates of points in Octave using "plot" command?

I am using the plot command in Octave to plot y versus x values. Is there a way such that the graph also shows the (x,y) value of every coordinate plotted on the graph itself?
I've tried using the help command but I couldn't find any such option.
Also, if it isn't possible, is there a way to do this using any other plotting function?
Have you tried displaying a text box at each coordinate?
Assuming x and y are co-ordinates already stored in MATLAB, you could do something like this:
plot(x, y, 'b.');
for i = 1 : numel(x) %// x and y are the same lengths
text(x(i), y(i), ['(' num2str(x(i)) ',' num2str(y(i)) ')']);
end
The above code will take each point in your graph and place a text box (with no borders) in the format of (x,y) where x and y are the coordinates for all of the points.
Note: You may have to play around with the position of the text boxes, because the above code will place each text box right on top of each pair of co-ordinates. You can play around by adding/subtracting appropriate constants in the first and second parameters of the text function. (i.e. text(x(i) + 1, y(i) - 1, .......); However, if you want something quick and for illustrative purposes, then the above code will be just fine.
Here's a method I've used to do something similar. Generating the strings for the labels is the most awkward part, really (I only had a single number per label, which is a lot simpler)
x = rand(1, 10);
y = rand(1, 10);
scatter(x, y);
% create a text object for each point
t = text(x, y, '');
% generate a cell array of labels - x and y must be row vectors in this case
c = strsplit(sprintf('%.2g,%.2g\n',[x;y]), '\n');
c(end) = []; % the final \n gives us an extra empty cell, remove it
c = c'; % transpose to match the dimensions of t
% assign each label to each text object
set(t, {'String'}, c);
You may want to play around with various properties like 'HorizontalAlignment', 'VerticalAlignment' and 'Margin' to tweak the label positions to your liking.
After a little more thought, here's an alternative, more robust way to generate a suitable cell array of coordinate labels:
c = num2cell([x(:) y(:)], 2);
c = cellfun(#(x) sprintf('%.2g,%.2g',x), c, 'UniformOutput', false);
There is a very useful package labelpoints
in MathWorks File Exchange that does exactly that.
It has a lot of convenient features.

matlab, how to plot the "root locus"

Given a function (call it sys(s)), we can use matlab: rlocus(sys) to plot the root locus of that function.
However,if we are given a function with a parameter (say b), eg sys(s)=(2s+2+b)/s , how can I use matlab to plot the rlocus(sys) as a function of the parameter b?
Let's say b changes between 1 and 100 with intervals of 1.
b = 1:100;
We need to create axes and hold them, so that we can plot root loci on top of each other.
axes();
hold('on');
Now we need to create a transfer function for each b and plot its root locus.
for idx = 1:length(b)
sys = tf([2 2+b(idx)], [1 0]);
rlocus(sys);
end
This is the resulting plot:
I could not find a vectorized solution, so it takes quite a long time. This took 45 seconds on my computer. If you need to calculate many values, you will need a vectorized solution.
To add a legend, you need to create a cell array to store b values.
legendStr = cell(1, length(b));
Then, inside the for loop you need to convert b values to string and store them in legendStr.
legendStr{idx} = num2str(b(idx));
After the for loop add the legend to the plot.
legend(legendStr)

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