Search code examples
arraysmatlabmultidimensional-arraygraphmatlab-figure

How to extract indices of non-zero elements from ND array?


I need to label edges of a directed graph with 4 different labels, so I store it in a N*N*4 array. (Let's stick with 4, which is my actual third dimension.) N is the number of nodes in the graph. i.e. for entry M(i,j,1), I would label an edge from node i to node j with the first kind of label. Here is a toy example to play with.

M(2,1,1)=1 indicates I add label text 'first label' on the edge from node 2 to node 1. M(3,2,2)=1 indicates I add label text 'second label' on the edge from node 3 to node 2. Each 'page' in the 3D array is one kind of label.

M(:,:,1)= 0 0 0      M(:,:,2)= 0 0 1         
          1 0 1                0 0 0
          0 0 0                0 1 0

But I don't know how to convert N*N*4 array M into s and t in labeledge(h,s,t,Labels). s is the indices of source nodes while t is the indices of target nodes.

Ideally, this is the plot:

s = [2 2 1 3];
t = [1 3 3 2];
G = digraph(s,t);
figure;
h = plot(G);

the key question is how I can get s1, t1, s2 and t2 from M like this:

labeledge(h,[2 2], [1 3], 'first label');
labeledge(h,[1 3], [3 2], 'second label');

enter image description here FYI: M(:,:,1) and M(:,:,2) do not have the same non-zero entries.


Solution

  • Some Background Insight:
    In your problem, the order of s and t is inter-linked i.e. shuffling of s does not matter if the elements of t are also shuffled in the same order. e.g; if

    s = [2 2 1 3];
    t = [1 3 3 2];
    %The combination of s and t given by you
    

    The above will give the same result as that of the following:

    s = [2 3 2 1];  
    t = [1 2 3 3];
    % replaced column 2 with column 3, column 3 with column 2, and column 4 with column 3
    

    There are many such combinations. The code I am going to show will give the following combination for the given M:

    s = [2 2 3 1];    %named as snew in my code
    t = [1 3 2 3];    %named as tnew in my code
    %In this combination, column 3 and 4 are inter-changed (See the combination given by you)
    

    Code:

    for k=1:size(M,3)           %Looping depending on the third dimension
        [r,c]= find(M(:,:,k));  %Finding non-zero elements
        %Storing the values in a cell since the number of non-zero elements in each 
        %slice of M can be different 
        s{k}=r;     t{k}=c;    
    end
    

    The above code gives s{1}=[2; 2], s{2}=[3; 1], t{1}=[1; 3] and t{2}=[2; 3].

    Now you can find s and t as combined as given in your question by extracting them from the above code with:

    snew=vertcat(s{:});   %Giving a different name to avoid confusion
    tnew=vertcat(t{:});
    

    Now you can make digraph using snew and tnew and label edges with s{1}, s{2}, t{1} and t{2}.

    For labeling the edges, you can use the following loop:

    for k=1:length(s)
        labeledge(h,s{k}, t{k}, ['label ',num2str(k)]);
    end
    

    This solves the issue of labeling if there are too many labels to make. Making the labels as first, second ,.... would be cumbersome and may be unnecessary.


    Output:
    With the above modifications, you get the following output:

    output