Les forces

Jeune padawan, il est maintenant temps d’apprendre à maitriser la force. ^^

Qu'est qu'une force

Petite définition :

Une force modélise, en physique, une action mécanique exercée par un objet sur un autre et capable d’imposer une accélération induisant la modification du vecteur vitesse (une force exercée sur l’objet fait aller celui-ci plus vite, moins vite ou le fait tourner). source Wikipédia

Dans le cas des graphes, la force correspond à la physique du graphe, c’est-à-dire aux forces d’attractions qu’exercent les noeuds les un sur les autres modifiant ainsi la position des autres noeuds. Vous avez surement remarqué que lorsque vous déplacez un noeud les autres le suivent, cela est dû tout simplement aux forces.

Ce sont donc ces forces qui vont gérer la manière dont les noeuds du graphe se positionnent.

Les différents algoritmes de force

VisNetwork nous fourni 4 algorithmes gérant les forces qu’il est possible de paramétrer :

  • barnesHut : C’est l’algorithme de placement par défaut, il a l’avantage d’être performant et paramétrable et il est recommandé de l’utiliser.
  • forceAtlas2Based : Est un algorithme de placement développé à la base pour le logiciel Gephi et très utilisé, il est axé sur la notion de centralité des noeuds, plus un noeud a de liens plus il sera central dans le graphe.
  • repulsion : Algorithme simple dans lequel les noeuds émettent des champs de répulsion sur les autres.
  • hierarchicalRepulsion : Même principe que la repulsion mais à utiliser plutôt pour les placements prédéfinis (layout) que nous verrons dans un autre chapitre.

Je vous met un exemple de chaque type de forces avec ses paramètres par défaut appliqués au même graphe pour que vous voyer les (subtiles) différences :

barnesHut
barnesHut
forceAtlas2Based
forceAtlas2Based
repulsion
repulsion
hierarchicalRepulsion
hierarchicalRepulsion

Voici le code pour l’algorithme barnesHut pour que vous pussiez essayer par vous-même :

let nodes = new vis.DataSet([]);
let edges = new vis.DataSet([]);

let container = document.getElementById('graphe');

let data = {
  nodes: nodes,
  edges: edges
};
let options = {
    nodes : {
      shape: "dot",
      color:
      {
        background: '#dddddd',    // Fond de couleur gris claire
        border: '#888888'         // Bordure de couleur gris foncé
      }, 
      borderWidth:3,              // Bordure de taille 3
      size : 12                   // Taille de 12
    },
    edges : {},
    physics:{
      enabled: true,              // Rend actif la physique
      solver: 'barnesHut'         // Type de force 'barnesHut'
    },
};

// Initialisation de l'instance de VisNetwork
let network = new vis.Network(container, data, options);

// Ajout des noeuds
nodes.add(
  [
    {
      id: "Animal",
      label: "Animal"
    },
    {
      id: "Mammifère",
      label: "Mammifère"
    },
    {
      id: "Cétacé",
      label: "Cétacé"
    },
    {
      id: "Baleine à bosse",
      label: "Baleine à bosse"
    },
    {
      id: "Dauphin",
      label: "Dauphin"
    },
    {
      id: "Félin",
      label: "Félin"
    },
    {
      id: "Tigre",
      label: "Tigre"
    },
    {
      id: "Oiseau",
      label: "Oiseau"
    },
    {
      id: "Flamant",
      label: "Flamant"
    },
    {
      id: "Corbeau",
      label: "Corbeau"
    },
    {
      id: "Poisson",
      label: "Poisson"
    },
    {
      id: "Requin",
      label: "Requin"
    }
  ]
);

// Ajout des liens
edges.add(
  [
    {
      from: "Animal",
      to: "Mammifère"
    },
    {
      from: "Mammifère",
      to: "Cétacé"
    },
    {
      from: "Mammifère",
      to: "Félin"
    },
    {
      from: "Cétacé",
      to: "Baleine à bosse"
    },
    {
      from: "Cétacé",
      to: "Dauphin"
    },
    {
      from: "Félin",
      to: "Tigre"
    },
    {
      from: "Animal",
      to: "Oiseau"
    },
    {
      from: "Oiseau",
      to: "Flamant"
    },
    {
      from: "Oiseau",
      to: "Corbeau"
    },
    {
      from: "Animal",
      to: "Poisson"
    },
    {
      from: "Poisson",
      to: "Requin"
    } 
  ]
);

Paramétrer une force

Voici les paramètres principaux des forces :

  • enabled : Si à false permet de désactiver la physique du graphe, je vous conseille d’essayer pour voir ce que donne un graphe sans force exercée.
  • solver : Définis le type de physique choisie entre les quatre que je vous ai présenté plus haut, par défaut l’algorithme barnesHut est utilisé.
  • barnesHut : Choix des paramètres des forces si le solver barnesHut a été choisi.
  • forceAtlas2Based : Choix des paramètres des forces si le solver forceAtlas2Based a été choisi.
  • repulsion : Choix des paramètres des forces si le solver repulsion a été choisi.
  • hierarchicalRepulsion : Choix des paramètres des forces si le solver hierarchicalRepulsion a été choisi.

Voici un exemple de paramétrage de la force barnesHut avec ses paramètres par défaut :

    physics:{
      enabled: true,
      solver: 'barnesHut',
      barnesHut : {
        gravitationalConstant : -2000,
        centralGravity : 0.3,
        springLength : 95,
        springConstant : 0.09
      }
    }

Exemple avec barnesHut

Je vais vous présenter les principaux paramètres de l’algorithme barnesHut, pour que vous voyer concrètement ce qu’apporte le paramétrage des forces.

barnesHut.gravitationalConstant : Variable d’attractivité, doit être négatif. Plus la variable est basse plus les noeuds liées sont éloignés les un des autres. Valeur par défaut : -2000

gravitationalConstant à -300 : image.png

gravitationalConstant à -10000 : image.png

barnesHut.centralGravity : Gravité vers le centre, plus la valeur est haute plus les noeuds du graphe sont attirés vers le centre. Valeur par défaut : 0.3

centralGravity à 2 : image.png

centralGravity à 0.05 : image.png

barnesHut.springLength : Taille des ressorts des liens, une valeur élevée donnera des liens distendus et une valeur basse des liens très tendus. Valeur par défaut : 95

springLength à 20 : image.png

springLength à 200 : image.png

barnesHut.springConstant : Modifie la robustesse des liens, plus la valeur est élevé, moins les liens sont élastiques. Valeur par défaut : 0.09.

Lorsque springConstant est à 0.5, lorsque vous déplacer un noeud vous verrez que tous les autres noeuds se déplacent instantanément.

Lorsque springConstant est à 0.005, les autres noeuds réagissent beaucoup moins à vos déplacements.

Gestion de la masse des noeuds

Un paramètre utile lors de la gestion des forces est le paramètre de mass que possède chaque noeuds, par défaut sa valeur est de 1 plus on augmente sa valeur, plus le noeuds va être éloigné dans autre noeuds (il augmente la répulsion appliquée à ses noeuds liés).

Voici un exemple de création de noeuds avec un paramétrage des masses :

nodes.add(
  [
    {
      id: "Animal",
      label: "Animal",
    },
    {
      id: "Mammifère",
      label: "Mammifère",
      mass : 10
    },
    {
      id: "Cétacé",
      label: "Cétacé",
      mass : 15
    },
    {
      id: "Baleine à bosse",
      label: "Baleine à bosse"
    },
    {
      id: "Dauphin",
      label: "Dauphin"
    },
    {
      id: "Félin",
      label: "Félin"
    },
    {
      id: "Tigre",
      label: "Tigre"
    },
    {
      id: "Oiseau",
      label: "Oiseau"
    },
    {
      id: "Flamant",
      label: "Flamant"
    },
    {
      id: "Corbeau",
      label: "Corbeau"
    },
    {
      id: "Poisson",
      label: "Poisson"
    },
    {
      id: "Requin",
      label: "Requin"
    }
  ]
);
Vous voyez que le noeud des Mammifères est éloigné que les autres et celui des Cétacés est encore plus éloigné
Vous voyez que le noeud des Mammifères est éloigné que les autres et celui des Cétacés est encore plus éloigné

Je ne mets exceptionnellement pas d’exercice pour ce chapitre, si vous souhaitez expérimenter les paramétrages des autres types de forces, je vous mets là encore un lien vers la doc qui est très complète et je vous propose cet exemple disponible en ligne qui permet d’expérimenter tous les paramétrages des forces en temps réel.

Dans le prochain nous rendrons notre graphe interactif grâce aux évènements.