I try to use the Matlab function gradient to calculate the gradient of a volume. I use quiver to display the gradients of slices.
I use a cube-like volume, which is symmetric with respect to x, y, and z axis. To my surprise, the result is not the same for all slices. Actually only the result in the xy-plane (Z-slice, last image) is the expected result.
I know that there are issues when calculating the gradient at the border of an image. But for me the result at the border is not important and so I don't care if the result next to the border is correct. For me it would be important that all three images look like the last one.
Can somebody tell me what is wrong with my code? Thanks!
f=zeros(20,20,20);
space = 5;
f(:,:,space) = 1; f(:,:,end-space) = 1;
f(:,space,:) = 1; f(:,end-space,:) = 1;
f(space,:,:) = 1; f(end-space,:,:) = 1;
space = 4;
f(:,:,space) = 1; f(:,:,end-space) = 1;
f(:,space,:) = 1; f(:,end-space,:) = 1;
f(space,:,:) = 1; f(end-space,:,:) = 1;
size_iso = size(f);
x_slice = round(size_iso(1)/2);
y_slice = round(size_iso(2)/2);
z_slice = round(size_iso(3)/2);
% display the gradient of the edge map
[fx,fy,fz] = gradient(f,0.1);
figure;
image(squeeze(f(x_slice,:,:))*50); colormap(gray(64)); hold on;
quiver(squeeze(fy(x_slice,:,:)),squeeze(fz(x_slice,:,:)));
axis equal;
title(['edge map gradient of X-slice ', num2str(x_slice)]);
figure;
image(squeeze(f(:,y_slice,:))*50); colormap(gray(64)); hold on;
quiver(squeeze(fx(:,y_slice,:)),squeeze(fz(:,y_slice,:)));
axis equal;
title(['edge map gradient of Y-slice ', num2str(y_slice)]);
figure;
image(squeeze(f(:,:,z_slice))*50); colormap(gray(64)); hold on;
quiver(squeeze(fx(:,:,z_slice)),squeeze(fy(:,:,z_slice)));
axis equal;
title(['edge map gradient of Z-slice ', num2str(z_slice)]);
Things are bit more complicated with 3D matrices and coordinates.
For example
img = rand(10,30);
imagesc(img);
axis equal;
will display an image 30 pixels wide and 10 pixels high.
In MatLab when you display an image its first dimension (rows) is actually Y-axis on the plot. Second dimension (columns) is X-axis on the plot.
See, for example, http://www.mathworks.com/help/matlab/math/multidimensional-arrays.html
To illustrate mistake in your code consider simplified example:
% we need a 3D matrix with
% 10 points along the X-axis
% 20 points along the Y-axis
% 30 points along the Z-axis
f = rand(20,10,30); % note the order of numbers
size_iso = size(f), % gives [20 10 30]
x_slice = round(size_iso(2)/2) % gives 5
y_slice = round(size_iso(1)/2) % gives 10
z_slice = round(size_iso(3)/2) % gives 15
figure;
image(squeeze(f(:,x_slice,:))*50); colormap(gray(64)); hold on;
axis equal;
title(['X-slice ', num2str(x_slice)]);
% this code produces image 30 pixels wide and 20 pixels high
% Thus 1st dimension (vertical axis) is actually the Y-axis
% Thus 2nd dimension (horizontal axis) is actually the Z-axis
figure;
image(squeeze(f(y_slice,:,:))*50); colormap(gray(64)); hold on;
axis equal;
title(['Y-slice ', num2str(y_slice)]);
% this code produces image 30 pixels wide and 10 pixels high
% Thus 1st dimension (vertical axis) is actually the X-axis
% Thus 2nd dimension (horizontal axis) is actually the Z-axis
figure;
image(squeeze(f(:,:,z_slice))*50); colormap(gray(64)); hold on;
axis equal;
title(['Z-slice ', num2str(z_slice)]);
% this code produces 10 pixels wide and 20 pixels high
% Thus 1st dimension (vertical axis) is actually the Y-axis
% Thus 2nd dimension (horizontal axis) is actually the X-axis
For your code to work properly you should pay attention not only to the order of dimensions in the slice image but also to the way they are shifted by squeeze function.
Therefore you should provide proper combination of coordinates to the subsequent quiver function call.
I modified your code to fill slab perpendicular to given axis with unique value so you should be able to distinguish them easier. Also I'm using different dimensions along each axis for the same purpose.
xvalue=0.33;
yvalue=0.66;
zvalue=1.00;
% we need a 3D matrix with
% 10 points along the X-axis
% 20 points along the Y-axis
% 30 points along the Z-axis
f = zeros(20,10,30); % note the order of numbers
space = 3;
f(:,space,:) = xvalue; f(:,end-space,:) = xvalue;
f(space,:,:) = yvalue; f(end-space,:,:) = yvalue;
f(:,:,space) = zvalue; f(:,:,end-space) = zvalue;
size_iso = size(f);
x_slice = round(size_iso(2)/2); % note dimension number here for x_slice
y_slice = round(size_iso(1)/2); % note dimension number here for y_slice
z_slice = round(size_iso(3)/2);
% display the gradient of the edge map
[fx,fy,fz] = gradient(f,0.1);
figure;
image(squeeze(f(:,x_slice,:))*50); colormap(gray(64)); hold on;
quiver(squeeze(fz(:,x_slice,:)),squeeze(fy(:,x_slice,:)));
axis equal;
title(['edge map gradient of X-slice ', num2str(x_slice)]);
xlabel('Z')
ylabel('Y')
figure;
image(squeeze(f(y_slice,:,:))*50); colormap(gray(64)); hold on;
quiver(squeeze(fz(y_slice,:,:)),squeeze(fx(y_slice,:,:)));
axis equal;
title(['edge map gradient of Y-slice ', num2str(y_slice)]);
xlabel('Z')
ylabel('X')
figure;
image(squeeze(f(:,:,z_slice))*50); colormap(gray(64)); hold on;
quiver(squeeze(fx(:,:,z_slice)),squeeze(fy(:,:,z_slice)));
axis equal;
title(['edge map gradient of Z-slice ', num2str(z_slice)]);
xlabel('X')
ylabel('Y')
Yes, this is tricky and hard to understand at first but you'll get used to it with practice.
Related
I'm trying to fill an area between two curves with respect to a function which depends on the values of the curves.
Here is the code of what I've managed to do so far
i=50;
cc = #(xx,x,y) 1./(1+(exp(-xx)/(exp(-x)-exp(-y))));
n_vec = 2:0.1:10;
x_vec = linspace(2,10,length(n_vec));
y_vec = abs(sin(n_vec));
N=[n_vec,fliplr(n_vec)];
X=[x_vec,fliplr(y_vec)];
figure(1)
subplot(2,1,1)
hold on
plot(n_vec,x_vec,n_vec,y_vec)
hp = patch(N,X,'b')
plot([n_vec(i) n_vec(i)],[x_vec(i),y_vec(i)],'linewidth',5)
xlabel('n'); ylabel('x')
subplot(2,1,2)
xx = linspace(y_vec(i),x_vec(i),100);
plot(xx,cc(xx,y_vec(i),x_vec(i)))
xlabel('x'); ylabel('c(x)')
This code produces the following graph
The color code which I've added represent the color coding that each line (along the y axis at a point on the x axis) from the area between the two curves should be.
Overall, the entire area should be filled with a gradient color which depends on the values of the curves.
I've assisted the following previous questions but could not resolve a solution
MATLAB fill area between lines
Patch circle by a color gradient
Filling between two curves, according to a colormap given by a function MATLAB
NOTE: there is no importance to the functional form of the curves, I would prefer an answer which refers to two general arrays which consist the curves.
The surf plot method
The same as the scatter plot method, i.e. generate a point grid.
y = [x_vec(:); y_vec(:)];
resolution = [500,500];
px = linspace(min(n_vec), max(n_vec), resolution(1));
py = linspace(min(y), max(y), resolution(2));
[px, py] = meshgrid(px, py);
Generate a logical array indicating whether the points are inside the polygon, but no need to extract the points:
in = inpolygon(px, py, N, X);
Generate Z. The value of Z indicates the color to use for the surface plot. Hence, it is generated using the your function cc.
pz = 1./(1+(exp(-py_)/(exp(-y_vec(i))-exp(-x_vec(i)))));
pz = repmat(pz',1,resolution(2));
Set Z values for points outside the area of interest to NaN so MATLAB won't plot them.
pz(~in) = nan;
Generate a bounded colourmap (delete if you want to use full colour range)
% generate colormap
c = jet(100);
[s,l] = bounds(pz,'all');
s = round(s*100);
l = round(l*100);
if s ~= 0
c(1:s,:) = [];
end
if l ~= 100
c(l:100,:) = [];
end
Finally, plot.
figure;
colormap(jet)
surf(px,py,pz,'edgecolor','none');
view(2) % x-y view
Feel free to turn the image arround to see how it looks like in the Z-dimention - beautiful :)
Full code to test:
i=50;
cc = #(xx,x,y) 1./(1+(exp(-xx)/(exp(-x)-exp(-y))));
n_vec = 2:0.1:10;
x_vec = linspace(2,10,length(n_vec));
y_vec = abs(sin(n_vec));
% generate grid
y = [x_vec(:); y_vec(:)];
resolution = [500,500];
px_ = linspace(min(n_vec), max(n_vec), resolution(1));
py_ = linspace(min(y), max(y), resolution(2));
[px, py] = meshgrid(px_, py_);
% extract points
in = inpolygon(px, py, N, X);
% generate z
pz = 1./(1+(exp(-py_)/(exp(-y_vec(i))-exp(-x_vec(i)))));
pz = repmat(pz',1,resolution(2));
pz(~in) = nan;
% generate colormap
c = jet(100);
[s,l] = bounds(pz,'all');
s = round(s*100);
l = round(l*100);
if s ~= 0
c(1:s,:) = [];
end
if l ~= 100
c(l:100,:) = [];
end
% plot
figure;
colormap(c)
surf(px,py,pz,'edgecolor','none');
view(2)
You can use imagesc and meshgrids. See comments in the code to understand what's going on.
Downsample your data
% your initial upper and lower boundaries
n_vec_long = linspace(2,10,1000000);
f_ub_vec_long = linspace(2, 10, length(n_vec_long));
f_lb_vec_long = abs(sin(n_vec_long));
% downsample
n_vec = linspace(n_vec_long(1), n_vec_long(end), 1000); % for example, only 1000 points
% get upper and lower boundary values for n_vec
f_ub_vec = interp1(n_vec_long, f_ub_vec_long, n_vec);
f_lb_vec = interp1(n_vec_long, f_lb_vec_long, n_vec);
% x_vec for the color function
x_vec = 0:0.01:10;
Plot the data
% create a 2D matrix with N and X position
[N, X] = meshgrid(n_vec, x_vec);
% evaluate the upper and lower boundary functions at n_vec
% can be any function at n you want (not tested for crossing boundaries though...)
f_ub_vec = linspace(2, 10, length(n_vec));
f_lb_vec = abs(sin(n_vec));
% make these row vectors into matrices, to create a boolean mask
F_UB = repmat(f_ub_vec, [size(N, 1) 1]);
F_LB = repmat(f_lb_vec, [size(N, 1) 1]);
% create a mask based on the upper and lower boundary functions
mask = true(size(N));
mask(X > F_UB | X < F_LB) = false;
% create data matrix
Z = NaN(size(N));
% create function that evaluates the color profile for each defined value
% in the vectors with the lower and upper bounds
zc = #(X, ub, lb) 1 ./ (1 + (exp(-X) ./ (exp(-ub) - exp(-lb))));
CData = zc(X, f_lb_vec, f_ub_vec); % create the c(x) at all X
% put the CData in Z, but only between the lower and upper bound.
Z(mask) = CData(mask);
% normalize Z along 1st dim
Z = normalize(Z, 1, 'range'); % get all values between 0 and 1 for colorbar
% draw a figure!
figure(1); clf;
ax = axes; % create some axes
sc = imagesc(ax, n_vec, x_vec, Z); % plot the data
ax.YDir = 'normal' % set the YDir to normal again, imagesc reverses it by default;
xlabel('n')
ylabel('x')
This already looks kinda like what you want, but let's get rid of the blue area outside the boundaries. This can be done by creating an 'alpha mask', i.e. set the alpha value for all pixels outside the previously defined mask to 0:
figure(2); clf;
ax = axes; % create some axes
hold on;
sc = imagesc(ax, n_vec, x_vec, Z); % plot the data
ax.YDir = 'normal' % set the YDir to normal again, imagesc reverses it by default;
% set a colormap
colormap(flip(hsv(100)))
% set alpha for points outside mask
Calpha = ones(size(N));
Calpha(~mask) = 0;
sc.AlphaData = Calpha;
% plot the other lines
plot(n_vec, f_ub_vec, 'k', n_vec, f_lb_vec, 'k' ,'linewidth', 1)
% set axis limits
xlim([min(n_vec), max(n_vec)])
ylim([min(x_vec), max(x_vec)])
there is no importance to the functional form of the curves, I would prefer an answer which refers to two general arrays which consist the curves.
It is difficult to achieve this using patch.
However, you may use scatter plots to "fill" the area with coloured dots. Alternatively, and probably better, use surf plot and generate z coordinates using your cc function (See my seperate solution).
The scatter plot method
First, make a grid of points (resolution 500*500) inside the rectangular space bounding the two curves.
y = [x_vec(:); y_vec(:)];
resolution = [500,500];
px = linspace(min(n_vec), max(n_vec), resolution(1));
py = linspace(min(y), max(y), resolution(2));
[px, py] = meshgrid(px, py);
figure;
scatter(px(:), py(:), 1, 'r');
The not-interesting figure of the point grid:
Next, extract the points inside the polygon defined by the two curves.
in = inpolygon(px, py, N, X);
px = px(in);
py = py(in);
hold on;
scatter(px, py, 1, 'k');
Black points are inside the area:
Finally, create color and plot the nice looking gradient colour figure.
% create color for the points
cid = 1./(1+(exp(-py)/(exp(-y_vec(i))-exp(-x_vec(i)))));
c = jet(101);
c = c(round(cid*100)+1,:); % +1 to avoid zero indexing
% plot
figure;
scatter(px,py,16,c,'filled','s'); % use size 16, filled square markers.
Note that you may need a fairly dense grid of points to make sure the white background won't show up. You may also change the point size to a bigger value (won't impact performance).
Of cause, you may use patch to replace scatter but you will need to work out the vertices and face ids, then you may patch each faces separately with patch('Faces',F,'Vertices',V). Using patch this way may impact performance.
Complete code to test:
i=50;
cc = #(xx,x,y) 1./(1+(exp(-xx)/(exp(-x)-exp(-y))));
n_vec = 2:0.1:10;
x_vec = linspace(2,10,length(n_vec));
y_vec = abs(sin(n_vec));
% generate point grid
y = [x_vec(:); y_vec(:)];
resolution = [500,500];
px_ = linspace(min(n_vec), max(n_vec), resolution(1));
py_ = linspace(min(y), max(y), resolution(2));
[px, py] = meshgrid(px_, py_);
% extract points
in = inpolygon(px, py, N, X);
px = px(in);
py = py(in);
% generate color
cid = 1./(1+(exp(-py)/(exp(-y_vec(i))-exp(-x_vec(i)))));
c = jet(101);
c = c(round(cid*100)+1,:); % +1 to avoid zero indexing
% plot
figure;
scatter(px,py,16,c,'filled','s');
I am saving two matlab figures as png and I want them to have the same size in order to be perfectly superposable.
The first figure is computed by the function 'FilledCircle2' which is a circle divided in half with two colors.
The second figure is computed by function 'FilledCircleL' which is the left half of the circle computed by the function 'FilledCircle2'.
I want to be able to have two figures, both with the same size so they can be perfectly superposed.
Can someone help me understand what I am doing wrong?
Here is my code, with both of the functions and respective outputs:
function []=FilledCircle2(x0,y0,Radius,N, col1, col2)
if(N<=1)
error('N must be greater than 1');
end
hold on
axis equal
axis off
hold on
t=(0:N)*2*pi/N; %t=-pi:0.01:pi
x=Radius*cos(t)+x0;
y=Radius*sin(t)+y0;
plot(x,y)
hold on
%Divide circle in to 2 equal parts
n=2;
thetas = linspace(-pi, pi,n+1); %linspace generates n points. The space between the points is [(pi/2)-(-pi/2)]/(n)
% Specify any colors wanted
colors = [col1; col2];
for k = 1:n
tt = linspace(thetas(k), thetas(k+1));
xi = Radius * cos(tt) + x0;
yi = Radius * sin(tt) + y0;
c2= fill([xi(:); x0], [yi(:); y0], colors(k,:)); %Assign diffrent colors to each circle 'slice'
set (c2, 'edgecolor','white')
set(c2,'LineWidth',2.0)
set(gcf,'PaperUnits','inches','PaperSize',[0.8666,0.8666],'PaperPosition',[0 0 0.8666 0.8666])%setting size (130/150, 130/150, 150pixels per inch being the default size of img), paper position is imporrtant as otherwise i will have extra border
set(gca, 'Position', [0 0 1 1]);
set(gcf,'color',[0.49019607843137 0.49019607843137 0.49019607843137])%figure properties, rgb(125/255,125/255,125/255)
fig = gcf;
fig.InvertHardcopy = 'off'; %saves the fig with the set background color
%rotates the plot
az= 90; %azimuth, az, is the horizontal rotation about the z axis as measured in degrees from the negative y-axis. Positive values indicate counterclockwise rotation
el= 90; % vertical elevation of the view point in degrees
view(az,el);
hold on
end
Here is the output of the function FilledCircle2(0,0,10,300, 'y', 'r'):
[
function []=HalfFilledCircleL(x0,y0,Radius,N, col1)
if(N<=1)
error('N must be greater than 1');
end
hold on
axis equal
% axis tight
axis off
hold on
t=(0:N)*(-pi)/N; %t=-pi:0.01:pi
x=Radius*cos(t)+x0;
y=Radius*sin(t)+y0;
hold on
c1=fill(x,y,col1); %filling the semi-circle
set (c1, 'edgecolor','white') %setting the outline color of the semi-circle
set(gcf,'color',[0.49019607843137 0.49019607843137 0.49019607843137])%figure properties, rgb(125/255,125/255,125/255)
set(c1,'LineWidth',2.0)
set(gcf,'PaperUnits','inches','PaperSize',[0.8666,0.8666],'PaperPosition',[0 0 0.8666,0.8666])%setting size (130/150, 130/150, 150pixels per inch being the default size of img), paper position is imporrtant as otherwise i will have extra border
set(gca, 'Position', [0 0 1 1]);
fig = gcf;
fig.InvertHardcopy = 'off'; %saves the fig with the set background color
% %rotates the plot
az= 90; %azimuth, az, is the horizontal rotation about the z axis as measured in degrees from the negative y-axis. Positive values indicate counterclockwise rotation
el= 90; % vertical elevation of the view point in degrees
view(az,el);
end
Here is the output of the function HalfFilledCircleL(0,0,10,300, 'r'):
use xlim and ylim to set the xy limits of the axes:
figure;
HalfFilledCircleL(0,0,10,300, 'r');
xlim([-12 12]);ylim([-12 12]);
az= -90; %azimuth, az, is the horizontal rotation about the z axis as measured in degrees from the negative y-axis. Positive values indicate counterclockwise rotation
el= 90; % vertical elevation of the view point in degrees
view(az,el);
figure;
FilledCircle2(0,0,10,300, 'y', 'r');
xlim([-12 12]);ylim([-12 12]);
The following code creates a 2D stacked histogram for two 2D distributions:
%%first dataset
x1 = 200 + 300.*rand(1000,1)'; %rand values between 0 and 200
y1 = 100 + 250.*rand(1000,1)'; %rand values between 100 and 500
%%secnd dataset
x2 = 100 + 200.*rand(1000,1)'; %rand values between 0 and 200
y2 = 200 + 400.*rand(1000,1)'; %rand values between 100 and 500
one = linspace(100,400,20);
two = linspace(100,500,20);
EDGES = {one, two}; %edges
[n1,c1] = hist3([x1' y1'],'Edges',EDGES);%first dataset
[n2,c2] = hist3([x2' y2'],'Edges',EDGES);%second dataset
figure('Color','w');
% plot the first data set
bh=bar3(n1);
% Loop through each row and shift bars upwards
for ii=1:length(bh)
zz = get(bh(ii),'Zdata');
kk = 1;
% Bars are defined by 6 faces(?), adding values from data2 will
% shift the bars upwards accordingly, I'm sure this could be made
% better!
for jj = 0:6:(6*length(bh)-6)
zz(jj+1:jj+6,:)=zz(jj+1:jj+6,:)+n2(kk,ii);
kk=kk+1;
end
%erase zero height bars
%# get the ZData matrix of the current group
Z = get(bh(ii), 'ZData');
%# row-indices of Z matrix. Columns correspond to each rectangular bar
rowsInd = reshape(1:size(Z,1), 6,[]);
%# find bars with zero height
barsIdx = all([Z(2:6:end,2:3) Z(3:6:end,2:3)]==0, 2);
%# replace their values with NaN for those bars
Z(rowsInd(:,barsIdx),:) = NaN;
%# update the ZData
set(bh(ii), 'ZData',Z)
end
% Set face colour to blue for data1
set(bh,'FaceColor',[0 0 1]);
% Apply hold so that data2 can be plotted
hold on;
% Plot data2
bh=bar3(n2);
%erase zero height bars
for ii=1:numel(bh)
%# get the ZData matrix of the current group
Z = get(bh(ii), 'ZData');
%# row-indices of Z matrix. Columns correspond to each rectangular bar
rowsInd = reshape(1:size(Z,1), 6,[]);
%# find bars with zero height
barsIdx = all([Z(2:6:end,2:3) Z(3:6:end,2:3)]==0, 2);
%# replace their values with NaN for those bars
Z(rowsInd(:,barsIdx),:) = NaN;
%# update the ZData
set(bh(ii), 'ZData',Z)
end
% Set face color to red
set(bh,'FaceColor',[1 0 0]);
%set ticks
set(gca,'XTick',1:6:numel(one),'XTickLabel',one(1:6:end))
set(gca,'YTick',1:6:numel(one),'YTickLabel',one(1:6:end))
view(20,40)
%labels
xlabel('x')
ylabel('y')
zlabel('z')
%set transparency
set(gcf,'renderer','opengl');
set(get(gca,'child'),'FaceAlpha',0.8);
set(get(gca,'child'),'EdgeAlpha',0.3);
A first issue is the transparency (but I think it is a problem of my matlab version 2014a, so I am not bothered by that). It just makes all blurry.
My question is how to add a mesh plot on the same picture. The code creating the meshes is the following:
%create surface I want to plot
[X,Y] = meshgrid(one,two);
inds1=find(X(:).*Y(:)<.3e5);%condition
inds2=find(X(:).*Y(:)>.3e5);
I=Y./X.^2;%first surface
I(inds1)=NaN;%second surface
figure('Color','w');hold on
mesh(X,Y,I,'FaceColor',[0 0 1],'EdgeColor','none')
I(:,:)=NaN;
I(inds1)=Y(inds1)./X(inds1);%second surface
mesh(X,Y,I,'FaceColor',[1 0 0],'EdgeColor','none')
alpha(.5)
grid on
view(20,40)
%labels
xlabel('x')
ylabel('y')
zlabel('z')
The domain of the histograms and the meshes are the same. So I just need to add an extra z-axis on the first figure.
I tried substituting figure('Color','w');hold on in the second code with AxesH = axes('NextPlot', 'add');, but I was really wrong about that:
That just overlayed the two figures..
I also tried something along the lines of:
%add axis
axesPosition = get(gca,'Position'); %# Get the current axes position
hNewAxes = axes('Position',axesPosition,... %# Place a new axes on top...
'Color','none',... %# ... with no background color
'ZLim',[0 400],... %# ... and a different scale
'ZAxisLocation','right',... %# ... located on the right
'XTick',[],... %# ... with no x tick marks
'YTick',[],... %# ... with no y tick marks
'Box','off');
but it is not feasible because the property ZAxisLocation does not exist.
Does anyone know how to add the z-axis?
Also, if you have other comments on how to ameliorate the code, they're welcome!
acknowledgements
2d stacked histogram:https://stackoverflow.com/a/17477348/3751931
erasing the zero values in the hist plot: https://stackoverflow.com/a/17477348/3751931
I now think that this is not yet possible (http://www.mathworks.com/matlabcentral/answers/95949-is-there-a-function-to-include-two-3-d-plots-with-different-z-axes-on-the-same-plot-area-similar-to).
So I just added a fake axis:
[X,Y] = meshgrid(one,two);
inds1=find(X(:).*Y(:)<.3e5);%condition
inds2=find(X(:).*Y(:)>.3e5);
s=Y./X.^2;%first surface
s(inds1)=NaN;%second surface
%mesh(X,Y,I,'FaceColor',[0 0 1],'EdgeColor','none')
mesh((X-min(min(X)))/max(max(X-min(min(X))))*20,(Y-min(min(Y)))/max(max(Y-min(min(Y))))*20,...
s/max(max(s))*max(max(n1))+max(max(n1)),'FaceColor','g','EdgeColor','none','facealpha',.5)
s(:,:)=NaN;
s(inds1)=Y(inds1)./X(inds1);%second surface
%mesh(X,Y,I,'FaceColor',[1 0 0],'EdgeColor','none')
mesh((X-min(min(X)))/max(max(X-min(min(X))))*20,(Y-min(min(Y)))/max(max(Y-min(min(Y))))*20,...
s/max(max(s))*max(max(n1))+max(max(n1)),'FaceColor','y','EdgeColor','none','facealpha',.5)
alpha(.5)
grid on
%add fake z axis
line([20 20],[1 1],[max(max(n1))-min(min(s)) 20],...
'color','g','linewidth',2)
% text(20*ones(1,5),zeros(1,5),linspace(max(max(n1))-min(min(I)),20,5),...
% num2str(linspace(0,max(max(I)),5)),'color','g')
z=linspace(max(max(n1))-min(min(s)),20,5);
txto=linspace(0,max(max(s)),5);
for ii=1:5
line([20 20.3],[1 1],[z(ii) z(ii)],'color','g')%ticks
text(20,0,z(ii),num2str(txto(ii)),'color','g')%ticklabel
end
text(19.8,1,21,'s','color','g')%label
Over all the code is quite ugly and needs a lot of tuning..
Hello and pardon me if my english is a bit rusty. I'm trying to create a circle that moves along a parametric function (coordinates are stored in vectors). I have written a function for drawing the circle and I know that you can use the axis equal command in matlab in order to create a circle shape and avoid an ellipse. My problem is that when I do this the figure window becomes very wide relative to the plotted graph. Any input is appreciated.
MAIN CODE:
t = linspace(0,3);
x = 30*cos(pi/4)/2*(1-exp(-0.5*t));
y = (30*sin(pi/4)/2 + 9.81/0.5^2)*(1-exp(0.5*t)) - 9.81*t/0.5;
for i = 1:length(t)
plot(x,y)
axis equal
hold on
cirkel(x(i),y(i),1,1,'r') % argument #3 is the radius #4 is 1 for fill
hold off
pause(0.01)
end
CIRCLE CODE:
function cirkel(x,y,r,f,c)
angle = linspace(0, 2*pi, 360);
xp = x + r*cos(angle);
yp = y + r*sin(angle);
plot(x,y)
if f == 1 && nargin == 5
fill(xp,yp,c)
end
When you call axis equal it makes one unit of the x axis be the same size as one unit of the y axis. You are seeing what you are because your y values span a much larger range than the x values.
One way to deal with this would be to query the aspect ratio and x/y limits of the current axes as shown in the second part of this answer. However, an easier approach is rather than using fill to plot your circle, you could instead use scatter with a circular marker which will be circular regardless of the aspect ratio of your axes.
t = linspace(0,3);
x = 30*cos(pi/4)/2*(1-exp(-0.5*t));
y = (30*sin(pi/4)/2 + 9.81/0.5^2)*(1-exp(0.5*t)) - 9.81*t/0.5;
% Plot the entire curve
hplot = plot(x, y);
hold on;
% Create a scatter plot where the area of the marker is 50. Store the handle to the plot
% in the variable hscatter so we can update the position inside of the loop
hscatter = scatter(x(1), y(1), 50, 'r', 'MarkerFaceColor', 'r');
for k = 1:length(t)
% Update the location of the scatter plot
set(hscatter, 'XData', x(k), ... % Set the X Position of the circle to x(k)
'YData', y(k)) % Set the Y Position of the circle to y(k)
% Refresh the plot
drawnow
end
As a side note, it is best to update existing plot objects rather than creating new ones.
If you want the small dot to appear circular, and you want to have a reasonable domain (x-axis extent), try this:
function cirkel(x,y,r,f,c)
angle = linspace(0, 2*pi, 360);
xp = x + 0.04*r*cos(angle); %% adding scale factor of 0.04 to make it appear circular
yp = y + r*sin(angle);
plot(x,y)
if f == 1 && nargin == 5
fill(xp,yp,c)
end
Note the addition of the scale factor in the computation of xp. If you want to automate this, you can add another parameter to cirkel(), let's call it s, that contains the scale factor. You can calculate the scale factor in your script by computing the ratio of the range to the domain (y extent divided by x extent).
I'm doing Gaussian processes and I calculated a regression per year from a given matrix where each row represents a year , so the code is:
M1 = MainMatrix; %This is the given Matrix
ker =#(x,y) exp(-1013*(x-y)'*(x-y));
[ns, ms] = size(M1);
for N = 1:ns
x = M1(N,:);
C = zeros(ms,ms);
for i = 1:ms
for j = 1:ms
C(i,j)= ker(x(i),x(j));
end
end
u = randn(ms,1);
[A,S, B] = svd(C);
z = A*sqrt(S)*u; % z = A S^.5 u
And I wanna plotting each regression in a Graph 3D as the below:
I know that plot is a ribbon, but I have not idea how can I do that
The desired plot can be generated without the use of ribbon. Just use a surf-plot for all the prices and a fill3-plot for the plane at z=0. The boundaries of the plane are calculated from the actual limits of the figure. Therefore we need to set the limits before plotting the plane. Then just some adjustments are needed to generate almost the same appearance.
Here is the code:
% generate some data
days = (1:100)';
price = days*[0.18,-0.08,0.07,-0.10,0.12,-0.08,0.05];
price = price + 0.5*randn(size(price));
years = 2002+(1:size(price,2));
% prepare plot
width = 0.6;
X = ones(size(price,1),1)*0.5;
X = [-X,X]*width;
figure; hold on;
% plot all 'ribbons'
for i = 1:size(price,2)
h = surf([days,days],X+years(i),[price(:,i),price(:,i)]);
set(h,'MeshStyle','column');
end
% set axis limits
set(gca,'ZLim',[-20,20]);
% plot plane at z=0
limx = get(gca,'XLim');
limy = get(gca,'YLim');
fill3(reshape([limx;limx],1,[]),[flip(limy),limy],zeros(1,4),'g','FaceAlpha',0.2)
% set labels
xlabel('Day of trading')
ylabel('Year')
zlabel('Normalized Price')
% tweak appearance
set(gca,'YTick',years);
set(gca,'YDir','reverse');
view([-38,50])
colormap jet;
grid on;
%box on;
This is the result:
That's a ribbon plot with an additional surface at y=0 which can be drawn with fill3