Kamel Ghabte
Cours gratuit · Creative Coding

Mini-cours gratuit — Data Art : donner une forme à l'invisible

Niveau : Débutant en code créatif
Durée estimée : 45-60 min
Outil : p5.js (navigateur, aucune installation)
Lien œuvre : DATA RUG — tapis génératif, open data → motif


Introduction — Quand la donnée devient ornement

Un tapis berbère est une archive. Chaque motif encode une information : la tribu d'origine, l'année du tissage, un événement familial, une prière. Les femmes artisanes du Moyen Atlas ne "décoraient" pas — elles écrivaient dans un langage visuel que seules elles maîtrisaient.

Le data art renoue avec cette logique ancienne : prendre une donnée invisible (une température, un score, une fréquence) et la transformer en forme, en couleur, en rythme. Ce n'est pas de l'illustration, c'est de la traduction. On appelle ça le mapping — établir un pont entre un domaine numérique (des chiffres) et un domaine visuel (des pixels).

Dans DATA RUG, des données de pollution sonore d'une ville sont mappées sur les paramètres d'un motif de tapis : les zones bruyantes génèrent des motifs denses et saturés, les zones calmes produisent des formes ouvertes et pâles. Le résultat ressemble à un tapis que personne n'a tissé à la main, et pourtant il parle d'un lieu réel.

Ce mini-cours vous fait parcourir ce processus de traduction en trois étapes : taille, couleur, puis interactivité révélatrice.


Étape 1 — Mapper des données sur la taille

La première étape du data art est la plus simple et la plus puissante : faire varier une dimension visuelle proportionnellement à une valeur.

Ici, 100 valeurs (simulées — températures, scores, votes, n'importe quoi) alimentent une grille 10×10. Chaque cercle a un diamètre proportionnel à sa valeur. Le map() de p5.js est votre outil central : il convertit une plage de valeurs en une plage de pixels.

let data = [];

function setup() {
  createCanvas(600, 600);
  noStroke();
  fill(255);

  // Données simulées — remplaçables par n'importe quel tableau JSON
  // (températures mensuelles, scores, fréquences de mots, etc.)
  for (let i = 0; i < 100; i++) {
    data.push(random(10, 90));
  }
}

function draw() {
  background(10);

  let cols = 10;
  let rows = 10;
  let cellW = width / cols;
  let cellH = height / rows;

  for (let i = 0; i < data.length; i++) {
    let x = (i % cols) * cellW + cellW / 2;
    let y = floor(i / cols) * cellH + cellH / 2;

    // map() : la magie du data art — convertir une valeur en taille
    // Si la valeur est 0 → cercle de 5px (présence minimale, pas d'absence)
    // Si la valeur est 100 → cercle qui remplit la cellule
    let d = map(data[i], 0, 100, 5, min(cellW, cellH) * 0.9);

    ellipse(x, y, d, d);
  }
}

Pourquoi min(cellW, cellH) * 0.9 ? Pour que le cercle ne dépasse jamais sa cellule quelle que soit l'orientation du canvas. Le 0.9 laisse une marge de respiration — sans espace, la grille devient illisible.


Étape 2 — Mapper sur la couleur

La taille encode une dimension. La couleur en encode une deuxième. Ensemble, elles permettent de visualiser deux variables simultanément — comme les tapis berbères qui combinent densité du motif et choix chromatique pour signifier.

Le mode HSB (Hue-Saturation-Brightness) est idéal pour le data art : la teinte (H) tourne sur 360°, ce qui crée une progression naturelle du froid au chaud, du proche au lointain.

function setup() {
  createCanvas(600, 600);
  colorMode(HSB, 360, 100, 100); // Activer HSB — plus intuitif que RGB pour les dégradés
  noStroke();

  for (let i = 0; i < 100; i++) {
    data.push(random(10, 90));
  }
}

function draw() {
  background(0, 0, 10); // Fond sombre en HSB

  let cols = 10, rows = 10;
  let cellW = width / cols, cellH = height / rows;

  for (let i = 0; i < data.length; i++) {
    let x = (i % cols) * cellW + cellW / 2;
    let y = floor(i / cols) * cellH + cellH / 2;

    // Même valeur → deux canaux visuels différents
    // Teinte : bleu (220°) pour les petites valeurs, jaune-vert (80°) pour les grandes
    // Cette palette évoque les céramiques zellige bleu-nuit et vert-citron
    let hue = map(data[i], 0, 100, 220, 80);
    let d = map(data[i], 0, 100, 5, min(cellW, cellH) * 0.9);

    fill(hue, 80, 90);
    ellipse(x, y, d, d);
  }
}

Étape 3 — L'interactivité révèle la donnée

Un graphique statique montre. Un graphique interactif interroge. Au survol d'une cellule, on révèle la valeur brute — le chiffre derrière la forme. C'est le principe du tooltip : rendre visible ce qui était encodé visuellement.

function draw() {
  // ... (suite du draw précédent)

  // Détection de la cellule sous la souris
  let col = floor(mouseX / cellW);
  let row = floor(mouseY / cellH);

  if (col >= 0 && col < cols && row >= 0 && row < rows) {
    let idx = row * cols + col;

    // Surligneur de cellule — le fond blanc révèle "je suis ici"
    noFill();
    stroke(255, 0, 80); // HSB : rouge-orangé, couleur d'alerte zellige
    strokeWeight(2);
    rect(col * cellW, row * cellH, cellW, cellH);
    noStroke();

    // Tooltip avec la valeur brute
    fill(255, 0, 90);
    textSize(13);
    textAlign(CENTER);
    text(nf(data[idx], 0, 1), mouseX, mouseY - 15);
  }
}

Sketch interactif complet — Spécification Kiro

Fichier : sketches/data-art-interactive.js
Dimensions : 600×600px
Conteneur HTML : <div id="sketch-data-art"></div>

Variables configurables

Variable Type Valeurs Rôle
dataSource Array[100] float 0-100 Données visualisées
colorPalette integer 0, 1, 2 Index palette active
showValues boolean true/false Affichage valeurs au survol

Palettes définies (colorMode HSB)

// palette 0 — Zellige Nuit (bleu profond → vert citron)
const palettes = [
  { low: [220, 80, 90], high: [80, 90, 85] },   // Zellige Nuit
  { low: [30, 70, 95], high: [0, 85, 80] },      // Sable du Sahara
  { low: [280, 60, 80], high: [180, 75, 90] }    // Urbain / néon
];

Interactions

Déclencheur Action
Survol cellule Affiche valeur brute (tooltip), surligne la cellule en rouge zellige
Clic gauche Cycle palette : 0 → 1 → 2 → 0
Barre espace Régénère 100 nouvelles valeurs aléatoires (animation de transition : fade sur 30 frames)
showValues toggle (bouton HTML externe) Active/désactive les tooltips

Code complet du sketch

// sketch : data-art-interactive.js
// Visualise 100 valeurs comme une grille de cercles colorés
// Principe : chaque donnée = une taille + une teinte — double encodage visuel

let data = [];
let colorPalette = 0;
let showValues = true;
let targetData = []; // Pour l'animation de transition
let lerpFactor = 1;  // 0 = ancien état, 1 = nouvel état

const palettes = [
  { low: [220, 80, 90], high: [80, 90, 85] },
  { low: [30, 70, 95],  high: [0, 85, 80]  },
  { low: [280, 60, 80], high: [180, 75, 90]}
];

function setup() {
  let cnv = createCanvas(600, 600);
  cnv.parent('sketch-data-art');
  colorMode(HSB, 360, 100, 100, 100);
  noStroke();
  textFont('monospace');
  generateData();
}

function generateData() {
  targetData = [];
  for (let i = 0; i < 100; i++) {
    targetData.push(random(10, 90));
  }
  // Si première génération, pas de transition
  if (data.length === 0) {
    data = [...targetData];
    lerpFactor = 1;
  } else {
    lerpFactor = 0; // Déclenche la transition
  }
}

function draw() {
  background(0, 0, 10);

  let cols = 10, rows = 10;
  let cellW = width / cols, cellH = height / rows;

  // Interpolation douce lors de la régénération (barre espace)
  // Cela évite le saut brutal — les données "glissent" vers les nouvelles valeurs
  if (lerpFactor < 1) {
    lerpFactor = min(lerpFactor + 0.05, 1);
    for (let i = 0; i < data.length; i++) {
      data[i] = lerp(data[i], targetData[i], lerpFactor);
    }
  }

  let pal = palettes[colorPalette];
  let hoveredIdx = -1;

  // Détecter la cellule sous la souris avant de dessiner (pour le surlignage)
  let hCol = floor(mouseX / cellW);
  let hRow = floor(mouseY / cellH);
  if (hCol >= 0 && hCol < cols && hRow >= 0 && hRow < rows) {
    hoveredIdx = hRow * cols + hCol;
  }

  for (let i = 0; i < data.length; i++) {
    let col = i % cols;
    let row = floor(i / cols);
    let x = col * cellW + cellW / 2;
    let y = row * cellH + cellH / 2;

    // Double mapping : la même valeur pilote deux canaux visuels indépendants
    let t = map(data[i], 0, 100, 0, 1);
    let h = lerp(pal.low[0], pal.high[0], t);
    let s = lerp(pal.low[1], pal.high[1], t);
    let b = lerp(pal.low[2], pal.high[2], t);
    let d = map(data[i], 0, 100, 5, min(cellW, cellH) * 0.9);

    // La cellule survolée est légèrement agrandie pour confirmer la sélection
    let scale = (i === hoveredIdx) ? 1.15 : 1.0;

    fill(h, s, b);
    ellipse(x, y, d * scale, d * scale);
  }

  // Surlignage et tooltip sur la cellule active
  if (hoveredIdx >= 0 && showValues) {
    let col = hoveredIdx % cols;
    let row = floor(hoveredIdx / cols);

    stroke(0, 85, 90);
    strokeWeight(2);
    noFill();
    rect(col * cellW + 2, row * cellH + 2, cellW - 4, cellH - 4, 3);
    noStroke();

    // Tooltip — positionné au-dessus du curseur, jamais hors canvas
    let tx = constrain(mouseX, 30, width - 30);
    let ty = (mouseY > 40) ? mouseY - 18 : mouseY + 30;
    fill(0, 0, 95);
    textSize(12);
    textAlign(CENTER);
    text(nf(data[hoveredIdx], 0, 1), tx, ty);
  }
}

function mousePressed() {
  // Clic → palette suivante — feedback immédiat, pas d'animation
  colorPalette = (colorPalette + 1) % palettes.length;
}

function keyPressed() {
  if (key === ' ') {
    generateData(); // Régénère + déclenche la transition
  }
}

Pour aller plus loin

Vous venez de construire le coeur d'un data art : mapper → encoder → révéler. DATA RUG pousse cette logique jusqu'à des données réelles (open data urbain), des palettes historiquement situées (la pigmentation des tapis de l'Atlas) et des motifs génératifs qui remplacent les cercles.

La grille est un outil. Ce que vous y mettez — des températures, des votes, des fréquences sonores — décide si le résultat est information ou ornement. En général, c'est les deux.


Continuer l'apprentissage

Cours gratuit zellige — Les fondements géométriques du motif marocain en code (grilles, symétries, rotations)
Accéder au cours gratuit

Masterclass complète — 97€ — 8 semaines pour maîtriser le code créatif ancré dans l'esthétique nord-africaine : data art, motifs génératifs, NFT, portfolio numérique
Rejoindre la Masterclass

Passez au niveau pro

Systemes generatifs signes, tuilages aperiodiques, export imprimable, design d'interaction. Ma methode complete.

Decouvrir la Masterclass (97 €)

Recevoir la suite (gratuit)