Matlab: Adding third dimenstion to 2D plot - matlab

I have the following code to generate me a 2D plot or 2 normal distributions:
res = zeros(2, 320);
index = 1:320;
% assign some data to the res array and then approximate:
PD = fitdist(index','normal', 'frequency', res(1,:)')
pdfNormal = normpdf(index',PD.mu,PD.sigma);
plot(index', pdfNormal, 'Color', 'r', 'LineWidth', 2);
hold on;
PD = fitdist(index','normal', 'frequency', res(2,:)')
pdfNormal = normpdf(index',PD.mu,PD.sigma);
plot(index', pdfNormal, 'Color', 'b', 'LineWidth', 2);
This code generates me then the following picture:
Now I am wondering how I could add a third dimension to this plot? Essentially,
I would like to plot another 2 normal distributions, but this time in the Z-axis,
ie., in the third dimension.
Anyone an idea how I could do that easily?
Thanks so much!

If I understood correctly, you can simply give the plots different z-values. Example:
%# some random data
x = 1:300;
y = zeros(5,300);
for i=1:5
y(i,:) = normpdf(x,100+i*20,10);
end
%# plot
hold on
clr = lines(5);
h = zeros(5,1);
for i=1:5
h(i) = plot(x, y(i,:), 'Color',clr(i,:), 'LineWidth',2);
set(h(i), 'ZData',ones(size(x))*i)
end
zlim([0 6]), box on, grid on
view(3)
hold off

Related

MATLAB Shading region between SEVERAL curves

There are many questions already on this site for something similar:
MATLAB, Filling in the area between two sets of data, lines in one figure
MATLAB fill area between lines
However, all of the existing questions relate to two curves only. How do you fill a region bounded by several curves that overlap each other?
A crude example would be:
% Create sample data as column vectors.
x = [1 : 100]';
curve1 = x/10;
curve2 = log(x/2) + rand(length(x), 1) - 0.5;
curve3 = log(x) + rand(length(x), 1) + 0.5;
% Plot it.
plot(x, curve1, 'r', 'LineWidth', 2);
hold on;
plot(x, curve2, 'b', 'LineWidth', 2);
plot(x, curve3, 'k', 'LineWidth', 2);
For the shading:
The upper limit would be the black curve followed by the red line.
The lower limit would be the blue curve (briefly), then the red line, followed by the blue curve.
In my actual dataset I have 10 curves which require a similar thing.
If I understand you correctly, you can do this by creating a min and max vectors of the area you want to shade, and use flipud to shade the region with fill
min_data=min([curve1,curve2,curve3],[],2);
max_data=max([curve1,curve2,curve3],[],2);
fill([x;flipud(x)],[min_data;flipud(max_data)],'g')
If I understood you correctly:
basevalue = min([curve1(:) ; curve2(:) ; curve3(:)]);
h = area([curve2 , curve1-curve2 , curve3-curve1],basevalue)
h(1).FaceColor = [1 1 1];
h(2).FaceColor = [0 0.5 0.5];
h(3).FaceColor = [1 1 1];
hold on
plot(x, curve1, 'r', 'LineWidth', 2);
plot(x, curve2, 'b', 'LineWidth', 2);
plot(x, curve3, 'k', 'LineWidth', 2);
ylim([ min([curve1(:) ; curve2(:) ; curve3(:)]); max([curve1(:) ; curve2(:) ; curve3(:)])])
So you need to play with area in a way that is consistent with what you want...

Computing the surface between two lines

I have the following figure, where I plotted two surfaces and I wanted to indicate the intersection of both of them. To do that, I did the following:
zdiff = z1-z2;
C = contours(x,y,zdiff,[0 0]);
xL = C(1, 2:end);
yL = C(2, 2:end);
zL = interp2(x, y, z1, xL, yL);
line(xL, yL, zL, 'Color', 'k', 'LineWidth', 2,'Linestyle','--'); hold on;
line(xL, yL, zeros(size(zL)), 'Color', 'k', 'LineWidth', 2); hold off;
Now, I want to plot the vertical surface between the actual intersection (dash line) and its projection over XY (solid line), but I cannot figure out how to do that. Any ideas?
Another really simple option:
dist = (diff(xL).^2+diff(yL).^2).^0.5; %distance between x,y
cdist = [0, cumsum(dist)]; %cumsum of the distance
area = trapz(cdist,zL); %The area
Why not calculating it manually?
Something like (untested):
Area = 0
for i=1:numel(xL)-1
base = sqrt( (xL(i)-xL(i+1))^2 + (yL(i)-yL(i+1))^2);
Area =Area + base * (zL(i) + zL(i+1))/2;
end;
maybe not pretty but its a oneliner it might do the trick. maybe you have to adjust the format as this code is for (1,N) vectors
xL=(1:100); %size 1 100
yL=(1:100) ;%size 1 100
zL=rand(1,100);%size 1 100
line(xL,yL,zL)
line(xL,yL,zeros(size(zL)))
hold on
surf(repmat(xL,100,1),repmat(yL,100,1),cell2mat(arrayfun(#(x,y) linspace(x,y,100)',zL,zeros(size(zL)),'UniformOutput',false)))
xL=sin((1:30)/10); % Data generation for test only. Use your data
yL=cos((1:30)/10); % Data generation for test only. Use your data
zL=2+xL.*yL; % Data generation for test only. Use your data
surf([xL;xL],[yL;yL],[zeros(size(zL));zL]); % plot the surface

How to smooth the edges in my contour plot corresponding to nan

This is the link to the dataset. I have this contour plot which has a bit rough edges. My question is, how can I smooth these edges these edges correspond to Nan. I filled in the Z matrix with Nan so as to remove unwanted values.
I also wanted to ask that why shading flat and interp is not working on this contour.
I have set shading to flat and in Matlab2013b I get proper flat figure but in Matlab 2014b and 2015b I am getting this figure.
MATLAB 2015b:
MATLAB 2013b
How can I obtain perfectly meshed plot in Matlab 2015b, I checked for shading options in the documentation and there are only 3 faceted, interp and flat.
shading flat works in 2013b but not in subsequent versions. Can someone tell me why is it so?
This is the sample code which I am using right now:
clear all; close all; clc;
load temperature.txt;
time = temperature(:,1); % This column contains the time
x = temperature(:,2); % This column contains the x values.
temperature_system = temperature(:,3); % This column contains the temperatures.
% Rejecting the outliers
pos = (temperature_system > prctile(temperature_system,97));
time(pos) = [];
x(pos) = [];
temperature_system(pos) = [];
X1 = [time x];
F = scatteredInterpolant(X1,temperature_system);
x1 = linspace(min(x),max(x),100);
x2 = linspace(min(time),max(time),100);
[X,Y] = meshgrid(x2,x1);
Z = F(X,Y);
% Is the data below the criteria for all points in space at a specific time
emptyTime = all(Z<10,1);
emptySpace = all(Z<10,2);
[emptyTime, emptySpace] = meshgrid(emptyTime, emptySpace);
Z(emptyTime | emptySpace) = nan;
% Replacing the remaining zeros with nan
pos = find(Z<1);
Z(pos) = nan;
f1 = figure(1);
%set(f1,'renderer','zbuffer');
%surf(X,Y,Z);
[C,h] = contourf(X,Y,Z, 'Linestyle', 'none');
shading flat;
colormap(jet);
q = colorbar;
set(q,'direction','reverse');
q.Label.String = 'Temperature';
xlabel('Time (ps)','FontSize', 16, 'FontWeight', 'bold',...
'FontName', 'Helvetica', 'Color', 'Black');
ylabel('Length of box (A)','FontSize', 16, 'FontWeight', 'bold',...
'FontName', 'Helvetica', 'Color', 'Black');
set(gca,'LineWidth',3,'TickLength',[0.02 0.02]);
set(gca,'XMinorTick','on');
set(gca,'YMinorTick','on','XTicksBetween', 5);
set(gca,'FontSize',12,'FontName','Helvetica');
It's difficult to test the issue without having your data. I got rid of the lines by means of the LineStyle property:
Code:
Z = peaks(20);
subplot(2,1,1);
contourf(Z,10);
colorbar;
subplot(2,1,2);
contourf(Z,10, 'LineStyle', 'none');
colorbar;

How to create three Y-axis in one graph? [duplicate]

I have 4 sets of values: y1, y2, y3, y4 and one set x. The y values are of different ranges, and I need to plot them as separate curves with separate sets of values on the y-axis.
To put it simple, I need 3 y-axes with different values (scales) for plotting on the same figure.
Any help appreciated, or tips on where to look.
This is a great chance to introduce you to the File Exchange. Though the organization of late has suffered from some very unfortunately interface design choices, it is still a great resource for pre-packaged solutions to common problems. Though many here have given you the gory details of how to achieve this (#prm!), I had a similar need a few years ago and found that addaxis worked very well. (It was a File Exchange pick of the week at one point!) It has inspired later, probably better mods. Here is some example output:
(source: mathworks.com)
I just searched for "plotyy" at File Exchange.
Though understanding what's going on in important, sometimes you just need to get things done, not do them yourself. Matlab Central is great for that.
One possibility you can try is to create 3 axes stacked one on top of the other with the 'Color' properties of the top two set to 'none' so that all the plots are visible. You would have to adjust the axes width, position, and x-axis limits so that the 3 y axes are side-by-side instead of on top of one another. You would also want to remove the x-axis tick marks and labels from 2 of the axes since they will lie on top of one another.
Here's a general implementation that computes the proper positions for the axes and offsets for the x-axis limits to keep the plots lined up properly:
%# Some sample data:
x = 0:20;
N = numel(x);
y1 = rand(1,N);
y2 = 5.*rand(1,N)+5;
y3 = 50.*rand(1,N)-50;
%# Some initial computations:
axesPosition = [110 40 200 200]; %# Axes position, in pixels
yWidth = 30; %# y axes spacing, in pixels
xLimit = [min(x) max(x)]; %# Range of x values
xOffset = -yWidth*diff(xLimit)/axesPosition(3);
%# Create the figure and axes:
figure('Units','pixels','Position',[200 200 330 260]);
h1 = axes('Units','pixels','Position',axesPosition,...
'Color','w','XColor','k','YColor','r',...
'XLim',xLimit,'YLim',[0 1],'NextPlot','add');
h2 = axes('Units','pixels','Position',axesPosition+yWidth.*[-1 0 1 0],...
'Color','none','XColor','k','YColor','m',...
'XLim',xLimit+[xOffset 0],'YLim',[0 10],...
'XTick',[],'XTickLabel',[],'NextPlot','add');
h3 = axes('Units','pixels','Position',axesPosition+yWidth.*[-2 0 2 0],...
'Color','none','XColor','k','YColor','b',...
'XLim',xLimit+[2*xOffset 0],'YLim',[-50 50],...
'XTick',[],'XTickLabel',[],'NextPlot','add');
xlabel(h1,'time');
ylabel(h3,'values');
%# Plot the data:
plot(h1,x,y1,'r');
plot(h2,x,y2,'m');
plot(h3,x,y3,'b');
and here's the resulting figure:
I know of plotyy that allows you to have two y-axes, but no "plotyyy"!
Perhaps you can normalize the y values to have the same scale (min/max normalization, zscore standardization, etc..), then you can just easily plot them using normal plot, hold sequence.
Here's an example:
%# random data
x=1:20;
y = [randn(20,1)*1 + 0 , randn(20,1)*5 + 10 , randn(20,1)*0.3 + 50];
%# plotyy
plotyy(x,y(:,1), x,y(:,3))
%# orginial
figure
subplot(221), plot(x,y(:,1), x,y(:,2), x,y(:,3))
title('original'), legend({'y1' 'y2' 'y3'})
%# normalize: (y-min)/(max-min) ==> [0,1]
yy = bsxfun(#times, bsxfun(#minus,y,min(y)), 1./range(y));
subplot(222), plot(x,yy(:,1), x,yy(:,2), x,yy(:,3))
title('minmax')
%# standarize: (y - mean) / std ==> N(0,1)
yy = zscore(y);
subplot(223), plot(x,yy(:,1), x,yy(:,2), x,yy(:,3))
title('zscore')
%# softmax normalization with logistic sigmoid ==> [0,1]
yy = 1 ./ ( 1 + exp( -zscore(y) ) );
subplot(224), plot(x,yy(:,1), x,yy(:,2), x,yy(:,3))
title('softmax')
Multi-scale plots are rare to find beyond two axes... Luckily in Matlab it is possible, but you have to fully overlap axes and play with tickmarks so as not to hide info.
Below is a nice working sample. I hope this is what you are looking for (although colors could be much nicer)!
close all
clear all
display('Generating data');
x = 0:10;
y1 = rand(1,11);
y2 = 10.*rand(1,11);
y3 = 100.*rand(1,11);
y4 = 100.*rand(1,11);
display('Plotting');
figure;
ax1 = gca;
get(ax1,'Position')
set(ax1,'XColor','k',...
'YColor','b',...
'YLim',[0,1],...
'YTick',[0, 0.2, 0.4, 0.6, 0.8, 1.0]);
line(x, y1, 'Color', 'b', 'LineStyle', '-', 'Marker', '.', 'Parent', ax1)
ax2 = axes('Position',get(ax1,'Position'),...
'XAxisLocation','bottom',...
'YAxisLocation','left',...
'Color','none',...
'XColor','k',...
'YColor','r',...
'YLim',[0,10],...
'YTick',[1, 3, 5, 7, 9],...
'XTick',[],'XTickLabel',[]);
line(x, y2, 'Color', 'r', 'LineStyle', '-', 'Marker', '.', 'Parent', ax2)
ax3 = axes('Position',get(ax1,'Position'),...
'XAxisLocation','bottom',...
'YAxisLocation','right',...
'Color','none',...
'XColor','k',...
'YColor','g',...
'YLim',[0,100],...
'YTick',[0, 20, 40, 60, 80, 100],...
'XTick',[],'XTickLabel',[]);
line(x, y3, 'Color', 'g', 'LineStyle', '-', 'Marker', '.', 'Parent', ax3)
ax4 = axes('Position',get(ax1,'Position'),...
'XAxisLocation','bottom',...
'YAxisLocation','right',...
'Color','none',...
'XColor','k',...
'YColor','c',...
'YLim',[0,100],...
'YTick',[10, 30, 50, 70, 90],...
'XTick',[],'XTickLabel',[]);
line(x, y4, 'Color', 'c', 'LineStyle', '-', 'Marker', '.', 'Parent', ax4)
(source: pablorodriguez.info)
PLOTYY allows two different y-axes. Or you might look into LayerPlot from the File Exchange. I guess I should ask if you've considered using HOLD or just rescaling the data and using regular old plot?
OLD, not what the OP was looking for:
SUBPLOT allows you to break a figure window into multiple axes. Then if you want to have only one x-axis showing, or some other customization, you can manipulate each axis independently.
In your case there are 3 extra y axis (4 in total) and the best code that could be used to achieve what you want and deal with other cases is illustrated above:
clear
clc
x = linspace(0,1,10);
N = numel(x);
y = rand(1,N);
y_extra_1 = 5.*rand(1,N)+5;
y_extra_2 = 50.*rand(1,N)+20;
Y = [y;y_extra_1;y_extra_2];
xLimit = [min(x) max(x)];
xWidth = xLimit(2)-xLimit(1);
numberOfExtraPlots = 2;
a = 0.05;
N_ = numberOfExtraPlots+1;
for i=1:N_
L=1-(numberOfExtraPlots*a)-0.2;
axesPosition = [(0.1+(numberOfExtraPlots*a)) 0.1 L 0.8];
if(i==1)
color = [rand(1),rand(1),rand(1)];
figure('Units','pixels','Position',[200 200 1200 600])
axes('Units','normalized','Position',axesPosition,...
'Color','w','XColor','k','YColor',color,...
'XLim',xLimit,'YLim',[min(Y(i,:)) max(Y(i,:))],...
'NextPlot','add');
plot(x,Y(i,:),'Color',color);
xlabel('Time (s)');
ylab = strcat('Values of dataset 0',num2str(i));
ylabel(ylab)
numberOfExtraPlots = numberOfExtraPlots - 1;
else
color = [rand(1),rand(1),rand(1)];
axes('Units','normalized','Position',axesPosition,...
'Color','none','XColor','k','YColor',color,...
'XLim',xLimit,'YLim',[min(Y(i,:)) max(Y(i,:))],...
'XTick',[],'XTickLabel',[],'NextPlot','add');
V = (xWidth*a*(i-1))/L;
b=xLimit+[V 0];
x_=linspace(b(1),b(2),10);
plot(x_,Y(i,:),'Color',color);
ylab = strcat('Values of dataset 0',num2str(i));
ylabel(ylab)
numberOfExtraPlots = numberOfExtraPlots - 1;
end
end
The code above will produce something like this:

Draw log graph curve on Matlab by clicking?

I'd like to draw a curve on an empty (semilog-y) graph by clicking the points I want it to run through, on the X-Y plane.
Is there a function for this?
edit: I'm trying to do this by obtaining the position of last pointer click -
axis([0 3000 0 1000]);
co=get(gcf, 'CurrentPoint');
It seems to return the cursor position at the time of execution, but it does not change later.
edit2: Here's what works for me. The actual drawing I can do by using the arrays of points collected.
clear
clc
h=plot(0);
grid on;
xlim([0 3000]);
ylim([0 1000]);
datacursormode on;
% Enlarge figure to full screen.
screenSize = get(0,'ScreenSize');
set(gcf, 'units','pixels','outerposition', screenSize);
hold on;
% Print the x,y coordinates - will be in plot coordinates
x=zeros(1,10); y=zeros(1,10);
for p=1:10;
[x(p),y(p)] = ginput(1) ;
% Mark where they clicked with a cross.
plot(x(p),y(p), 'r+', 'MarkerSize', 20, 'LineWidth', 3);
% Print coordinates on the plot.
label = sprintf('(%.1f, %.1f)', x(p), y(p));
text(x(p)+20, y(p), label);
end
Not really, but now there is:
function topLevel
%// parameters
xrange = [0 100];
yrange = [1e-4 1e4];
%// initialize figure, plot
figure, clf, hold on
plot(NaN, NaN);
axis([xrange yrange]);
set(gca, 'YScale', 'log')
t = text(sum(xrange)/2, sum(yrange)/2, ...
'<< Need at least 3 points >>',...
'HorizontalAlignment', 'center');
%// Main loop
xs = []; p = [];
ys = []; P = [];
while true
%// Get new user-input, and collect all of them in a list
[x,y] = ginput(1);
xs = [xs; x]; %#ok<AGROW>
ys = [ys; y]; %#ok<AGROW>
%// Plot the selected points
if ishandle(p)
delete(p); end
p = plot(xs, ys, 'rx');
axis([xrange yrange]);
%// Fit curve through user-injected points
if numel(xs) >= 3
if ishandle(t)
delete(t); end
%// Get parameters of best-fit in a least-squares sense
[A,B,C] = fitExponential(xs,ys);
%// Plot the new curve
xp = linspace(xrange(1), xrange(end), 100);
yp = A + B*exp(C*xp);
if ishandle(P)
delete(P); end
P = plot(xp,yp, 'b');
end
end
%// Fit a model of the form y = A + B·exp(C·x) to data [x,y]
function [A, B, C] = fitExponential(x,y)
options = optimset(...
'maxfunevals', inf);
A = fminsearch(#lsq, 0, options);
[~,B,C] = lsq(A);
function [val, B,C] = lsq(A)
params = [ones(size(x(:))) x(:)] \ log(abs(y-A));
B = exp(params(1));
C = params(2);
val = sum((y - A - B*exp(C*x)).^2);
end
end
end
Note that as always, fitting an exponential curve can be tricky; the square of the difference between model and data is exponentially much greater for higher data values than for lower data values, so there will be a strong bias to fit the higher values better than the lower ones.
I just assumed a simple model and used a simple solution, but this gives a biased curve which might not be "optimal" in the sense that you need it to be. Any decent solution really depends on what you want specifically, and I'll leave that up to you ^_^