tarrasch
tarrasch

Reputation: 2680

How do i visualize a connection Matrix with Matplotlib?

I am trying to visualize a connection matrix of an bi-partite set problem. How do i do this in a way that demonstrates best?

I have started with this using a graphics program yed:

example

The circles describe a certain kind of connection between red and blue and the squares another. Both red and blue squares will have some kind of text on them.

However it would be nicer to generate this grafic with matplotlib, since i would like to generate this on the fly with data attached. How would i proceed to do that? My data looks kinda like this:

Data:

name_blue name_red Connection Type
bluepart1 redpart1 1
bluepart1 redpart2 1
bluepart1 redpart3 1
bluepart3 redpart2 2 
bluepart4 redpart2 2
...

and so on. I would like to write the nametags onto the blue/red squares, so that the user knows which is which.

Followup question: How can i generate a graph from this with the nodes partly marked blue/red? Kind of like this:

graphexample

But with the nodes reflecting their bipartite nature. I am still a bit in the dark on this, mainly because i don't know how to tackle this with matplotlib. I am hoping for a few good suggestions on how to visualize this and maybe an example implementation that shows me the way.

Upvotes: 6

Views: 4186

Answers (3)

Aric
Aric

Reputation: 25299

Here is another NetworkX/Matplotlib idea

import random
import networkx as nx
from networkx.algorithms.bipartite import biadjacency_matrix
import matplotlib.pyplot as plt
# generate random bipartite graph, part 1: nodes 0-9, part 2: nodes 10-29
B = nx.bipartite_random_graph(10,20,0.25)
# add some random weights
for u,v in B.edges():
    B[u][v]['weight']=random.randint(0,4)

# spring graphy layout
plt.figure(1)
pos = nx.spring_layout(B)
colors = [d['weight'] for (u,v,d) in B.edges(data=True)]
nx.draw(B,pos,node_color='#A0CBE2',edge_color=colors,width=4,edge_cmap=plt.cm.Blues,with_labels=False)
plt.savefig('one.png')

# simple bipartite layout
plt.figure(2)
pos = {}
for n in range(10):
    pos[n]=(n*2,1)
for n in range(10,30):
    pos[n]=(n-10,0)
nx.draw(B,pos,node_color='#A0CBE2',edge_color=colors,width=4,edge_cmap=plt.cm.Blues,with_labels=False)
plt.savefig('two.png')

# biadjacency matrix colormap
M = biadjacency_matrix(B,row_order=range(10),column_order=range(10,30))
plt.matshow(M,cmap=plt.cm.Blues)
plt.savefig('three.png')
plt.show()

enter image description here

enter image description here

enter image description here

Upvotes: 5

bcurcio
bcurcio

Reputation: 548

What about doing a bipartite representation with color edges like this?

Bipartite graph with different kinds of connections

Following is the code that generated the image.

import matplotlib.pyplot as plt

def addconnection(i,j,c):
  return [((-1,1),(i-1,j-1),c)]

def drawnodes(s,i):
  global ax
  if(i==1):
    color='r'
    posx=1
  else:
    color='b'
    posx=-1

  posy=0
  for n in s:
    plt.gca().add_patch( plt.Circle((posx,posy),radius=0.05,fc=color))
    if posx==1:
      ax.annotate(n,xy=(posx,posy+0.1))
    else:
      ax.annotate(n,xy=(posx-len(n)*0.1,posy+0.1))
    posy+=1

ax=plt.figure().add_subplot(111)
set1=['Man1','Man2','Man3','Man4']
set2=['Woman1','Woman2','Woman3','Woman4','Woman5']
plt.axis([-2,2,-1,max(len(set1),len(set2))+1])
frame=plt.gca()
frame.axes.get_xaxis().set_ticks([])
frame.axes.get_yaxis().set_ticks([])

drawnodes(set1,1)
drawnodes(set2,2)

connections=[]
connections+=addconnection(1,2,'g')
connections+=addconnection(1,3,'y')
connections+=addconnection(1,4,'g')
connections+=addconnection(2,1,'g')
connections+=addconnection(4,1,'y')
connections+=addconnection(4,3,'g')
connections+=addconnection(5,4,'y')

for c in connections:
  plt.plot(c[0],c[1],c[2])

plt.show()

To get something like what your are drawing in yEd

Connection matrix

import matplotlib.pyplot as plt

COLOR1='r'
COLOR2='b'

def addconnection(i,j,c):
  if(c==1):
    plt.gca().add_patch( plt.Rectangle((j-0.1,-i-0.1),0.2,0.2,fc='y'))
  if(c==2):
    plt.gca().add_patch( plt.Circle((j,-i),radius=0.1,fc='y'))

def drawnodes(s,i):
  global ax
  if(i==1):
    color=COLOR1
    vx=1
    vy=0
  else:
    color=COLOR2
    vx=0
    vy=1

  step=1
  for n in s:
    posx=step*vx
    posy=step*vy

    plt.gca().add_patch( plt.Circle((posx,-posy),radius=0.1,fc=color))
    ax.annotate(n,xy=(posx-len(n)*0.1,-posy+0.15))
    step+=1

f=open('input.txt')
t=f.readlines()
t=map(lambda x: x.replace('(',' ').replace(')',' ').split(':'),t)

set1=set([])
set2=set([])

for x in t:
  s=x[1].split()
  set1.add(s[0])
  set2.add(s[1])

set1=list(set1)
set2=list(set2)

dic={}
for e in zip(set1,xrange(1,len(set1)+1)): dic[(e[0],1)]=e[1]
for e in zip(set2,xrange(1,len(set2)+1)): dic[(e[0],2)]=e[1]

ax=plt.figure(figsize=(max(len(set1),len(set2))+1,max(len(set1),len(set2))+1)).add_subplot(111)
plt.axis([-1,max(len(set1),len(set2))+1,-max(len(set1),len(set2))-1,1])
frame=plt.gca()
frame.axes.get_xaxis().set_ticks([])
frame.axes.get_yaxis().set_ticks([])

drawnodes(set1,1)
drawnodes(set2,2)

for x in t:
  s=x[1].split()
  addconnection(dic[(s[0],1)],dic[(s[1],2)],int(x[2]))

plt.show()

Upvotes: 1

job
job

Reputation: 9273

Try using networkx. You can use it to display the graph with specific colors on the nodes and links to match your data.

Here's an example:

import itertools
import networkx as nx
import matplotlib.pyplot as plt
edgelist = [(u,v,(u+v)%2) for u,v in itertools.product(range(3),range(3,6))]
G = nx.Graph()
for u,v,t in edgelist:
    G.add_edge(u,v,attr_dict={'t':t})
ecolors = tuple('g' if G[u][v]['t'] == 1 else 'm' for u,v in G.edges())
nx.draw_networkx(G,node_color='rrrccc',edge_color=ecolors)
plt.show()

Simple Example

Upvotes: 7

Related Questions