User Tools

Site Tools


clanterne_frandriamanana:celestin_lanterne_franck_randriamanana

Table of Contents

Visual Analytics Course

Social circles Twitter celestin LANTERNE - franck RANDRIAMANANA

1) Problématique:

Il existe sur les réseaux sociaux une fonction qui permet à l’utilisateur de créer une liste ou un cercle d’amis. Il peut dans cette liste ajouter d’autres utilisateurs qui ont en général des attraits communs. Cela permet un tri des amis sur un réseau social.

Nous nous somme posé la question de savoir si il étais possible de construire ce type de cercle automatiquement : quelles sont les paramètres qui justifient la création d’un cercle ? Et celle de savoir s’il était possible, une fois un cercle donné, de suggérer l’ajout d’un utilisateur précis dans un groupe qui lui conviendrais : est ce que ces paramètres sont assez cohérents pour permettre l’ajout de membre, sans perdre la cohérence du cercle?

Nous nous somme donc demandés quels sont les éléments qui pourraient favoriser la création d’un groupe, et nous en avons retenu trois : Premièrement nous avons pensé qu’un groupe pourrait être formé autour d’un sujet, par exemple le cinéma : groupe formé par sujet de conversation. Deuxièmement nous nous somme dit qu’un utilisateur pourrait vouloir faire un groupe autour d’une personne particulière que nous appellerons “Star”. Cette personne à la particularité d’être suivis par beaucoup d’autre : groupe formé autours d’une personne. Pour finir nous avons imaginé un groupe qui serait formé autour de plusieurs personnes, très connectées les unes aux autres. Ce genre de groupe peut par exemple être une famille.

2) Les données:

Pour répondre à ces question nous avons choisis un jeu de données qui provient du réseaux social “Twitter”. Ce jeu de données avait pour avantage de fournir plusieurs éléments qui nous permettaient de répondre aux questions qu’on se posait. Tout d’abord, il possède des informations sur les cercles d’amis des utilisateurs. Ensuite il a aussi des informations sur les “Feat” c’est à dire des sujet de discutions. Pour finir le jeu de données a évidement des information sur la connectivité entre les utilisateurs.

Le jeu de donnés tourne autour de la notion d’”ego node”. Un ego node est un noeud particulier sur lequel nous avons des donnés, comme sont voisinage ou ces cercles. Notre jeu de donnée est constitué de plusieurs petit graphes qui chaqu’un sont constitué du voisinage (et des relations de voisinage) d’un ego noeud différent.

Pour chaque ego noeud nous avons cinq fichiers différents. Le fichier “.Edges” : Il contient la liste des arrêtes qui relie le voisinage de l’ego noeud : les relation de son voisinage, autrement dit, la relation qu’il y a entre les personnes que l’ego-noeud suit. Le fichier “.Circles” : Il contient des listes de noeud qui représentent les différents cercles de l’ego noeud. Le fichier “.Featnames” référence le nom de tout les “features” présents dans cette partie de graphe, associé a un index. Il est utilisé avec le fichier “.Feat” qui référence pour chaque noeud si oui ou non il est associé à un feat : Au niveau d’un noeud dans le fichier “.feat’, pour un index donné, la valeur (0 ou 1) indique si le feature retrouvé dans le fichier “Featnames” a cet index est associé ou non au noeud considéré..

Nous construisons le graphe uniquement pour un ego node à la fois. En effet le jeu de donnés est constitué de plusieurs petits graphes non liés entre eux, chaque graphe etant constitué autour d’un ego noeud différent. Nous avons décidé sur ces graphes de ne pas représenter l’ego noeud car il n’a pas d'intérêt particulier à relier tous les noeud a cet ego-noeud, ce qui permet de rendre le graphe bien plus lisible puisqu’un grand nombre d’arrêts inutiles est enlevé.

Notre algorithme de construction fonctionne de la façons suivant. Dans un premier temps nous construisons tout les noeuds utilisateur grâce au fichier “Feat”, dans lequel on à les identifiants de tous les noeuds. Nous en profitons pour créer un tableau qui référence les identifiants des noeud de tulip couplés avec les identifiants de nos données qui sont utilisé comme indice. C’est ce qui vas nous permette de retrouver noeud a partir des identifiant très rapidement. Nous construisons ensuite les arrêtes entre les utilisateurs en parcourant le fichier “Edges”. Dans un deuxième temps nous construisons les noeud qui représentent les “features” grâce au fichier “Featnames”. Nous reliions ensuite les utilisateurs aux features associés, en construisant les arrêtes à partir du fichier “feat”.

3) Visualisation:

A partir du graphe construit à partir des données nous avons décidé de construire plusieurs sous graphes pour avoir une meilleur visualisation des cercles. Nous avons fait deux type de sous graphes : le premier sans afficher les feats et le deuxième en les affichant. Pour ces deux cas nous avons fait un sous graphe par cercle, à partir du fichier “Circles”. Nous avons utilisé ces sous graphes pour réaliser des visualisations différentes afin de répondre aux différentes questions que nous nous étions posées.

Nous avons, dans un premier temps, chercher a mettre en valeur le fait qu’un cercle puisse être formé autour d’une “star” : Nous nous sommes donc basé sur les graphs sans les features. Premièrement nous avons changé la taille des noeuds en fonction du nombre de leurs degrés entrant. Ainsi nous pouvons voir si au sein d’un cercle, un noeud se démarque des autres. Pour accentuer ceci, nous avons décidé de changer la couleur du point qui à le degrés entrant le plus élevé, ainsi que les arrêtes entrantes et les noeuds qui le suivent. Notre visualisation permet du coup de bien voir si un cercle est formé autour d d’un noeud en particulier, qui serait suivis par tous, ou quasiment tous les points de ce cercle.

Cependant, un cercle pourrait aussi être formé d’utilisateurs, fortement connectés entre eux. Nous avons donc mis en place un système de visualisation, qui permet de mettre en valeur ce genre de cercle. La méthode utilisée est très semblable que celle utilisée précédemment. Nous avons changé la taille des noeuds du cercle en fonction de leur degré entrant. Pour y voir plus clair, nous avons rajouté pour chaque noeud un label indiquant le rapport entre le degrés du noeud, divisé par le nombre de total de noeud dans ce cercle. Plus la moyenne de ces valeurs est proche de 1, plus il a une forte connexité entre les membres de ce cercle.

Nous avons ensuite vouu voir si un cercle pouvait être construit autour d’un sujet (feature). A partir d’un sous graphe représentant un cercle avec ces “Feat” associé, nous voulions savoir si un ou plusieurs “Feat” étaient souvent utilisés par les utilisateurs du cercle. Pour le représenter nous avons compté le degrés entrant de chacun des feats, puis nous avons regroupé dans un meta-noeud les feats de même degrés. Nous affichons ensuite ce degrés en label du meta noeud. Ainsi plus le nombre est grand, plus les features dans le meta-noeud sont utilisés dans le cercle.

Une fois ces méthodes de visualisation mises en place, il aisé de mettre en place des algorithmes permettant l’ajout d’une personne dans le cercle. Dans le premier cas, avec un cercle de type star, il suffit de regarder dans le graphe principal (contenant tous les éléments) les personnes qui suivent la “star” Dans le cas d’un cercle fortement connexe, il faut parcourir le graphe principal, en recherchant par exemple, un utilisateur qui une fois ajouté au cercle, ne ferait pas baisser la connexité moyenne de celui-ci. Enfin, dans notre dernier cas, dès qu’on à trouvé un feature pertinent, il est facile d’aller chercher dans le graphe principal si d’autres utilisateurs y sont associés.

Nous pensons qu’en regroupant ces 3 methodes, nous pouvons ajouter à un cercle des utilisateurs pertinents.

4) Résultat:

Bien que le jeu de donné de départ soit assez volumineux, il est fortement divisé. De plus la taille des cercle est, pour certains ego noeuds, très réduite comparées aux donnés fournies. Nos résultat étant basée sur la visualisation de cercle particulier, il ne nous a pas été possible de visualiser tous les cercles du jeu de donné.

Nous pouvons voir sur ces deux images la différence entre un cercle qui à effectivement une star et un cercle qui n’en n’a pas. Sur la première quasiment tout les points sont colorés et sont reliés au noeud star en bleu clair. De plus nous remarquons que tout les autres noeuds sont plus petits que le noeud star. Cela montre que ce noeud et le plus important dans ce groupe. Sur la deuxième image nous voyons toujours effectivement un noeud suivi par tous les autres membres du cercle. Mais nous pouvons aussi remarquer que beaucoup d’autres points du cercle ont une taille équivalente à ce noeud. On ne peut donc pas objectivement dire que ce groupe a été formé autour d’un noeud Star : nous pouvons grâce à la visualisation de la connexité, remarquer que c’est un cercle fortement connexe (de type membre d’une famille qui se suivent entre eux)

Sur la première image on peut voir que le label le plus important des meta noeud est (chiffre). On remarque ensuite que ce chiffre est assez conséquents par rapport au nombre de noeud dans le cercle. Sur l’image qui suit nous avons un zoom sur ce méta noeud. Nous pouvons voir (le ou les) features qui peuvent être la raison de la création de ce cercle. La troisième image nous montre cette fois que les label sur les méta noeud sont largement inférieur au nombre de noeud qu’il y a dans le cercle. Ce qui veut dire que peu de personne dans ce groupe parle du même sujet. Il y a donc peu de chance que ce cercle soit fondé sur un seul sujet en particulier.

Pour finir voici l’image d’un cercle très connexe on voit bien grâce a cette visualisation que beaucoup de noeud on une taille grande. De plus leurs label nous aide a quantifier ceci en nous montrons qu’ils sont presque tous proche de 1. Il y a de forte chance que ce cercle soit constituer de personne qui ce connaissent tous les uns les autres.

5) Vision globale: Pour visualiser nos hypothèses, nous avons décidé de charger uniquement les cercles de tous les fichiers de nos données. Le code dans twitt.py permet de charger tous les cercles ( avec comme paramètre le pourcentage des données a charger). Pour chaque cercle, il crée un noeud dans le sous graphe “view”, en fonction des propriétés du cercle.

Pour l'axe des abscisses [0,1]: ⇒ 1-(nmax/nbnodes) nmax = nombre de noeuds que le maximum de personnes du cercle suit. nbnodes = nombre de noeuds dans le cercle Plus on s'approche de 1, plus le cercle est construit autout d'une seule personne : - tous les noeuds du cercle suivent un noeud - tous les noeuds se suivent entre eux ( graphe connexe )

Pour différencier ces deux cas, on a en ordonné [0,1]: le pourcentage de connexité du graphe. On a ensuite une échelle de couleur [bleu, rouge]: Il correspond au pourcentage de personne du cercle, qui utilise le feature le plus utilisé du groupe. Plus le noeud est rouge, plus le feature le plus utilisé dans ce cercle est utilisé par un grand nombre de noeuds. Cela nous sert a visualiser a quel points les membres d'un cercle utilisent le même feature.

Comme on peut voir dans l'image la plupart des cercles sont dans la zone [0,5 ; 1] au niveau des abscisses. Ce qui veut dire que la plupart des cercles sont formés autour d'un nombre de noeud n, au minimum égal a la moitié du nombre de noeud du cercle.

Plus on se rapproche du point de coordonné (0,1) [dans cette zone, les cercle sont formés autour d'un nombre réduit de peronnes, et la connexité est très faible ], plus les sujets de conversations sont larges (point de couleur bleu) Au contraire, plus le cercle est connexe ( plus on va vers le haut du graphique ), plus les sujets de conversations utilisent les mêmes features ( noeud de couleur rouge)

6) Code: Utilisation : modifier la variable “path” des fichiers twitt.py, et loadFile.py vers le dossier contenant les données.

-Le fichier twitt.py permet de charger les cercles des données. La fonction makecircles prend en paramètre le pourcentage des données a charger. Il construit dans un sous graphe “circles” tous les cercles, puis, céer dans le sous graphe “view” le graphique vu précédamment.

-le fichier loadFile.py permet de charger toutes les données relatives a un egoNode dans tulip. La fonction loadFileInGraph prend en parametre l'id de l'egonode (par exemple 123456 pour les fichier 123456.feat, .egofeat, .featnames, .edges, .circles ) Il construit dans un sous graphe de nom [id de l'ego noeud] 3 sous graphes: -un sous graphe contenant tous les cercles sans les features -un sous graphe contenant tous les cercles avec les features -un sous graphe contenant tous les cercles, avec les faatures réunis dans des meta-noeuds, en fonction de leur degré. Ce mode de visualisation permet de voir les différentes relations qui peuvent exister au niveau des cercles pour un même ego-node.

Dans un premier temps, on peut utiliser le fichier twitt.py pour visualiser tous les cercles, puis utiliser le fichier loadFile.py pour voir en detail un cercle, avec dans son “contexe”

loadFile.py
from tulip import *
import os
 
 
axeX = 200
axeY = 200
minSize = 1
maxSize = 50
feat_ext =".feat"
featn_ext =".featnames"
edges_ext=".edges"
circles_ext=".circles"
path ="/home/frandria/Bureau/twitter/"
 
def main(graph): 
 
	#loadFileInGraph(egoID,graph)
	loadFileInGraph("759679",graph)
 
 
def addSubGraph(graph,prop,name):
	g = graph.addSubGraph(prop)
	g.setName(name)
	return g
 
 
 
 
#loadfile (n file, parent graph)
def loadFileInGraph(nfile,graph):
	p = graph.getSubGraph("graphs")
	if p==None:
		p = addSubGraph(graph,None,"graphs")
	graph = addSubGraph(p,None,nfile)
	viewLabel =  graph.getStringProperty("viewLabel")
	viewSelection =  graph.getBooleanProperty("viewSelection")
	viewSelectionWF =  graph.getBooleanProperty("viewSelectionWF")
	viewColor =  graph.getColorProperty("viewColor")
	twitterId =  graph.getIntegerProperty("twitterId")
	isFeat =  graph.getBooleanProperty("isFeat")
 
	egoId = nfile
 
	#ego node :
#	ego = graph.addNode()
#	twitterId.setNodeValue(ego,int(egoId))
#	twittNodeId = {int(egoId):ego}
	twittNodeId = {}
	#list featnames
	isFeat.setAllNodeValue(False)
	featnameNodes=[]
 
	#add nodes featname in graph
	fichier = open(path+egoId+featn_ext, "r")
	for ligne in fichier:
		featname = ligne.split()[1]
		n = graph.addNode()
		viewColor.setNodeValue(n,tlp.Color(0,0,255,255))
		viewLabel.setNodeValue(n,featname)
		isFeat.setNodeValue(n,True)
		featnameNodes.append(n)
	fichier.close()
 
 
	#add node in graph and add edge between features and nodes
	viewSelection.setAllNodeValue(False)
	viewSelection.setAllEdgeValue(False)
	fichier = open(path+egoId+feat_ext, "r")
	for ligne in fichier:
		n = graph.addNode()
		splitedLine = ligne.split()
		id = int(splitedLine[0])
		twitterId.setNodeValue(n,id);
		twittNodeId[id] = n
		viewSelection.setNodeValue(n,True)
		for i in range(1,len(splitedLine)):
			if splitedLine[i] == "1":
				e = graph.addEdge(n,featnameNodes[i-1])
	fichier.close()
 
	#1st sub graph with no features (only nodes)
	graphn = addSubGraph(graph,viewSelection,"nodes")
 
	#add edge between nodes
	fichier = open(path+egoId+edges_ext, "r")
	for ligne in fichier:
		id1 = int(ligne.split(' ')[0])
		id2 = int(ligne.split(' ')[1])
		e = graphn.addEdge(twittNodeId[id1],twittNodeId[id2])
		viewSelection.setEdgeValue(e, True)
	fichier.close()
 
	#2nd sub graph with no features
 
	#clone of graph in 2 subgraphs (3rd, and 4th subgraph)
	graphnf = graph.addCloneSubGraph("Features and nodes")
	graphnmf = graph.addCloneSubGraph("MetaFeatures and nodes")
 
 
	#circles
	#property to add node/edge in 3rd and 4th subgraph, or 1st and 2nd subgraph
	viewSelection.setAllNodeValue(False)
	viewSelection.setAllEdgeValue(False)
	viewSelectionWF.setAllNodeValue(False)
	viewSelectionWF.setAllEdgeValue(False)
	fichier = open(path+egoId+circles_ext, "r")
	for ligne in fichier:
		circleIds=[]
		#read line
		ids = ligne.split()
		#add ids of circle in circleIds
		for i in range(1,len(ids)):
			#add nodes from circle in all subgraph
			circleIds.append(int(ids[i]))
			nodei = twittNodeId[int(ids[i])]
			viewSelection.setNodeValue(nodei, True)
			viewSelectionWF.setNodeValue(nodei, True)
		#add edges
		for i in range(0,len(circleIds)-1):
			rnode = twittNodeId[circleIds[i]]
			#add edge bewteen nodes and feats in 3rd and 4th subgraph
			for ext in graph.getInOutEdges(rnode):
				tnode = graph.target(ext)
				if isFeat.getNodeValue(tnode):
					viewSelection.setNodeValue(tnode,True)
					viewSelection.setEdgeValue(ext,True)
			#add edge between nodes in circle in all subgraph
			for j in range(i+1,len(circleIds)):
				cedge =  graph.existEdge(rnode,twittNodeId[circleIds[j]])
				if graph.isElement(cedge):
					viewSelection.setEdgeValue(cedge,True)
					viewSelectionWF.setEdgeValue(cedge,True)
		#create sub graph for each circles in all subgrpah
		mcircleSubGraph = addSubGraph(graphnmf,viewSelection,ids[0])
		circleSubGraph =addSubGraph( graphnf,viewSelection,ids[0])
		st = addSubGraph(graphn,viewSelectionWF,ids[0])
		metanodeTab=[]
		for i in range(mcircleSubGraph.numberOfNodes()):
			metanodeTab.append([])
		for node in mcircleSubGraph.getNodes():
			if isFeat.getNodeValue(node):
				index = mcircleSubGraph.deg(node)
				metanodeTab[index].append(node)
		#add sub graph for 4th subgraph for metanodes
		msub = mcircleSubGraph.addCloneSubGraph("metaNodes "+str(ids[0]))
		i = 0
		#add metanodes in 4th graph
		for mlist in metanodeTab:
			if len(mlist) > 0:
				msub.createMetaNode(mlist)
			i=i+1
		viewSelection.setAllNodeValue(False)
		viewSelection.setAllEdgeValue(False)
		viewSelectionWF.setAllNodeValue(False)
		viewSelectionWF.setAllEdgeValue(False)
		for mn in msub.getNodes():
			if msub.isMetaNode(mn):
				g = msub.getNodeMetaInfo(mn)
				l = mcircleSubGraph.indeg(g.getOneNode())
				viewLabel.setNodeValue(mn,str(l))
	fichier.close()
	viewSelection.setAllNodeValue(False)
	viewSelection.setAllEdgeValue(False)
twitt.py
from tulip import *
import os
 
 
axeX = 200
axeY = 200
minSize = 1
feat_ext =".feat"
featn_ext =".featnames"
edges_ext=".edges"
circles_ext=".circles"
path ="/home/frandria/Bureau/twitter/"
 
def main(graph): 
	graph.push()	
 
#	makecircls(pourcentage_de_donnés chargés)
	makecircles(10)
 
def maxFeatDeg(graph):
	isFeat =  graph.getBooleanProperty("isFeat")
	maxdeg = 0
	for node in graph.getNodes():
		if isFeat.getNodeValue(node):
			deg=graph.indeg(node)
			if deg>maxdeg:
				maxdeg=deg
	return maxdeg
 
def nbNode(graph):
	done = graph.getBooleanProperty("done")
	viewSelection =  graph.getBooleanProperty("viewSelection")
	isFeat =  graph.getBooleanProperty("isFeat")
	viewSelection.setAllNodeValue(False)
	done.setAllNodeValue(False)
	nb = 0
	ret = 0
	nu = numNode(graph,False)
	while nb < nu:
		nbmax = 0
		nodemax = graph.getOneNode()
		for node in graph.getNodes():
			if not isFeat.getNodeValue(node):
				if not done.getNodeValue(node):
					cpt = 0
					for n in graph.getInNodes(node):
						if viewSelection.getNodeValue(n) == False:
							cpt = cpt+1
					if cpt > nbmax:
						nbmax = cpt
						nodemax = node
		for n in graph.getInNodes(nodemax):
			viewSelection.setNodeValue(n,True)
		done.setNodeValue(nodemax,True)
		nb = nb + nbmax+1
		ret = ret + 1
	viewSelection.setAllNodeValue(False)
#	done.setAllNodeValue(False)
	return ret
 
def connex(graph):
	isFeat =  graph.getBooleanProperty("isFeat")
	cpt = 0
	nb = 0
	for n in graph.getNodes():
		if not isFeat.getNodeValue(n):
			cpt = cpt+1
			for nn in graph.getOutNodes(n):
				if not isFeat.getNodeValue(nn):
					nb = nb +1
	if cpt == 1:
		return -1.0
	return nb*1.0/(cpt*(cpt-1))
 
def numNode(graph,feat):
	isFeat =  graph.getBooleanProperty("isFeat")
	cpt = 0
	for n in graph.getNodes():
		if isFeat.getNodeValue(n) == feat:
			cpt = cpt+1
	return cpt
 
def cons(vSub,cSub):
	viewLabel =  graph.getStringProperty("viewLabel")
	isFeat =  graph.getBooleanProperty("isFeat")
	viewColor =  graph.getColorProperty("viewColor")
	viewLayout =  graph.getLayoutProperty("viewLayout")
 
 
	o = vSub.addNode()
	viewLayout.setNodeValue(o,tlp.Coord(0,0,0))
	ox = vSub.addNode()
	viewLayout.setNodeValue(ox,tlp.Coord(axeX,0,0))
	oy = vSub.addNode()
	viewLayout.setNodeValue(oy,tlp.Coord(0,axeY,0))
	xx = vSub.addEdge(o,ox)
	viewColor.setEdgeValue(xx,tlp.Color(0,0,0,255))
	yy = vSub.addEdge(o,oy)
	viewColor.setEdgeValue(yy,tlp.Color(0,0,0,255))
	nbs = cSub.numberOfSubGraphs()
	ss = 1
	for gr in cSub.getSubGraphs():
		print "computing "+str(percent(ss,nbs))+"%"
		ss = ss+1
		y = connex(gr)
		nbnodes = numNode(gr,False)
		if y == -1.0 or nbnodes == 0 :
			continue
		node = vSub.addNode()
		x = 1-nbNode(gr)*1.0/nbnodes
		z = maxFeatDeg(gr)*1.0/nbnodes
		viewLayout.setNodeValue(node,tlp.Coord(x*axeX,y*axeY,0))
		c = int(z*255)
 
		viewColor.setNodeValue(node,tlp.Color(c, 0, 255-c, 255))
 
 
 
 
 
 
def makecircles(per):
	view = addSubGraph(graph,None,"view")
	circle = addSubGraph(graph,None,"Circles")
	isFeat =  graph.getBooleanProperty("isFeat")
	isFeat.setAllNodeValue(False)
	listdir = os.listdir(path)
	tot = len(listdir)/5
	tot = int (tot*1.0*per/100)
	cpt = 1
	for file in listdir:
		if cpt >= tot:
			break
		info = file.split('.')
		if info[1]=="circles":
			print "loading " +str(percent(cpt,tot))+"%"
			cpt+=1
			loadGraph(info[0],circle)
#			circle.delAllSubGraphs(c)
	cons(view,circle)
 
 
def percent(a,b):
	return int((a*1.0/b)*100)
 
def addSubGraph(graph,prop,name):
	g = graph.addSubGraph(prop)
	g.setName(name)
	return g
 
def loadGraph(egoId ,graph):
	viewLabel =  graph.getStringProperty("viewLabel")
	isFeat =  graph.getBooleanProperty("isFeat")
	done = graph.getBooleanProperty("done")
	viewColor =  graph.getColorProperty("viewColor")
 
	nodeId = {}
	#list featnames
	featId = {}
 
	fichier = open(path+egoId+edges_ext, "r")
	edges = []
	for ligne in fichier:
		lnk = ligne.split()
		e = [int(lnk[0]),int(lnk[1])]
		edges.append(e)
	fichier.close()
 
	fichier1 = open(path+egoId+circles_ext, "r")
	fichier2 = open(path+egoId+feat_ext, "r")
	Finfo = []
	for ligne in fichier2:
		ln = []
		split = ligne.split()
		for l in split:
			ln.append(l)
		Finfo.append(ln)
	fichier2.close()
	t = 0
	for ligne in fichier1:
		t = t+ 1
		circleIds=[]
		ids = ligne.split()
		cna = addSubGraph(graph,None,egoId)
 
		#add ids of circle in circleIds
		for i in range(1,len(ids)):
			#add nodes from circle in all subgraph
			circleIds.append(int(ids[i]))
			node = cna.addNode()
			nodeId[int(ids[i])] = node
		for edge in edges:
			if edge[0] in circleIds:
				if edge[1] in circleIds:
					e=cna.addEdge(nodeId[edge[0]],nodeId[edge[1]])
		for info in Finfo:
			idn = int(info[0])
			if idn in circleIds:
				node = nodeId[idn]
				for i in range(1,len(info)):
					if info[i] == "1":
						if i in featId:
							if not featId[i] in cna.getNodes():
								cna.addNode(featId[i])
							cna.addEdge(node,featId[i])
						else:
							nf = cna.addNode()
							featId[i] = nf
							viewColor.setNodeValue(nf,tlp.Color(0, 0, 255, 255))
							isFeat.setNodeValue(nf,True)
							cna.addEdge(node,featId[i])	
		for n in cna.getNodes():
			if done.getNodeValue(n):
				viewLabel.setNodeValue(n,"T")
	fichier1.close()

5) Présentation: visu_1_.pdf

/net/html/perso/melancon/Visual_Analytics_Course/data/pages/clanterne_frandriamanana/celestin_lanterne_franck_randriamanana.txt · Last modified: 2013/01/13 22:32 by frandriamanana