Explorer son

réseau facebook

avec sigma.js

@parisjs 31 Octobre 2012


Alexis Jacomy

développeur Javascript
@ Linkfluence
@ radarlyapp

github : jacomyal
twitter : jacomyal

Linkfluence recrute !


ingénieur industrialisation
ingénieur développeur
stagiaires front-end
stagiaires moteur

(lien vers les offres)

Contactez-nous :
twitter.com/linklabs




SIGMA.js


sigma.js


est une bibliothèque Javascript open-source
d'affichage de graphes

github : github.com/jacomyal/sigma.js
site web : sigmajs.org
twitter : sigmajs




C'est quoi, un graphe?


Un graphe est un ensemble de points, dont certaines paires sont directement reliées par un (ou plusieurs) lien(s).

source

Exemples :

réseaux sociaux

graphes hypertextes

graphes de dépendances de classes

...





Pourquoi afficher

des graphes?




Un outil de visualisation bien conçu
peut permettre à l'utilisateur d'observer des structures dans un graphe qu'il serait difficile ou impossible à voir dans le graphe sous sa forme brute.
source


Exemples


Réseaux sociaux :
InMaps (Linkedin)
NameGenDev (Facebook)

Autres :
Atlas Linkfluence




Quelques outils existants

Gephi


GEPHI



"The Photoshop for graphs"

Application Java
+100 000 téléchargements

site web : gephi.org

mais pas de version Web

SEADRAGON


SEADRAGON


exemple : CPAN explorer (Linkfluence)

image haute résolution
zoomable "à la Google Maps"

export dispo depuis Gephi

scalable - mais pas interactif

D3.js


D3.js

contrôleur de données, plus pleins d'helpers
pour visualiser différents types de données

incontournable

mais...

un peu overkill
affichage des graphes en SVG
non optimisé, donc peu scalable

sigma.js



sigma.js


outil Javascript - donc Web

dédié à l'affichage de graphes, et
uniquement à l'affichage de graphes

scalable (canvas, injection de frames)

orienté interactions



Le vif du sujet...

Récupérer ses

données sur facebook

NETVIZZ



Une application Facebook
pour exporter son réseau

lien : apps.facebook.com/netvizz/

GDF


Format de stockage de graphes (specs)


  nodedef>name VARCHAR,label VARCHAR
  toto,noeud Toto
  tutu,noeud Tutu
  edgedef>node1 VARCHAR, node2 VARCHAR
  toto,tutu

les noeuds représentent les personnes,
deux personnes sont liées si elles sont "amies" sur Facebook



Le code de l'application

HTML

  <!DOCTYPE html>
  <html lang="fr">
    <head>
      <meta charset="utf-8" />
      <!-- sigma files import -->
      <script src="sigma.min.js"></script>
      <script src="sigma.forceatlas2.js"></script>
      <!-- demo files import -->
      <script src="parisjs.js"></script>
      <link rel="stylesheet" href="parisjs.css">
    </head>
    <body>
      <div id="container"></div>
    </body>
  </html>

CSS


  body {
  background-color: #eee;
}
div#container {
  box-shadow: 0px 2px 8px #333;
  -moz-box-shadow: 0px 2px 8px #333;
  -webkit-box-shadow: 0px 2px 8px #333;
  background-color: #fff;
  position: absolute;
  width: 900px;
  height: 90%;
  margin-top: 5%;
  margin-left: -450px;
  left: 50%;
}

Initialiser sigma.js



  var sigInst = sigma.init(
  document.getElementById('container')
).graphProperties({
  minNodeSize: 0.5,
  maxNodeSize: 5
});

CHARGER LE .GDF


  var loader = new XMLHttpRequest();
  
  loader.open('GET', 'graphe.gdf');
  loader.onreadystatechange = function() {
    if (loader.readyState == 4) {
      initGraph(loader.responseText);
    }
  }

  loader.send();

PARSER LE .GDF

  var lines = rawData.split(/\r?\n/),
      line,
      parsingEdges = false,
      parsingNodes = false;

  // On parcourt les lignes:
  for (var i = 0; i < lines.length; i++) {
    line = lines[i];

    if (line.match(/^[Nn]odedef>/)) {
      // On récupère les attributs des noeuds
      parsingNodes = true;
    } else if (line.match(/^[Ee]dgedef>/)) {
      // On récupère les attributs des arcs
      parsingEdges = true;
    } else if (parsingEdges) {
      // On ajoute les arcs
    } else if (parsingNodes) {
      // On ajoute les noeuds
    }
  }

Attributs

  var nodeAttributes, edgeAttributes;

  // [...]
  if (line.match(/^nodedef>/i)) {
    // Récupérer les attributs des noeuds
    parsingNodes = true;
    nodeAttributes = line.replace(
      /^nodedef>/i, ''
    ).split(/,/g).map(function(s) {
      return s.replace(/ .*/, '');
    });
  } else if (line.match(/^edgedef>/i)) {
    // Récupérer les attributs des arcs
    parsingEdges = true;
    edgeAttributes = line.replace(
      /^edgedef>/i, ''
    ).split(/,/g).map(function(s) {
      return s.replace(/ .*/, '');
    });
  }
  // [...]

NOEUDS


  // [...]
  var node = {},
      nodeId,
      values = line.split(/,/g);

  nodeAttributes.forEach(function(attr, i) {
    if (attr === 'name' || attr === 'id')
      nodeId = values[i];
    else
      node[attr] = values[i];
  });

  if (nodeId)
    sigInst.addNode(nodeId, node);
  // [...]

ARCS


  // [...]
  var edge = {},
      source, target,
      values = line.split(/,/g);

  edgeAttributes.forEach(function(attr, i) {
    if (attr === 'node1')
      source = values[i];
    else if (attr === 'node2')
      target = values[i];
    else
      edge[attr] = values[i];
  });

  if (source && target)
    sigInst.addEdge(++edgesCount, source, target, edge);
  // [...]

FINE TUNING


Le graphe est maintenant stocké dans
l'instance de sigma.js

Il reste à déterminer :
La position des noeuds
La couleur des noeuds
La taille des noeuds

FINE TUNING



La taille représentera le degré du noeud

La couleur représentera le sexe

Les noeuds seront initialement disposés en cercle,
puis un algorithme de spatialisation donnera
sa position définitive au graphe

Itérer sur les noeuds

  var R = 100,
      i = 0,
      L = sigInst.getNodesCount();

  sigInst.iterNodes(function(n) {
    // Position
    n.x = Math.cos(Math.PI*(i++)/L)*R;
    n.y = Math.sin(Math.PI*(i++)/L)*R;

    // Couleur
    n.color =
      n.attr.sex === 'female' ?
        '#D37' :
      n.attr.sex === 'male' ?
        '#33D' :
        '#888';

    // Taille
    n.size = n.degree;
  });

FORCE DIRECTED LAYOUT


Algorithme physique, pour donner
une "forme" au graphe

A chaque étape :
Toutes les paires de noeuds se repoussent
Toutes les paires de noeuds liés s'attirent

(Wikipedia FR - EN)

FORCE DIRECTED LAYOUT



Heureusement, sigma.js propose un plugin
qui implémente l'algorithme ForceAtlas2


description de l'algorithme
lien vers le plugin

FORCE DIRECTED LAYOUT


Donc, pour cette question de "la forme du graphe" :

  // On lance l'algo...
  sigInst.startForceAtlas2();

  // ... et on l'arrête 8 secondes plus tard:
  window.setTimeout(function() {
    sigInst.stopForceAtlas2();
  }, 8000);



Démo time !

(un volontaire?)

Autres exemples


moviegalaxies.com
namegendev
exemples sur le site

ou encore :
chez datapublica
sur le Guardian Data Blog


Merci beaucoup!


présentation disponible sur
rvl.io/jacomyal/parisjs-octobre-2012

code source de la démo sur github
github.com/jacomyal/parisjs-oct2012-demo