I want to fill the unit circle with dots. But the code I have written is very slow. Is there an alternative that Matlab can run faster?
y = linspace(-1, 1, 200);
x = linspace(-1, 1, 200);
for i = 1: length(x)
for j = 1: length(y)
if (x(i)^2 + y(j)^2 < 1)
plot(x(i),y(j),'.');
end
end
end
Rather than looping through every permutation of x and y, you can use meshgrid to create two matrices (xx and yy) where each corresponding value in the two is a unique combination of x and y values. You can then use these matrices to evaluate your conditional (xx.^2 + yy.^2 < 1) at once. This will result in a logical array the size of xx that we can use to plot just the points that were inside of the unit circle.
[xx,yy] = meshgrid(x, y);
inside = xx.^2 + yy.^2 < 1;
% Now plot just these points
plot(xx(inside), yy(inside), '.');
Related
I've been trying to evaluate a function in matlab. I want my x vector to go from 0 to 1000 and my y vector to go from 0 to 125. They should both have a length of 101.
The equation to be evaluated is z(x,y) = ay + bx, with a=10 and b=20.
a = 10;
b = 20;
n = 101;
dx = 10; % Interval length
dy = 1.25;
x = zeros(1,n);
y = zeros(1,n);
z = zeros(n,n);
for i = 1:n;
x(i) = dx*(i-1);
y(i) = dy*(i-1);
for j = 1:n;
z(i,j) = a*dy*(j-1) + b*dx*(j-1);
end
end
I get an answer, but I don't know if I did it correctly with the indices in the nested for loop?
See MATLAB's linspace function.
a=10;
b=20;
n=101;
x=linspace(0,1000,n);
y=linspace(0,125,n);
z=a*y+b*x;
This is easier and takes care of the interval spacing for you. From the linspace documentation,
y = linspace(x1,x2,n) generates n points. The spacing between the points is (x2-x1)/(n-1).
Edit:
As others have pointed out, my solution above makes a vector, not a matrix which the OP seems to want. As #obchardon pointed out, you can use meshgrid to make that 2D grid of x and y points to generate a matrix of z. Updated approached would be:
a=10;
b=20;
n=101;
x=linspace(0,1000,n);
y=linspace(0,125,n);
[X,Y] = meshgrid(x,y);
z=a*Y+b*X;
(you may swap the order of x and y depending on if you want each variable along the row or column of z.)
TL;DR: I am trying to optimize the following short code in Matlab. Because it involves loops over large matrices, it is too slow.
for i = 1:sz,
for j = 1:sz,
if X(j) == Q(i) && Y(j) == R(i),
S(i) = Z(j);
break
end
end
end
Specifics: Basically, I started with three vectors of x, y and z data that I wanted to plot as a surface. I generated a mesh of the x and y data and then made a matrix for the corresponding z values using
[X, Y] = meshgrid(x, y);
Z = griddata(x, y, z, X, Y);
Because the data is collected in random order, when generating the surface plot the connections are all wrong and the plot looks all triangulated like the following example.
So, to make sure Matlab was connecting the right dots, I then reorganized the X and Y matrices using
[R, R_indx] = sort(Y);
[Q, Q_indx] = sort(X, 2);
From here I thought it would be a simple problem of reorganizing the matrix Z based on the indices of the sorting for matrix X and Y. But I run into trouble because no matter how I use the indices, I cannot produce the correct matrix. For example, I tried
S = Z(R_indx); % to match the rearrangement of Y
S = S(Q_indx); % to match the rearrangement of X
and I got this barcode...
Running the first block of code gives me the "desired" result pictured here. However, this takes far too long as it is a double loop over a very large matrix.
Question: How can I optimize this rearrangement of the matrix Z without for loops?
Please have a look at the following solutions, and test both with your matrices. Do they perform faster? The array indexing solution does, what you asked for, i.e. the re-arrangement of the matrices. The vector indexing might be even better, since it sorts your original vectors instead of the matrices, and generates the output directly from there.
% Parameters.
dim = 4;
% Test input.
x = [2, -2, 5, 4];
y = [1, -4, 6, -2];
z = rand(dim);
[X, Y] = meshgrid(x, y);
Z = griddata(x, y, z, X, Y);
[R, R_indx] = sort(Y);
[Q, Q_indx] = sort(X, 2);
% Initialize output.
S = zeros(dim);
% Provided solution using loop.
for i = 1:numel(z)
for j = 1:numel(z)
if (X(j) == Q(i) && Y(j) == R(i))
S(i) = Z(j);
break
end
end
end
% Output.
S
% Solution using array indexing; output.
S_array = reshape(((X(:) == Q(:).') & (Y(:) == R(:).')).' * Z(:), dim, dim)
% Solution using vector indexing; output.
[r, r_indx] = sort(y);
[q, q_indx] = sort(x);
[X, Y] = meshgrid(q, r);
Z = griddata(q, r, z, X, Y);
idx = (ones(dim, 1) * ((q_indx - 1) * dim) + r_indx.' * ones(1, dim));
S_vector = Z(idx)
Example output:
S =
0.371424 0.744220 0.777214 0.778058
0.580353 0.686495 0.356647 0.577780
0.436699 0.217288 0.883900 0.800133
0.594355 0.405309 0.544806 0.085540
S_array =
0.371424 0.744220 0.777214 0.778058
0.580353 0.686495 0.356647 0.577780
0.436699 0.217288 0.883900 0.800133
0.594355 0.405309 0.544806 0.085540
S_vector =
0.371424 0.744220 0.777214 0.778058
0.580353 0.686495 0.356647 0.577780
0.436699 0.217288 0.883900 0.800133
0.594355 0.405309 0.544806 0.085540
For a mathematics course for first year university science students we (the teaching assistants) need to prepare material for pc-sessions using Matlab. All computers are equipped with Matlab version R2016b.
We are working through some material from the previous years. In the section covering the plotting of piecewise functions, we found some inconsistencies in the way Matlab handles an if condition.
I would like to know why these things happen so we are prepared for any difficulties the students might experience in these sessions. The goal of the exercise is to draw a house in the plotting window by plotting two piecewise functions.
The first function, f1(x), evaluates to x+2 when x <= 0 and evaluates to -x+2 otherwise. The students are asked to implement this function in Matlab using an if/else construct. Our implementation is
function y = f1( x )
if x < 0
y = x + 2;
else
y = -x + 2;
end
end
The second function, f2(x), is the characteristic function of the interval [-1, 1]. It should also be implemented using if/else conditions. Our implementation is
function y = f2( x )
if x < -1
y = 0;
elseif x > 1
y = 0;
else
y = 1;
end
end
Finally, the plotting code should draw both functions on the interval [-1.5, 1.5] using fplot like so
fplot(#f1, [-1.5, 1.5])
hold on
fplot(#f2, [-1.5, 1.5])
The function f2 is plotted without problems. In plotting f1, however, it seems Matlab decided the first branch of the if-clause didn't matter as only the line -x+2 is plotted.
It seems vectorization issues lie at the heart of our problem since f1(-1) evaluates correctly to 1 but f1([-1, 1]) evaluates to [3, 1]. Then again, f2 seems to be evaluating correctly without any issues.
Things get stranger when we change the -x + 2 in the else part of f1 to -x^2 + 2. With this definition both functions are plotted correctly and Matlab seems to have no problem dealing with the conditionals.
What is going wrong?
Is there a way we can edit the exercises such that it never poses any problems but is still accessible to students having their first experiences with Matlab?
In MATLAB if vector is like if all(vector), and that is the source to your error. use indexing instead:
function y = f2( x )
y = zeros(size(x));
idxs1 = x >= -1;
idxs2 = x <= 1;
y(idxs1 & idxs2) = 1;
end
function y = f1( x )
y = zeros(size(x));
idxs = x < 0;
y(idxs) = x(idxs) + 2;
y(~idxs) = -x(~idxs) + 2;
end
fplot(#f1, [-1.5, 1.5])
hold on
fplot(#f2, [-1.5, 1.5])
Using an If Statement
You say that you want to specifically use an if structure, in which case you will have to evaluate each element of the input vector in turn
function y = f1( x )
y = zeros(size(x)); % Initialise y to the correct size
for ii = 1:numel(x) % Loop through elements of x (and so y)
if x(ii) < 0
y(ii) = x(ii) + 2;
else
y(ii) = -x(ii) + 2;
end
end
end
This is because otherwise you may have the following issue:
x = [1, 2, -1, 3, -2];
% x < 0 = [0, 0, 1, 0, 1];
% "if x < 0" is the same as "if all(x < 0)" = false, so if statement skipped
Logical Indexing
If the course material can be changed / extended, then a much better option in Matlab is to leverage logical indexing.
x = [1, 2, -1, 3, -2];
y = -x + 2; % Initialise variable y, assign its values to -x + 2 by default
y(x<0) = x + 2; % Assign values of y, where x<0, to x + 2
Now it can be seen how this can be done in a one liner...
coef = (x < 0)*2 - 1; % For the above example, coef = [-1, -1, 1, -1, 1];
y = coef.*x + 2; % Coeff can be done in-line without being declared
So, with a similar (but even simpler) approach to f2 as well,
function y = f1(x)
y = ((x<0)*2 - 1).*x + 2;
end
function y = f2(x)
y = (abs(x) < 1);
end
Then your demo gives the desired result
As for your mysteries when changing part of the piecewise function and everything working... For me, your code all works anyway (2015b)! My guess is that this is something to do with how fplot is calling your functions. I currently can't access the docs, which may contain the answer. In my above examples, I'm assuming x is being passed as a vector (which may have 1 or more elements). If fplot determines the x values and calls the function as if for single points, then your code should work.
A way to edit the task to make things clearer may be to just use the normal plot function, which I think is more useful for students to be familiar with anyway.
Then your demo would be called like so
x = -1.5:0.1:1.5 % or could use linspace(-1.5, 1.5, 100) etc
hold on;
plot(x, f1(x)); % x,y syntax, more apparent where the points will be plotted
plot(x, f2(x)); % than when using fplot
hold off; % good habit to hold off so that you don't accidentally plot on this fig later
Notice that, with this clear definition of x, your -x^2 + 2 would throw an error as you are asking for matrix multiplication of a 1D vector. You would actually have to use -x.^2 + 2. There's a cue for students to learn about element-wise operations in Matlab!
I want to plot a function y[n] = x[n+2]. My problem is that it does not plot in right range or even does not draw the zero sample points.
n = 1:6;
x = 1:1:8;
f = figure;
subplot(1,2,1)
stem(n, x(n));
axis([-3,8, 0, 7]);
xlabel('n');
ylabel('x[n]');
title('Subplot 1')
subplot(1,2,2)
stem(n, x(n + 2));
xlabel('n');
ylabel('y[n]');
title('Subplot 2')
How to change the variables n or x to get the right plot?
In the end, it ought to look like this:
You are confusing the concept of indices with your dependent variable. You should construct a function x which transforms an input n using the relationship that you know
function y = x(n)
% Set all outputs to 0
y = zeros(size(n));
% Replace the values that fall between 0 and 6 with their same value
y(n >= 0 & n <= 6) = n(n >= 0 & n <= 6);
end
Then you should pass this function a range of n values to evaluate.
nvalues = -3:8;
yvalues = x(nvalues);
stem(nvalues, yvalues)
You can also apply a transformation to the n values
nvalues = -3:8;
yvalues = x(nvalues + 2);
stem(nvalues, yvalues)
I have a three dimensional array of points.
I need to plot them on a 2D [x,z] grid, where every line is based on the value of Y inside a range.
es. the first line is made by points with 0 < y < 1, the second with 1 < y < 2, etc..
I can plot points just fine using this script(to have a better looking graph i'm also changing the color for every set of point by moving inside an rgb triplet).
set is the range of the line (in my case Y is time and i need to plot every 0.1 seconds). i is the index for my array of points.
w= 0;
yend = 100;
set = 0.1;
numberOfColors = 1/2*(Yinterval)*(1/set);
incrementOfColor = 1/numberOfColors;
red = 0;
green = 0;
blue = 1;
color=[red green blue];
while w < yend
while y(i)>w&&y(i)<w+set
figure(1)
hold on
plot(x(i),z(i),'.','Color',color);
hold on
i=i+1;
end
w=w+set;
if red < 1-incrementOfColor && blue > 0
red = red + incrementOfColor;
blue = blue - incrementOfColor;
end
if red > incrementOfColor && blue < incrementOfColor
red = red-incrementOfColor;
green = green + incrementOfColor;
blue = 0;
end
color = [red green blue];
end
And this is the result:
http://i.imgur.com/HTyzWai.png
When there's too much data the plot becomes cumbersome to read, and with too little data isolated points don't really tell much.
I've tried converting the points inside a "set" interval into an array but it really didn't work out:
while w < yend
while y(i)>w&&y(i)<w+set
vX(a,:)=x(i);
vZ(a,:)=z(i);
i=i+1;
a=a+1;
end
figure(2)
hold on
plot(vX,vZ,'-','Color',color);
Gave this result: imgur.com/S7OasUn.jpg
Is my conversion wrong or arrays are just not the proper way to handle this? If so, what should I use?
I'm rather new to matlab so if this is really obvious or i'm asking something in the wrong way, please excuse me.
edit:
This is the result i want to achieve:
imgur.com/jPZTO8E.png
and it was obtained with Origin's contour profile tool.
I guess you mean this with functional example:
myPoints[i]:
i=0, x = 1, y= 0.03, z = 1
i=1, x = 2, y= 0.06, z = 3
i=2, x = 2.5, y = 0.09, z = 4
i=3, x = 1.2, y = 1.01, z = 3.1
i=4, x = 1.3, y = 1.04, z = 1.1
i=5, x = 1.2, y = 1.06, z = 2.5
i=6, x = 2, y = 1.09, z = 3.1
i=7, x = 1.2, y = 2.02, z = 3.1
etc..
i want the points i 0,1,2 plotted as one line, i 3,4,5 as another line and i 7 etc.. plotted as a third line. In my data i have a lot of points.
this is one example of the data i'm using.
https://drive.google.com/file/d/0B9GHAkIYepQcRXdBdy03dFJtT1k/view?usp=sharing
where:
x = myPoints(:,1);
y = myPoints(:,2);
z = myPoints(:,3);
In this specific case, i only care about the points with y value between 85.85 and 90.85, and i want to "place an edge" (?) every 0.1
x = myPoints(:,1);
y = myPoints(:,2);
z = myPoints(:,3);
ymin = 85.85;
ymax = 90.85;
set = 0.1;
nbins = (ymax-ymin)/set;
binedge = linspace(ymin, ymax, (nbins + 1));
I think I'm understanding what you're attempting to accomplish and I believe you can accomplish your task with a vectorized use of plot rather than having to loop through each of your points.
Given your example data we can give this method a shot:
load('mypoints.mat');
x = myPoints(:,1);
y = myPoints(:,2);
z = myPoints(:,3);
% Bin your data by y values
ymin = 85.85;
ymax = 90.85;
set = 0.1;
nbins = (ymax-ymin)/set;
binedge = linspace(ymin, ymax, (nbins + 1));
[~, ~, binidx] = histcounts(y, binedge);
binloop = unique(binidx);
% Fix for error with unique. If you try to use a for loop with a column
% vector it passes the whole vector as your iterator, so you need to
% transpose it to a row vector.
temp = size(binloop);
if temp(1) ~= 1
binloop = binloop';
end
% Plot
figure
hold on
for ii = binloop
if ii == 0
% These fall outside of our bins, don't plot them
continue
else
dataidx = find(binidx == ii);
% Plot has its own color cycle, or you can add your color changing logic to this loop
plot(x(dataidx), z(dataidx), '-', 'LineWidth', 0.25);
end
end
hold off
What I've done here is to utilize the third output of histcounts to bin your y data and return a bin index for each value in your y vector.
To break the code down a bit:
Define your bin boundaries:
ymin = 85.85;
ymax = 90.85;
set = 0.1;
nbins = (ymax-ymin)/set;
binedge = linspace(ymin, ymax, (nbins + 1));
The linspace call returns the edges of each data bin. Given your example data we get binedge = [86.85, 86.95, 86.05, ..., 90.85]. We then plug in these edges and your y vector to histcounts to obtain our bin indices:
[~, ~, binidx] = histcounts(y, binedge);
Where the bins are defined per the documentation:
The value X(i) is in the kth bin if edges(k) ≤ X(i) < edges(k+1). The
last bin also includes the right bin edge, so that it contains X(i) if
edges(end-1) ≤ X(i) ≤ edges(end).
We can use unique to loop through all of the bins that are present. We can utilize find with MATLAB's logical indexing to plot all data from a single bin in each loop iteration. I ignore where ii == 0 as it indicates where data does not fall under one of the bins (and 0 index is meaningless in MATLAB).
I also played around a bit with the line sizes to try and make the plot a bit easier to read. There's a lot of data to visualize here but it helps a bit. You'll need to do a bit of pruning of your data since your x values wrap back, but that should be trivial.