I am doing some analysis and need to produce a histogram plot. I know how to create the standard histogram plot but I need something like the image below, where each point is an interval on the x axis. Each bin is based on a value from x-x for example.
You can use the histogram function, and then set the XTick positions and XTickLabels accordingly. See the comments in the code for explanation.
% random normally distrubuted data
x = 1*randn(1000,1);
edges = -5:1:5;
% create vector with labels (for XTickLabel ... to ...)
labels = [edges(1:end-1); edges(2:end)];
labels = labels(:);
% plot the histogram
figure();
ax = axes;
h = histogram(x, 'BinEdges', edges, 'Normalization', 'Probability');
ax.XTick = edges + mean(diff(edges)/2);
ax.XTickLabel = sprintf('%.1f to %.1f\n', labels);
ax.XTickLabelRotation = 90;
% set yticks to percentage
ax.YTickLabel = cellfun(#(a) sprintf('%i%%', (str2double(a)*100)), ax.YTickLabel, 'UniformOutput', false);
% text above bars
bin_props = h.BinCounts/numel(x); % determine probabilities per bin in axis units
bin_centers = ax.XTick(1:end-1); % get the bin centers
txt_heigts = bin_props + 0.01; % put the text slightly above the bar
txt_labels = split(sprintf('%.1f%% ', bin_props*100), ' ');
txt_labels(end) = []; % remove last cell, is empty because of split.
text(ax, bin_centers, txt_heigts, txt_labels, 'HorizontalAlignment', 'center')
% set ylim to fit all text (otherwise text is outside axes)
ylim([0 .4]);
Putting the text at the right location may require some tweaking. Most important is the 'HorizontalAlignment' option, and the distance to the bars. I also used the 'Normalization', 'probability' option from the histogram function, and set the y axis to also show percentages.
I figure you can make the addition below yourself when needed.
When your data can be outside of the defined binedges, you can clip your data, and set the XTickLabels with less than or greater than signs.
% when data can be outside of defined edges
x = 5*randn(1000,1);
xclip = x;
xclip(x >= max(edges)) = max(edges);
xclip(x <= min(edges)) = min(edges);
% plot the histogram
figure();
ax = axes;
h = histogram(xclip, 'BinEdges', edges);
ax.XTick = edges + mean(diff(edges)/2);
ax.XTickLabel = sprintf('%.1f to %.1f\n', labels);
ax.XTickLabelRotation = 90;
% set boundary labels
ax.XTickLabel{1} = sprintf('\\leq %.1f', edges(2));
ax.XTickLabel{end-1} = sprintf('\\geq %.1f', edges(end-1));
You can also set the outer edges to -Inf and Inf, as user2305193 pointed out. Since the outer bins are then much wider (because they actually extend to Inf on the x axis), which you can correct by setting the axis xlim. By the default the XTickLabels will display -Inf to -5.0, which I personally don't like, so I set them to lesser (and equal) than and greater than signs.
step = 1;
edges = -5:step:5; % your defined range
edges_inf = [-Inf edges Inf]; % for histogram
edges_ext = [edges(1)-step edges]; % for the xticks
x = 5*randn(1000,1);
% plot the histogram
figure();
ax = axes;
h = histogram(x, 'BinEdges', edges_inf, 'Normalization', 'probability');
labels = [edges_inf(1:end-1); edges_inf(2:end)];
labels = labels(:);
ax.XTick = edges_ext + step/2;
ax.XTickLabel = sprintf('%.1f to %.1f\n', labels);
ax.XTickLabelRotation = 90;
% show all bins with equal width (Inf bins are in fact wider)
xlim([min(edges)-step max(edges)+step])
% set boundary labels
ax.XTickLabel{1} = sprintf('\\leq %.1f', edges(1));
ax.XTickLabel{end-1} = sprintf('\\geq %.1f', edges(end));
Related
How can I build my own function in Matlab that does the same work as the Matlab built-in function 'semilogx'?
Example: in this example both fig.1 and fig.2 plot x as a log scale but the values on the x-axis of fig.1 are not correct. So the question is "how can I make the values in fig.1 same as the values in fig.2 without using semilogx?"
x = 0:1000;
y = 2*x;
figure(1), plot(log10(x), y)
figure(2), semilogx(x,y)
I guess in my example above: in Fig.1 x limit is between [0,3] and in Fig.2 x limit is between [0,1000]. What I understand is that x limit should be [0:1000] but when we use log scale this would change to [0,3] so the semilogx function only maps the [0,3] limit to [0,1000]
Basically you have to reconstruct the x-axis tick mark locations and the corresponding tick labels on a log-scaled grid:
% Some data
x = 1:1000;
y = cumsum(rand(size(x)));
% For comparison
subplot(311); plot(log10(x), y)
subplot(312); semilogx(x,y)
% Simulated semilogx plot
subplot(313); plot(log10(x), y)
ax = gca; % Get a handle to the axis for tick modifications
% Compute tick mark locations in log10 scale
logxmax = ceil(log10(x(end)));
ticks = log10(1:9);
ticks = ticks' + (0:logxmax-1);
ticks = [ticks(:); logxmax];
% Set tick marks and labels
ax.XTick = ticks;
ax.XLim = [0 logxmax];
% Reset tick labels
ax.XTickLabel(:) = ''; % clear all tick labels
I = 1+9*(0:logxmax); % Tick labels for 10^n locations
S = arrayfun(#(x)'10^{'+string(x)+'}', (0:logxmax), 'UniformOutput', false);
ax.XTickLabel(I) = S;
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');
Data Plot
%% Data
% Imports the array data (x and y) to the workspace by loading Excel data
% that has been imported and converted to *.mat format.
load('900day_r') % y data.
load('x_degreesb'); % x axis data
%% Remove non linear trends
opol = 0;% Degree of filtering on original profile
[p,s,mu] = polyfit(x_degreesb,x900day_r,opol);
f_y = polyval(p,x_degreesb,[],mu);
x900day_r = x900day_r - f_y;
max_x = max(x900day_r);% Find maximum in array
x900day_r = x900day_r/max_x;% Normalize height to max
min_x = min(x900day_r);% Find minimum in array
x900day_r = x900day_r - min_x;% Shift profile (lowest value in array = 0)
%% Find Peaks & Valleys
[pks, locs] = findpeaks(x900day_r); % returns peaks & locations
x900day_r_Inv = max(x900day_r)-x900day_r; % invert y data
vlys = max(vlys)-vlys; % invert data for valley markers
%% Plot Profile
% Plot profile and markers for peaks
plot(x_degreesb,x900day_r,'b',x_degreesb(locs),pks+0.04,'v','markersize',5,'markerfacecolor','b','linewidth',1);
hold on
% Plot profile and markers for valleys
plot(x_degreesb(min_locs),vlys-0.04,'^','markersize',5,'markerfacecolor','b','linewidth',1);
% Plot characteristics
axis('tight') % Makes the graph fill the figure.
grid on % Turns the grid on (major not minor).
% Sets up the figure (fig) for display
fig = gca;
set(fig,'fontname','Bodoni 72','fontsize',20);
% Set y limits to auto. Set x limits and x tick marks
ylim('auto'); % Sets the y limits
xlim([0, 360]); % Sets the x limits from 0 to 360
set (fig, 'XTick', [0, 45, 90, 135, 180, 225, 270, 315, 360]) % Sets x axis tick marks
% Set fig for presentation appearance
x = xlabel('$Location On Cylinder Perimiter {[degrees]}$'); % x label.
y = ylabel('$Curve Height {[mm]}$'); % y label.
t = title('$900 Days Cylinder$ r'); % Title (presentation fraction).
% Set vertical lines at quadrant boundaries
hold on
x1 = 90;
x2 = 180;
x3 = 270;
x4 = 360;
y1 = get(gca, 'ylim');
plot ([x1 x1],y1,'k')%Caudal Medial(0:90)
plot ([x2 x2],y1,'k')%Cranial Medial(90:180)
plot ([x3 x3],y1,'k')%Cranial Lateral(180:270)
plot ([x4 x4],y1,'k')%Cadual Lateral(270:360)
hold on
% Interpretation of text characters for presentation
set(t,'Interpreter','Latex');
set(x,'Interpreter','Latex');
set(y,'Interpreter','Latex');
%% Isolate Cranial Medial & Lateral Section of Profile
x = x_degreesb;% Quadrant data
y = x900day_r;% Profile data
indx = (x >= 90) & (x <= 270);% Index section
[pks, locs, widths, proms] = findpeaks(y(indx));% Find peaks in section
Rmax = max(pks);% Find maximum peak
Rmin = min(y(indx));% Find minimum in section
CL = (Rmax + Rmin)/2;% Center line of sectioned profile
%% Plot Center Line
hold on
x1 = 90;
x2 = 270;
y1 = CL;
plot ([x1 x2],[y1 y1],'r','linewidth',1.5);
%% Plot Rmax
hold on
x1 = 90;
x2 = 270;
y1 = Rmax;
plot ([x1 x2],[y1 y1],'k','linewidth',1.5);
%% Plot Rmin
hold on
x1 = 90;
x2 = 270;
y1 = Rmin;
plot ([x1 x2],[y1 y1],'k','linewidth', 1.5);
%% Highlight Region of Interest
%subplot(2,1,2)
x = x_degreesb;% Quadrant data
y = x900day_r;% Profile data
indx = (x >= 90) & (x <= 270);% Index section
plot(x(indx),y(indx),'k','linewidth',2)% Plot 90:270 curve in black
level = CL;% set the centerline as the level for area shading
% Shade the area of the curve in the indexed section grey [.7 .7 .7] above the level CL
area(x(indx), max(y(indx), level),level, 'EdgeColor', 'none', 'FaceColor',[.7 .7 .7],'showbaseline', 'off');
% Shade the area of the curve in the indexed section dark grey below the level CL
area(x(indx), min(y(indx), level),level, 'EdgeColor', 'none', 'FaceColor',[.5 .5 .5],'showbaseline','off');
Does anyone know how I can find the area above (light grey) and below (dark grey) the centerline (red) for the specific range between 90:270 using MATLAB? I have been trying to use trapz, setting the level (red line in Data Plot picture) but can't seem to get trapz to calculate just the highlighted areas. I posted the code, but not the data, as its a rather large set of data that makes up the curve. Any help would be greatly appreciated!
RP
#Some Guy: Thanks for the quick responses. Here is an example script that you can run. You can change the ratio of blue area to grey area by changing the level value. In pic 1 with level set to 2 they should be equal. In pic 2 blue should be more than grey with level set to 1.6. Thats what I was trying to do. Any thoughts?
%% Example
x = 0:.01:4*pi;% x data
y = sin(x)+2;% y data
level = 1.6;% 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');
y_above = max(y_interest - level,0); % Take only the part of curve above y_split
y_below = max(-y_above,0); % Take the part below y_split
A_above = trapz(y_above)
A_below = trapz(y_below)
If I had data in a vector y and a scalar y_split at which I wanted to split I would do:
y_above = y - y_split;
y_below = max(-y_above,0); % Take the part below y_split
y_above = max(y_above,0); % Take the part above y_split
A_above = trapz(y_above);
A_below = trapz(y_below);
You can plot y_above and y_below to make sure you are integrating as you intend to.
EDIT: With OPs example script the areas with level = 2 is:
A_above =
399.9997
A_below =
399.9976
And level = 1.6 is
A_above =
683.5241
A_below =
181.1221
I have about four series of data on a Matlab plot, two of them are quite close and can only be differentiated with a zoom. How do I depict the zoomed part within the existing plot for the viewer. I have checked similar posts but the answers seem very unclear.
I look for something like this:
Here is a suggestion how to do this with MATLAB. It may need some fine tuning, but it will give you the result:
function pan = zoomin(ax,areaToMagnify,panPosition)
% AX is a handle to the axes to magnify
% AREATOMAGNIFY is the area to magnify, given by a 4-element vector that defines the
% lower-left and upper-right corners of a rectangle [x1 y1 x2 y2]
% PANPOSTION is the position of the magnifying pan in the figure, defined by
% the normalized units of the figure [x y w h]
%
fig = ax.Parent;
pan = copyobj(ax,fig);
pan.Position = panPosition;
pan.XLim = areaToMagnify([1 3]);
pan.YLim = areaToMagnify([2 4]);
pan.XTick = [];
pan.YTick = [];
rectangle(ax,'Position',...
[areaToMagnify(1:2) areaToMagnify(3:4)-areaToMagnify(1:2)])
xy = ax2annot(ax,areaToMagnify([1 4;3 2]));
annotation(fig,'line',[xy(1,1) panPosition(1)],...
[xy(1,2) panPosition(2)+panPosition(4)],'Color','k')
annotation(fig,'line',[xy(2,1) panPosition(1)+panPosition(3)],...
[xy(2,2) panPosition(2)],'Color','k')
end
function anxy = ax2annot(ax,xy)
% This function converts the axis unites to the figure normalized unites
% AX is a handle to the figure
% XY is a n-by-2 matrix, where the first column is the x values and the
% second is the y values
% ANXY is a matrix in the same size of XY, but with all the values
% converted to normalized units
pos = ax.Position;
% white area * ((value - axis min) / axis length) + gray area
normx = pos(3)*((xy(:,1)-ax.XLim(1))./range(ax.XLim))+ pos(1);
normy = pos(4)*((xy(:,2)-ax.YLim(1))./range(ax.YLim))+ pos(2);
anxy = [normx normy];
end
Note that the units of areaToMagnify are like the axis units, while the units of panPosition are between 0 to 1, like the position property in MATLAB.
Here is an example:
x = -5:0.1:5;
subplot(3,3,[4 5 7 8])
plot(x,cos(x-2),x,sin(x),x,-x-0.5,x,0.1.*x+0.1)
ax = gca;
area = [-0.4 -0.4 0.25 0.25];
inlarge = subplot(3,3,3);
panpos = inlarge.Position;
delete(inlarge);
inlarge = zoomin(ax,area,panpos);
title(inlarge,'Zoom in')
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