La personnalisation visuelle partie 2

Dans ce second chapitre dédié à la personnalisation visuelle des graphes, je vais vous présenter la gestion des groupes avec de nouvelles options de personnalisations des noeuds et la gestion des images.

Pour les plus courageux d’entre vous, ce chapitre se terminera par un petit défi ;) .

Les groupes

VisNetwork nous permet de définir des groupes pour permettre la simplification du paramétrage visuel des noeuds, pour cela il suffit d’ajouter un paramètre group à nos noeuds et de définir les paramétrages du groupe dans les options.

Dans ce chapitre nous allons travailler à partir d’un autre exemple, représentant les liens entre des tutoriels, des auteurs et des tags issue de Zeste de Savoir:

Voici le graphe que nous allons chercher à obtenir
Voici le graphe que nous allons chercher à obtenir

Je vous donne le code de base de ce chapitre avec des noeuds appartenant à des groupes.

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

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

let data = {
  nodes: nodes,
  edges: edges
};
let options = {
    nodes : {},
    edges : {}
};

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

// Ajout des noeuds
nodes.add(
  [
    {
      id: "TUTO_VIS",
      label: "Introduction à la visualisation de graphes avec VisNetwork ",
      group : "tuto"
    },
    {
      id: "USER_SHE",
      label: "Shevek",
      group : "user"
    },
    {
      id: "TAG_JS",
      label: "Javascript",
      group : "tag"
    },
    {
      id: "TAG_GRA",
      label: "Graphes",
      group : "tag"
    },
    {
      id: "TAG_VIS",
      label: "vis.js",
      group : "tag"
    },
    {
      id: "TUTO_GRA",
      label: "À la découverte des algorithmes de graphe",
      group : "tuto"
    },
    {
      id: "USER_ALG",
      label: "Algue-Rythme",
      group : "user"
    },
    {
      id: "TAG_ALG",
      label: "algorithmique",
      group : "tag"
    },
    {
      id: "TUTO_CAR",
      label: "Des cartes sur votre site",
      group : "tuto"
    },
    {
      id: "TAG_LEA",
      label: "Leaflet",
      group : "tag"
    },
    {
      id: "TAG_GEO",
      label: "géographie",
      group : "tag"
    },
    {
      id: "TAG_CAR",
      label: "cartographie",
      group : "tag"
    },
    {
      id: "USER_ESK",
      label: "Eskimon",
      group : "user"
    }
  ]
);

// Ajout des liens
edges.add(
  [
    {
      from: "TUTO_VIS",
      to: "USER_SHE",
      label: ""
    },
    {
      from: "TUTO_VIS",
      to: "TAG_JS",
      label: ""
    },
    {
      from: "TUTO_VIS",
      to: "TAG_GRA",
      label: ""
    },
    {
      from: "TUTO_VIS",
      to: "TAG_VIS",
      label: ""
    },
    {
      from: "TUTO_GRA",
      to: "USER_ALG",
      label: ""
    },
    {
      from: "TUTO_GRA",
      to: "TAG_ALG",
      label: ""
    },
    {
      from: "TUTO_GRA",
      to: "TAG_GRA",
      label: ""
    },
    {
      from: "TUTO_CAR",
      to: "USER_ESK",
      label: ""
    },
    {
      from: "TUTO_CAR",
      to: "TAG_LEA",
      label: ""
    },
    {
      from: "TUTO_CAR",
      to: "TAG_GEO",
      label: ""
    },
    {
      from: "TUTO_CAR",
      to: "TAG_CAR",
      label: ""
    },
    {
      from: "TUTO_CAR",
      to: "TAG_JS",
      label: ""
    },
  ]
);

Nous obtenons ce graphe que nous allons pouvoir personnaliser :

VisNetwork attribut automatiquement une couleur à chaque groupe de noeuds
VisNetwork attribut automatiquement une couleur à chaque groupe de noeuds

Le design des groupes

Le design des groupes ce fait directement dans les options, on ajoute un objet groups dans lequel on ajoute un objet par groupe (avec pour nom celui du groupe), dans lequel on va définir nos propriétés :

let options = {
  nodes : {},
  edges : {},
  groups: 
  {
    mongroupe : 
    {
      // Paramètres des noeuds du groupe
    }
  }

Dans notre cas on crée 3 groupes de paramétrage : tuto, user et tag.

Voici une petite description des nouvelles propriétés utilisées que nous allons utiliser :

  • margin : Marge entre le label et la bordure du noeud (lorsque le label est contenu dans le noeud), exprimé en pixel.
  • color.highlight : Paramètres de couleur du noeud lorsqu’il est sélectionné.

    • color.highlight.background : Couleur de fond du noeud lorsqu’il est sélectionné.
    • color.highlight.border : Couleur de bordure du noeud lorsqu’il est sélectionné.
  • font : Paramétrage de la police d’écriture du label, peut-être définie directement (ex : 14px arial red) ou peut être paramétré via ses paramètres enfant :

    • font.color : Couleur de l’affichage du label.
    • font.size : Taille de la police de caractère du label.

Voici le code complet :

let options = {
  nodes : {},
  edges : {},
  groups: 
  {
    tuto: 
    {
      shape: "box",               // Nœud affiché sous forme de boîte entourant le label
      margin : 10,                // Marge de 10 entre le contour et le label
      color:
      {
        background: '#dddddd',    // Fond de couleur gris clair
        border: '#222222'         // Bordure de couleur noir
      }, 
      borderWidth:3               // Bordure de taille 3
    },
    user : {
      shape: "star",              // Nœud affiché sous forme d'étoile
      borderWidth: '3',           // Bordure de taille 3
      color:
      {
        background: '#edcb54',    // Fond de couleur jaune/orange
        border: '#c34032',        // Bordure de couleur rouge
        highlight : 
        {
          background: '#c34032',  // Fond de couleur rouge lorsque le noeud est sélectionné
          border: '#c34032'       // Bordure de couleur rouge lorsque le noeud est sélectionné
        }
      },
      font: {
        color: "#c34032",         // Couleur de l'écriture du label en rouge
        size: 20                  // Police d'écriture du label de taille 20
      }
    },
    tag: {
      shape: "circle",            // Nœud affiché sous forme de cercle
      borderWidth: '5',           // Bordure de taille 5
      color:
      {
        background: '#7ec1d7',    // Fond de couleur Bleue
        border: '#21677e',        // Bordure de couleur Bleue foncée
        highlight : 
        {
          background: '#7ec1d7',  // Fond de couleur Bleue lorsque le noeud est sélectionné
          border: '#21677e'       // Bordure de couleur Bleue foncé lorsque le noeud est sélectionné
        }
      }
    }
  }
};
Nous obtenons notre super graphe !
Nous obtenons notre super graphe !

Je ne vous le présente pas dans ce tuto, mais sachez que vous pouvez également utiliser les groupes pour définir le design des liens.

Les images

VisNetwork possède deux types d’affichages d’images qui se définissent dans la propriété shape du noeud :

  • image : Une image est affichée à la place du noeud.
  • circularImage : Nœud avec une image contenue dans un cercle.

Les images possèdent des options qui leur sont propres :

  • image : URL de l’image à afficher.
  • brokenImage : URL de l’image par défaut qui est affichée lorsque le chargement de l’image choisie a échoué.

Pour l’exemple suivant, je vous fournis quelques images qui nous permettront de créer notre graphe :

perso.png place.png france.png

Voici un exemple de création d’un graphe avec 3 images (deux images circulaires et une image normale) :

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

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

let data = {
  nodes: nodes,
  edges: edges
};
let options = {
    nodes : {
    },
    edges : { /* Paramètre par defaut des liens */
        arrows: "to",
        color : {
            color: "#f8944b"
        },
        width : 1,
        selectionWidth: 2,
    }
};

let network = new vis.Network(container, data, options);

nodes.add(
    [
        { /* Noeud représentant une personne */
            id: 1,
            label: "Personne",
            shape: "circularImage",
            image: "perso.png",
            borderWidth: 1,
            size: 15,
            color: {
              border: "#42a250",
              background: "#cdf4d2"
            },
        },
        { /* Noeud avec un drapeau représentant la France */
            id: 2,
            label: "France",
            shape: "image",
            size: 15,
            image: "france.png",
        },
        { /* Noeud de la ville de Paris */
            id: 3,
            label: "Paris",
            shape: "circularImage",
            image: "place.png",
            size: 20,
            borderWidth: 3,
            color: {
              border: "#75cbd0",
              background: "#caf3f6"
            },
        }
    ]
);

edges.add(
    [
        { /* Lien entre la personne et la france */
            from: 1,
            to: 2,
            label: "Nationalitée"
        },
        { /* Lien entre la personne et Paris */
            from: 1,
            to: 3,
            label: "Née à"
        }
    ]
);
Représentation d'une personne née à Paris et de nationalité française
Représentation d'une personne née à Paris et de nationalité française

Excercice

Je vous propose un petit exercice pour mettre en pratique le paramétrage des groupes et des images, le but va être d’obtenir un joli graphe qui représente des espèces d’animaux triés par catégories.

Voici le code de base avec des images issues de Wikipédia :

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

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

let data = {
  nodes: nodes,
  edges: edges
};
let options = {
    nodes : {},
    edges : {},
    groups : {}
};

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

// Ajout des noeuds
nodes.add(
  [
    {
      id: "Animal",
      label: "Animal",
      group : "grande_catégorie"
    },
    {
      id: "Mammifère",
      label: "Mammifère",
      group : "moyenne_catégorie"
    },
    {
      id: "Cétacé",
      label: "Cétacé",
      group : "petite_catégorie",
      image: "https://upload.wikimedia.org/wikipedia/commons/thumb/2/2b/The_Cetacea.jpg/290px-The_Cetacea.jpg"
    },
    {
      id: "Baleine à bosse",
      label: "Baleine à bosse",
      group : "espece",
      image : "https://upload.wikimedia.org/wikipedia/commons/thumb/9/9e/Humpback_stellwagen_edit.jpg/290px-Humpback_stellwagen_edit.jpg"
    },
    {
      id: "Dauphin",
      label: "Dauphin",
      group : "espece",
      image : "https://upload.wikimedia.org/wikipedia/commons/thumb/1/10/Tursiops_truncatus_01.jpg/220px-Tursiops_truncatus_01.jpg"
    },
    {
      id: "Félin",
      label: "Félin",
      group : "petite_catégorie",
      image: "https://upload.wikimedia.org/wikipedia/commons/thumb/5/5b/The_Felidae.jpg/290px-The_Felidae.jpg"
    },
    {
      id: "Tigre",
      label: "Tigre",
      group : "espece",
      image : "https://upload.wikimedia.org/wikipedia/commons/thumb/4/41/Siberischer_tiger_de_edit02.jpg/290px-Siberischer_tiger_de_edit02.jpg"
    },
    {
      id: "Oiseau",
      label: "Oiseau",
      group : "moyenne_catégorie"
    },
    {
      id: "Flamant",
      label: "Flamant",
      group : "espece",
      image : "https://upload.wikimedia.org/wikipedia/commons/thumb/4/45/Greater_Flamingo%2C_Phoenicopterus_roseus_at_Marievale_Nature_Reserve%2C_Gauteng%2C_South_Afr_%2822773937344%29.jpg/290px-Greater_Flamingo%2C_Phoenicopterus_roseus_at_Marievale_Nature_Reserve%2C_Gauteng%2C_South_Afr_%2822773937344%29.jpg"
    },
    {
      id: "Corbeau",
      label: "Corbeau",
      group : "espece",
      image : "https://upload.wikimedia.org/wikipedia/commons/thumb/2/29/Common_raven_by_David_Hofmann.jpg/1024px-Common_raven_by_David_Hofmann.jpg"
    },
    {
      id: "Poisson",
      label: "Poisson",
      group : "moyenne_catégorie"
    },
    {
      id: "Requin",
      label: "Requin",
      group : "espece",
      image : "https://upload.wikimedia.org/wikipedia/commons/thumb/5/56/White_shark.jpg/290px-White_shark.jpg"
    }
  ]
);

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

L’objectif va être d’obtenir ce graphe :

Graphe à obtenir
Graphe à obtenir

Comme vous pouvez le voir on a 4 groupes :

  • grande_catégorie : Affiché sous forme de rectangle entourant le label avec une marge de 10. Il a une couleur de fond gris clair (#dddddd) et une bordure gris foncé (#222222) de taille 3.
  • moyenne_catégorie : Affiché sous forme de cercle à fond gris clair (#dddddd) et à bordure gris foncé (#222222).
  • petite_catégorie : Affiché sous forme d’image circulaire de taille 40, avec une bordure de taille 6 et de couleur gris foncé (#222222).
  • espece : Affiché sous forme d’image.

Je vous souhaite bonne chance, si vous avez oublié les propriétés vues lors du chapitre précédent, vous pouvez utiliser le récapitulatif des propriétés présent plus bas.

Vous pouvez retrouver la correction ci-dessous :

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

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

let data = {
  nodes: nodes,
  edges: edges
};
let options = {
    nodes : {},
    edges : {},
    groups : {
      grande_catégorie : 
      {
        shape: "box",               // Nœud affiché sous forme de boîte entourant le label
        margin : 10,                // Marge de 10 entre le contour et le label
        color:
        {
          background: '#dddddd',    // Fond de couleur gris clair
          border: '#222222'         // Bordure de couleur gris foncé
        }, 
        borderWidth:3               // Bordure de taille 3
      },
      moyenne_catégorie : 
      {
        shape: "circle",            // Nœud affiché sous forme de cercle entourant le label
        color:
        {
          background: '#dddddd',    // Fond de couleur gris clair
          border: '#222222'         // Bordure de couleur gris foncé
        }
      },
      petite_catégorie : 
      {  
        shape: 'circularImage',    // Nœud affiché sous forme d'image contenu dans un cercle
        borderWidth: 6,            // Bordure de l'image
        size: 40,                  // Taille du noeud
        color:
        {
          border: '#333333'        // Bordure de couleur gris foncé
        }
      },
      espece : 
      {
        shape: 'image'            // Nœud affiché sous forme d'image
      }
    }
};

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

// Ajout des noeuds
nodes.add(
  [
    {
      id: "Animal",
      label: "Animal",
      group : "grande_catégorie"
    },
    {
      id: "Mammifère",
      label: "Mammifère",
      group : "moyenne_catégorie"
    },
    {
      id: "Cétacé",
      label: "Cétacé",
      group : "petite_catégorie",
      image: "https://upload.wikimedia.org/wikipedia/commons/thumb/2/2b/The_Cetacea.jpg/290px-The_Cetacea.jpg"
    },
    {
      id: "Baleine à bosse",
      label: "Baleine à bosse",
      group : "espece",
      image : "https://upload.wikimedia.org/wikipedia/commons/thumb/9/9e/Humpback_stellwagen_edit.jpg/290px-Humpback_stellwagen_edit.jpg"
    },
    {
      id: "Dauphin",
      label: "Dauphin",
      group : "espece",
      image : "https://upload.wikimedia.org/wikipedia/commons/thumb/1/10/Tursiops_truncatus_01.jpg/220px-Tursiops_truncatus_01.jpg"
    },
    {
      id: "Félin",
      label: "Félin",
      group : "petite_catégorie",
      image: "https://upload.wikimedia.org/wikipedia/commons/thumb/5/5b/The_Felidae.jpg/290px-The_Felidae.jpg"
    },
    {
      id: "Tigre",
      label: "Tigre",
      group : "espece",
      image : "https://upload.wikimedia.org/wikipedia/commons/thumb/4/41/Siberischer_tiger_de_edit02.jpg/290px-Siberischer_tiger_de_edit02.jpg"
    },
    {
      id: "Oiseau",
      label: "Oiseau",
      group : "moyenne_catégorie"
    },
    {
      id: "Flamant",
      label: "Flamant",
      group : "espece",
      image : "https://upload.wikimedia.org/wikipedia/commons/thumb/4/45/Greater_Flamingo%2C_Phoenicopterus_roseus_at_Marievale_Nature_Reserve%2C_Gauteng%2C_South_Afr_%2822773937344%29.jpg/290px-Greater_Flamingo%2C_Phoenicopterus_roseus_at_Marievale_Nature_Reserve%2C_Gauteng%2C_South_Afr_%2822773937344%29.jpg"
    },
    {
      id: "Corbeau",
      label: "Corbeau",
      group : "espece",
      image : "https://upload.wikimedia.org/wikipedia/commons/thumb/2/29/Common_raven_by_David_Hofmann.jpg/1024px-Common_raven_by_David_Hofmann.jpg"
    },
    {
      id: "Poisson",
      label: "Poisson",
      group : "moyenne_catégorie"
    },
    {
      id: "Requin",
      label: "Requin",
      group : "espece",
      image : "https://upload.wikimedia.org/wikipedia/commons/thumb/5/56/White_shark.jpg/290px-White_shark.jpg"
    }, 
    
    // 
  ]
);

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

Défis

Je propose aux plus motivés d’entre vous un petit défis :

Le but est de reprendre le principe du graphe précédent et d’essayer d’ajouter de nouveaux animaux, de nouvelles catégories et surtout de nouveaux paramétrage de design pour tenter de réaliser le graphe le plus beau possible. :)

Si vous êtes satisfait du résultat je vous invite à le partager dans les commentaires du tutoriel (En bas de la page d’accueil).

Récapitulatif des propriétés

Voici un petit récapitulatif des propriétés de paramétrage des noeuds, tous ne sont pas cités. Vous pouvez retrouver les autres dans la documentation de VisNetwork :

  • shape : Défini la forme d’affichage du noeuds :

    • image : Affichage d’une image.
    • circularImage : Affichage d’une image contenue dans un cercle.
    • circle : Cercle avec le label du noeud au centre.
    • ellipse : Ellipse entourant le label du nœud.
    • box : Rectangle/boîte entourant le label du nœud.
    • diamond, dot, star, triangle, triangleDown, hexagon et square : Symbole avec le label affiché en dessous.
  • color : Corresponds à la couleur du noeud, peut être soit une couleur ou un objet contenant des informations plus détaillées :

    • color.background : Couleur de fond du noeud.
    • color.border : Couleur de la bordure, s’affichant si le nœud possède une bordure.
    • color.highlight : Paramètres de couleur du noeud lorsqu’il est sélectionné.

      • color.highlight.background : Couleur de fond du noeud lorsqu’il est sélectionné.
      • color.highlight.border : Couleur de bordure du noeud lorsqu’il est sélectionné.
  • font : Paramétrage de la police d’écriture du label, peut-être définie directement (ex : 14px arial red) ou peut être paramétré via ses paramètres enfants :

    • font.color : Couleur de l’affichage du label.
    • font.size : Taille de la police de caractère du label (en pixel).
  • size : Taille du noeud (en pixel).
  • borderWidth : Taille de la bordure du noeud (en pixel).
  • margin : Marge entre le label et la bordure du noeud (lorsque le label est contenu dans le noeud), exprimé en pixel.

Voici une petite liste des principaux paramétrages des liens, tous ne sont pas cités vous pouvez retrouver les autres dans la documentation de VisNetwork :

  • arrows : Défini le type de représentation du lien :

    • to : Flèche sur le noeud choisi dans la propriété to du lien.
    • from : Flèche sur le noeud choisi dans la propriété from du lien.
    • middle : Flèche au centre du lien.
    • to;from : Flèches aux deux extrémités du lien.
    • Peut également être paramétré avec d’autres icônes et des tailles personnalisés (voir la doc pour plus d’infos).
  • color : Paramétrages de la couleur du lien.

    • color.color : Couleur du lien à l’état normal.
    • color.highlight : Couleur du lien lorsqu’il est sélectionné ou adjacent à un noeud sélectionné.
  • font : Paramètre de la police d’écriture du label du lien, peut-être défini directement (ex : 14px arial red) ou peut être paramétré via ses paramètres enfants :

    • font.color : Couleur du label.
    • font.size : Taille de la police du label (en pixel).
    • font.strokeColor : Couleur de surbrillance du label.
  • width : Épaisseur du lien (en pixel).

  • selectionWidth : Épaisseur du lien lorsqu’il est sélectionné (en pixel).

  • smooth : Définis la manière dont les liens sont dessinés, je ne vais pas présenter cette option dans ce tutoriel, si vous souhaitez l’utiliser cet exemple qui vous permettra d’expérimenter les différents types de smooth.


Nous en avons fini avec la personnalisation visuelle, si vous souhaitez vous exercer un peu au paramétrage avant de passer au chapitre suivant, vous pouvez retrouver via la doc la liste complète des paramètres sur les noeuds et les liens.

Le prochain chapitre traitera des notions de forces exercés sur les graphes.