How to display separate disconnected trees in MATLAB when doing hierarchical clustering and producing dendrograms? - matlab

I am working with MATLAB, and I have an adjacency matrix:
mat =
0 1 0 0 0 0
1 0 0 0 1 0
0 0 0 1 0 0
0 0 1 0 0 1
0 1 0 0 0 0
0 0 0 1 0 0
which is not fully connected. Nodes {1,2,5} are connected, and {3,4,6} are connected (the edges are directed).
I would like to see the separate clusters in a dendrogram on a single plot. Since there is not path from one cluster to the next, I would like to see separate trees with separate roots for each cluster. I am using the commands:
mat=zeros(6,6)
mat(1,2)=1;mat(2,1)=1;mat(5,2)=1;mat(2,5)=1;
mat(6,4)=1;mat(4,6)=1;mat(3,4)=1;mat(4,3)=1;
Y=pdist(mat)
squareform(Y)
Z=linkage(Y)
figure()
dendrogram(Z)
These commands are advised from Hierarchical Clustering. And the result is attached: imageDendrogram. Other than that the labels don't make sense, the whole tree is connected, and I connect figure out how to have several disconnected trees which reflect the disconnected nature of the data. I would like to avoid multiple plots as I wish to work with larger datasets that may have many disjoint clusters.

I see this was asked a while ago, but in case you're still interested, here's something to try:
First extract the values above the diagonal from the adjacency matrix, like so:
>> matY = [];
>> for n = 2:6
for m = n:6
matY = [matY mat(n,m)];
end
end
>> matY
matY =
Columns 1 through 13
0 0 0 1 0 0 1 0 0 0 0 1 0
Columns 14 through 15
0 0
Now you have something that looks like the Y vector pdist would have produced. But the values here are the opposite of what you probably want; the unconnected vertices have a "distance" of zero and the connected ones are one apart. Let's fix that:
>> matY(matY == 0) = 10
matY =
Columns 1 through 13
10 10 10 1 10 10 1 10 10 10 10 1 10
Columns 14 through 15
10 10
Better. Now we can compute a regular cluster tree, which will represent connected vertices as "close together" and non-connected ones as "far apart":
>> linkage(matY)
ans =
3 6 1
1 5 1
2 4 1
7 8 10
9 10 10
>> dendrogram(ans)
The resulting diagram:
Hope this is a decent approximation of what you're looking for.

Related

Counting islands in a matrix (preferably in IDL)

How can I count the number of values that are contiguous in an matrix? For example, if
A= [ 1 0 1 0 0 0 0 \
1 1 1 0 0 0 1\
1 1 0 1 1 1 1]
is a 7 by 3 matrix then the result should indicate that there are 12 contiguous values that are "1" (highlighted in bold), that there are 8 contiguous 0 values (highlighted in italics) and one lone 0 value. Code in IDL is preferred but MATLAB would also be helpful.
This is what you can do in MATLAB using the bwconncomp function. This is a function in the Image Processing Toolbox. I don't know a whole lot about IDL, it might have a similar function.
bwconncomp returns a struct with some information, one of the fields is PixelIdxList, which is a cell array with one element per connected component. Each of these elements is a vector with the indices to one of the array elements in the connected component. For the case of the 1 elements in your example, this cell array will have one vector with 12 values. For the case of the 0 elements, it will have two vectors, one with 1 value and one with 8:
>> A = [ 1 0 1 0 0 0 0 ; 1 1 1 0 0 0 1 ; 1 1 0 1 1 1 1 ];
>> CC = bwconncomp(A==1, 8);
>> cellfun(#numel, CC.PixelIdxList)
ans =
12
>> CC = bwconncomp(A==0, 8);
>> cellfun(#numel, CC.PixelIdxList)
ans =
1 8
The bwconncomp takes 4 or 8 as the second argument. This specifies what are considered connected elements (contiguous values, neighbors). 4 means only the 4 elements N,S,E,W are connected; 8 means also diagonal connections exist (8 neighbors).

Create a matrix from a vector such that its height and width are powers of multiples in matlab

I have tried multiple solutions in matlab to convert a vector for example
A = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17]
into
B= [ 1 2 3 4 ]
5 6 7 8
9 10 11 12
13 14 15 16
17 0 0 0
0 0 0 0
0 0 0 0
0 0 0 0
Here the desired matrix is 8x4 or rather the height or width is any multiple of 4. This would mean the nearest greater multiple of 4 if we keep any one dimension(height or width) fixed for fitting all elements and padding the extra elements with zeroes. I have tried reshape like so
reshape([c(:) ; zeros(rem(nc - rem(numel(c),nc),nc),1)],nc,[])
Here c is the original vector or matrix, nc is the number of columns.
It simply changes the number of rows and cols but does not take into account the possible powers required by the condition for height and width. I don't have the Communications Toolbox which has the vec2mat function.
Another possible alternative thought is to initialize a matrix with all zeroes and then assign. But at this point I'm stuck. So please help me matlab experts.
i think this what you mean:
n = 4;
A = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17];
B = zeros(n,ceil(numel(A)/n^2)*n);
B(1:numel(A)) = A;
B = B'
B = [ 1 2 3 4
5 6 7 8
9 10 11 12
13 14 15 16
17 0 0 0
0 0 0 0
0 0 0 0
0 0 0 0]

Fastest way to copy values between two matrix

I am looking for a fastest way to copy some special value of a matrix to other matrix. Assume that I have matrix A such as
A =[4 1 5 4 4
-2 -1 1 2 2
3 -1 1 7 3
5 3 -1 1 -2
6 4 4 -1 1]
My aim is that copy element that have value 1 and -1 to matrix B. The expected matrix B such as
B =[ 0 1 0 0 0
0 -1 1 0 0
0 -1 1 0 0
0 0 -1 1 0
0 0 0 -1 1]
I performed two way to create matrix B. However, I think that my way is still not fastest way if size of matrix A becomes larger. I know that the forum has many expert matlab guy. Could you suggest to me another way?
This is my code
%%First way:
tic;B=((A==1)|(A==-1)).*A;toc
Elapsed time is 0.000026 seconds.
%%Second way:
tic;idx1=find(A==1);idx2=find(A==-1);B=zeros(size(A));B(idx1)=1; B(idx2)=-1;toc;B
Elapsed time is 0.000034 seconds.
here's somthing on par with #thewaywewalk
B=A.*reshape(abs(A(:))==1,size(A));
This is how I test these:
A=randi(10,1000,1000)-7;
B1=#() ((A==1)|(A==-1)).*A;
B2=#() (abs(A) == 1).*A;
B3=#() A.*reshape(abs(A(:))==1,size(A));
timeit(B1)
ans =
0.0136
timeit(B2)
ans =
0.0080
timeit(B3)
ans =
0.0079
These will change from run to run, but the methods are on par...
here's the same test on a range of matrix sizes:
The only thing which comes to my mind, which could be faster:
B = (abs(A) == 1).*A;

how to find local maxima in image

The question is about feature detection concept.
I'm stuck after I finding the corner of image and I want to know how to finding the feature point within the computed corners.
Suppose I have grayscale image that have data like this
A = [ 1 1 1 1 1 1 1 1;
1 3 3 3 1 1 4 1;
1 3 5 3 1 4 4 4;
1 3 3 3 1 4 4 4;
1 1 1 1 1 4 6 4;
1 1 1 1 1 4 4 4]
if I use
B = imregionalmax(A);
the result would be like this
B = [ 0 0 0 0 0 0 0 0;
0 1 1 1 0 0 1 0;
0 1 1 1 0 1 1 1;
0 1 1 1 0 1 1 1;
0 0 0 0 0 1 1 1;
0 0 0 0 0 1 1 1]
The question is how do I pick the highest peak inside max local region (in sample how did I chose 5 from 3 and 6 from 4)?
My idea was using B to detect each region and use imregionalmax() again but I'm not good at coding and I need some advice or other ideas.
There are a couple of other easy ways to implement a 2D peak finder: ordfilt2 or imdilate.
ordfilt2
The most direct method is to use ordfilt2, which sorts values in local neighborhoods and picks the n-th value. (The MathWorks example demonstrates how to implemented a max filter.) You can also implement a 3x3 peak finder with ordfilt2 by, (1) using a 3x3 domain that does not include the center pixel, (2) selecting the largest (8th) value and (3) comparing to the center value:
>> mask = ones(3); mask(5) = 0 % 3x3 max
mask =
1 1 1
1 0 1
1 1 1
There are 8 values considered in this mask, so the 8-th value is the max. The filter output:
>> B = ordfilt2(A,8,mask)
B =
3 3 3 3 3 4 4 4
3 5 5 5 4 4 4 4
3 5 3 5 4 4 4 4
3 5 5 5 4 6 6 6
3 3 3 3 4 6 4 6
1 1 1 1 4 6 6 6
The trick is compare this to A, the center value of each neighborhood:
>> peaks = A > B
peaks =
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 1 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 1 0
0 0 0 0 0 0 0 0
imdilate
Image dilation is usually done on binary images, but grayscale image dilation is simply a max filter (see Definitions section of imdilate docs). The same trick used with ordfilt2 applies here: define a neighborhood that does not include the center neighborhood pixel, apply the filter and compare to the unfiltered image:
B = imdilate(A, mask);
peaks = A > B;
NOTE: These methods only find a single pixel peak. If any neighbors have the same value, it will not be a peak.
The function imregionalmax gives you the 8-connected region containing the maximum and its 8 neighbours (i.e. the 3x3-regions you are seeing). You could then use morphological operations with the same 3x3 structural element to thin out those regions to their centers. E.g.
B = imregionalmax(A);
C = imerode(B, ones(3));
or equivalently
B = imregionalmax(A);
D = bwmorph(B, 'erode');
Alternatively you could write your own maximum finding function using block-processing:
fun = #(block) % your code working on 'block' goes here ...
B = blockproc(A, ones(3), fun)
But most likely this will be slower than the built-in functions.
(I don't have the toolbox available right now, so I can't try that out.)
Also have a look here and here.

Inverse lookup table

This is a follow up question from a previous SO question. Now I have a bit which I have spread it into 8 bits. I have use Amro's solution to spread the bit to 8 bits. Now I want an inverse way to convert the 8bits back to the single bit.
I have only managed to implement the inverse using for loop which take alot of time in the application.
Is there a faster way of doing it?
Since you are using the solution I suggested last time, lets say you have a matrix N-by-8 of these 'bits' where each row represent one 8-bit binary number. To convert to decimal in a vectorized way, its as simple as:
» M = randi([0 1], [5 8]) %# 5 random 8-bit numbers
M =
1 0 1 0 1 0 1 1
0 1 1 0 1 1 1 0
1 1 0 1 1 0 1 1
1 0 0 0 0 1 1 0
1 0 0 1 0 1 1 0
» d = bin2dec( num2str(M) )
d =
171
110
219
134
150
An alternative solution:
d = sum( bsxfun(#times, M, power(2,7:-1:0)), 2)