Animated 3D Scatter-Plot in Matlab - matlab

I have a set of data with a total of 4 independent variables, and I figure the only way to represent 4 independent variables and one dependent variables is to animate a 3D scatter-plot.
Let's say I have the following set of data:
W X Y Z Val
0 0 0 0 5.5
0 0 0 1 2.3
0 0 1 0 1.6
0 0 1 1 8.8
0 1 0 0 2.6
0 1 0 1 4.8
0 1 1 0 0.1
0 1 1 1 1.1
1 0 0 0 1.0
1 0 0 1 0.0
1 0 1 0 0.4
1 0 1 1 4.4
1 1 0 0 4.4
1 1 0 1 7.9
1 1 1 0 9.1
1 1 1 1 2.3
And the values were read in and converted to the following arrays:
W = {0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1}
x = {0,0,0,0,1,1,1,1,0,0,0,0,1,1,1,1}
X = {0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1}
Z = {0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1}
Val = {5.5,2.3,1.6,8.8,2.6,4.8,0.1,1.1,1.0,0.0,0.4,4.4,4.4,7.9,9.1,2.3}
I'm wondering how to create a 3D scatter-plot (scatter3) with X, Y, and Z as the independent variables, Val as represented by the colors of the dots, and to animate with respect with the variable W as time?
Basically, when the different values of Val for when W=0 and W=1 are plotted at different times with respect to X, Y, and Z.

Based on your edit, I have slightly refined my suggestions:
mat=cell2mat([W;x;X;Z;Val])'; %Convert cells into a matrix
colors=prism(numel(mat(:,1)));
scatter3(mat(1,2),mat(1,3),mat(1,4),100,colors(1,:),'filled');
axis tight;
for jj=1:8:numel(mat(:,1))
scatter3(mat(jj:jj+7,2),mat(jj:jj+7,3),...
mat(jj:jj+7,4),100,colors(jj:jj+7,:),'filled');
drawnow
pause(1)
end
In the above example the colors are sequentially assigned, but if you want the colors to be the same where VAL is the same, you could do something like the following:
mat=cell2mat([W;x;X;Z;Val])';
val_new=mat(:,5)/max(mat(:,5)); %0<VAL<1
scatter3(mat(1,2),mat(1,3),mat(1,4),100,[0 val_new(1) 0],'filled');
axis tight;
for jj=1:8:numel(mat(:,1))
scatter3(mat(jj:jj+7,2),mat(jj:jj+7,3),...
mat(jj:jj+7,4),100,[zeros(8,1) val_new(jj:jj+7,:) zeros(8,1)],'filled');
drawnow
pause(1)
end
Of course, both these examples assume that you will consistently have 8 entries at each time. And in the second instance there will be occasions where the differences in the colors are only very slight. If you want to actually save a video or a animated gif, just take a look at getframe and imwrite.

Related

How do I populate matrix with a vector, considering Matrix as chart and vector as line

Consider following values
result=zeros(11,11);
line=(4:0.4:8);
Imagine result as a 11x11 X-Y chart paper. So initially we have a blank chart paper. As in a chart plot, I want to populate values of line in result matrix so that we get an upward sloping line when we display matrix.
Consider following figure which I want as result.
Here, result matrix can be visualized as chart paper with origin at bottom left corner. Now, for X=1, line(1)=4; for X=2, line(2)=4.4,.. and so on.
I have written following code which serves the purpose.
result=zeros(11,11);
line=(4:0.4:8);
for i=1:length(line)
temp=floor(line(i));
result(length(line)-temp+1,i)=line(i);
end
Is there a more efficient way to implement this solution? (I shall be working with 20000x20000 matrix, so method needs to be fast)
As suggested in comments, Problem Description is as follows:
I have lets say 1000 lines. All of these lines have different slopes and intercept. I know the x range of the lines and y range of the lines. There is not much I can infer from data if I plot these lines simultaneously on a single plot. The resulting image will be something like this:
Not much can be inferred about this plot. However, if I can get this information saved in a big matrix, then I can analyse where maximum lines are passing through at a particular X index and make further analysis accordingly.
Further Details
I am discretinizing Y axis into 1000 equally spaced interval:
sample code as follows:
range=max(data)-min(data);
percent=0.20;
outerRange= max(data)+range*percent - (min(data)-range*percent);
outerRangeValues=min(data)-range*percent:outerRange/1000:max(data)+range*percent;
Even though it is entirely possible that a particularly steep line will pass through 2 or more rows in a single column, I'll only select only one of the rows to be filled by line in a single column. This can be done by taking average of rows values for a particular column and assigning single row to be its value for that column
You can use sub2ind to keep things vectorized and avoid loops.
The idea is to find all the row and column indices which will have to be modified.
For X axis it is easy, it is simply one per column so the X indices will be 1,2,3,...,np.
For the Y axis, you have to bin the line values into the Y grid. Since indices have to be integers, you have to convert your floating point values into integers. For that you can choose between round, floor and ceil. Each will place some values slightly differently, it is up to you to define which rounding method makes sense for your problem.
Once you have your indices [row_indices,column_indices], you convert them to linear indices into the matrix by using sub2ind, then you assign the values of line into these linear indices.
In code:
line=(4:0.4:8); % your input (line vector)
np = numel(line) ; % determine size of matrix/chart
% identify column and row indices to modify
idCol = 1:np ;
idRow = fliplr( round( line ) ) ; % choose "round", "floor" or "ceil"
% build the result
result = zeros(np);
linearInd = sub2ind( [np,np], idRow, idCol ) ;
result(linearInd) = line ;
Gives you:
>> result
result =
0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 7.2 7.6 8
0 0 0 0 0 0 6.4 6.8 0 0 0
0 0 0 5.2 5.6 6 0 0 0 0 0
0 4.4 4.8 0 0 0 0 0 0 0 0
4 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0

Determine matrix boundary without loops

I have got a 2D matrix. There is some region in the matrix where the elements are non-zero, in particular everywhere around the edge they are zero.
I plot the matrix using image as a colorplot and would like to add the curve that shows the boundary between non-zero values to zero values in the matrix. Is there any neat way to do this without loops?
This looks like a job for convhull :
To illustrate this code i'll take a dummy example :
A=zeros(10);
B=binornd(1,0.5,8,8);
A(2:end-1,2:end-1)=B
A =
0 0 0 0 0 0 0 0 0 0
0 0 0 1 0 0 0 0 0 0
0 0 1 1 1 1 1 1 0 0
0 0 1 1 0 0 0 0 1 0
0 0 0 1 0 0 0 1 0 0
0 1 0 0 0 0 0 1 0 0
0 0 0 1 1 1 1 1 1 0
0 0 1 0 1 1 1 1 0 0
0 1 0 1 1 1 1 0 1 0
0 0 0 0 0 0 0 0 0 0
1/ Find the locations of all non zero entries :
[row,col]=find(A);
2/ Take the convex hull of these locations
k=convhull(row,col);
3/ Plot the convex hull (I plot the non zero points aswell but in your problem it will be your image points)
plot(row(k),col(k),'r-',row,col,'b*')
Result :
Another option is using the image processing toolbox and the bwperim function. This will work if you know that your area is completely closed (i.e. has no holes in the boundary)
This is an example using a black and white image, and you have 2 options: fill the inner gaps before, or not. You can see in the result the differences.
A = imread('circles.png');
Afill=imfill(A,'holes'); % optional
Abound1=bwperim(Afill);
Abound2=bwperim(A);
imshow([A,Abound, Abound2])
You can plot one on top of the other with:
[x,y]= find(Abound2);
hold on
image(A*255) %// If A is logical, else use just A (not *255)
colormap('gray')
plot(y,x,'r.')
hold off
axis tight
If you have a gray-scale image (or a matrix with a single value in each position (2D matrix), then you can binarize it first by either:
If you know everything outside your object is EXACTLY zero
A=yourA>0;
If you want to separate your object from the background, and the background is not exactly zero by A=im2bw(yourA,level), by choosing your own level, or letting Otsu do it for you with level=graythresh(yourA)

assigning coordinate to a matrix in MATLAB

I'm writing a MATLAB code, I encountered a problem: I have a (2N+1)*(2N+1) matrix for example 7*7. I want to assign coordinate system to it such that the matrix center is the origin of coordinate system. I mean I want to assign (0,0) to row 4 and column 4 of matrix, (1,0) to row 4 and column 5 of matrix and so on. please help me
Thank you in advance
I want to generate a line of ones in all possible directions in a square matrix like this:
0 0 0 0 0 0 0
0 0 0 0 0 0 1
0 0 0 0 0 1 0
0 0 0 1 0 0 0
0 1 0 0 0 0 0
1 0 0 0 0 0 0
0 0 0 0 0 0 0
center of matrix is the origin. this line has 30 degree from horizontal axis.
What you want is a simple mapping from the original matrix counting system to a customized one. Here I have built two cell matrices, representing the coordinates of the elements in the matrix.
Here I have done a simple mapping as follows:
for ii = 1:7
for jj=1:7
D{ii,jj} = C{ii,jj} - [4,4];
end
end
Generally, for matrix of size 2*N+1, you will do the following:
for ii = 1:2*N+1
for jj = 1:2*N+1
D{ii,jj} = C{ii,jj} - [N+1,N+1];
end
end
where C is the original matrix and D is the mapped matrix. After you well-understood what I have done here, you can then replace the for-loops with more efficient functions such as bsxfun.

Creating a square wave to overlay data set in matlab

In Matlab I am trying to achieve the following:
I have a data set that biologically represents activation in the brain when stimulus is given. So the data is such that we have 9 data points of stimulation, and then 15 of rest and it keeps going on like that for around 300 data points (4 mins in real-time).
I am able to plot the data easily but I am trying to overlay a square wave which represents the time in which there is "stimuluation" so that just by looking at the graph it is easy to see which is the rest period and which stimulation.
Very simply I have created a vector X and made it so that (the first 3 points are meant to be 0)
X = [0 0 0 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0]
And plotted it on the same graph as the data. It works fine but the problem is that I need X to be created automatically according to my time scale.
Total_time = [-3:1.5:302]
This is my total time scale, from -3 to 302 seconds with the sampling rate as 1.5s. the first 3 points
-3, -1.5, 0 are period of rest. Then from 0 seconds the stimulus starts for about 9 seconds (that will make 6 data points in that 9 second period).
So my question is - is it possible to use some sort of for loop to create this vector X to say that for 6 data points from 0 X = 1 and for the next 10 X = 0? I was thinking of the following:
X = zeros(1,304) %to create a 1x304 vector of zeros
X(0:3)=0
X(3:9)=1
X(9:19)=0
But then again.. this is writing it by hand.
Can anyone help?
Thanks!
As you already told us: What you have is a repeating pattern.
In your case the pattern is the vector
pattern = [zeros(1,3) ones(1,9) zeros(1,15-3)];
So you could generate your signal by replicating this vector using repmat:
startTime = -3;
endTime = 302;
timeStep = 1.5;
%%// Computation
time = startTime:timeStep:endTime;
numPatterns = ceil(length(time)/length(pattern));
X = repmat(pattern, 1, numPatterns);
%// As the pattern will end after endTime, we remove everything beyond endTime
X(length(time)+1:end) = [];
%%// Plot
plot(time, X);
This is easy with modulo operations:
m = 3; %// initial low period
n = 6; %// high period
p = 10; %// low period
s = 304; %// x size
x = [zeros(1,m) mod(0:s-m-1, n+p)<n];
Result (first values):
0 0 0 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 0 0 ...
Note that n and p can be non-integer if needed. For example, if the high period lasts for 5 seconds and your sampling period is 1.5 seconds, just define n=5/1.5, which gives
0 0 0 1 1 1 1 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 ...
As can be seen, the high period lasts either 4 or 3 samples to accomodate the non-integer n.

Matlab PRBS 4 waveform generation

I have a variable which has values of PRBS 4 sequence.
Output = [0 0 0 1 0 0 1 1 0 1 0 1 1 1 1];
I want to plot this in Matlab. I know I have to use idinput() function to generate prbs sequences. But I am using an old version of Matlab and this function is not available for me. Just by using plot(Output) will not give me the PRBS signal, since in the transition from 0 to 1 and 1 to 0, it will be like a triangle. I need to have a square waveform for PRBS.
Also, I want to make this signal 1 Gbps signal. Is this possible to do?
Best Regards,
nkp.
You can repeat each of output bit by some number and then plot.
For example: output = [0 0 1 0];
Then you repeat each bit by some number (let say 4), so the output vector is
[0 0 0 0 0 0 0 0 1 1 1 1 0 0 0 0].