Clustering Connected Squares in MATLAB - matlab

Assume there is a mesh which is colored in the specific pattern:
As you can see, these 62 red squares are connected together in three different groups(Clusters). You might like to download the data from the following link.
Click here for downloading mesh coordinates (XX, YY, ZZ) and its colours(C)
Then, you can generate the mesh below with this code:
load('data.mat');
figure('units','normalized','outerposition',[0 0 1 1]); % Opening big figure
axis equal; axis off;
SURF = surf( XX , YY , ZZ, C);
Now, I am looking for a code which can segment these three clusters.
Please bear in mind that you should consider those squares as a one group which have maximum one square gap distance in any direction. It means, in this particular case, we have three clusters of 11 , 13 and 38 squares.
Thank you in advance for your time.

You can use connected component labeling.
In Matlab, assuming your matrix contains only 0 and 1 (or you can make it so), you would use bwlabel.
L = bwlabel(data, 8)
Now L will be a matrix the same size as data with labels 1, 2, 3... in place of the 1's.
The 8 as the second parameter denotes the connectivity of the components. 4-connected would mean that one square is connected to the other only if it is to the left, right, above or below the square. 8-connected means that squares are also connected if they are adjacent diagonally, as in the bottom-right of your sample. 8 is the default, and you can leave it out, but you should be aware of the distinction in case you need it to behave differently in the future.

Related

Reducing the area of the voronoi cells and determining the coordinates of new vertices

I have written a MATLAB code to create the figure attached using the voronoi. My region of interest is the red circle. Hence the seeds for voronoi were kept within the region.
Idea: One approach would be to use a homothetic transformation of the Voronoi cell C{k} about the corresponding point X(k,:), with a ratio R such as 0 < R < 1. The shape of the cells—the number of corners and their associated angles—will be preserved, and the areas will be reduced proportionally (i.e. by a factor R2, and not by a constant value).
Please note that this will "destroy" your cells, because the reduced Voronoi cells will not share anymore vertices/edges, thus the [V,C] representation doesn't work anymore as it is. Also, the distances between what were once common edges will depend on the areas of the original cells (bigger cells, bigger distances between adjacent edges).
Transformation example for 2 2D points:
A = [1,2]; %'Center'
B = [10,1]; %'To be transformed'
R = 0.8; %'Transformation ratio'
trB = A + R*(B-A); %'Transformed'
couldn't follow your implementation of CST-link's idea, but here is one that works (i tested it in matlab, but not yet in abaqus, the code it spits out looks like abaqus should be happy with it)
rng(0);
x=rand(40,2);
plot(x(:,1),x(:,2),'x')
[v,c]=voronoin(x);
fact=0.9;
for i=1:length(c)
cur_cell=c{i};
coords=v(cur_cell,:);
if isfinite(coords)
%fact=somefunctionofarea?;
centre=x(i,:); % i used the voronoi seeds as my centres
coords=bsxfun(#minus,coords,centre); %move everything to a local coord sys centred on the seed point
[theta,rho] = cart2pol(coords(:,1),coords(:,2));
[xnew, ynew]= pol2cart(theta,rho*fact);
xnew=xnew+centre(1); % put back in real coords.
ynew=ynew+centre(2);
xnew2=circshift(xnew,1);
ynew2=circshift(ynew,1);
fprintf('s1.Line(point1=(%f,%f),point2=(%f,%f))\n',...
[xnew, ynew, xnew2,ynew2]');
line(xnew,ynew); %testing purposes - doesn't plot last side in matlab
end
end
Having seen the results of this one, i think you will need a different way factor to shrink your sides. either to subtract a fixed area or some other formula.

MATLAB: Density-time Plot

I have 11 1x50 matrices that contain densities. The first looks like [20, 20, 20... 20] and represents time=0. The second looks like [20, 19, 22,..], etc. and represents time=100. These continue to vary until t=1000.
What I'm hoping to do is to create a plot with the elements' position on the x-axis (50 positions for the 50 pieces of data in each) and time (0-1000) on the y-axis. Ideally, I'd like the plot to be completely filled in with color densities, and a colorbar on the side that shows what densities the color range represents.
Any help would be greatly appreciated!
Sort of inspired by: http://www.chrisstucchio.com/blog/2012/dont_use_scatterplots.html
Assuming you have (or can arrange to have) all those vectors as columns of a 11x50 matrix:
A = randi(100, 11,50); %//example data
you can just use
imagesc(1:50, 0:100:1000, A)
colorbar
axis xy %// y axis increasing, not decreasing
Example:
Looking at the comments, it will be easier to stack these vectors into a 2D matrix. You have 11 individually named vectors. Assuming that your vectors are named vec1, vec2, vec3, etc., create a 2D matrix A that stacks these vectors on top of each other. Also, you'll need to include an extra row and column at the end of this matrix that contains the minimum over all of your vectors. The reason why this is will be apparent later, but for now take my word for it as this is what you need.
In other words:
A = [vec1; vec2; vec3; vec4; vec5; vec6; vec7; vec8; ...
vec9; vec10; vec11];
minA = min(A(:));
A = [A minA*ones(11,1); minA*ones(1,51)];
As such, the first row contains the information at time 0, the next row contains information at time 100, etc. up to time 1000.
Now that we have that finished, we can use the pcolor function to plot this data for you. pcolor stands for pseudo-coloured checkerboard plot. You call this by doing:
pcolor(A);
This will take a matrix stored in A and produce a checkerboard plot of your data. Each point in your matrix gets assigned a colour. The colours get automatically mapped so that the least value gets mapped to the lowest colour while the highest value gets mapped to the highest colour. pcolor does not plot the last row and last column of the matrix, but pcolor does use all of the data in the matrix. In order to ensure that the colours get properly mapped, we need to pad your matrix so that the last row and last column get assigned to the smallest value over all of your vectors. As you want to plot all values in the matrix, that's why we did what we did above.
Once we do this, we'll need to modify the X and Y ticks so that it conforms to your data. As such:
pcolor(A);
set(gca, 'XTick', 0.5:5:51.5);
set(gca, 'XTickLabel', 0:5:50);
set(gca, 'YTick', 1.5:11.5);
set(gca, 'YTickLabel', 0:100:1000);
xlabel('Sample Number');
ylabel('Time');
colorbar;
What the code does above is that it generates a checkerboard pattern like what we talked about. This labels the Sample Number on the x axis while time is on the y axis. You'll see with the two set commands that I did, this is a bit of a hack. The y axis by default labeled the ticks going from 1 - 12. What I did was that I changed these labels so that they go from 0 to 1000 in steps of 100 instead and I also removed the tick of 12. In addition, I have made sure that these labels go in the middle of each row. I do this by setting the YTick property so that I add 0.5 to each value going from 1 - 11. Once I do this, I then change the labels so that they go from 0 - 1000 in steps of 100. I also do the same for the x axis in a similar fashion to the y axis. I then add a colorbar to the side as per your request.
Following the above code, and generating random integer data that is between 13 and 27 as per your comments:
A = randi([13,27], 11, 50);
minA = min(A(:));
A = [A minA*ones(11,1); minA*ones(1,51)];
We get:
Obviously, the limits of the colour bar will change depending on the dynamic range of your data. I used randi and generated random integers within the range of 13 to 27. When you use this code for your purposes, the range of the colour bar will change depending on the dynamic range of your data, but the colours will be adjusted accordingly.
Good luck!

Contouring a mesh and assigning magnitude arrows in Matlab

I want to assign vector to a contourf graph, in order to show the direction and magnitude of wind.
For this I am using contourf(A) and quiver(x,y), where as A is a matrix 151x401 and x,y are matrices with the same sizes (151x401) with magnitude and direction respectively.
When I am using large maps i get the position of the arrows but they are to densily placed and that makes the graph look bad.
The final graph has the arrows as desired, but they are to many of them and too close, I would like them to be more scarce and distributed with more gap between them, so as to be able to increase their length and at the same time have the components of the contour map visible.
Can anyone help , any pointers would be helpful
i know its been a long time since the question was asked, but i think i found a way to make it work.
I attach the code in case someone encounters the same issues
[nx,ny]= size(A) % A is the matrix used as base
xx=1:1:ny; % set the x-axis to be equal to the y
yy=1:1:nx; % set the y-axis to be equal to the x
contourf(xx,yy,A)
hold on, delta = 8; %delta is the distance between arrows)
quiver(xx(1:delta:end),yy(1:delta:end),B(1:delta:end,1:delta:end),C(1:delta:end,1:delta:end),1) % the 1 at the end is the size of the arrows
set(gca,'fontsize',12);, hold off
A,B,C are the corresponding matrices ones want to use

Drawing a network of nodes in circular formation with links between nodes

I would like to draw a circular graph of nodes where certain nodes have a link between them. Here are a few examples from social network graphs:
(source: wrightresult.com)
(source: twit88.com)
How can this be done with MATLAB? Is it possible without installing a separate package?
Here is one way you can do what you want. First, generate points on the circle that you are interested in
clear;
theta=linspace(0,2*pi,31);theta=theta(1:end-1);
[x,y]=pol2cart(theta,1);
Next, if you know the pairs of nodes that are connected, you can skip this step. But in many cases, you get a connectivity matrix from other computations, and you find the indices of the connected nodes from that. Here, I've created a Boolean matrix of connections. So, if there are N nodes, the connectivity matrix is an NxN symmetric matrix, where if the i,jth element is 1, it means you have a connection from node i to node j and 0 otherwise. You can then extract the subscripts of the non-zero pairs to get node connections (only the upper triangle is needed).
links=triu(round(rand(length(theta))));%# this is a random list of connections
[ind1,ind2]=ind2sub(size(links),find(links(:)));
This is the connectivity matrix I generated with the code above.
Now we just need to plot the connections, one at a time
h=figure(1);clf(h);
plot(x,y,'.k','markersize',20);hold on
arrayfun(#(p,q)line([x(p),x(q)],[y(p),y(q)]),ind1,ind2);
axis equal off
which will give you a figure similar to your examples
Inspired by the latest blog post by Cleve Moler, you could also use the gplot function to draw a graph given an adjacency matrix and node coordinates.
Here is an example using bucky; a demo function part of MATLAB that generates the graph of a truncated icosahedron (looks like a soccer ball). We will only use its adjacency matrix for this example since we are laying out the vertices in a circular shape:
%# 60-by-60 sparse adjacency matrix
A = bucky();
N = length(A);
%# x/y coordinates of nodes in a circular layout
r = 1;
theta = linspace(0,2*pi,N+1)'; theta(end) = [];
xy = r .* [cos(theta) sin(theta)];
%# labels of nodes
txt = cellstr(num2str((1:N)','%02d'));
%# show nodes and edges
line(xy(:,1), xy(:,2), 'LineStyle','none', ...
'Marker','.', 'MarkerSize',15, 'Color','g')
hold on
gplot(A, xy, 'b-')
axis([-1 1 -1 1]); axis equal off
hold off
%# show node labels
h = text(xy(:,1).*1.05, xy(:,2).*1.05, txt, 'FontSize',8);
set(h, {'Rotation'},num2cell(theta*180/pi))
We can take this a step further and try to minimize edge crossings. That is we want to rearrange the nodes so that the edges are as close as possible to the circumference of the circle.
This can be done by finding a symmetric permutation of the matrix that minimizes its bandwidth (non-zeros are closer to the diagonal)
p = symrcm(A);
A = A(p,p);
txt = txt(p);
The result in this case:
Other improvements include replacing straight lines with curved splines to draw the edges, (that way you get a nicer graph similar to the second one you've shown), or using different colors to show clusters of vertices and their edges (obviously you'll need to do graph clustering). I will leave those steps to you :)

MATLAB: Return array of values between two co-ordinates in a large matrix (diagonally)

If I explain why, this might make more sense
I have a logical matrix (103x3488) output of a photo of a measuring staff having been run through edge detect (1=edge, 0=noedge). Aim- to calculate the distance in pixels between the graduations on the staff. Problem, staff sags in the middle.
Idea: User inputs co-ordinates (using ginput or something) of each end of staff and the midpoint of the sag, then if the edges between these points can be extracted into arrays I can easily find the locations of the edges.
Any way of extracting an array from a matrix in this manner?
Also open to other ideas, only been using matlab for a month, so most functions are unknown to me.
edit:
Link to image
It shows a small area of the matrix, so in this example 1 and 2 are the points I want to sample between, and I'd want to return the points that occur along the red line.
Cheers
Try this
dat=imread('83zlP.png');
figure(1)
pcolor(double(dat))
shading flat
axis equal
% get the line ends
gi=floor(ginput(2))
x=gi(:,1);
y=gi(:,2);
xl=min(x):max(x); % line pixel x coords
yl=floor(interp1(x,y,xl)); % line pixel y coords
pdat=nan(length(xl),1);
for i=1:length(xl)
pdat(i)=dat(yl(i),xl(i));
end
figure(2)
plot(1:length(xl),pdat)
peaks=find(pdat>40); % threshhold for peak detection
bigpeak=peaks(diff(peaks)>10); % threshold for selecting only edge of peak
hold all
plot(xl(bigpeak),pdat(bigpeak),'x')
meanspacex=mean(diff(xl(bigpeak)));
meanspacey=mean(diff(yl(bigpeak)));
meanspace=sqrt(meanspacex^2+meanspacey^2);
The matrix pdat gives the pixels along the line you have selected. The meanspace is edge spacing in pixel units. The thresholds might need fiddling with, depending on the image.
After seeing the image, I'm not sure where the "sagging" you're referring to is taking place. The image is rotated, but you can fix that using imrotate. The degree to which it needs to be rotated should be easy enough; just input the coordinates A and B and use the inverse tangent to find the angle offset from 0 degrees.
Regarding the points, once it's aligned straight, all you need to do is specify a row in the image matrix (it would be a 1 x 3448 vector) and use find to get non-zero vector indexes. As the rotate function may have interpolated the pixels somewhat, you may get more than one index per "line", but they'll be identifiable as being consecutive numbers, and you can just average them to get an approximate value.