Home > other >  Draw multipartite graphs with fixed levels in Python (or R)
Draw multipartite graphs with fixed levels in Python (or R)

Time:09-10

I have two adjacency matrices a and b that express a set of relationship in a hierarchical order. Basically, the rows of a are the nodes of a, and the columns of b are the nodes of b. So the nodes of a points to the nodes of b. The same applies for b: the rows of b (that are equal to the columns of a) are the nodes of b, which point to the nodes of c, represented in the columns.

Here is a Python representation in the form of two adjacency matrices (list of lists)

import numpy as np
import pandas as pd
import networkx as nx

a_net= [[1,1,0],[0,0,0]]
b_net = [[1,0],[1,1],[0,0]]

They can be represented as pandas dataframes:

data_a = pd.DataFrame(a_net)
data_a.index = ['a1','a2'] 
data_a.columns = ['b1','b2','b3'] 

data_b = pd.DataFrame(b_net)
data_b.index = data_a.columns
data_b.columns = ['c1','c2']

matrix_a matrix_b

If necessary, I wrote a code to concatenate them into a unique matrix

#JOINING THE MATRICES INTO A UNIQUE ONE
for i in range(1,len(data_a.columns) 1):
    data_b['b' str(i)] = [0]*len(data_b)
    
data_a['c1'] = [0]*len(data_a)
data_a['c2'] = [0]*len(data_a)

adj = pd.concat([data_a,data_b])

adj['a1'] = [0]*len(adj)
adj['a2'] = [0]*len(adj)

c1c2 = pd.DataFrame([[0,0,0,0,0,0,0],[0,0,0,0,0,0,0]])
c1c2.index = ['c1','c2']
c1c2.columns = adj.columns

adj = pd.concat([adj,c1c2])
adj

adj_matrix

I'd like to obtain a multilayer plot were nodes that starts with "a" are at the first layer, with "b" at the second, and with "c" at the third:

plot

As you can see, I want that also nodes without links (like a2 and b3) are visualized at the right levels.

What can I do? If you know a way to do it in R it would also be good. In that case, you could run these commands to export the tables and to load them in R:

a_net.to_csv("a_net.csv")
b_net.to_csv("b_net.csv")

CodePudding user response:

  • SET x = 1
  • SET y = 1
  • LOOP prefix OVER a,b,c
    • LOOP N over nodes
      • IF N name begins with prefix
        • Place N at x,y
        • SET y = y 1
    • ENDLOOP over Nodes
    • SET x = x 1
  • ENDLOOP over a,b,c
  • LOOP src over nodes
    • LOOP dst over nodes starting at src 1
      • IF src and dst adjacent
        • draw line between src and dst

Bt the way, you adjacency matrix is arranged strangely. Usually it would be done this way:

 X    a1 a2 b1 b2 b3 c1 c2
 a1   0  1   1  0   0  0
 a2          0  0   0  0
 b1             0   1  0
 b2                 1  1
 c1                    0
 c2

CodePudding user response:

This code returns the hyperlink of the IP-address leading to a locally launched web-server that shows html-graph similar to what you want

import pandas as pd
from dash import Dash, html
import dash_cytoscape as cyto
a_net= [[1,1,0],[0,0,0]]
b_net = [[1,0],[1,1],[0,0]]

data_a = pd.DataFrame(a_net)
data_a.index = ['a1','a2']
data_a.index.name = 'source'
data_a.columns = ['b1','b2','b3'] 

data_b = pd.DataFrame(b_net)
data_b.index = data_a.columns
data_b.index.name = 'source'
data_b.columns = ['c1','c2']

ids = list(set(data_a.columns) | set(data_b.columns) | set(data_a.index) | set(data_b.index))
labels = [i.upper() for i in ids]
data_list = [{'id': i[0], 'label': i[1]} for i in zip(ids, labels)]
data_a = data_a.reset_index().melt(id_vars='source', var_name='target', value_name='linked')
data_b = data_b.reset_index().melt(id_vars='source', var_name='target', value_name='linked')
data_list.extend(data_a.loc[data_a.linked == 1,['source', 'target']].to_dict('records'))
data_list.extend(data_b.loc[data_b.linked == 1,['source', 'target']].to_dict('records'))
plot_elements = [{'data': i} for i in data_list]

app = Dash('__name__')

app.layout = html.Div([
    html.P("Multilayer plot with nodes"),
    cyto.Cytoscape(
        id = 'cytoscape',
        elements = plot_elements,
        layout = {'name': 'breadthfirst'},
        style = {'width': '400px', 'height': '500px'}
    )
])

app.run_server(debug=False)
  • Related