Line with variable width in Matlab - matlab

How can I draw a line whose thickness varies at each point in Matlab? I need to plot an average line, and then the standard deviation plotted as a shadow below it. Any ideas?
Thanks,

This is something I've written a while ago - it's a bit long, but you can just copy the whole thing. It deals with variable size input and produces a beautifully shaded plot - with std and min/max. Signal should be 2D. If you need a version for plotting two signals - just ask :)
function H = plotp(varargin)
switch nargin
case{1}
signal = varargin{1};
time = 1:size(signal,2);
prop = 'r-';
new_figure = true;
case{2}
time = varargin{1};
signal = varargin{2};
prop = 'r-';
new_figure = true;
case{3}
time = varargin{1};
signal = varargin{2};
prop = varargin{3};
new_figure = true;
case{4}
time = varargin{1};
signal = varargin{2};
prop = varargin{3};
new_figure = varargin{4};
end
if ischar(new_figure)
temp7 = regexpi(new_figure,'true');
if isempty(temp7)
new_figure = false;
H = get(0,'CurrentFigure');
else
new_figure = true;
end
elseif isnumeric(new_figure)
H = new_figure;
new_figure = false;
end
% prepare vectors for plotting
time2 = [time fliplr(time)];
sigm = nanmean(signal);
sigs = nanstd(signal);
sigms = [sigm-sigs fliplr(sigm+sigs)];
sigmin = nanmin(signal);
sigmax = nanmax(signal);
sigmm = [sigmin fliplr(sigmax)];
% check color
if strcmpi(prop(1),'r')
c1 = [1 0 0];
elseif strcmpi(prop(1),'g')
c1 = [0 1 0];
elseif strcmpi(prop(1),'b')
c1 = [0 0 1];
else
c1 = [1 1 1];
end
color1 = c1 + .7*(1-c1);
color2 = c1 + .8*(1-c1);
%
if length(prop) == 1
prop(2) = '-';
end
if new_figure
H = figure;
else
figure(H);
end
whole_screen = get(0,'ScreenSize');
% max figure size - add
fig_size = whole_screen + [-4 -4+2*32 +4+4 4+4-2*32];
set(H,'OuterPosition',fig_size);
plot(time,sigm,prop,'LineWidth',1.5)
hold all
fill(time2(~isnan(sigms)), sigms(~isnan(sigms)),color1,'EdgeColor',color1,'FaceAlpha', 0.4);
fill(time2(~isnan(sigmm)), sigmm(~isnan(sigmm)),color2,'EdgeColor',color2,'FaceAlpha', 0.3);
legend([{'Mean'} {'\pm Stddev'} {'Min/Max'} ],'Location','Best')

could you plot three lines, one as an average and the other two as + and - standard deviations.
If you're feeling particularly masochistic you could calculate the confidence interval of your line and plot that.

Related

How do I eliminate points outside the contour lines?

I have the code that generate a plot which has points plotted both inside and outside the contour line. I want to eliminate the points outside the outermost contour line. I'm using gaussian copula function.
plot(givenData(:,1),givenData(:,2),'b.','MarkerSize',3);
givenData is a 5000x2 matrix and I want only those values that lie inside the outer contour line to be plotted.
plot i'm getting
plot i want to generate
i want to eliminate the points lying outside the red contour which are shown as geen dots.
function [xgrid,ygrid,Z] = biVariateContourPlotsGMMCopula(givenData,gmmObject,~,numMeshPoints,x_dim,y_dim)
d = 2;
if nargin < 5
x_dim = 1;
y_dim = 2;
end
if x_dim == y_dim
hist(givenData(:,x_dim),10);
return;
end
numMeshPoints = min(numMeshPoints,256);
givenData = givenData(:,[x_dim y_dim]);
alpha = gmmObject.alpha;
mu = gmmObject.mu(:,[x_dim y_dim]);
sigma = gmmObject.sigma([x_dim y_dim],[x_dim y_dim],:) + 0.005*repmat(eye(d),[1 1 numel(alpha)]);
gmmObject = gmdistribution(mu,sigma,alpha);
bin_num = 256;
for j = 1:2
l_limit = min(gmmObject.mu(:,j))-3*(max(gmmObject.Sigma(j,j,:))^0.5);
u_limit = max(gmmObject.mu(:,j))+3*(max(gmmObject.Sigma(j,j,:))^0.5);
xmesh_inverse_space{j} = (l_limit:(u_limit-l_limit)/(bin_num-1):u_limit);
end
[~,pdensity{i},xmesh{i}]=kde(currentVar,numMeshPoints);
pdensity{i}(pdensity{i}<0) = 0;
cdensity{i} = cumsum(pdensity{i});
cdensity{i} = (cdensity{i}-min(cdensity{i}))/(max(cdensity{i})-min(cdensity{i})); % scaling the cdensity value to be between [0 1]
end
[xgrid,ygrid] = meshgrid(xmesh{1}(2:end-1),xmesh{2}(2:end-1));
for k = 1:d
marginalLogLikelihood_grid{k} = log(pdensity{k}(2:end-1)+eps);
marginalCDFValues_grid{k} = cdensity{k}(2:end-1);
end
[marg1,marg2] = meshgrid(marginalLogLikelihood_grid{1},marginalLogLikelihood_grid{2});
[xg,yg] = meshgrid(marginalCDFValues_grid{1},marginalCDFValues_grid{2});
inputMatrix = [reshape(xg,numel(xg),1) reshape(yg,numel(yg),1)];
copulaLogLikelihoodVals = gmmCopulaPDF(inputMatrix,gmmObject,xmesh_inverse_space);
Z = reshape(copulaLogLikelihoodVals,size(marg1,1),size(marg1,2));
Z = Z+marg1+marg2;
Z = exp(Z);
plot(givenData(:,1),givenData(:,2),'b.','MarkerSize',3);hold
contour(xgrid,ygrid,Z,40,'EdgeColor',[1 0 0]);
axis tight;

Use a variable outside the function in matlab

I've written the following function:
% This function plots the contours of likelihood values on the scatter plot of a 2 dimensional data.
function [xgrid,ygrid,Z,xy_matrix] = biVariateContourPlotsGMMCopula(givenData,gmmObject,~,numMeshPoints,x_dim,y_dim)
%INPUT: givenData (MxN, M=number of points, N=Dimension)
% : plo = binary variable (1 plot contour plot, 0 do not plot)
%OUTPUT: xgrid,ygrid,Z ( Z contains the likelihood values of the points defined by xgrid and ygrid)
%load general_info;
d = 2;
if nargin < 5
x_dim = 1;
y_dim = 2;
end
if x_dim == y_dim
hist(givenData(:,x_dim),10);
return;
end
numMeshPoints = min(numMeshPoints,256);
givenData = givenData(:,[x_dim y_dim]);
alpha = gmmObject.alpha;
mu = gmmObject.mu(:,[x_dim y_dim]);
sigma = gmmObject.sigma([x_dim y_dim],[x_dim y_dim],:) + 0.005*repmat(eye(d),[1 1 numel(alpha)]);
gmmObject = gmdistribution(mu,sigma,alpha);
bin_num = 256;
for j = 1:2
l_limit = min(gmmObject.mu(:,j))-3*(max(gmmObject.Sigma(j,j,:))^0.5);
u_limit = max(gmmObject.mu(:,j))+3*(max(gmmObject.Sigma(j,j,:))^0.5);
xmesh_inverse_space{j} = (l_limit:(u_limit-l_limit)/(bin_num-1):u_limit);
end
%if isempty(xmesh)||isempty(pdensity)||isempty(cdensity)
% Following for loop does the non-parameteric estimation of marginal % densities if not provided
for i = 1:d
currentVar = givenData(:,i);
[~,pdensity{i},xmesh{i}]=kde(currentVar,numMeshPoints);
pdensity{i}(pdensity{i}<0) = 0;
cdensity{i} = cumsum(pdensity{i});
cdensity{i} = (cdensity{i}-min(cdensity{i}))/(max(cdensity{i})-min(cdensity{i})); % scaling the cdensity value to be between [0 1]
end
[xgrid,ygrid] = meshgrid(xmesh{1}(2:end-1),xmesh{2}(2:end-1));
for k = 1:d
marginalLogLikelihood_grid{k} = log(pdensity{k}(2:end-1)+eps);
marginalCDFValues_grid{k} = cdensity{k}(2:end-1);
end
[marg1,marg2] = meshgrid(marginalLogLikelihood_grid{1},marginalLogLikelihood_grid{2});
[xg,yg] = meshgrid(marginalCDFValues_grid{1},marginalCDFValues_grid{2});
inputMatrix = [reshape(xg,numel(xg),1) reshape(yg,numel(yg),1)];
clear xg yg;
copulaLogLikelihoodVals = gmmCopulaPDF(inputMatrix,gmmObject,xmesh_inverse_space);
Z = reshape(copulaLogLikelihoodVals,size(marg1,1),size(marg1,2));
Z = Z+marg1+marg2;
Z = exp(Z);
% Getting the likelihood value from the log-likelihood
plot(givenData(:,1),givenData(:,2),'b.','MarkerSize',5);hold
[~,h] = contour(xgrid,ygrid,Z,[4e-6,4e-6]);
% Extract the (x, y) coordinates of the contour and concatenate them along the first dimension
xy_matrix = [];
for i = 1:length(h)
xy = get(h(i), 'XData');
x = xy(1, :);
y = xy(2, :);
xy_matrix = [xy_matrix, [x; y]];
end
% Print the concatenated matrix
disp(xy_matrix);
%title_string = ['GMCM fit (Log-Likelihood = ',num2str(logLikelihoodVal), ')'];
%title(title_string,'FontSize',12,'FontWeight','demi');
axis tight
however xy_matrix is not shown on the workspace.
How do I return the variable xy_matrix so that I can use it in another function?
Function call is inside a for loop as in below:
for i = 1:d
for j = 1:d
subplot(d,d,count); count = count+1;
[xgrid,ygrid,Z,xy_matrix] = biVariateContourPlotsGMMCopula(power_curve_reference_build_T2,gmcObject_bestfit,0,256,i,j);
end
end
So, when I'm including xy_matrix as a params in the function call, it generates the following error:
Have I missed anything here?
When you're calling the function with i==j==1 as parameters x_dim and y_dim, the function ends in the following if:
if x_dim == y_dim
hist(givenData(:,x_dim),10);
return;
end
The return values aren't defined at that point. If you define them in the beginning of the function, you won't get the error message.
function [xgrid,ygrid,Z,xy_matrix] = biVariateContourPlotsGMMCopula(givenData,gmmObject,~,numMeshPoints,x_dim,y_dim)
%INPUT: givenData (MxN, M=number of points, N=Dimension)
% : plo = binary variable (1 plot contour plot, 0 do not plot)
%OUTPUT: xgrid,ygrid,Z ( Z contains the likelihood values of the points defined by xgrid and ygrid)
%load general_info;
xgrid=0;
ygrid=0;
Z=0;
xy_matrix=0;
d = 2;
if nargin < 5
x_dim = 1;
y_dim = 2;
end
Below is a suggestion of some changes of your function call. The return values are saved in cells so that you don't overwrite them in the next iteration. The function is also not called when i==j==x_dim==y_dim.
xgrids={};
ygrids={};
Zs={};
xy_matrices={};
for i = 1:d
for j = 1:d
if i~=j
subplot(d,d,count); count = count+1;
[xgrids{i,j},ygrids{i,j},Zs{i,j},xy_matrices{i,j}] = biVariateContourPlotsGMMCopula(power_curve_reference_build_T2,gmcObject_bestfit,0,256,i,j);
end
end
end

Using the if Statement in a for Loop in MATLAB

I am working on a project and my aim is to color and 20 randomly generated lines of all fixed length, then count all lines crossing y=0 and color them green else color them blue.
I have come up with the code below but it doesn't work well in the if statement.
Can someone please have at look? Thank you if you can help!
Question:
How do I correct the if statement to display all the lines and count those lines crossing y = 0?
clear
clc
L = 1.5;
a = -5;
b = 5;
GLines = 0:5:5;
m = 0;
for i = 1:20
X1 = rand(1,i)*(b-a)+a;
Y1 = rand(1,i)*(b-a)+a;
Angle = rand(1,i)*360;
X2 = L*cosd(Angle) + X1;
Y2 = L*sind(Angle) + X2;
if X1(i) < L/2* sind(Angle)
m = m + 1;
plot([X1(i); X2(i)],[Y1(i); Y2(i)], '-g');
else
plot([X1(i); X2(i)],[Y1(i); Y2(i)], '-b');
end
for j = 1:length(GLines)
axis square
ylim([-5 5]);
xlim([-5 5]);
y = yline(GLines(j));
end
end
disp(m)
If a line crosses zero, the sign of Y1 and Y2 will be opposite, so you can do the following:
clear; clc
L = 1.5;
a = -5;
b = 5;
GLines = 0:5:5;
m = 0;
figure;
hold all;
for i = 1:20
X1 = rand*(b-a)+a;
Y1 = rand*(b-a)+a;
Angle = rand*360;
X2 = L*cosd(Angle) + X1;
Y2 = L*sind(Angle) + Y1;
if Y1*Y2 < 0 % if line crosses zero
m = m + 1;
c = 'g'; % color = green
else
c = 'b'; % color = blue
end
plot([X1; X2],[Y1; Y2],'color',c);
end
axis equal
disp(m)
which gives the follwing plot
and correctly outputs m = 2.

Plot equally spaced markers along a spiral

I want to move a red star marker along the spiral trajectory with an equal distance of 5 units between the red star points on its circumference like in the below image.
vertspacing = 10;
horzspacing = 10;
thetamax = 10*pi;
% Calculation of (x,y) - underlying archimedean spiral.
b = vertspacing/2/pi;
theta = 0:0.01:thetamax;
x = b*theta.*cos(theta)+50;
y = b*theta.*sin(theta)+50;
% Calculation of equidistant (xi,yi) points on spiral.
smax = 0.5*b*thetamax.*thetamax;
s = 0:horzspacing:smax;
thetai = sqrt(2*s/b);
xi = b*thetai.*cos(thetai);
yi = b*thetai.*sin(thetai);
plot(x,y,'b-');
hold on
I want to get a figure that looks like the following:
This is my code for the circle trajectory:
% Initialization steps.
format long g;
format compact;
fontSize = 20;
r1 = 50;
r2 = 35;
r3= 20;
xc = 50;
yc = 50;
% Since arclength = radius * (angle in radians),
% (angle in radians) = arclength / radius = 5 / radius.
deltaAngle1 = 5 / r1;
deltaAngle2 = 5 / r2;
deltaAngle3 = 5 / r3;
theta1 = 0 : deltaAngle1 : (2 * pi);
theta2 = 0 : deltaAngle2 : (2 * pi);
theta3 = 0 : deltaAngle3 : (2 * pi);
x1 = r1*cos(theta1) + xc;
y1 = r1*sin(theta1) + yc;
x2 = r2*cos(theta2) + xc;
y2 = r2*sin(theta2) + yc;
x3 = r3*cos(theta3) + xc;
y3 = r3*sin(theta3) + yc;
plot(x1,y1,'color',[1 0.5 0])
hold on
plot(x2,y2,'color',[1 0.5 0])
hold on
plot(x3,y3,'color',[1 0.5 0])
hold on
% Connecting Line:
plot([70 100], [50 50],'color',[1 0.5 0])
% Set up figure properties:
% Enlarge figure to full screen.
set(gcf, 'Units', 'Normalized', 'OuterPosition', [0, 0, 1, 1]);
drawnow;
axis square;
for i = 1 : length(theta1)
plot(x1(i),y1(i),'r*')
pause(0.1)
end
for i = 1 : length(theta2)
plot(x2(i),y2(i),'r*')
pause(0.1)
end
for i = 1 : length(theta3)
plot(x3(i),y3(i),'r*')
pause(0.1)
end
I can't think of a way to compute distance along a spiral, so I'm approximating it with circles, in hopes that it will still be useful.
My solution relies on the InterX function from FEX, to find the intersection of circles with the spiral. I am providing an animation so it is easier to understand.
The code (tested on R2017a):
function [x,y,xi,yi] = q44916610(doPlot)
%% Input handling:
if nargin < 1 || isempty(doPlot)
doPlot = false;
end
%% Initialization:
origin = [50,50];
vertspacing = 10;
thetamax = 5*(2*pi);
%% Calculation of (x,y) - underlying archimedean spiral.
b = vertspacing/(2*pi);
theta = 0:0.01:thetamax;
x = b*theta.*cos(theta) + origin(1);
y = b*theta.*sin(theta) + origin(2);
%% Calculation of equidistant (xi,yi) points on spiral.
DST = 5; cRes = 360;
numPts = ceil(vertspacing*thetamax); % Preallocation
[xi,yi] = deal(NaN(numPts,1));
if doPlot && isHG2() % Plots are only enabled if the MATLAB version is new enough.
figure(); plot(x,y,'b-'); hold on; axis equal; grid on; grid minor;
hAx = gca; hAx.XLim = [-5 105]; hAx.YLim = [-5 105];
hP = plot(xi,yi,'r*');
else
hP = struct('XData',xi,'YData',yi);
end
hP.XData(1) = origin(1); hP.YData(1) = origin(2);
for ind = 2:numPts
P = InterX([x;y], makeCircle([hP.XData(ind-1),hP.YData(ind-1)],DST/2,cRes));
[~,I] = max(abs(P(1,:)-origin(1)+1i*(P(2,:)-origin(2))));
if doPlot, pause(0.1); end
hP.XData(ind) = P(1,I); hP.YData(ind) = P(2,I);
if doPlot, pause(0.1); delete(hAx.Children(1)); end
end
xi = hP.XData(~isnan(hP.XData)); yi = hP.YData(~isnan(hP.YData));
%% Nested function(s):
function [XY] = makeCircle(cnt, R, nPts)
P = (cnt(1)+1i*cnt(2))+R*exp(linspace(0,1,nPts)*pi*2i);
if doPlot, plot(P,'Color',lines(1)); end
XY = [real(P); imag(P)];
end
end
%% Local function(s):
function tf = isHG2()
try
tf = ~verLessThan('MATLAB', '8.4');
catch
tf = false;
end
end
function P = InterX(L1,varargin)
% DOCUMENTATION REMOVED. For a full version go to:
% https://www.mathworks.com/matlabcentral/fileexchange/22441-curve-intersections
narginchk(1,2);
if nargin == 1
L2 = L1; hF = #lt; %...Avoid the inclusion of common points
else
L2 = varargin{1}; hF = #le;
end
%...Preliminary stuff
x1 = L1(1,:)'; x2 = L2(1,:);
y1 = L1(2,:)'; y2 = L2(2,:);
dx1 = diff(x1); dy1 = diff(y1);
dx2 = diff(x2); dy2 = diff(y2);
%...Determine 'signed distances'
S1 = dx1.*y1(1:end-1) - dy1.*x1(1:end-1);
S2 = dx2.*y2(1:end-1) - dy2.*x2(1:end-1);
C1 = feval(hF,D(bsxfun(#times,dx1,y2)-bsxfun(#times,dy1,x2),S1),0);
C2 = feval(hF,D((bsxfun(#times,y1,dx2)-bsxfun(#times,x1,dy2))',S2'),0)';
%...Obtain the segments where an intersection is expected
[i,j] = find(C1 & C2);
if isempty(i), P = zeros(2,0); return; end
%...Transpose and prepare for output
i=i'; dx2=dx2'; dy2=dy2'; S2 = S2';
L = dy2(j).*dx1(i) - dy1(i).*dx2(j);
i = i(L~=0); j=j(L~=0); L=L(L~=0); %...Avoid divisions by 0
%...Solve system of eqs to get the common points
P = unique([dx2(j).*S1(i) - dx1(i).*S2(j), ...
dy2(j).*S1(i) - dy1(i).*S2(j)]./[L L],'rows')';
function u = D(x,y)
u = bsxfun(#minus,x(:,1:end-1),y).*bsxfun(#minus,x(:,2:end),y);
end
end
Result:
Note that in the animation above, the diameter of the circle (and hence the distance between the red points) is 10 and not 5.

How to find Orientation of axis of contour in matlab?

I want to find Orientation, MajorAxisLengthand MinorAxisLength of contour which is plotted with below code.
clear
[x1 , x2] = meshgrid(linspace(-10,10,100),linspace(-10,10,100));
mu = [1,3];
sigm = [2,0;0,2];
xx_size = length(mu);
tem_matrix = ones(size(x1));
x_mesh= cell(1,xx_size);
for i = 1 : xx_size
x_mesh{i} = tem_matrix * mu(i);
end
x_mesh= {x1,x2};
temp_mesh = [];
for i = 1 : xx_size
temp_mesh = [temp_mesh x_mesh{i}(:)];
end
Z = mvnpdf(temp_mesh,mu,sigm);
z_plat = reshape(Z,size(x1));
figure;contour(x1, x2, z_plat,3, 'LineWidth', 2,'color','m');
% regionprops(z_plat,'Centroid','Orientation','MajorAxisLength','MinorAxisLength');
In my opinion, I may have to use regionprops command but I don't know how to do this. I want to find direction of axis of contour and plot something like this
How can I do this task? Thanks very much for your help
Rather than trying to process the graphical output of contour, I would instead recommend using contourc to compute the ContourMatrix and then use the x/y points to estimate the major and minor axes lengths as well as the orientation (for this I used this file exchange submission)
That would look something like the following. Note that I have modified the inputs to contourc as the first two inputs should be the vector form and not the output of meshgrid.
% Compute the three contours for your data
contourmatrix = contourc(linspace(-10,10,100), linspace(-10,10,100), z_plat, 3);
% Create a "pointer" to keep track of where we are in the output
start = 1;
count = 1;
% Now loop through each contour
while start < size(contourmatrix, 2)
value = contourmatrix(1, start);
nPoints = contourmatrix(2, start);
contour_points = contourmatrix(:, start + (1:nPoints));
% Now fit an ellipse using the file exchange
ellipsedata(count) = fit_ellipse(contour_points(1,:), contour_points(2,:));
% Increment the start pointer
start = start + nPoints + 1;
count = count + 1;
end
orientations = [ellipsedata.phi];
% 0 0 0
major_length = [ellipsedata.long_axis];
% 4.7175 3.3380 2.1539
minor_length = [ellipsedata.short_axis];
% 4.7172 3.3378 2.1532
As you can see, the contours are actually basically circles and therefore the orientation is zero and the major and minor axis lengths are almost equal. The reason that they look like ellipses in your post is because your x and y axes are scaled differently. To fix this, you can call axis equal
figure;contour(x1, x2, z_plat,3, 'LineWidth', 2,'color','m');
axis equal
Thank you #Suever. It help me to do my idea.
I add some line to code:
clear
[X1 , X2] = meshgrid(linspace(-10,10,100),linspace(-10,10,100));
mu = [-1,0];
a = [3,2;1,4];
a = a * a';
sigm = a;
xx_size = length(mu);
tem_matrix = ones(size(X1));
x_mesh= cell(1,xx_size);
for i = 1 : xx_size
x_mesh{i} = tem_matrix * mu(i);
end
x_mesh= {X1,X2};
temp_mesh = [];
for i = 1 : xx_size
temp_mesh = [temp_mesh x_mesh{i}(:)];
end
Z = mvnpdf(temp_mesh,mu,sigm);
z_plat = reshape(Z,size(X1));
figure;contour(X1, X2, z_plat,3, 'LineWidth', 2,'color','m');
hold on;
% Compute the three contours for your data
contourmatrix = contourc(linspace(-10,10,100), linspace(-10,10,100), z_plat, 3);
% Create a "pointer" to keep track of where we are in the output
start = 1;
count = 1;
% Now loop through each contour
while start < size(contourmatrix, 2)
value = contourmatrix(1, start);
nPoints = contourmatrix(2, start);
contour_points = contourmatrix(:, start + (1:nPoints));
% Now fit an ellipse using the file exchange
ellipsedata(count) = fit_ellipse(contour_points(1,:), contour_points(2,:));
% Increment the start pointer
start = start + nPoints + 1;
count = count + 1;
end
orientations = [ellipsedata.phi];
major_length = [ellipsedata.long_axis];
minor_length = [ellipsedata.short_axis];
tet = orientations(1);
x1 = mu(1);
y1 = mu(2);
a = sin(tet) * sqrt(major_length(1));
b = cos(tet) * sqrt(major_length(1));
x2 = x1 + a;
y2 = y1 + b;
line([x1, x2], [y1, y2],'linewidth',2);
tet = ( pi/2 + orientations(1) );
a = sin(tet) * sqrt(minor_length(1));
b = cos(tet) * sqrt(minor_length(1));
x2 = x1 + a;
y2 = y1 + b;
line([x1, x2], [y1, y2],'linewidth',2);