Skip to content

Sankey ​

Flux

« Où tout cela va-t-il ? » Un diagramme de Sankey retrace le flux à travers un système : les nœuds sont disposés en colonnes, et l'épaisseur de chaque bande représente la valeur du flux. C'est l'image qu'il faut pour le commerce entre exportateurs et marchés, le budget des sources vers les usages, le trafic des référents vers les pages - partout où une quantité se divise et se recombine sur son parcours.

Example
canvas · responsive
Aller plus loin : Guide Insights·Guide DevTools

La disposition est calculée avec d3-sankey : les nœuds sont assignés à des colonnes à partir de la topologie du graphe, empilés verticalement, et les liens sont dessinés comme des bandes horizontales lissées. Survolez un nœud ou un flux pour voir ses chiffres.

Quand le choisir ​

  • Des flux structurés. Commerce entre exportateurs et marchés, budget des sources vers les usages, utilisateurs à travers un entonnoir : d'où viennent les quantités, où elles vont, ce qui se divise et se recombine.
  • Repérer le chemin dominant et les fuites. L'épaisseur des bandes est la valeur, si bien que les grandes routes et les petites pertes se lisent instantanément - la vue d'audit de n'importe quel système.
  • Une seule étape ? Si rien ne traverse à travers, une barre comparable classe les sources plus proprement qu'un Sankey à deux colonnes.

Mise en avant au survol ​

Le survol affiche toujours une infobulle. Avec hoverHighlight: true, le graphique met aussi en avant ce que vous pointez : survolez un nœud, et ce nœud, chaque flux qui y entre ou en sort et les nœuds à l'autre extrémité restent pleinement visibles tandis que le reste s'estompe ; survolez un flux, et seuls ce flux et ses deux nœuds d'extrémité restent allumés. Désactivé par défaut.

Example
canvas · responsive
Aller plus loin : Guide Insights·Guide DevTools
tsx
<SankeyChart {...props} hoverHighlight />
vue
<SankeyChart :options="{ ...props, hoverHighlight: true }" />
svelte
<div use:sankeyChart={{ ...props, hoverHighlight: true }}></div>
ts
applySankeyChartProps(this.c.nativeElement, { ...props, hoverHighlight: true });
html
<michi-vz-sankey-chart hover-highlight></michi-vz-sankey-chart>
  • La mise en avant s'applique sur place : en svg, l'opacité des marques déjà dessinées change ; canvas et webgpu redessinent. Le survol ne redessine jamais le graphique, il est donc inutile de renvoyer onHighlightItem dans highlightItems pour obtenir cet effet. onHighlightItem se déclenche toujours comme avant, pour votre propre interface.
  • Elle atténue aux mêmes niveaux que highlightItems (flux au quart de linkOpacity, nœuds à 0,25). Pendant le survol, elle l'emporte sur highlightItems ; en vous éloignant, l'état highlightItems revient.
  • Cliquez pour épingler l'infobulle : la mise en avant reste avec elle jusqu'à ce que l'épingle soit levée (clic sur l'infobulle, ou n'importe où hors du graphique).
  • En svg, le fondu suit enableTransitions ; canvas et webgpu basculent immédiatement.

Données volumineuses sur WebGPU Expérimental ​

Le renderer="webgpu" optionnel de ce graphique dessine ses marques sur le GPU tandis que les axes/libellés/infobulles restent sur SVG ; conditionné aux capacités du navigateur, avec repli automatique sur canvas.

⚗️ Experimental - not yet stable. WebGPU rendering is an opt-in preview. It needs a WebGPU-capable browser (Chrome / Edge, or Safari 26+); everywhere else it falls back to canvas automatically. Axes, labels and tooltips stay on the SVG layer - only the data marks are painted on the GPU.
Heavy-data demo · ~150 links… detecting

Faire defiler les annees ​

Étiquetez chaque lien avec une date et activez timeline : l'instantané d'une année est constitué des liens partageant cette date - les nœuds restent partagés d'une année à l'autre, seuls les flux vont et viennent - et l'épaisseur des bandes glisse d'une année à l'autre. Désactivé par défaut - sans opt-in, rien ne change. C'est un défilement interactif année par année, pas l'entrée ponctuelle plus bas.

Appuyez sur le bouton lecture sous le graphique : les données défilent année par année, un instantané à la fois. Faites glisser le curseur pour sauter à une année.

tsx
const ref = useRef<SankeyChartHandle>(null);

<SankeyChart ref={ref} {...props} timeline={{ speedMs: 1000, loop: true }} />;
// ref.current?.timeline() -> play() / pause() / seek(year) / seekIndex(i) / stepForward()
vue
<SankeyChart :options="{ ...props, timeline: { speedMs: 1000, loop: true } }" />
svelte
<div use:sankeyChart={{ ...props, timeline: { speedMs: 1000, loop: true } }}></div>
ts
applySankeyChartProps(this.c.nativeElement, { ...props, timeline: { speedMs: 1000, loop: true } });
html
<michi-vz-sankey-chart id="c"></michi-vz-sankey-chart>
<script>
  const el = document.getElementById("c");
  el.timeline = { speedMs: 1000, loop: true };
  // el.getTimeline() -> play() / pause() / seek(year) / seekIndex(i)
</script>
  • speedMs règle le rythme, loop reboucle, autoplay: true démarre au montage, showControl: false masque la barre intégrée.
  • Les valeurs glissent d'une période à l'autre par défaut (interpolate) ; ajustez le mouvement avec tweenMs et easing, ou passez interpolate: false pour des coupes nettes. Avec reduced motion, la coupe est toujours nette.
  • Le contrôleur headless reste disponible : chart.timeline() expose play() / pause() / toggle() / seek(period) / seekIndex(i) / stepForward() / stepBack(), plus onStep et formatPeriod dans la config pour une UI maison.
  • seek(period) cherche d'abord la période, en comparant le texte : seek(2021) et seek("2021") vont tous les deux sur 2021, que vos dates soient des nombres ou des chaînes. Un nombre ne compte comme une position (0 = la première) que si aucune période ne correspond, et une chaîne qui ne correspond à rien ne fait rien. seekIndex(i) va toujours par position, comme le curseur intégré.
  • Les liens sans date restent visibles à chaque période.
  • timeline l'emporte sur progressiveDraw quand les deux sont définis - l'animation de révélation plus bas reste inactive tant que le timeline garde la main.

Animation de révélation ​

Le graphique se dessine de gauche à droite au montage, révélant ses éléments dans l'ordre avant de se stabiliser. Désactivé par défaut - un graphique l'active avec la prop progressiveDraw.

Chaque ligne grandit de la première à la dernière année ; l'étiquette suit la pointe puis se pose à l'extrémité de la ligne. Avec reduced motion activé, le graphique s'affiche entièrement tracé, instantanément.

progressiveDraw: true applique les réglages par défaut (1200 ms, easeInOutCubic). Un objet de configuration affine le comportement :

tsx
const ref = useRef<SankeyChartHandle>(null);

<SankeyChart
  ref={ref}
  {...props}
  progressiveDraw={{ durationMs: 2000 }}
/>;
// ref.current?.replay() rejoue l'animation à la demande
vue
<SankeyChart :options="{ ...props, progressiveDraw: { durationMs: 2000 } }" />
svelte
<div use:sankeyChart={{ ...props, progressiveDraw: { durationMs: 2000 } }}></div>
ts
applySankeyChartProps(this.c.nativeElement, {
  ...props,
  progressiveDraw: { durationMs: 2000 },
});
html
<michi-vz-sankey-chart id="c"></michi-vz-sankey-chart>
<script>
  const el = document.getElementById("c");
  el.progressiveDraw = { durationMs: 2000 };
  // el.replay() rejoue l'animation
</script>
  • durationMs et easing ("linear", "easeOutQuad", "easeInOutCubic", ou une fonction (t) => t personnalisée) façonnent le rythme du tracé.
  • autoplay: false rend le graphique entièrement tracé ; appelez replay() (handle de ref React, méthode du web component ou instance core) pour lancer l'animation à la demande. replayOnUpdate: true la rejoue à chaque changement de données.
  • Respecte prefers-reduced-motion : le graphique s'affiche alors entièrement tracé, instantanément.
  • L'animation de révélation est une entrée ponctuelle ; le défilement par année ci-dessus avance plutôt année par année.

Utilisation ​

tsx
import { SankeyChart } from "@michi-vz/react";

export default () => <SankeyChart {...props} />; // props = the chart options
vue
<script setup>
import { SankeyChart } from "@michi-vz/vue";
</script>

<template>
  <SankeyChart :options="props" />
</template>
svelte
<script>
  import { sankeyChart } from "@michi-vz/svelte";
</script>

<div use:sankeyChart={props}></div>
ts
// main.ts - register the elements once
import "@michi-vz/angular";
import { applySankeyChartProps } from "@michi-vz/angular";

// component (uses CUSTOM_ELEMENTS_SCHEMA)
// template: <michi-vz-sankey-chart #c></michi-vz-sankey-chart>
applySankeyChartProps(this.c.nativeElement, props);
html
<script type="module" src="https://cdn.jsdelivr.net/npm/@michi-vz/wc/dist/michi-vz-wc.bundle.js"></script>

<michi-vz-sankey-chart id="c"></michi-vz-sankey-chart>
<script>
  Object.assign(document.getElementById("c"), props); // nodes, links, …
</script>
ts
import { mountSankeyChart } from "@michi-vz/core";

const chart = mountSankeyChart(el, props);
chart.update(next);
chart.getContext(); // renderer-agnostic, LLM-ready
chart.destroy();

Forme des données ​

Contrairement aux autres graphiques, un Sankey prend deux tableaux : nodes (chacun avec un id unique, un label et une color optionnels) et links (source → target par id, avec une value).

ts
const props = {
  linkColorMode: "source", // colour links by their source (or "target")
  nodes: [
    { id: "France" }, { id: "Germany" },
    { id: "EU" }, { id: "Asia" },
  ],
  links: [
    { source: "France", target: "EU", value: 40 },
    { source: "France", target: "Asia", value: 22 },
    { source: "Germany", target: "EU", value: 55 },
    { source: "Germany", target: "Asia", value: 35 },
  ],
};

Un lien vers un id de nœud inconnu (ou un nœud dans disabledItems) est supprimé avec un datawarning ; désactiver un nœud supprime aussi ses liens.

Réglages de disposition ​

nodeWidth définit la largeur du rectangle du nœud, nodePadding l'écart vertical entre les nœuds d'une colonne, et linkOpacity la translucidité des bandes. linkColorMode colore chaque bande selon son nœud source (par défaut) ou target. Le miroir d'accessibilité et getContext() exposent les liens sous forme de tableau lisible « Source → Target : valeur ».

Nœuds arrondis. nodeRadius (px, par défaut 2) arrondit les coins du rectangle du nœud - augmentez-le pour un aspect « pilule », ou mettez 0 pour des coins carrés. Il est plafonné à la moitié du côté le plus court du nœud, afin de ne jamais déformer un nœud fin.

Flux arrondis. Les flux sont dessinés comme des rubans remplis ; linkRadius (px, par défaut 2) arrondit leurs coins à la jonction avec les nœuds, pour une connexion plus douce (plafonné à la moitié de l'épaisseur de la bande ; 0 = coins nets). linkColorMode colore chaque flux selon son nœud source ou target, à l'opacité linkOpacity :

ts
const props = { nodeRadius: 4, linkRadius: 4, /* …nodes, links */ };

Ordre des nœuds. Par défaut, d3-sankey range les nœuds d'une colonne pour réduire les croisements. nodeSort: "input" garde l'ordre de votre tableau nodes (et l'ordre des links pour les bandes qui partent d'un nœud), de sorte qu'un nœud « Reste du monde » ou « Autres » reste là où vous l'avez listé, en général en dernier.

Flux fins. Un filet à côté d'un gros flux peut n'être qu'une bande d'un pixel, impossible à survoler. minLinkValue (en unités de valeur) dispose ces liens comme s'ils avaient au moins cette valeur ; seule la géométrie change, l'infobulle, le contexte et les totaux gardent les vraies valeurs. Choisissez-le d'après vos données, par exemple 15 % du plus grand lien.

Clics. onNodeClick(node, event) et onLinkClick(link, event) se déclenchent au clic sur un nœud ou un flux, en svg comme via le test de collision du canvas, avec le même contexte que reçoit le formateur d'infobulle. Le clic épingle toujours l'infobulle ; utilisez les callbacks pour naviguer ou sélectionner depuis la marque elle-même.

ts
const props = { nodeSort: "input", minLinkValue: 0.15 * maxLinkValue, onNodeClick: (n) => go(n.id) };

API ​

Les props sont typées comme SankeyChartProps dans @michi-vz/core. Communes à tous les graphiques : width, height, margin, colors / colorsMapping, renderer ("svg", "canvas", ou "webgpu" expérimental), highlightItems, disabledItems, et les callbacks on*. onChartDataProcessed / getContext() renvoient le ChartContext indépendant du moteur de rendu. Référence complète : API Sankey.