Using splines() forms problem if x coordinates go from increasing to decreasing - matlab

I have two columns with data, x and y. Now I want to connect these data points in the order they appear in the columns. Say I have x=[1 2 3 4 3 2] and y=[3 4 2 1 3 3]. Now if I use spline to create a smooth curve, it 'sorts' the columns in an increasing order. I would like it to just take the data points, thus firstly x(1),y(1) and connect these to x(2), y(2) and so on.
Is this possible?

spline generates a function from the reals to the reals. This means a more general curve cannot be expressed as y = f(x) but we need to parametrize it as (x(t), y(t)):
x=[1 2 3 4 3 2];
y=[3 4 2 1 3 3];
plot(x,y,'o-');
% cannot be represented as function y=f(x)
% because x=2 and 3 have two different y values
% -> parametrize x and y:
t = 1:numel(x);
tt = linspace(min(t), max(t), 1000);;
tx = spline(t,x,tt);
ty = spline(t,y,tt);
hold on
plot(tx,ty,'-');

Related

How to plot all the matrix elements in matlab whitout knowing the size?

Lets say there is the next matrix
A = [ 1 2 2 ;
1 2 3 ;
2 3 4 ;
3 4 5 ;
4 4 6 ;
1 11 12]
I try to use quiver3 to plot the row in the next way:
quiver3(0,0,0,A(1:1),A(1:2),A(1:3),0);
quiver3(0,0,0,A(2:1),A(2:2),A(2:3),0);
quiver3(0,0,0,A(3:1),A(3:2),A(3:3),0);
and so on until the last row, but how can apply quiver3 for each row of the matrix instead of making one line per row?
Besides, isn't the same size of matrix always, so making one one command per row would yield some rows without plotting sometimes and perhaps not enough rows to plot other .
(Example: the matrix provided has 6 rows so I make 6 quiver3 expressions, but later if the matrix has only 3 rows, it gives me an error and if later it has 8 rows, there would be 2 vectors/row that aren't plotted).
Im guessing that it has to do with the range and meshgrid operator but I can not see how.
If your matrix A has N rows, where each row stores the [u v w] components to pass to quiver3, then you can plot all N arrows in one call to quiver3, provided you ensure all of your input arguments are the same size. If you are plotting all of them starting from the origin, then you have to create an N-by-1 vector of zeroes to use for your x, y, and z inputs:
A = [1 2 2;
1 2 3;
2 3 4;
3 4 5;
4 4 6;
1 11 12];
z = zeros(size(A, 1), 1);
quiver3(z, z, z, A(:, 1), A(:, 2), A(:, 3), 0);
Note the indexing syntax I used to split A up into columns to pass to quiver3. And here's the resulting plot for the given sample data:

Angles between n vectors - Matlab

Consider a set of points (just an example)
x = [0 1 2 5 4 8 5 6];
y = [5 8 4 2 5 6 4 5];
and another reference point:
xc=1;
yc=1;
In which I use to represent these points as vectors:
vec=[x-xc y-yc];
I wish to obtain a matrix with all the angles between all vectors which is obtained by the calculation (for single vectors)
angle = acosd(dot(v,u)/norm(u)*norm(v));
How can I obtain this calculation in a few lines without going vector by vector in a loop? In my calculation the number of points is very very large.
I think you mean vec = [x-xc; y-yc];. To calucate the dotproduct between all rows, you can use
vec.'*vec
The norm (Euclidean) of each vector can be determined as
no = sqrt(sum(vec.*vec,1))
The product of the different norms can be calculated the same as for vec:
no.'*no
The angles can thus be found as
no = sqrt(sum(vec.*vec,1));
angles = acosd(vec.'*vec./(no.'*no));

Count occurrences and stretch array in matlab

Let
input = [0 0 0 5 5 7 8 8];
I now want to transform this vector into the form
output = [3 3 3 3 5 5 6 8];
Which basically is a stairs plot.
Explanation
The input vector is used to plot data points along the x-axis. The y-axis is thereby provided by 1:length(input). So the resulting plot shows the cumulative number of datapoints along the y-axis and the time of occurrence along the x-axis.
I now want to fit a model against my dataset. Therefor I need a vector that provides the correct value for a certain time (x-value).
The desired output vector basically is the result of a stairs plot. I am looking for an efficient way to generate the desired vector in matlab. The result of
[x, y] = stairs(input, 1:length(input));
did not bring me any closer.
It can be done with bsfxun as follows:
x = [0 0 0 5 5 7 8 8];
y = sum(bsxfun(#le, x(:), min(x):max(x)), 1);
This counts, for each element in 1:numel(x), how many elements of x are less than or equal to that.

How do I add up two scatter points with the same values of x but different values of y?

On a stem plot, how can I add points that have the same values of x but different values of y?
For example, given the following code:
x = [1 2 3 6 6 4 5];
y = [3 6 1 8 9 4 2];
stem(x,y);
If you plot x, and y, this will be the output:
I want to add up (6,8) and (6,9) so it becomes (6,17), just like what the image is showing.
How can I achieve this?
Use accumarray with x and y so you can bin or group like entries together that share the same x. Once these values are binned, you can sum all of the values that share the same bin together. As such, we see that for x = 6, we have y = 8 and y = 9. accumarray allows you to group multiple y values together that share the same x. Once these values are grouped, you then apply a function to all of the values in the same group to produce a final output for each group. In our case, we want to sum them, so we need to use the sum function:
x = [1 2 3 6 6 4 5];
y = [3 6 1 8 9 4 2];
Z = accumarray(x(:), y(:), [], #sum);
stem(unique(x), Z);
xlim([0 7]);
We use unique on X so that we have no repeats for X when plotting the stem plot. unique also has the behaviour of sorting your x values. Doing x(:) and y(:) is so that you can make your input data either as row or column vectors independently. accumarray accepts only column vectors (or matrices, but we won't go there) and so doing x(:) and y(:) ensures that both inputs are column vectors.
We get:
The above code assumes that x is integer and starting at 1. If it isn't, then use the third output of unique to assign each number a unique ID, then run this through accumarray. When you're done, use the output of accumarray like normal:
[xu,~,id] = unique(x);
Z = accumarray(id, y(:), [], #sum);
stem(xu, Z);

drow cumulative distribution function in matlab

I have two vectors of the same size. The first one can have any different numbers with any order, the second one is decreasing (but can have the same elements) and consists of only positive integers. For example:
a = [7 8 13 6];
b = [5 2 2 1];
I would like to plot them in the following way: on the x axis I have points from a vector and on the y axis I have the sum of elements from vector b before this points divided by the sum(b). Therefore I will have points:
(7; 0.5) - 0.5 = 5/(5+2+2+1)
(8; 0.7) - 0.7 = (5+2)/(5+2+2+1)
(13; 0.9) ...
(6; 1) ...
I assume that this explanation might not help, so I included the image
Because this looks to me as a cumulative distribution function, I tried to find luck with cdfplot but with no success.
I have another option is to draw the image by plotting each line segment separately, but I hope that there is a better way of doing this.
I find the values on the x axis a little confusing. Leaving that aside for the moment, I think this does what you want:
b = [5 2 2 1];
stairs(cumsum(b)/sum(b));
set(gca,'Ylim',[0 1])
And if you really need those values on the x axis, simply rename the ticks of that axis:
a = [7 8 13 6];
set(gca,'xtick',1:length(b),'xticklabel',a)
Also grid on will add grid to the plot