How can I plot in horizontal lines along X axis corresponding to a value on the y axis? - matlab

I have 2 arrays Q and Z. I want to plot Q on the y-axis and Z on the x-axis. The elements of Z are 0s and 1s.
What I want is to draw a horizontal line from one '1' to the next '1'.
E.g. in vector Z, the first 1 to the next 1, has its corresponding y value as the first element of Q, Then the 3rd 1 to the fourth 1 has its y value as the 2nd value in Q and so on.
now i will have several _ _ _ (horizontal lines spanning length of the distance between the 1s as plots)
any help will be appreciated.

Assuming that Q and Z are column vectors, you could do something like this:
Q2=[Q,Q];
inds=1:numel(Z);
inds=inds(Z==1);
X=reshape(inds',2,numel(inds)/2);
At this point, Q2 and X should have the same dimensions (two-column matrices).
Then plot the horizontal lines beside each other:
plot(X,Q2)
Or above each other, starting at x=0 with different lengths:
X2=[zeros(numel(Q),1),diff(X)]
plot(X2,Q2)
I'm not at a computer so I can't confirm details on returned dimensions.
Hope it helps!

You can find the endpoints of each horizontal line with find(), then plot the lines with plot.
Q = [1 2 3 4];
Z = [1 0 1 1 0 0 1 1 1 0 1 0 1];
z_endpoints = find(Z);
figure;
for i = 1:numel(Q)
plot(z_endpoints([i*2-1,i*2]),Q([i,i]))
hold on
end
hold off
To get the lines all the same color and in the same plot, you can put the points in a vector with NaNs (not-a-number) to produce the gaps. A bit more work, but with a cleaner plot.
Q = [1 2 3 4];
Z = [1 0 1 1 0 0 1 1 1 0 1 0 1];
z_endpoints = find(Z);
zpoints = [z_endpoints(1:2:end-1);z_endpoints(2:2:end);nan(size(Q))];
zpoints = zpoints(:);
qpoints = [Q;Q;nan(size(Q))];
qpoints = qpoints(:);
plot(zpoints,qpoints)

Related

Generate a binary matrix H knowing only the positions of the 1's

I would like to construct a binary matrix H of very large size, knowing only the positions of the '1's in the matrix.
For example if I know the following coordinates : (1,1) = 1 , (3,1) = 1 , (2,2) = 1, (1,3) = 1.The generated matrix gives : H = [1 0 1 ; 0 1 0 ; 1 0 0]
I tried to do it manually but with a very large matrix (For example 512*1024) it becomes very complicated.
Thank you.
Use a sparse matrix:
% The coordinates
x = [1 3 2 1]
y = [1 1 2 3]
% Create a sparse matrix, then convert the sparse matrix to a full storage matrix
H = full(sparse(x,y,1))
Or even shorter (but using the same logic):
H = sparse(x,y,1)+0
% It works because matlab use an implicit class conversion

Matlab generate smooth curve between scatter points

I need to generate a curve between scatter points then identify the unit normal of the curve at each point. Here is an example of a point cloud
figure
x = [1 2 0 0 1 1 2 3 4 2];
y = [4 6 9 1 1 2 4 9 2 3];
scatter(x,y)
hold on
line(x,y)
xlim([0 4])
ylim([0 10])
NOTE: the 2 points along the y-axis are connected
Instead of a line between the points, I'd like to create a smooth curve. I'm not sure how to do this when points in x and y repeat. An attempt using spline fails. After I know the curve, I need to find the unit normals at each point. How do I go about this?
EDIT:
Basically I want to do what is show here for polyfit in the matlab docs. Assuming that x was unique in my case, this wouldn't be an issue. I could identify the polynomial and then, I believe, determine the unit normals from the polynomial function evaluated at that point. But in my case, the x and y data repeat so a straight forward application doesn't work.
One way to get a smooth path is to treat this as a parametric function and interpolate x and y separately.
x = [1 2 0 0 1 1 2 3 4 2];
y = [4 6 9 1 1 2 4 9 2 3];
t = 1:numel(x);
tq = 1:0.1:t(end);
xq = interp1(t,x,tq,'v5cubic');
yq = interp1(t,y,tq,'v5cubic');
plot(x,y,' ob',xq,yq,'-r');
To estimate the normals you can take the average normal of the two line segments around the sample points. This code is a bit ugly but it gets the job done.
n = zeros(2,numel(x));
for tidx = 1:numel(t)
tt = t(tidx);
idx1 = find(tq <= tt,1,'last');
idx0 = idx1 - 1;
idx2 = idx1 + 1;
if idx0 > 0
n1 = [yq(idx1) - yq(idx0); xq(idx0) - xq(idx1)];
n(:,tidx) = n(:,tidx) + n1/norm(n1);
end
if idx2 <= numel(tq)
n2 = [yq(idx2) - yq(idx1); xq(idx1) - xq(idx2)];
n(:,tidx) = n(:,tidx) + n2/norm(n2);
end
n(:,tidx) = n(:,tidx) / norm(n(:,tidx));
end
plot(x,y,' ob',xq,yq,'-r',[x.' x.'+n(1,:).'].', [y.' y.'+n(2,:).'].',' -k');
axis equal;
If you use pchip instead of v5cubic for the interpolation method then you get more symmetry around the sample points. However, it appears that any sharp turns (90 degrees or greater) are not smoothed.

3D visualization of some data in MATLAB

This is my data matrix in MATLAB:
a = [43.676289 -79.477386 1
43.676370 -79.477107 5
43.676517 -79.477375 20
43.676417 -79.477509 8
43.676129 -79.477278 15];
The first column is Y axis, the second column is X axis and the third column is my data. How can I draw a bar graph, and adjust the color of the bars according to the value of data (like colorbar in a surface plot) for each data point in MATLAB?
I added an example graph which I drew for another data matrix. In this example X, Y, and Z were linear and I could draw this graph using 'surf' command with no problem. I need to draw the same graph for mentioned data, but the unit of the XY axis is not compatible with Z, and this confused me.
Just as an additional comment, if we plot only the XY plane, the result looks like the next picture:
scatter(a(:,2),a(:,1),'*')
Moreover, this is a simple example that might be useful to expand it:
z = [5 0 2 0
0 0 0 0
0 0 0 0
0 0 0 0];
[X,Y] = meshgrid(0:1:3);
surf(X,Y,Z)
Thanks
Here is something you can do - build Z as a matrix from your data:
a = [43.676289 -79.477386 1
43.676370 -79.477107 5
43.676517 -79.477375 20
43.676417 -79.477509 8
43.676129 -79.477278 15];
[X,Y] = meshgrid(sort(a(:,2)),sort(a(:,1)));
Z = zeros(size(X));
for k = 1:size(a,1)
xind = abs(X-a(k,2))<eps;
yind = abs(Y-a(k,1))<eps;
Z(xind & yind) = a(k,3);
end
Typing surf(X,Y,Z) will give you this:
However, I think that bar3 might be a better choice:
b = bar3(sort(a(:,1)),Z);
xticklabels(sort(a(:,2)));
cdata_sz = size(b(1).CData);
z_color = repelem(Z,6,4);
z_color(abs(z_color)<1) = nan;
z_color = mat2cell(z_color,...
cdata_sz(1),ones(1,size(Z,2))*cdata_sz(2));
set(b,{'CData'},z_color.')
view(-70,30)

Matlab stairs plot doesn't start from the origin

I am trying to plot a binary input using stairs, but the data doesn't start from zero. So how to make the plot starts from zero instead of one?
Matlab Code:
a = [ 0 0 1 0 1 0 0 1 0 1 1 1 1 1 ];
stairs(a);
axis([0 14 -0.5 1.5 ]);
grid on;
You should add the x vector, in order to clarify where your data start on the x axis.
y = round(rand(1,10)); %binary vector
x = [0:length(y)-1]; %[0,1,2,3,4....]
stairs(x,y);
axis([0,10,-0.5,1.5])
Taking a look at the help for the plot command:
plot(Y) creates a 2-D line plot of the data in Y versus the index of
each value.
If Y is a vector, then the x-axis scale ranges from 1 to length(Y).
If Y is a matrix, then the plot function plots the columns of Y versus their row number. The x-axis scale ranges from 1 to the
number of rows in Y.
If Y is complex, then the plot function plots the imaginary part of Y versus the real part of Y, such that plot(Y) is equivalent to
plot(real(Y),imag(Y)).
To plot starting from zero:
vectors: plot(0:length(y) - 1, y)
matrices: plot(0:size(M, 1) - 1, M)
The same applies to stairs, the easy way of starting at 0 is to add the x axis to your plot, easily like this:
>> stairs(0:length(a)-1,a),axis([0 14 -0.5 1.5 ]);grid on;

How to map a matrix to a coordinate and plot it

I have been struggling with this problem for a while and I would appreciate if anyone can help me out. I am able to generate a 10 by 10 matrix and have it randomly assign "1"s in the matrix. My goal is to plot a "star" at the location of each element in the vector that has a value of "1", but I can't seem to figure out how to map the vector to a x-y coordinate system. The code I wrote below generates a plot of 100 stars at each cell and also generates a vector "v", but I don't know how I can link the plot to the vector that instead of having 100 "star"s in my plot, I have however many that there is a value of "1" at the corresponding location of the element.
Thanks!!
David
davidtongg#gmail.com
close all
clear all
clc
a=10;b=10;
v = zeros(a,b);
xy = int32(randi(a, 100, 2));
z = randi(1, 100, 1); % 100 values.
indexes = sub2ind([a, b], xy(:,1), xy(:,2))
v(indexes) = z
m=length(v);
ctr=0;
for i=1:m^2
x_cor(i)=(i-(floor(i/m)*m))*200-100;
y_cor(i)=(floor(i/m)+1)*200-100;
for j=1:m
if i==j*m
x_cor(i)=((i-(floor(i/m)*m))*200-100)+(2*m*100);
y_cor(i)=(floor(i/m))*200-100;
end
end
end
figure(1)
plot(x_cor,y_cor,'*');
grid on
I may of course have misinterpreted this because that code is confusingly complicated, but this is what I think you're after.
For an axb matrix with a random number of ones:
v = randi([0 1], a, b);
Or for a specific number n of ones, in random locations:
v = zeros(a, b);
idx = randi([1 numel(v)], n, 1);
v(idx) = 1; % linear indexing into a matrix
Then to plot them in arbitrarily scaled coordinates:
[y x] = find(v);
x = x * xscale + xoffset;
y = y * yscale + yoffset;
plot(x, y, '*');
Or the really cheaty way:
spy(v);
You can do it easily taking into account that plot(A) , where A is a matrix, plots the columns of the matrix vs their index, and that NaNs are not plotted:
v =[ 1 0 0 0
1 1 0 0
0 0 0 1
1 1 1 1
0 1 1 0 ]; %// example data
v2 = double(v); %// create copy; will be overwritten
v2(~v2) = NaN; %// change zeros to NaNs
plot(bsxfun(#plus, fliplr(v2.'), 0:size(v,1)-1) ,'b*')
%'// transpose and flip from left to right.
%// Add 1 incrementally to each column to have all of them "stacked" in the plot
axis([0 size(v,2)+1 0 size(v,1)+1]) %// set axis limits
set(gca,'xtick',1:size(v,2),'ytick',1:size(v,1)) %// set ticks
grid