Drawing a pyramid on MATLAB - matlab

I want to draw this figure on Matlab (without the bubbles)!
I wrote following code :
figure
hold on
axis equal
axis([0 20 0 10])
n = 20
n = n - 1
for y = 0:10
for x = (y+1):n
rectangle('Position',[x y 1 1],'curvature',[0 0],'facecolor',(rand(1,3)))
pause(0.05)
end
end
I get the following figure on executing this code :
I need help in writing part of the code where the correct figure can be drawn.

Your loop on x start at the right point but goes to the maximum at every iteration.
Just modify the loop definition for x = (y+1):n to for x = (y+1):n-y and you'll get the desired result:
for y = 0:10
for x = (y+1):n-y
rectangle('Position',[x y 1 1],'curvature',[0 0],'facecolor',(rand(1,3)))
pause(0.05)
end
end
edit: according to your comment, you wanted to achieve that by controling n, this is also possible but you have to decrement n at each iteration of the outer loop, like so:
for y = 0:10
for x = (y+1):n
rectangle('Position',[x y 1 1],'curvature',[0 0],'facecolor',(rand(1,3)))
pause(0.001)
end
n=n-1 ;
end

Related

Plotting a graph - Different line styles for different edges

I have a graph of nodes and edges that I am plotting against (x, y, z) coordinates for each node.
I would like to use a dotted line for the "inner" edges, and a straight line for the "outer" edges.
LineStyle may help me, but I think that will make all of my edges dotted lines. I would like to specify which edges are dotted.
Here is the code I am using to plot the graph: (G is a graph)
plot(G, 'XData', A(1,:), 'YData', A(2,:), 'ZData', A(3,:))
Any help is much appreciated!
I have a function to create the graph, it gives this output:
G =
graph with properties:
Edges: [11×1 table]
Nodes: [6×0 table]
And a coordinate system similar to this:
A =
0 1 0 -1 0 0
0 1 3 2 1 2
1 1 1 1 1 1
Using the plot function above, this provides this output:
Ok you didn't really put enough effort in making your question easy to answer for everybody but I was curious about a method and it seem to work so I'll post it anyway.
The classic trick for these cases where a sub-group of points/lines have to be plotted differently than the whole group is to:
Plot the whole group
Plot the sub-group on top with different line properties
In your case, it means you have to find the points and edges which are part of the boundary. I'll explain one method below. Be aware that this method will only work for convex boundaries (see the difference with a concave set where the method wouldn't work: concave vs. convex hull ).
First I need to get to the state of your question, so let's consider:
%% Initial data
A =[ 0 1 0 -1 0 0
0 1 3 2 1 2
1 1 1 1 1 1 ];
G = graph ;
G = addedge(G,[1 1 1 1 1 2 2 2 3 4 4],[2 3 4 5 6 3 5 6 4 5 6]) ;
plot(G, 'XData', A(1,:), 'YData', A(2,:) , 'LineStyle','--')
grid on ; hold on
np = size(A,2) ; % Number of points/nodes
This will produce a figure exactly like yours, with only one linestyle, which was set to dashed lines for the full graph. The exercise is now to plot a contour with a solid line.
To find the contour (at least in 2D cases like yours), the method used is:
find one point of the contour (initial point), the lowest x
possible.
calculate the angle between unit vector ux=[1,0,0] and
all the other vectors (formed by the initial point and all the other
points of the matrix).
Assign the next point of the contour (it is the one which vector has
the minimum angle) . You now have a current vector vec (between
point 1 and 2), and a current point pt2.
Calculate the angle between vec and all the other vectors (formed
by the current point pt2 and all the other points of the matrix)
the next point of the contour is the one which vector has the
minimum angle.
Repeat (3) and (4) until the next point of the contour is the
starting point.
Translated in code:
%% find a point on the edge
% (I chose to start with the lowest point on Y axis)
[~,idxNext] = min(A(2,:)) ;
%% initialise counters
isOnEdge = false(np,1) ; % this will hold a logical register of contour points
idxEdge = idxNext ; % this will hold the points of the contour, in order
%% setup start conditions
isOnEdge(idxNext) = true ; % initial point
p = A(:,idxNext) ; % initial point
v = [1;0;0] ; % initial vector (start with unit vector oriented Ox)
%% search for contour
isRunning = true ;
iter = 0 ;
while isRunning
iter = iter + 1 ; % make sure we're not stuck in infinite loop
angs = find_angles(v,p,A) ; % find angles between initial vector and all other points
angs(idxNext) = Inf ; % Exclude current point
if numel(idxEdge) > 1 % Exclude last point (if not at first iteration)
angs(idxEdge(end-1)) = Inf ;
end
[~,idxNext] = min(angs) ; % find the index of the minimum angle
if isOnEdge(idxNext)
% we've completed the close profile, bail out
isRunning = false ;
else
% move on to next point/vector
idxEdge = [idxEdge idxNext] ; %#ok<AGROW>
isOnEdge(idxNext) = true ;
p = A(:,idxNext) ;
v = A(:,idxNext) - A(:,idxEdge(end-1)) ;
end
if iter > np
break % make sure we're not stuck in infinite loop
end
end
%% present results
if isRunning
fprintf('Could''t find a closed profile\n')
else
fprintf('Found points defining a closed profile:\n')
disp(idxEdge)
end
%% Plot on top of graph
% create a matrix conataining only the contour points, close the contour by
% replicating the first point in last position
C = [A(:,idxEdge) , A(:,idxEdge(1))] ;
% plot
plot3( C(1,:) , C(2,:) , C(3,:) ,'b', 'LineWidth',2)
view(2)
Which will yield:
In the script above I am using the function find_angles.m. The code for it:
function angs = find_angles(Uin,p,M)
% find angle between Uin vector and the vectors formed between p and
% all the points in M
np = size(M,2) ;
angs = zeros(np,1) ;
for iv=1:np
vec = M(:,iv) - p ;
c = cross(Uin,vec) ;
d = dot(Uin,vec) ;
angs(iv) = rad2deg( atan2( norm(c) , d ) ) * sign( c(3) ) ;
% take care of an edge case
if c(3)==0 && d==-1 ; angs(iv) = 180 ; end
% give [0 360] degree results
if angs(iv) < 0 ; angs(iv) = 180 + (180+angs(iv) ) ; end
end

Creating graphs that show the distribution in space of a large number of 2D Random Walks at three different time points

So essentially I have this code here that I can use to generate a 2D Random Walk discretely along N number of steps with M number of walkers. I can plot them all on the same graph here.
clc;
clearvars;
N = 500; % Length of the x-axis, also known as the length of the random walks.
M = 3; % The amount of random walks.
x_t(1) = 0;
y_t(1) = 0;
for m=1:M
for n = 1:N % Looping all values of N into x_t(n).
A = sign(randn); % Generates either +1/-1 depending on the SIGN of RAND.
x_t(n+1) = x_t(n) + A;
A = sign(randn); % Generates either +1/-1 depending on the SIGN of RAND.
y_t(n+1) = y_t(n) + A;
end
plot(x_t, y_t);
hold on
end
grid on;
% Enlarge figure to full screen.
set(gcf, 'Units', 'Normalized', 'Outerposition', [0, 0.05, 1, 0.95]);
axis square;
Now, I want to be able to Create graphs that show the distribution in space of the positions of a large number
(e.g. n = 1000) random walkers, at three different time points (e.g. t = 100, 200 and 300 or any three time points really).
I'm not sure how to go about this, I need to turn this into a function and iterate it through itself three different times and store the coordinates? I have a rough idea but iffy on actually implementing. I'd assume the safest and least messy way would be to use subplot() to create all three plots together in the same figure.
Appreciate any assistance!
You can use cumsum to linearize the process. Basically you only want to cumsum a random matrix composed of [-1 and 1].
clc;
close all;
M = 50; % The amount of random walks.
steps = [10,200,1000]; % here we analyse the step 10,200 and 1000
cc = hsv(length(steps)); % manage the color of the plot
%generation of each random walk
x = sign(randn(max(steps),M));
y = sign(randn(max(steps),M));
xs = cumsum(x);
xval = xs(steps,:);
ys = cumsum(y);
yval = ys(steps,:);
hold on
for n=1:length(steps)
plot(xval(n,:),yval(n,:),'o','markersize',1,'color',cc(n,:),'MarkerFaceColor',cc(n,:));
end
legend('10','200','1000')
axis square
grid on;
Results:
EDIT:
Thanks to #LuisMendo that answered my question here, you can use a binomial distribution to get the same result:
steps = [10,200,10000];
cc = hsv(length(steps)); % manage the color of the plot
M = 50;
DV = [-1 1];
p = .5; % probability of DV(2)
% Using the #LuisMendo binomial solution:
for ii = 1:length(steps)
SDUDx(ii,:) = (DV(2)-DV(1))*binornd(steps(ii), p, M, 1)+DV(1)*steps(ii);
SDUDy(ii,:) = (DV(2)-DV(1))*binornd(steps(ii), p, M, 1)+DV(1)*steps(ii);
end
hold on
for n=1:length(steps)
plot(SDUDx(n,:),SDUDy(n,:),'o','markersize',1,'color',cc(n,:),'MarkerFaceColor',cc(n,:));
end
legend('10','200','1000')
axis square
grid on;
What is the advantage ? Even if you have a big number of steps, let's say 1000000, matlab can handle it. Because in the first solution you have a bruteforce solution, and in the second case a statistical solution.
If you want to show the distribution of a large number, say 1000, of these points, I would say the most suitable way of plotting is as a 'point cloud' using scatter. Then you create an array of N points for both the x and the y coordinate, and let it compute the coordinate in a loop for i = 1:Nt, where Nt will be 100, 200, or 300 as you describe. Something along the lines of the following:
N = 500;
x_t = zeros(N,1);
y_t = zeros(N,1);
Nt = 100;
for tidx = 1:Nt
x_t = x_t + sign(randn(N,1));
y_t = y_t + sign(randn(N,1));
end
scatter(x_t,y_t,'k*');
This will give you N x and y coordinates generated in the same way as in the sample you provided.
One thing to keep in mind is that sign(0)=0, so I suppose there is a chance (admittedly a small one) of not altering the coordinate. I am not sure if you intended this behaviour to be possible (a walker standing still)?
I will demonstrate the 1-dimensional case for clarity; you only need to implement this for each dimension you add.
Model N steps for M walkers using an NxM matrix.
>> N = 5;
>> M = 4;
>> steps = sign(randn(N,M));
steps =
1 1 1 1
-1 1 -1 1
1 -1 -1 -1
1 1 -1 1
1 -1 -1 -1
For plotting, it is useful to make a second NxM matrix s containing the updated positions after each step, where s(N,M) gives the position of walker M after N steps.
Use cumsum to vectorize instead of looping.
>> s = cumsum(steps)
s =
1 1 1 1
0 2 0 2
1 1 -1 1
2 2 -2 2
3 1 -3 1
To prevent plot redraw after each new line, use hold on.
>> figure; hold on
>> plot(1:N, s(1:N, 1:M), 'marker', '.', 'markersize', 20, 'linewidth', 3)
>> xlabel('Number of steps'); ylabel('Position')
The output plot looks like this: picture
This method scales very well to 2- and 3-dimensional random walks.

Plotting "saw-tooth like" functions on MATLAB

I'm trying to plot a piece-wise function (of the form y = αx + β) on a single plot, such that for different regions on the x-axis, I have different values of α and β for the function.
I want to make the locations (on the x-axis) of these steps modifiable at will instead of having a predetermined number of such piece-functions. When plotted, it should ideally look like set of lines of different slopes and intercepts, each separated by a spacing. So if my spacing vector has 10 elements, I wrote my code such that I will correspondingly have 10 different piece-functions for different regions on the x-axis.
Here is the code that I wrote.
x = linspace(0,100,10000);
y = zeros(1,10000);
spacing = 0:10:100;
alpha = linspace(1,3,length(spacing)); %setting arbitrary upper lim
beta = linspace(1,5,length(spacing));
for j = 1:length(spacing)
for i=1:10000
if x(i) <= spacing(j)
y(i) = alpha(j)*x(i) + beta(j);
i = i + 1;
else
j = j + 1;
end
end
end
plot(x,y)
However, when I plot this, I get a single slope. It doesn't seem to be recognizing a change in spacing(j) due to the j = j + 1 iterator in the else statement
Any suggestions or help on how I should approach this would be much appreciated!
You should first iterate over x and then over spacing. Because for every element in x you are trying to find the correct interval. Then once you found that interval you should move to the next element of x and stop the iteration over spacing. You can do that using brake. If you don't do that then it will always choose the last interval, since x(i) <= spacing(end). See the code below:
x = linspace(0,100,10000);
y = zeros(1,10000);
spacing = 0:10:100;
alpha = linspace(1,3,length(spacing)); %setting arbitrary upper lim
beta = linspace(1,5,length(spacing));
for i=1:10000
for j = 1:length(spacing)
if x(i) <= spacing(j)
y(i) = alpha(j)*x(i) + beta(j);
break
end
end
end
plot(x,y)
ylim([0 max(y)])
The last line is to set y to start from 0.

How to implement a piecewise function and then plot it on certain intervals in MATLAB

I am actually attempting to write code for the cubic spline interpolation. Cubic spline boils down to a series of n-1 segments where n is the number of original coordinates given initially and the segments are each represented by some cubic function.
I have figured out how to get all the coefficients and values for each segment, stored in vectors a,b,c,d, but I don't know how to plot the function as a piecewise function on different intervals. Here is my code so far. The very last for loop is where I have attempted to plot each segment.
%initializations
x = [1 1.3 1.9 2.1 2.6 3.0 3.9 4.4 4.7 5.0 6 7 8 9.2 10.5 11.3 11.6 12 12.6 13 13.3].';
y = [1.3 1.5 1.85 2.1 2.6 2.7 2.4 2.15 2.05 2.1 2.25 2.3 2.25 1.95 1.4 0.9 0.7 0.6 0.5 0.4 0.25].';
%n is the amount of coordinates
n = length(x);
%solving for a-d for all n-1 segments
a = zeros(n,1);
b = zeros(n,1);
d = zeros(n,1);
%%%%%%%%%%%%%% SOLVE FOR a's %%%%%%%%%%%%%
%Condition (b) in Definition 3.10 on pg 146
%Sj(xj) = f(xj) aka yj
for j = 1: n
a(j) = y(j);
end
%initialize hj
h = zeros(n-1,1);
for j = 1: n-1
h(j) = x(j+1) - x(j);
end
A = zeros(n,n);
bv = zeros(n,1); %bv = b vector
%initialize corners to 1
A(1,1) = 1;
A(n,n) = 1;
%set main diagonal
for k = 2: n-1
A(k,k) = 2*(h(k-1) + h(k));
end
%set upper and then lower diagonals
for k = 2 : n-1
A(k,k+1) = h(k); %h2, h3, h4...hn-1
A(k,k-1) = h(k-1); %h1, h2, h3...hn
end
%fill up the b vector using equation in notes
%first and last spots are 0
for j = 2 : n-1
bv(j) = 3*(((a(j+1)-a(j)) / h(j)) - ((a(j) - a(j-1)) / h(j-1)));
end
%augmented matrix
A = [A bv];
%%%%%%%%%%%% BEGIN GAUSSIAN ELIMINATION %%%%%%%%%%%%%%%
offset = 1;
%will only need n-1 iterations since "first" pivot row is unchanged
for k = 1: n-1
%Searching from row p to row n for non-zero pivot
for p = k : n
if A(p,k) ~= 0;
break;
end
end
%row swapping using temp variable
if p ~= k
temp = A(p,:);
A(p,:) = A(k,:);
A(k,:) = temp;
end
%Eliminations to create Upper Triangular Form
for j = k+1:n
A(j,offset:n+1) = A(j,offset:n+1) - ((A(k, offset:n+1) * A(j,k)) / A(k,k));
end
offset = offset + 1;
end
c = zeros(n,1); %initializes vector of data of n rows, 1 column
%Backward Subsitution
%First, solve the nth equation
c(n) = A(n,n+1) / A(n,n);
%%%%%%%%%%%%%%%%% SOLVE FOR C's %%%%%%%%%%%%%%%%%%
%now solve the n-1 : 1 equations (the rest of them going backwards
for j = n-1:-1:1 %-1 means decrement
c(j) = A(j,n+1);
for k = j+1:n
c(j) = c(j) - A(j,k)*c(k);
end
c(j) = c(j)/A(j,j);
end
%%%%%%%%%%%%% SOLVE FOR B's and D's %%%%%%%%%%%%%%%%%%%%
for j = n-1 : -1 : 1
b(j) = ((a(j+1)-a(j)) / h(j)) - (h(j)*(2*c(j) + c(j+1)) / 3);
d(j) = (c(j+1) - c(j)) / 3*h(j);
end
%series of equation segments
for j = 1 : n-1
f = #(x) a(j) + b(j)*(x-x(j)) + c(j)*(x-x(j))^2 + d(j)*(x-x(j))^3;
end
plot(x,y,'o');
Let's assume that I have calculated vectors a,b,c,d correctly for each segment. How do I plot each cubic segment such that they all appear graphed on a single plot?
I appreciate the help.
That's pretty easy. You've already done half of the work by defining an anonymous function that is for the cubic spline in between each interval. However, you need to make sure that the operations in the function are element-wise. You currently have it operating on scalars, or assuming that we are using matrix operations. Don't do that. Use .* instead of * and .^ instead of ^. The reason why you need to do this is to make generating the points on the spline a lot easier, where my next point follows.
All you have to do next is define a bunch of x points within the interval defined by the neighbouring x key points and substitute them into your function, then plot the result.... so something like this:
figure;
hold on;
for j = 1 : n-1
f = #(x) a(j) + b(j).*(x-x(j)) + c(j).*(x-x(j)).^2 + d(j)*(x-x(j)).^3; %// Change function to element-wise operations - be careful
x0 = linspace(x(j), x(j+1)); %// Define set of points
y0 = f(x0); %// Find output points
plot(x0, y0, 'r'); %// Plot the line in between the key points
end
plot(x, y, 'bo');
We spawn a new figure, then use hold on so that when we call plot multiple times, we append the results to the same figure. Next, for each set of cubic spline coefficients we have, define a spline function, then generate a bunch of x values with linspace that are between the current x key point and the one beside it. By default, linspace generates 100 points between a start point (i.e. x(j)) and end point (i.e. x(j+1)). You can control how many points you want to generate by specifying a third parameter (so something like linspace(x(j), x(j+1), 25); to generate 25 points). We use these x values and substitute them into our spline equation to get our y values. We then plot this result on the figure using a red line. Once we're done, we plot the key points as blue open circles on top of the curve.
As a bonus, I ran your code with the above plotting mechanism, and this is what I get:

Connect different points with line in matlab

I have matrix of 2 column (x and y) and 100 rows, and each row make one point like (x1,y1).
I need to draw a line consecutively between them, like point (x1,y1) to (x2,y2) and (x2,y2) to (x3,y3) and so on till (x100,y100).
I have written this code and it's working properly. The problem is, it takes too long as I have to do this for 55000 matrix.
figure;
for j=1:length(data); % data = 55000 different matrices which should draw in the same figure
for i=1:length(data(j).x);
x= (data(j).x(i));
y= (data(j).y(i));
if i == length(data(j).x);
break;
end
x1= (data(j).x(i+1));
y1= (data(j).y(i+1));
line([x,x1],[y,y1]);
end
end
Is there any more efficient and quicker way to do that?
Try plot:
x = [];
y = [];
for j=1:length(data)
x = [x; data(j).x];
y = [y; data(j).y];
end
plot(x, y);