31

I'm trying to plot/sketch (matplotlib or other python library) a 2D network of a big distance matrix where distances would be the edges of the sketched network and the line and column its nodes.

DistMatrix =
[       'a',   'b',     'c',    'd'],
['a',   0,      0.3,    0.4,    0.7],
['b',   0.3,    0,      0.9,    0.2],
['c',   0.4,    0.9,    0,      0.1],
['d',   0.7,    0.2,    0.1,    0] ]

I'm searching to sketch/plot the 2d network from such (bigger: thousand of columns and lines) distance matrix: node 'a' is linked to node 'b' by an edge depth of 0.3, nodes 'c' and 'd' would be tied by an edge depth of 0.1. What are the tools/libraries I can used (distance matrix can be converted into numpy matrix) to get the sketch/graphical projection of such network? (pandas, matplotlib, igraph,...?) and some leads to do that quickly (I would not define my self Tkinter function to do that ;-) ) ? thanks for your incoming answers.

2
  • 1
    In theory, this could be impossible for certain distance matrices. Imagine e.g. a 4 x 4 distance matrix with all entries 1. This defines a three-dimensional simplex. There is no way to embed this graph into two dimensions isometrically. What should the program do in that case? Commented Nov 22, 2012 at 13:18
  • right, so no "edge length" but "edge depth that links two nodes Commented Nov 22, 2012 at 13:24

3 Answers 3

35

The graphviz program neato tries to respect edge lengths. doug shows a way to harness neato using networkx like this:

import networkx as nx
import numpy as np
import string

dt = [('len', float)]
A = np.array([(0, 0.3, 0.4, 0.7),
               (0.3, 0, 0.9, 0.2),
               (0.4, 0.9, 0, 0.1),
               (0.7, 0.2, 0.1, 0)
               ])*10
A = A.view(dt)

G = nx.from_numpy_matrix(A)
G = nx.relabel_nodes(G, dict(zip(range(len(G.nodes())),string.ascii_uppercase)))    

G = nx.drawing.nx_agraph.to_agraph(G)

G.node_attr.update(color="red", style="filled")
G.edge_attr.update(color="blue", width="2.0")

G.draw('/tmp/out.png', format='png', prog='neato')

yields

enter image description here


If you want to generate a dot file, you can do so using

G.draw('/tmp/out.dot', format='dot', prog='neato')

which yields

strict graph {
    graph [bb="0,0,226.19,339.42"];
    node [color=red,
        label="\N",
        style=filled
    ];
    edge [color=blue,
        width=2.0
    ];
    B    [height=0.5,
        pos="27,157.41",
        width=0.75];
    D    [height=0.5,
        pos="69,303.6",
        width=0.75];
    B -- D   [len=2.0,
        pos="32.15,175.34 40.211,203.4 55.721,257.38 63.808,285.53"];
    A    [height=0.5,
        pos="199.19,18",
        width=0.75];
    B -- A   [len=3.0,
        pos="44.458,143.28 77.546,116.49 149.02,58.622 181.94,31.965"];
    C    [height=0.5,
        pos="140.12,321.42",
        width=0.75];
    B -- C   [len=9.0,
        pos="38.469,174.04 60.15,205.48 106.92,273.28 128.62,304.75"];
    D -- A   [len=7.0,
        pos="76.948,286.17 100.19,235.18 167.86,86.729 191.18,35.571"];
    D -- C   [len=1.0,
        pos="94.274,309.94 100.82,311.58 107.88,313.34 114.45,314.99"];
    A -- C   [len=4.0,
        pos="195.67,36.072 185.17,90.039 154.1,249.6 143.62,303.45"];
}

The png file could then be generated using the graphviz neato program:

neato -Tpng -o /tmp/out.png /tmp/out.dot 
Sign up to request clarification or add additional context in comments.

6 Comments

I have tried the code you suggest, adapted to my needs (remove the A.view) and it hasn't worked even for just 7 nodes. G is correct. What could have gone wrong? I am using graphviz 2.36.
This cases me error 'module' object has no attribute 'to_agraph'. To fix I used stackoverflow.com/questions/35279733/… and instead used nx.drawing.nx_agraph.to_agraph
How to draw the same graph in pure graphviz without python?
@Snochacz: I updated the answer to include the dot file generated by networkx.
I cannot install pygraphviz. Is it to possible to use neato and write the same algorithm with graphviz package (using pydot) ?
|
22

You can use the networkx package, that work perfectly with this kind of problems. Adjust your matrix to remove a simple numpy array like this:

DistMatrix =array([[0,      0.3,    0.4,    0.7],
[0.3,    0,      0.9,    0.2],
[0.4,    0.9,    0,      0.1],
[0.7,    0.2,    0.1,    0] ])

then import networkx and use it

import networkx as nx
G = G=nx.from_numpy_matrix(DistMatrix)
nx.draw(G)

if you want to draw a weighted version of the graph, you have to specify the color of each edge (at least, I couldn't find a more automated way to do it):

nx.draw(G,edge_color = [ i[2]['weight'] for i in G.edges(data=True) ], edge_cmap=cm.winter )

6 Comments

What is cm.winter?
@Sepide cm is from matplotlib and winter is a color map. matplotlib.org/stable/tutorials/colors/colormaps.html
how do we represent a missing edge? when there is no edge?
How to add the names on the points?
@MohamedHachaichi, nx.draw(G, with_labels=True) should do it.
|
1

I had the same problem with you, so I made a Python package springpy to draw a graph from a distance matrix. Instead of using networkx and lots of code, springpy can create a graph in the simplest way possible.

Check this out:

import springpy as sp
matrix = [[0,      0.3,    0.4,    0.7],
          [0.3,    0,      0.9,    0.2],
          [0.4,    0.9,    0,      0.1],
          [0.7,    0.2,    0.1,    0]]
sp.graph(matrix)

Moreover, it can even animate the process of caculation, by just the following code:

# Init matrix as above
sp.animate(matrix)

More infomation click here.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.