From vector to heatmap in matlab - matlab

My data looks like this:
A = [1 1 0;
1 2 1;
2 2 0;
2 1 1]
The first two columns represent interactions. The third one represents the presents or absence of the interaction. How can I transform this into a heat map like this:
1 2
1 0 1
2 1 0
I used find, but is there a faster and more elegant way to do it?

Is it simple enough?
n = max(A(:, 1));
m = max(A(:, 2));
b = nan(n, m);
for i = 1:length(A)
b(A(i, 1), A(i, 2)) = A(i, 3);
end
I've tried some other code, but it failed. Thus the above might be the simpliest:
n = max(A(:, 1));
m = max(A(:, 2));
b = nan(n, m);
b(A(:, 1), A(:, 2)) = A(:, 3);
Anyway, I'd like to how you implement using find

Related

Create a dynamic matlab function using arrayfun or some other way

I am looking for a way to create a dynamic functions in length with multiple inputs, tried doing it this way but it seems over kill am guessing slow too, is there a better way of doing this to be compact and fast.
Problem want to create a cos with inputs from nX3 matrix sum(A*cos(W*t + F)) where A, W, F are columns from the matrix sum them all up then divide by its norm. Here is what I have so far .
% example input can have n rows
A = [1 2 3; 4 5 6];
item.fre = 0;
item.amp = 0;
item.pha = 0;
items = repmat(item, size(A, 1), 1);
for i = 1:size(A, 1)
items(i).fre = A(i, 1);
items(i).amp = A(i, 2);
items(i).pha = A(i, 3);
end
fun = #(t) sum(cell2mat(arrayfun(#(i) i.amp*cos(2*pi*t*i.fre + i.pha), items, 'un',0)));
% test run all this steps just to get a norm vector
time = 1:10;
testSignal = fun(time);
testSignal = testSignal/norm(testSignal);
I agree with a comment made by Cris Luengo to forget about anonymous functions and structures, you should try the simplest solution first. It looks like you're trying to add cosines with different amplitudes, frequencies, and phases. Here is how I would do it to make it very readable
A = [1 2 3; 4 5 6];
freq = A(:, 1);
amp = A(:, 2);
phase = A(:, 3);
time = 1:.01:10;
testSignal = zeros(size(time));
for i = 1:length(freq)
testSignal = testSignal + amp(i) * cos(2*pi*freq(i) * time + phase(i));
end
testSignal = testSignal/norm(testSignal);
plot(time, testSignal)
grid on
You could eliminate the amp, phase, and freq variables by accessing the columns of A directly, but that would make the code much less readable.

How to get a certain output in Matlab without for loops?

I have a list of vertices where each row corresponds to a (x, y) coordinate.
For example, the following includes the vertices (0, 0), (1, 0), and (0, 1)
V = [0 0;
1 0;
0 1];
I also have a list of edges where the first column specifies the row of the starting vertex and the second column specifies the row of the ending vertex.
For example, the following includes the edges (0, 0) to (1, 0) and (0, 0) to (0, 1)
E = [1 2; % V(1) -> V(2) = (0, 0) -> (1, 0)
1 3] % V(1) -> V(3) = (0, 0) -> (0, 1)
I need to produce a list of edges with their actual coordinates from these two lists. That is, from V and E, I need
edge1 = [0 0]; % = E(1, 1) = V(1)
edge2 = [0 0]; % = E(2, 1) = V(1)
edge3 = [1 0]; % = E(1, 2) = V(2)
edge4 = [0 1]; % = E(2, 2) = V(3)
I know how to do this with for loops, but my supervisor said there is a more optimal solution using the function find(x), which returns the nonzero indices in an array. I do not see how this could be done with find. Is there a way that this could be done without using for loops but using the find function?
As far as I remember find is not really recommended when it comes to runtime, and for loops are not as bad as they where in the past taking JIT into consideration and MATLAB's effort to improve them.
However one possible solution without using for-loops (and without find) would be:
E = [1 2;
1 3];
V = [0 0;
1 0;
0 1];
Edges=V(E(:),:)
Edges =
0 0
0 0
1 0
0 1
So the output is not a list of different variables / edges but rather a matrix holding all of them row-wise.

How to determine number of hops using a vector?

I have a MATLAB matrix like below:
column no: 1 2 3 4 5 6
matrix elements 1 1 2 3 6 2
Column numbers represent node ID and elements of the matrix represent the node towards which that node points. Please help me find hop count from a particular node to node 1. I have written the following code but it doesn't solve the problem.
x = ones(1, n);
checkbit = zeros(1, n);
nodedest = [1 1 2 3 6 2];
hopcount = zeros(1, n);
for i = 1:n
for j = 1:n
if nodedest(j) == 1 && checkbit(j) == 0
hopcount(j) = hopcount(j) + 1;
checkbit(j) = 1;
else
x(j) = nodedest(j);
end
if x(j) ~= 1
hopcount(j) = hopcount(j) + 1;
x(j) = nodedest(x(j));
end
end
end
You are looking for a breadth-first search to find the shortest path in your graph. Without touching the data in any way, you can do this in O(n) time per node, given the tree-like structure of your graph:
nodedest = [1 1 2 3 6 2];
hopcount = zeros(1, 6);
for n = 2:6
k = n
while k ~= 1
hopcount(n) = hopcount(n) + 1
k = nodedest(k)
end
end
If you are willing to reverse the sense of your edges (introducing a one-to-many relationship), you could accomplish the same thing in one pass, reducing the entire algorithm from O(n2) to O(n) time complexity. The trade-off would be that memory complexity would increase from O(1) to O(n):
nodedest = [1 1 2 3 6 2];
% Reverse the input
nodesource = cell(1, 6);
nodesource(:) = {[]}
for n = 2:6
k = nodedest(n);
nodesource{k} = [nodesource{k} n];
end
% implement bfs, using the assumption that the graph is a simple tree
hopcount = zeros(1, 6);
cache = [1];
hops = 0;
while ~isempty(cache)
next = []
for c = cache
hopcount(c) = hops;
next = [next nodesource(c)]
end
hops = hops + 1;
cache = next
end

Matlab: interpolation operator for multigrid methods

I have to build the following matrix:
1 2 1
1 2 1
1 2 1
I tried the following:
N = 8;
full( ( spdiags(repmat([1/4,1/2,1/4], N/2-1, 1), 0:2, N/2-1, N-1) ) )
but the output is not what I want.
It is not clean but it should work anyway:
N = 10;
w(1, :) = [1, 2, 1, zeros(1, (N-1)-3)];
for i = 1:(N/2-2)
w(i+1, :) = [zeros(1, i*2), 1, 2, 1, zeros(1, (N-1)-(3+i*2))];
end
I'm sure this could be condensed a bit, but here's a solution without loops. Assuming h is the grid spacing and N=1/h-1 is odd:
wdiag = 2*ones(N,1);
wsubsuperdiag = ones(N,1);
w = spdiags([wsubsuperdiag wdiag wsubsuperdiag],[-2 -1 0],N,(N+1)/2-1);
w = 1/2*cell2mat(arrayfun(#(k) circshift(w(:,k),k-1),1:(N+1)/2-1,'uni',0));
Some credit to Jon.

Create a zero-filled 2D array with ones at positions indexed by a vector

I'm trying to vectorize the following MATLAB operation:
Given a column vector with indexes, I want a matrix with the
same number of rows of the column and a fixed number of columns. The
matrix is initialized with zeroes and contains ones in the locations
specified by the indexes.
Here is an example of the script I've already written:
y = [1; 3; 2; 1; 3];
m = size(y, 1);
% For loop
yvec = zeros(m, 3);
for i=1:m
yvec(i, y(i)) = 1;
end
The desired result is:
yvec =
1 0 0
0 0 1
0 1 0
1 0 0
0 0 1
Is it possible to achieve the same result without the for loop? I tried something like this:
% Vectorization (?)
yvec2 = zeros(m, 3);
yvec2(:, y(:)) = 1;
but it doesn't work.
Two approaches you can use here.
Approach 1:
y = [1; 3; 2; 1; 3];
yvec = zeros(numel(y),3);
yvec(sub2ind(size(yvec),1:numel(y),y'))=1
Approach 2 (One-liner):
yvec = bsxfun(#eq, 1:3,y)
Yet another approach:
yvec = full(sparse(1:numel(y),y,1));
You could do this with accumarray:
yvec = accumarray([(1:numel(y)).' y], 1);
I did it this way:
classes_count = 10;
sample_count = 20;
y = randi([1 classes_count], 1, sample_count);
y_onehot = zeros(classes_count, size(y, 2));
idx = sub2ind(size(y_onehot), y, [1:size(y, 2)]);
y_onehot(idx) = 1