Bar3 plot with seperate x,y,height and width values - matlab

Solution posted below function to plot bar 3 with separate x, y values and separate width and height values
bar3(x,y,z,xWidth,yWidth)
We are currently working on a project that allow one to visualize the area under a 3d function, f(x,y). The purpose of this is to demonstrate how the bars cut a 3d surface. Indirectly to visualize the desired integral.
We wish to have the bars match up with the intervals of the surface grid.
Below is a rough demonstration of the idea.
bar3 only has input for the x-values bar3(x,z), where as surf has a input for both the x and y surf(x,y,z)
Unfortunately this is what we are getting. - this is because bar3 cant be in terms of x and y
CODE:
clc;
cla;
d=eval(get(handles.edtOuterUpperB,'string'));
c=eval(get(handles.edtOuterLowerB,'string'));
b=eval(get(handles.edtInnerUpperB,'string'));
a=eval(get(handles.edtInnerLowerB,'string'));
n=eval(get(handles.edtInnerInterval,'string'));
m=eval(get(handles.edtOuterInterval,'string'));
h=(b-a)/n;
k=(d-c)/m;
[x,y] = meshgrid(a:h:b, c:k:d);
f=eval(get(handles.edtFunc,'string'));
surf(x,y,f);
hold on
bar3(f,1);

If you look closely, you will see that the XData and YData are different from the mesh to the 3D bar plot. This is because your mesh uses "real" x and y values while the bar plot uses indexes for the x and y values.
To fix this, you will want to change one or the other. For your case, the easiest one to change is going to be the surface. You can actually just omit the x and y inputs and the indexed x and y values will be used instead by default when generating the surface.
surf(f);
From the documentation for surf:
surf(Z) creates a three-dimensional shaded surface from the z components in matrix Z, using x = 1:n and y = 1:m, where [m,n] = size(Z). The height, Z, is a single-valued function defined over a geometrically rectangular grid. Z specifies the color data, as well as surface height, so color is proportional to surface height.
Update
If you want to keep the non-indexed values on the x and y axes, you will want to convert the bar3 plot instead. Unfortunately, MATLAB provides a way to specify the x axis bot not the y axis. You can take one of two approaches.
Change the XData
You can get the XData property of the resulting bar objects and change them to the data you want.
x = a:h:b;
y = c:k:d;
%// Anonymous function to scale things for us
scaler = #(vals)x(1) + ((vals-1) * (x(end) - x(1)) / (numel(x) - 1));
%// Create the bar plot
bars = bar3(y, f);
%// Change the XData
xdata = get(bars, 'XData');
xdata = cellfun(scaler, xdata, 'uni', 0);
set(bars, {'XData'}, xdata);
set(gca, 'xtick', x)
%// Now plot the surface
surf(x,y,f);
And just to demonstrate what this does:
x = linspace(0.5, 1.5, 5);
y = linspace(2.5, 4.5, 4);
f = rand(4,5);
scaler = #(vals)x(1) + ((vals-1) * (x(end) - x(1)) / (numel(x) - 1));
bars = bar3(y, f);
set(bars, {'XData'}, cellfun(scaler, get(bars, 'XData'), 'uni', 0))
set(gca, 'xtick', x)
axis tight
Change the XTickLabels
Instead of changing the actual data, you could simply change the values that are displayed to be what you want them to be rather than the indexed values.
x = a:h:b;
y = c:k:d;
labels = arrayfun(#(x)sprintf('%.2f', x), x, 'uni', 0);
bar3(y, f);
set(gca, 'xtick', 1:numel(x), 'xticklabels', labels);
hold on
%// Make sure to use the INDEX values for the x variable
surf(1:numel(x), y, f);

We found a user contributed function scatterbar3, which does what we want, in a different way than what bar3 uses:
http://www.mathworks.com/matlabcentral/fileexchange/1420-scatterbar3
There was however a slight hiccup that we had to correct:
hold on
scatterbar3(x,y,f,h);
scatterbar3 does not have separate inputs for the width and height of the bars, thus large gaps occur when the intervals do not equal one another. Demonstrated below.
We thus edited the scatterbar3 function in order to take both the width and height of the bars as inputs:
Edited scatterbar3 function:
function scatterbar3(X,Y,Z,widthx,widthy)
[r,c]=size(Z);
for j=1:r,
for k=1:c,
if ~isnan(Z(j,k))
drawbar(X(j,k),Y(j,k),Z(j,k),widthx/2,widthy/2)
end
end
end
zlim=[min(Z(:)) max(Z(:))];
if zlim(1)>0,zlim(1)=0;end
if zlim(2)<0,zlim(2)=0;end
axis([min(X(:))-widthx max(X(:))+widthx min(Y(:))-widthy max(Y(:))+widthy zlim])
caxis([min(Z(:)) max(Z(:))])
function drawbar(x,y,z,widthx,widthy)
h(1)=patch([-widthx -widthx widthx widthx]+x,[-widthy widthy widthy -widthy]+y,[0 0 0 0],'b');
h(2)=patch(widthx.*[-1 -1 1 1]+x,widthy.*[-1 -1 -1 -1]+y,z.*[0 1 1 0],'b');
h(3)=patch(widthx.*[-1 -1 -1 -1]+x,widthy.*[-1 -1 1 1]+y,z.*[0 1 1 0],'b');
h(4)=patch([-widthx -widthx widthx widthx]+x,[-widthy widthy widthy -widthy]+y,[z z z z],'b');
h(5)=patch(widthx.*[-1 -1 1 1]+x,widthy.*[1 1 1 1]+y,z.*[0 1 1 0],'b');
h(6)=patch(widthx.*[1 1 1 1]+x,widthy.*[-1 -1 1 1]+y,z.*[0 1 1 0],'b');
set(h,'facecolor','flat','FaceVertexCData',z)
Finally the working solution in action:
hold on
scatterbar3(x,y,f,h,k);

Related

How to plot a rectangular in MATLAB

It is necessary for me that plot a rectangular in MATLAB by contour. But when I plot this, the figure is like square and no rectangular.
In fact the length of X axis and Y axis are true, but figure is not rectangular.
How could I find a rectangular figure?
Once before I needed to plot a n eliptical by countour and it was like circle, by setting axes([xmin xmax ymin ymax]) this problem was solved but know this command do not work.
Here is my code u0,x,y are 3 vectors of length nx*ny. and nx and ny are the number of points in x axis and y axis.
figure
for i=1:ny
z(i,:)=u0((i-1)*nx+1:i*nx);
x1(i,:)=x((i-1)*nx+1:i*nx);
y1(i,:)=y((i-1)*nx+1:i*nx);
end;
cMap = [0.45 0.6 0.65;1 1 1]; % [green;yellow] on rgb-color
colormap(cMap);
axis equal
contourf(x1,y1,z,'LineColor','none')
colorbar
Let 's=0:0.1:0.2' and 'x=repmat(s,1,ny)' and 'd=0:0.1:1', 'y=repmat(d,1,nx)'
'u0=x+y'
I think the problem is the size of the vector you are using. Check out this example:
x = linspace(0,2,20);
y = linspace(0,1,10);
z = meshgrid(x,y);
contourf(x,y,z,20);
axis equal
it gives the following result:
Now if we check the sizes:
>> size(x)
ans =
1 20
>> size(y)
ans =
1 10
>> size(z)
ans =
10 20
if the size of x vector is equal to the size of the y vector it gives you a square obviously! in your case first check the size of x1, y1, z just before using the contourf an make sure that you are using axis equal after that.

How to plot a intersection operation on two vectors MatLab

I'm trying to represent a the intersection of two fuzzy sets as a 3d mesh in MatLab.
Here are my sets of vectors:
x = [0.3 0.5 0.7]
y = [0.5 0.7 0.1]
Followed by these statements:
[u,v] = meshgrid(x,y)
w = min(u,v)
mesh(u,v,w)
The x and y ticks seem to be all over the place and do not correlate to the actual index number of each vector i.e. 1 to 3, and the graph should represent the shape of a small triangle/T-norm.
At the moment it looks like this:
Here is an example out of my book I'm following:
Ignore what looks like fractions, they are delimiters. Here is the resulting graph:
After looking up fuzzy sets and intersections, here's what I've come up with. First, let's reproduce the textbook example:
% possible values and associated degrees of truth for F
Fv = 1 : 5;
Ft = [0 0.5 1 0.5 0];
% possible values and associated degrees of truth for D
Dv = 2 : 4;
Dt = [0 1 0];
% determine degrees of truth for fuzzy intersection
It = bsxfun(#min, Ft', Dt);
% plot
h = mesh(Dv, Fv, It);
set(h, 'FaceColor', 'none')
set(h, 'EdgeColor', 'k')
xlim([0 4.5])
ylim([0 5])
xlabel D
ylabel F
view(37.5, 30)
The result is:
Not as pretty as in your book, but the same thing.
Applying the same code to your example yields:
Via the arguments u,v you are telling mesh to use the values in them, i.e. the values from x and y, for the positioning of the data points and corresponding ticks. If you just want positions and ticks at 1, 2, 3, leave these arguments out.
mesh(w)

How to let the axes in matlab have different lengths without changing axes limits

I'm trying to plot a 3D surface in Matlab and I want to "compress" the plot a little bit in the z dimension. Now the lengths of x, y and z axes are the same, and the plot looks like a cube. I'd like it to look flatter in the z dimension, without altering the axes limits.
Is there any easy way to achieve this?
Try fiddling with the DataAspectRatio and the PlotBoxAspectRatio properties of the axes, which may also be controlled by the pbaspect and daspect commands, correspondingly.
Example
%// Plot surface
[X, Y] = meshgrid(-10:.1:10, -10:.1:10);
Z = 100 - X .^ 2 - Y .^ 2;
surf(X, Y, Z, 'EdgeColor', 'None')
%// Flatten the z-axis a bit
pbaspect([1 1 .2])
daspect([1 1 50])
Original plot:
Flattened plot:

error in plotting a 3D matrix as a 3D bar graph

Hi I have the 3D matrix daily_renewables_excess which I am trying to plot a 3D bar graph for the x y and z dimensions in axis.
The size(daily_renewables_excess) is 11,7,10. So I am trying to get a 3D bar chart with 11 x intervals of x, 7 of y and 10 of z.
However when i try
figure;
bar3(daily_renewables_excess(:,:,:))
I get an error saying "Error using bar3 (line 39)
Inputs must be 2-D."
From my understanding of the documentation, the bar3 function will plot a 3D bar as above.
Do I need to rearrange the matrices somehow?
thank you
Since you have a 3D matrix (volume) you cannot simultaneously show 3 intervals (3 axis) + a scale value for the bars (4th variable). This would amount to plotting a 4D diagram (e.g. using color to color-code the 4-th dimension, bar size to size-code it, or even vertical stacking).
For example, the following volume D is of size [11x10x7] and you can get 7 bar3 plots by indexing in the 3rd (z) dimension
% random 3D input
D = randi(10, [11, 10, 7]);
[m,n,l] = size(D);
% plot bar for first z-
figure; bar3(D(:,:,1));
What you can do instead is reshape in either x- or y- dimesions, sort (in order to keep the notion of ordered intervals (in x- or y- respectively) and plot with bar3 the resulting matrices.
% reshape to x
Dx = reshape(D, m*l, n);
Dx = sort(Dx, 1, 'descend');
figure; bar3(Dx)
% reshape to y
Dy = reshape(D, m, n*l);
Dy = sort(Dy, 2, 'descend');
figure; bar3(Dy)

Set surf minimum for matlab

I have a function which takes a voxel representation of a 3D landscape and can plot a X-Y section to show the middle of the landscape. The voxel representation is stored in a 3 dimensional matrix with a number that represents something important. Obviously the matrix is
1,1,1
2,2,2
in terms of accessing the elements but the actual 3D locations are found in the following method:
(index-1)*resolution+0.5*resolution+minPos;
where resolution is the grid size :
resolution
<-->
__ __ __
|__|__|__|
<- Min pos
and minPos is where the grid starts.
Now in terms of the actual question, i would like to extract a single X-Y section of this voxel representation and display it as a surf. This can be done by just doing this:
surf(voxel(:, :, section))
however then you get this:
The obvious problem is that the grid will start at 0 because that is how the matrix representation is. How can i set the minimum and cell size for surf, ie so that the grid will start at the minimum (shown above) and will have the grid spacing of resolution (shown above).
Read the documentation of surf, you can also provide x and y coordinates corresponding to your data points.
surf(X,Y,Z)
X and Y can be either vectors or matrices:
surf(X,Y,Z) uses Z for the color data and surface height. X and Y are vectors or matrices defining the x and y components of a surface. If X and Y are vectors, length(X) = n and length(Y) = m, where [m,n] = size(Z). In this case, the vertices of the surface faces are (X(j), Y(i), Z(i,j)) triples. To create X and Y matrices for arbitrary domains, use the meshgrid function
Example
Z=[ 0 1 2 3;
7 6 5 4;
8 9 10 11];
x=[-1 0 1 2];
y=[-2 0 2];
surf(x,y,Z);
Of course you have to match Z, x and y matrices/vectors as clearly described in the doc^^
Just remember that elements in columns of Z are surf'ed as values along the y-axis, elements in rows of Z are surf'ed as values along the x-axis. This is clearly to be seen in the example picture.
Solution
I think you switched the x and y-axis around, which you can fix by just transposing z:
s = size(voxel);
xi = (minPosX:resolution:(minPosX+resolution*s(1)-1));
yi = (minPosY:resolution:(minPosY+resolution*s(2)-1));
z = (voxel(:,:,section));
surf(xi, yi, z');
or that you're picking the wrong numbers for constructing xi and yi and it should be this instead:
xi = (minPosX:resolution:(minPosX+resolution*s(2)-1));
yi = (minPosY:resolution:(minPosY+resolution*s(1)-1));
z = (voxel(:,:,section));
surf(xi, yi, z);
So it was easy enough to do:
lets say we have a 3D matrix "voxel";
s = size(voxel);
xi = (minPosX:resolution:(minPosX+resolution*s(1)-1));
yi = (minPosY:resolution:(minPosY+resolution*s(2)-1));
z = (voxel(:,:,section));
[x y] = meshgrid(xi, yi);
x = x';
y = y';
surf(x, y, z);
Provides the following plot:
This is rotated which is annoying, I cant seem to get it to rotate back (I could just visualise around the other way but that's ok)