LODEX s’appuie sur Vega-Lite, une grammaire de visualisation déclarative, pour générer la plupart de ses graphiques. Grâce à ce langage, il est possible de personnaliser les visualisations proposées par LODEX, mais aussi de créer des représentations plus avancées adaptées à la structure de vos données.
|
|
|
|
|
|
|
|
Qu’il s’agisse de modifier les couleurs, les polices, les axes, les légendes, les infobulles ou les étiquettes, de combiner plusieurs représentations ou encore de construire un nouveau type de graphique, Vega-Lite permet d’aller au-delà des paramètres proposés directement dans l’interface.
Cette section rassemble des modèles de graphiques Vega-Lite prêts à être adaptés et réutilisés dans LODEX. Chaque modèle part d’un besoin de visualisation concret et présente la configuration nécessaire pour obtenir le résultat souhaité.
Certains modèles permettent de personnaliser un graphique existant, tandis que d’autres proposent des visualisations plus élaborées, comme des graphiques combinés, des barres empilées, des aires superposées ou des cercles imbriqués. Lorsque cela est nécessaire, la préparation des données à l’aide d’une routine LODEX est également expliquée.
Aucune connaissance approfondie de Vega-Lite n’est nécessaire pour utiliser ces modèles. Les scripts proposés peuvent être copiés puis adaptés à vos propres données en suivant les indications fournies pour chaque modèle. Ils permettent également de se familiariser progressivement avec la structure d’une spécification Vega-Lite.
Activer le Mode avancé
Pour accéder à la configuration complète d’un graphique, commencez par activer le Mode avancé dans les paramètres du format. Ce mode permet d’éditer directement la spécification Vega-Lite du graphique et de personnaliser son apparence ainsi que son comportement.
Tous les modèles présentés dans cette section nécessitent que le Mode avancé soit activé.
L’activation du Mode avancé ne modifie pas le fonctionnement du graphique. Elle permet simplement d’accéder à sa spécification Vega-Lite. Vous pouvez revenir à tout moment à la configuration précédente en désactivant ce mode.
Diagramme à barres colorées par catégories

Le diagramme à barres est particulièrement adapté pour comparer les effectifs de plusieurs catégories. L’utilisation d’une couleur différente pour chaque catégorie permet de les distinguer rapidement et de faciliter la lecture du graphique.
Dans cet exemple, le graphique permet de visualiser la répartition des publications d’un corpus selon leur voie d’accès à la science ouverte : Diamond, Gold, Green, Bronze, Hybrid ou Closed.
Configurer la routine
Dans cet exemple, les données sont préparées à l’aide de la routine distinct-by.
La routine est appliquée au champ contenant les voies d’accès. Elle permet de compter le nombre de publications correspondant à chaque valeur du champ.

Elle produit automatiquement une structure de données contenant deux champs :
{
"_id": "Gold",
"value": 577
}
- _id : la catégorie à représenter, ici la voie d’accès.
- value : le nombre de publications correspondant à cette catégorie.
Cette structure est directement exploitable par Vega-Lite pour représenter chaque catégorie sous la forme d’une barre dont la hauteur correspond à son nombre de publications.
Créer le graphique
Le script suivant attribue une couleur différente à chaque voie d’accès. Il calcule également la part représentée par chaque catégorie dans l’ensemble des publications. Cette valeur est stockée dans le champ Taux et affichée dans l’infobulle sous l’intitulé Taux de publication.
{
"transform": [
{
"window": [
{
"op": "sum",
"field": "value",
"as": "NbPublisPerYear"
}
],
"frame": [
null,
null
]
},
{
"calculate": "round(datum.value*1000/datum.NbPublisPerYear)/1000",
"as": "Taux"
}
],
"layer": [
{
"mark": {
"type": "bar"
},
"encoding": {
"x": {
"field": "_id",
"type": "nominal",
"axis": {
"labelAngle": 0,
"tickMinStep": 1
},
"title": "",
"sort": [
"Diamond",
"Gold",
"Green",
"Bronze",
"Hybrid",
"Closed"
]
},
"y": {
"field": "value",
"type": "quantitative",
"axis": {
"labelAngle": 0,
"tickMinStep": 1
},
"scale": {
"type": "linear"
},
"title": ""
},
"color": {
"field": "_id",
"scale": {
"domain": [
"Diamond",
"Gold",
"Green",
"Bronze",
"Hybrid",
"Closed"
],
"range": [
"#00bfff",
"#f9bc01",
"#228B22",
"#c97522",
"#ffff67",
"#7f7f7f"
]
},
"type": "nominal",
"legend": null
},
"tooltip": [
{
"field": "_id",
"type": "nominal",
"title": "Voie d'accès"
},
{
"field": "value",
"type": "quantitative",
"title": "Nb publis"
},
{
"field": "Taux",
"title": "Taux de publication",
"format": ".1%",
"type": "quantitative"
}
],
"size": {
"value": 50
}
}
},
{
"mark": {
"type": "text",
"color": "black",
"fontSize": 10,
"fontWeight": "bold",
"baseline": "bottom",
"align": "center",
"dx": 0
},
"encoding": {
"x": {
"field": "_id",
"type": "nominal",
"title": "",
"sort": [
"diamond",
"gold",
"green",
"bronze",
"hybrid",
"closed"
]
},
"y": {
"field": "value",
"type": "quantitative",
"axis": null
},
"text": {
"field": "value",
"type": "quantitative"
}
}
}
],
"padding": {
"left": 0,
"right": 0,
"top": 0,
"bottom": 0
},
"config": {
"view": {
"strokeWidth": 0
}
},
"width": 600,
"height": 300
}
Adapter le graphique à vos données
Cette recette peut être utilisée avec d’autres catégories. Les valeurs et les couleurs associées sont définies dans les propriétés domain et range :
"scale": {
"domain": [
"Diamond",
"Gold",
"Green",
"Bronze",
"Hybrid",
"Closed"
],
"range": [
"#00bfff",
"#f9bc01",
"#228B22",
"#c97522",
"#ffff67",
"#7f7f7f"
]
}
Chaque valeur du tableau domain correspond à la couleur située à la même position dans le tableau range. Vous pouvez donc remplacer les catégories et les couleurs par celles adaptées à vos propres données.
Pensez également à adapter l’ordre des catégories défini dans la propriété sort :
"sort": [
"Diamond",
"Gold",
"Green",
"Bronze",
"Hybrid",
"Closed"
]
_id et value. Vous pouvez ainsi représenter des types de documents, des disciplines, des établissements, des pays ou toute autre catégorie présente dans votre jeu de données.
Graphiques combinés : diagramme à barres et graphique en courbes

Les graphiques combinés permettent de représenter plusieurs informations dans une même visualisation en associant différents types de représentations.
Dans cet exemple, un diagramme à barres indique le nombre total de publications par année, tandis que plusieurs courbes permettent de visualiser leur répartition selon leur voie d’accès à la science ouverte.
Configurer la routine
Dans cet exemple, les données sont préparées à l’aide de la routine pairing-with.
La routine est appliquée à deux champs :
- Champ source : l’année de publication ;
- Champ cible : la voie d’accès à la science ouverte.

La routine produit une structure de données contenant trois champs :
{
"source": "2023",
"target": "Gold",
"weight": 42
}
- source : la première dimension, ici l’année de publication ;
- target : la seconde dimension, ici la voie d’accès ;
- weight : le nombre de publications correspondant à cette combinaison.
Cette structure permet de représenter simultanément le nombre total de publications par année et leur répartition selon les différentes voies d’accès.
Créer le graphique
Le script suivant combine plusieurs couches Vega-Lite. Les barres représentent le nombre de publications par année, tandis que les courbes et leurs points représentent les différentes voies d’accès.
{
"background": "transparent",
"padding": 40,
"width": "container",
"height": "container",
"autosize": {
"type": "fit",
"contains": "padding"
},
"transform": [
{
"window": [
{
"op": "sum",
"field": "weight",
"as": "NbDocsParAnnnées"
}
],
"groupby": [
"source"
],
"frame": [
null,
null
]
}
],
"layer": [
{
"mark": {
"type": "bar"
},
"encoding": {
"x": {
"field": "source",
"type": "nominal",
"axis": {
"labelAngle": 0,
"labelOverlap": true,
"tickMinStep": 1
},
"title": "",
"sort": null
},
"y": {
"field": "weight",
"type": "quantitative",
"axis": {
"labelAngle": 0,
"tickMinStep": 1
},
"scale": {
"type": "linear"
},
"title": "",
"sort": null
},
"color": {
"value": "#1f77b4"
},
"tooltip": [
{
"field": "source",
"type": "nominal",
"title": "Années"
},
{
"field": "NbDocsParAnnnées",
"type": "quantitative",
"title": "Nombre de publications"
}
],
"size": {
"value": 60
}
}
},
{
"mark": {
"type": "line",
"point": true
},
"encoding": {
"x": {
"field": "source",
"type": "nominal",
"axis": {
"labelAngle": 0,
"labelOverlap": true
},
"title": "Années",
"sort": "x"
},
"y": {
"field": "weight",
"type": "quantitative",
"axis": {
"labelAngle": 0
},
"scale": {
"type": "linear"
},
"title": "Nombre de documents"
},
"color": {
"field": "target",
"title": "Voie d'accès",
"scale": {
"domain": [
"Diamond",
"Gold",
"Green",
"Bronze",
"Hybrid",
"Closed"
],
"range": [
"#00bfff",
"#f9bc01",
"#228B22",
"#c97522",
"#ffff67",
"#7f7f7f"
]
},
"type": "nominal"
},
"data": {
"name": "values"
},
"tooltip": [
{
"field": "NbDocsParAnnnées",
"title": "N Docs de l'année",
"type": "quantitative"
},
{
"field": "target",
"type": "nominal",
"title": "Voie d'accès"
},
{
"field": "weight",
"type": "quantitative",
"title": "Nb Docs Année / Statut OA"
}
],
"mark": {
"type": "text",
"color": "darkblue",
"fontSize": 10,
"fontWeight": "bold",
"baseline": "bottom",
"align": "center",
"sort": "target",
"dx": 0,
"dy": -5
},
"encoding": {
"x": {
"field": "source",
"type": "nominal",
"title": "",
"sort": "x"
},
"y": {
"line": {
"field": "target",
"type": "quantitative"
}
}
}
}
},
{
"mark": {
"type": "text",
"color": "black",
"fontSize": 20,
"fontWeight": "bold",
"baseline": "bottom",
"align": "center",
"dx": 0,
"dy": -5
},
"encoding": {
"x": {
"field": "source",
"type": "nominal",
"title": "",
"sort": null
},
"y": {
"field": "NbDocsParAnnnées",
"type": "quantitative",
"axis": {
"labelAngle": 0,
"tickMinStep": 1
},
"scale": {
"type": "linear"
},
"sort": null
},
"text": {
"field": "NbDocsParAnnnées",
"type": "quantitative"
}
}
}
]
}
Adapter le graphique à vos données
Ce modèle peut être adapté en modifiant plusieurs propriétés du script.
Modifier les couleurs
Les catégories et les couleurs des différentes courbes sont définies dans les propriétés domain et range :
"scale": {
"domain": [
"Diamond",
"Gold",
"Green",
"Bronze",
"Hybrid",
"Closed"
],
"range": [
"#00bfff",
"#f9bc01",
"#228B22",
"#c97522",
"#ffff67",
"#7f7f7f"
]
}
Chaque valeur du tableau domain correspond à la couleur située à la même position dans le tableau range.
Modifier la taille des éléments
La largeur des barres peut être modifiée en adaptant la propriété size :
"size": {
"value": 60
}
La taille des textes peut quant à elle être modifiée à l’aide de la propriété fontSize des marques de type text.
Remplacer les courbes par des points
Il est également possible de supprimer les lignes reliant les points afin d’obtenir un graphique combinant un diagramme à barres et un nuage de points.
Pour cela, remplacez :
"mark": {
"type": "line",
"point": true
}
par :
"mark": {
"type": "circle"
}
Vous obtiendrez alors une variante de type bar chart + scatterplot :

source, target et weight.
Donut

Le donut permet de représenter la répartition de plusieurs catégories au sein d’un ensemble. L’affichage direct des valeurs sur le graphique facilite la lecture en évitant de devoir consulter uniquement les infobulles.
Dans cet exemple, le graphique permet de visualiser la répartition des publications d’un corpus selon leur voie d’accès à la science ouverte. Chaque voie d’accès est représentée par une couleur différente et le nombre de publications correspondant est affiché directement autour du donut.
Configurer la routine
Dans cet exemple, les données sont préparées à l’aide de la routine distinct-by.
La routine est appliquée au champ contenant les voies d’accès. Elle permet de compter le nombre de publications correspondant à chaque valeur du champ.

Elle produit une structure de données contenant deux champs :
{
"_id": "gold",
"value": 577
}
- _id : la catégorie à représenter, ici la voie d’accès ;
- value : le nombre de publications correspondant à cette catégorie.
Cette structure est directement exploitable par Vega-Lite pour déterminer la taille de chaque portion du donut.
Créer le graphique
Le script suivant construit le donut à partir des valeurs produites par la routine. Il calcule également la proportion représentée par chaque catégorie afin de l’afficher dans l’infobulle sous l’intitulé Taux de publication.
{
"$schema": "https://vega.github.io/schema/vega-lite/v5.json",
"width": "container",
"height": 450,
"transform": [
{
"joinaggregate": [
{
"op": "sum",
"field": "value",
"as": "total"
}
]
},
{
"calculate": "datum.value / datum.total",
"as": "proportion"
},
{
"window": [
{
"op": "rank",
"as": "rank"
}
],
"sort": [
{
"field": "value",
"order": "descending"
}
]
},
{
"calculate": "datum.rank - 1",
"as": "rank_minus_1"
},
{
"calculate": "format(datum.value, ',.0f')",
"as": "texte"
}
],
"layer": [
{
"mark": {
"type": "arc",
"innerRadius": 130
},
"encoding": {
"theta": {
"field": "value",
"type": "quantitative",
"stack": true
},
"color": {
"field": "_id",
"type": "nominal",
"legend": {
"orient": "right",
"title": "Voie d'accès",
"columns": 1
},
"scale": {
"domain": [
"gold",
"unknown",
"bronze",
"hybrid",
"closed"
],
"range": [
"#FFC40C",
"#C0C0C0",
"#CD7F32",
"#EC5800",
"#E23D28"
]
}
},
"tooltip": [
{
"field": "_id",
"type": "nominal",
"title": "Voie d'accès"
},
{
"field": "value",
"type": "quantitative",
"title": "Nb publis",
"format": ",.0f"
},
{
"field": "proportion",
"type": "quantitative",
"title": "Taux de publication",
"format": ".1%"
}
],
"order": {
"field": "rank_minus_1"
}
}
},
{
"mark": {
"type": "text",
"fill": "black",
"radius": 250,
"fontSize": 14
},
"encoding": {
"theta": {
"field": "value",
"type": "quantitative",
"stack": true
},
"text": {
"field": "texte"
},
"color": {
"field": "_id",
"type": "nominal"
},
"order": {
"field": "rank_minus_1"
}
}
}
],
"view": {
"stroke": null
},
"background": "transparent"
}
Adapter le graphique à vos données
Les catégories et les couleurs qui leur sont associées sont définies dans les propriétés domain et range :
"scale": {
"domain": [
"gold",
"unknown",
"bronze",
"hybrid",
"closed"
],
"range": [
"#FFC40C",
"#C0C0C0",
"#CD7F32",
"#EC5800",
"#E23D28"
]
}
Chaque valeur du tableau domain correspond à la couleur située à la même position dans le tableau range. Ces valeurs peuvent être remplacées par les catégories et les couleurs correspondant à votre propre jeu de données.
Modifier la taille du donut
La taille de l’espace central du donut est définie par la propriété innerRadius :
"innerRadius": 130
Une valeur plus élevée agrandit le trou central, tandis qu’une valeur plus faible rapproche le graphique d’un diagramme circulaire classique.
Modifier l’affichage des valeurs
Les valeurs affichées autour du donut sont positionnées à l’aide de la propriété radius de la marque de type text :
"radius": 250,
"fontSize": 14
Vous pouvez modifier radius pour rapprocher ou éloigner les valeurs du centre du graphique et fontSize pour ajuster leur taille.
_id et value. Elle n’est donc pas limitée aux voies d’accès à la science ouverte.
Graphique en cercles imbriqués

Le graphique en cercles imbriqués (nested ou concentric circles) permet de représenter deux niveaux de catégories dans une même visualisation. Le cercle intérieur présente les catégories principales, tandis que le cercle extérieur détaille les sous-catégories qui leur sont associées.
Par exemple, il peut être utilisé pour représenter la part de publications en Open Access ou non, puis détailler les différentes voies d’ouverture : Diamond, Gold, Green, Bronze, Hybrid ou Closed.
Configurer la routine
Dans cet exemple, les données sont préparées à l’aide de la routine pairing-with.
La routine prend en entrée deux champs :

- Champ source : Open Access, avec par exemple les valeurs
OuietNon. - Champ cible : Voie d’ouverture, avec par exemple les valeurs
Diamond,Gold,Green,Bronze,HybridetClosed.
Elle produit automatiquement une structure de données contenant trois champs :
{
"source": "Oui",
"target": "Diamond",
"weight": 120
}
- source : la catégorie principale, représentée dans le cercle intérieur.
- target : la sous-catégorie, représentée dans le cercle extérieur.
- weight : le nombre de documents correspondant à chaque couple
source/target.
Un résultat de routine peut par exemple contenir les données suivantes :
[
{
"source": "Oui",
"target": "Diamond",
"weight": 120
},
{
"source": "Oui",
"target": "Gold",
"weight": 80
},
{
"source": "Oui",
"target": "Green",
"weight": 50
},
{
"source": "Oui",
"target": "Bronze",
"weight": 30
},
{
"source": "Oui",
"target": "Hybrid",
"weight": 20
},
{
"source": "Non",
"target": "Closed",
"weight": 70
}
]
Dans cet exemple, les valeurs Diamond, Gold, Green, Bronze et Hybrid sont rattachées à Oui, tandis que Closed est rattaché à Non.
Cette relation est importante : elle permet d’aligner les portions des deux cercles. La somme des sous-catégories appartenant à une même valeur de source détermine automatiquement la taille de cette catégorie dans le cercle intérieur.
Créer le graphique
Le script suivant construit les deux cercles à partir des relations entre les catégories source et target. La taille des portions est déterminée par le champ weight.
{
"$schema": "https://vega.github.io/schema/vega-lite/v6.json",
"background": "transparent",
"width": "container",
"height": "container",
"padding": 20,
"transform": [
{
"calculate": "toNumber(datum.weight)",
"as": "value"
},
{
"filter": "isValid(datum.value) && datum.value > 0"
},
{
"joinaggregate": [
{
"op": "sum",
"field": "value",
"as": "grandTotal"
}
]
},
{
"calculate": "datum.value / datum.grandTotal",
"as": "targetPercent"
},
{
"calculate": "format(datum.targetPercent, '.1%')",
"as": "targetPercentLabel"
},
{
"calculate": "datum.targetPercent >= 0.04 ? datum.target : ''",
"as": "targetVisibleLabel"
},
{
"calculate": "datum.targetPercent >= 0.04 ? format(datum.targetPercent, '.1%') : ''",
"as": "targetVisiblePercent"
},
{
"calculate": "datum.source === 'Oui' ? 1 : datum.source === 'Non' ? 2 : 99",
"as": "sourceOrder"
},
{
"calculate": "datum.target === 'Diamond' ? 1 : datum.target === 'Gold' ? 2 : datum.target === 'Green' ? 3 : datum.target === 'Bronze' ? 4 : datum.target === 'Hybrid' ? 5 : datum.target === 'Closed' ? 6 : 99",
"as": "targetOrder"
}
],
"layer": [
{
"transform": [
{
"aggregate": [
{
"op": "sum",
"field": "value",
"as": "sourceTotal"
},
{
"op": "max",
"field": "grandTotal",
"as": "grandTotal"
},
{
"op": "min",
"field": "sourceOrder",
"as": "sourceOrder"
}
],
"groupby": [
"source"
]
},
{
"calculate": "datum.sourceTotal / datum.grandTotal",
"as": "sourcePercent"
},
{
"calculate": "format(datum.sourcePercent, '.1%')",
"as": "sourcePercentLabel"
}
],
"mark": {
"type": "arc",
"radius": 135,
"radius2": 80,
"stroke": "white",
"strokeWidth": 3,
"cornerRadius": 3
},
"encoding": {
"theta": {
"field": "sourceTotal",
"type": "quantitative",
"stack": true
},
"color": {
"field": "source",
"type": "nominal",
"legend": null,
"scale": {
"domain": [
"Oui",
"Non"
],
"range": [
"#4C956C",
"#E23D28"
]
}
},
"order": {
"field": "sourceOrder",
"type": "quantitative",
"sort": "ascending"
},
"tooltip": [
{
"field": "source",
"type": "nominal",
"title": "Accès ouvert"
},
{
"field": "sourceTotal",
"type": "quantitative",
"title": "Nombre",
"format": ",d"
},
{
"field": "sourcePercent",
"type": "quantitative",
"title": "Part",
"format": ".1%"
}
]
}
},
{
"transform": [
{
"aggregate": [
{
"op": "sum",
"field": "value",
"as": "sourceTotal"
},
{
"op": "max",
"field": "grandTotal",
"as": "grandTotal"
},
{
"op": "min",
"field": "sourceOrder",
"as": "sourceOrder"
}
],
"groupby": [
"source"
]
},
{
"calculate": "datum.sourceTotal / datum.grandTotal",
"as": "sourcePercent"
},
{
"calculate": "format(datum.sourcePercent, '.1%')",
"as": "sourcePercentLabel"
}
],
"mark": {
"type": "text",
"radius": 107,
"dy": -8,
"fontSize": 15,
"fontWeight": "bold",
"color": "white"
},
"encoding": {
"theta": {
"field": "sourceTotal",
"type": "quantitative",
"stack": true
},
"order": {
"field": "sourceOrder",
"type": "quantitative",
"sort": "ascending"
},
"text": {
"field": "source",
"type": "nominal"
}
}
},
{
"transform": [
{
"aggregate": [
{
"op": "sum",
"field": "value",
"as": "sourceTotal"
},
{
"op": "max",
"field": "grandTotal",
"as": "grandTotal"
},
{
"op": "min",
"field": "sourceOrder",
"as": "sourceOrder"
}
],
"groupby": [
"source"
]
},
{
"calculate": "datum.sourceTotal / datum.grandTotal",
"as": "sourcePercent"
},
{
"calculate": "format(datum.sourcePercent, '.1%')",
"as": "sourcePercentLabel"
}
],
"mark": {
"type": "text",
"radius": 107,
"dy": 10,
"fontSize": 13,
"fontWeight": "bold",
"color": "white"
},
"encoding": {
"theta": {
"field": "sourceTotal",
"type": "quantitative",
"stack": true
},
"order": {
"field": "sourceOrder",
"type": "quantitative",
"sort": "ascending"
},
"text": {
"field": "sourcePercentLabel",
"type": "nominal"
}
}
},
{
"mark": {
"type": "arc",
"radius": 200,
"radius2": 145,
"stroke": "white",
"strokeWidth": 3,
"cornerRadius": 3
},
"encoding": {
"theta": {
"field": "value",
"type": "quantitative",
"stack": true
},
"color": {
"field": "target",
"type": "nominal",
"legend": null,
"scale": {
"domain": [
"Diamond",
"Gold",
"Green",
"Bronze",
"Hybrid",
"Closed"
],
"range": [
"#00BFFF",
"#FFC40C",
"#4CBB17",
"#CD7F32",
"#EC5800",
"#E23D28"
]
}
},
"order": {
"field": "targetOrder",
"type": "quantitative",
"sort": "ascending"
},
"tooltip": [
{
"field": "source",
"type": "nominal",
"title": "Accès ouvert"
},
{
"field": "target",
"type": "nominal",
"title": "Voie"
},
{
"field": "value",
"type": "quantitative",
"title": "Nombre",
"format": ",d"
},
{
"field": "targetPercent",
"type": "quantitative",
"title": "Part",
"format": ".1%"
}
]
}
},
{
"mark": {
"type": "text",
"radius": 172,
"dy": -8,
"fontSize": 12,
"fontWeight": "bold",
"color": "#111"
},
"encoding": {
"theta": {
"field": "value",
"type": "quantitative",
"stack": true
},
"order": {
"field": "targetOrder",
"type": "quantitative",
"sort": "ascending"
},
"text": {
"field": "targetVisibleLabel",
"type": "nominal"
}
}
},
{
"mark": {
"type": "text",
"radius": 172,
"dy": 9,
"fontSize": 12,
"fontWeight": "bold",
"color": "#111"
},
"encoding": {
"theta": {
"field": "value",
"type": "quantitative",
"stack": true
},
"order": {
"field": "targetOrder",
"type": "quantitative",
"sort": "ascending"
},
"text": {
"field": "targetVisiblePercent",
"type": "nominal"
}
}
},
{
"transform": [
{
"aggregate": [
{
"op": "sum",
"field": "value",
"as": "total"
}
]
}
],
"mark": {
"type": "text",
"fontSize": 26,
"fontWeight": "bold",
"color": "#00284B"
},
"encoding": {
"text": {
"field": "total",
"type": "quantitative",
"format": ",d"
}
}
},
{
"mark": {
"type": "text",
"fontSize": 13,
"dy": 25,
"color": "#555"
},
"encoding": {
"text": {
"datum": "publications"
}
}
}
],
"resolve": {
"scale": {
"color": "independent"
}
},
"config": {
"view": {
"stroke": null
}
}
}
Adapter le graphique à vos données
Pour utiliser cette recette avec d’autres données, certaines parties du script doivent être adaptées.
L’ordre des catégories principales est défini ici :
{
"calculate": "datum.source === 'Oui' ? 1 : datum.source === 'Non' ? 2 : 99",
"as": "sourceOrder"
}
Remplacez Oui et Non par les valeurs présentes dans votre champ source.
L’ordre des sous-catégories est défini ici :
{
"calculate": "datum.target === 'Diamond' ? 1 : datum.target === 'Gold' ? 2 : datum.target === 'Green' ? 3 : datum.target === 'Bronze' ? 4 : datum.target === 'Hybrid' ? 5 : datum.target === 'Closed' ? 6 : 99",
"as": "targetOrder"
}
Remplacez ces valeurs par celles présentes dans votre champ target.
targetOrder. L’ordre des groupes doit également correspondre à celui défini dans sourceOrder. C’est ce qui permet de conserver l’alignement entre les deux cercles.
Les couleurs du cercle intérieur sont définies dans :
"scale": {
"domain": [
"Oui",
"Non"
],
"range": [
"#4C956C",
"#E23D28"
]
}
Les couleurs du cercle extérieur sont définies dans :
"scale": {
"domain": [
"Diamond",
"Gold",
"Green",
"Bronze",
"Hybrid",
"Closed"
],
"range": [
"#00BFFF",
"#FFC40C",
"#4CBB17",
"#CD7F32",
"#EC5800",
"#E23D28"
]
}
Chaque valeur du tableau domain correspond à la couleur située à la même position dans le tableau range.
Affichage des pourcentages
Les pourcentages sont calculés automatiquement à partir du champ weight. Ils sont affichés directement dans les cercles ainsi que dans les infobulles.
Pour éviter de surcharger les petites portions, les libellés du cercle extérieur sont masqués lorsqu’ils représentent moins de 4 % du total :
{
"calculate": "datum.targetPercent >= 0.04 ? datum.target : ''",
"as": "targetVisibleLabel"
},
{
"calculate": "datum.targetPercent >= 0.04 ? format(datum.targetPercent, '.1%') : ''",
"as": "targetVisiblePercent"
}
Vous pouvez modifier ce seuil. Par exemple, utilisez 0.02 pour afficher les catégories représentant au moins 2 % du total ou 0.05 pour un seuil de 5 %.
Modifier le texte central
Le total est calculé automatiquement. Le texte affiché sous celui-ci est défini ici :
"text": {
"datum": "publications"
}
Remplacez publications par le type de ressources représenté, par exemple documents, projets, ressources ou établissements.
source, target et weight, dès lors que les valeurs de target peuvent être rattachées à des catégories source. Elle peut par exemple être utilisée pour représenter des types de documents et leurs sous-types, des catégories de projets et leurs statuts, des disciplines et leurs sous-disciplines ou toute autre organisation hiérarchique à deux niveaux.
Diagramme à barres empilées

Le diagramme à barres empilées permet de représenter simultanément l’évolution d’un ensemble et sa répartition entre plusieurs catégories.
Dans cet exemple, chaque barre représente le nombre de publications d’une année et les différentes portions qui la composent correspondent aux voies d’accès à la science ouverte : Diamond, Gold, Green, Bronze, Hybrid ou Closed.
Configurer la routine
Dans cet exemple, les données sont préparées à l’aide de la routine pairing-with.
La routine prend en entrée deux champs :
- Champ source : l’année de publication ;
- Champ cible : la voie d’accès à la science ouverte.

Elle produit automatiquement une structure de données contenant trois champs :
{
"source": "2023",
"target": "Gold",
"weight": 42
}
- source : la première dimension, ici l’année de publication ;
- target : la seconde dimension, ici la voie d’accès ;
- weight : le nombre de publications correspondant à cette combinaison.
Cette structure permet à Vega-Lite de construire une barre pour chaque année et de la subdiviser en fonction des différentes valeurs de target.
Créer le graphique
Le script suivant construit le diagramme à barres empilées à partir des champs source, target et weight.
Il calcule également le nombre total de publications pour chaque année ainsi que la part représentée par chaque voie d’accès. Cette dernière est stockée dans le champ Taux et affichée dans l’infobulle sous l’intitulé % Publication.
{
"background": "transparent",
"width": "container",
"height": "container",
"autosize": {
"type": "fit",
"contains": "padding"
},
"transform": [
{
"window": [
{
"op": "sum",
"field": "weight",
"as": "NbDocsParAnnnées"
}
],
"groupby": [
"source"
],
"frame": [
null,
null
]
},
{
"calculate": "round(datum.weight*1000/datum.NbDocsParAnnnées)/1000",
"as": "Taux"
}
],
"layer": [
{
"mark": {
"type": "bar"
},
"encoding": {
"x": {
"field": "source",
"type": "nominal",
"axis": {
"labelAngle": 0,
"labelOverlap": true
},
"title": "Années",
"sort": "x"
},
"y": {
"field": "weight",
"type": "quantitative",
"axis": {
"labelAngle": 0
},
"scale": {
"type": "linear"
},
"title": "Nombre de documents"
},
"color": {
"field": "target",
"title": "Voie d'accès",
"scale": {
"domain": [
"Diamond",
"Gold",
"Green",
"Bronze",
"Hybrid",
"Closed"
],
"range": [
"#00bfff",
"#f9bc01",
"#228B22",
"#c97522",
"#ffff67",
"#7f7f7f"
]
}
},
"tooltip": [
{
"field": "NbDocsParAnnnées",
"title": "N Docs de l'année",
"type": "quantitative"
},
{
"field": "target",
"type": "nominal",
"title": "Voie d'accès"
},
{
"field": "weight",
"type": "quantitative",
"title": "Nb Docs Année / Statut OA"
},
{
"field": "Taux",
"title": "% Publication",
"format": ".1%",
"type": "quantitative"
}
],
"size": {
"value": 60
},
"mark": {
"type": "text",
"color": "darkblue",
"fontSize": 20,
"fontWeight": "bold",
"baseline": "bottom",
"align": "center",
"sort": "target",
"dx": 0,
"dy": -5
},
"encoding": {
"x": {
"field": "source",
"type": "nominal",
"title": "",
"sort": "x"
},
"y": {
"line": {
"field": "target",
"type": "quantitative"
}
}
}
}
},
{
"mark": {
"type": "text",
"color": "black",
"fontSize": 20,
"fontWeight": "bold",
"baseline": "bottom",
"align": "center",
"dx": 0,
"dy": -5
},
"encoding": {
"x": {
"field": "source",
"type": "nominal",
"title": "",
"sort": null
},
"y": {
"field": "NbDocsParAnnnées",
"type": "quantitative",
"axis": {
"labelAngle": 0,
"tickMinStep": 1
},
"scale": {
"type": "linear"
},
"sort": null
},
"text": {
"field": "NbDocsParAnnnées",
"type": "quantitative"
}
}
}
],
"data": {
"name": "values"
}
}
Adapter le graphique à vos données
Pour utiliser cette recette avec d’autres données, adaptez les champs utilisés par la routine pairing-with. Le champ source détermine les différentes barres du graphique, tandis que le champ target détermine les catégories empilées à l’intérieur de chaque barre.
Modifier les catégories et les couleurs
Les catégories et les couleurs qui leur sont associées sont définies dans les propriétés domain et range :
"scale": {
"domain": [
"Diamond",
"Gold",
"Green",
"Bronze",
"Hybrid",
"Closed"
],
"range": [
"#00bfff",
"#f9bc01",
"#228B22",
"#c97522",
"#ffff67",
"#7f7f7f"
]
}
Chaque valeur du tableau domain correspond à la couleur située à la même position dans le tableau range. Remplacez ces valeurs par les catégories et les couleurs correspondant à votre propre jeu de données.
Modifier les axes
Le champ utilisé sur l’axe horizontal est défini ici :
"x": {
"field": "source",
"type": "nominal",
"title": "Années"
}
Le titre Années peut être remplacé par l’intitulé correspondant à votre champ source.
L’axe vertical représente les effectifs contenus dans le champ weight :
"y": {
"field": "weight",
"type": "quantitative",
"title": "Nombre de documents"
}
Vous pouvez également adapter le titre Nombre de documents au type de ressources représenté.
Modifier les informations affichées au survol
Les informations présentes dans l’infobulle sont définies dans la propriété tooltip. Dans cet exemple, elle affiche le nombre total de documents de l’année, la voie d’accès, le nombre de documents correspondant à cette voie et sa part dans l’ensemble des publications de l’année.
Les intitulés peuvent être adaptés en modifiant les propriétés title.
Modifier la largeur des barres
La largeur des barres est définie par la propriété size :
"size": {
"value": 60
}
Augmentez cette valeur pour obtenir des barres plus larges ou diminuez-la pour les rendre plus étroites.
source, target et weight. Elle permet notamment de comparer la composition de plusieurs groupes, périodes ou catégories.
Graphique en courbe

Le graphique en courbe est particulièrement adapté pour représenter une évolution au cours du temps ou comparer plusieurs séries de données sur un même axe. Par exemple, il permet de visualiser le nombre de publications par année selon leur statut Open Access.
Configurer la routine
Dans cet exemple, les données sont préparées à l’aide de la routine pairing-with.
La routine prend en entrée deux champs :
- Champ source : Année de publication.
- Champ cible : Open Access.

Elle produit automatiquement une structure de données contenant trois champs :
{
"source": "2018",
"target": "Ouvert",
"weight": 42
}
- source : les valeurs affichées sur l’axe des abscisses, ici les années de publication.
- target : les différentes séries représentées par une courbe, ici les statuts Open Access.
- weight : le nombre de documents correspondant à chaque couple
source/target.
Cette structure est directement exploitable par Vega-Lite pour tracer une courbe par valeur du champ target.
Créer le graphique
Le script suivant trace une courbe pour chaque valeur du champ target. Les valeurs du champ source sont placées sur l’axe horizontal et les effectifs contenus dans weight sur l’axe vertical.
{
"background": "transparent",
"padding": 40,
"width": "container",
"height": 400,
"autosize": {
"type": "fit",
"contains": "padding"
},
"transform": [
{
"filter": "datum.source != null && datum.source != '' && datum.target != null && datum.target != '' && datum.weight > 0"
}
],
"mark": {
"type": "line",
"point": {
"filled": true,
"size": 40
},
"strokeWidth": 3
},
"encoding": {
"x": {
"field": "source",
"type": "ordinal",
"sort": "ascending",
"title": "Nom de l'axe des abscisses",
"axis": {
"labelAngle": 0,
"labelOverlap": true
}
},
"y": {
"aggregate": "sum",
"field": "weight",
"type": "quantitative",
"title": "Nom de l'axe des ordonnées",
"axis": {
"format": "d",
"tickMinStep": 1
}
},
"color": {
"field": "target",
"type": "nominal",
"title": "Légende"
},
"tooltip": [
{
"field": "source",
"type": "ordinal",
"title": "Axe X"
},
{
"field": "target",
"type": "nominal",
"title": "Courbe / Ressource"
},
{
"aggregate": "sum",
"field": "weight",
"type": "quantitative",
"title": "Nombre de documents"
}
]
}
}
Adapter le graphique à vos données
Pour utiliser cette recette avec d’autres données, adaptez tout d’abord les champs utilisés par la routine pairing-with. Le champ source correspond aux valeurs placées sur l’axe horizontal, tandis que chaque valeur du champ target produit une série distincte.
Modifier le titre des axes
Le titre de l’axe horizontal est défini dans :
"x": {
"field": "source",
"type": "ordinal",
"title": "Nom de l'axe des abscisses"
}
Remplacez Nom de l'axe des abscisses par l’intitulé correspondant à votre champ source, par exemple Année de publication.
Le titre de l’axe vertical est défini dans :
"y": {
"aggregate": "sum",
"field": "weight",
"type": "quantitative",
"title": "Nom de l'axe des ordonnées"
}
Remplacez Nom de l'axe des ordonnées par le type de valeur représenté, par exemple Nombre de publications.
Modifier le titre de la légende
La légende correspond aux différentes valeurs du champ target. Son titre est défini ici :
"color": {
"field": "target",
"type": "nominal",
"title": "Légende"
}
Vous pouvez remplacer Légende par un intitulé adapté à vos données, par exemple Statut Open Access.
Modifier l’apparence des courbes
L’épaisseur des courbes est définie par la propriété strokeWidth :
"strokeWidth": 3
La taille des points affichés sur les courbes est définie ici :
"point": {
"filled": true,
"size": 40
}
Vous pouvez augmenter ou diminuer ces valeurs pour adapter l’affichage du graphique.
Modifier les informations affichées au survol
Les informations présentes dans l’infobulle sont définies dans la propriété tooltip. Dans cet exemple, elle affiche la valeur de l’axe horizontal, la série correspondante et le nombre de documents.
Les intitulés peuvent être adaptés en modifiant les propriétés title.
source, target et weight. Vous pouvez par exemple représenter une évolution par type de document, discipline, laboratoire, pays ou toute autre catégorie adaptée à votre jeu de données.
Cette recette est issue d’une proposition d’une utilisatrice de LODEX. Merci à elle pour ce partage.
Graphique en aires superposées

Le graphique en aires superposées permet de représenter l’évolution de plusieurs séries sur un même axe tout en donnant une représentation visuelle de leur importance respective.
Contrairement à un graphique en aires empilées, les différentes séries ne sont pas additionnées les unes aux autres : elles sont dessinées sur le même espace et se superposent. L’utilisation de couleurs, de transparence et de styles de lignes différents permet de les distinguer.
Dans cet exemple, le graphique représente l’évolution du nombre de thèses selon leur statut. Les thèses Soutenue sont représentées par une aire bleue et les thèses En cours par une aire violette superposée.
Configurer la routine
Dans cet exemple, les données sont préparées à l’aide de la routine cross-by.
Deux champs sont croisés :
- Statut de la thèse : par exemple
SoutenueouEn cours. - Année de référence : l’année utilisée pour représenter l’évolution dans le temps.
La routine produit une structure de données contenant trois champs :
{
"source": "Soutenue",
"target": "2023",
"weight": 50
}
- source : la série à représenter, ici le statut de la thèse ;
- target : la valeur placée sur l’axe horizontal, ici l’année de référence ;
- weight : le nombre de ressources correspondant à chaque couple
source/target.
Cette structure permet à Vega-Lite de tracer une aire différente pour chacune des valeurs du champ source.
Créer le graphique
Le script suivant construit deux aires superposées à partir des champs source, target et weight. Chaque série possède son propre style afin de faciliter leur comparaison : couleur, dégradé, ligne, points et transparence.
{
"$schema": "https://vega.github.io/schema/vega-lite/v6.json",
"background": "transparent",
"padding": 35,
"width": "container",
"height": "container",
"autosize": {
"type": "fit",
"contains": "padding"
},
"transform": [
{
"filter": "datum.target != null && datum.target != '' && datum.target != '?'"
},
{
"calculate": "toNumber(datum.target)",
"as": "year"
}
],
"encoding": {
"x": {
"field": "year",
"type": "ordinal",
"title": "Année de référence",
"sort": "ascending",
"axis": {
"labelAngle": 0,
"labelFontSize": 14,
"labelFontWeight": "bold",
"titleFontSize": 16,
"titleFontWeight": "bold",
"titlePadding": 15
}
},
"y": {
"field": "weight",
"type": "quantitative",
"title": "Nombre de thèses",
"axis": {
"grid": true,
"labelFontSize": 14,
"titleFontSize": 16,
"titleFontWeight": "bold",
"titlePadding": 15
}
},
"tooltip": [
{
"field": "source",
"type": "nominal",
"title": "Statut"
},
{
"field": "year",
"type": "ordinal",
"title": "Année"
},
{
"field": "weight",
"type": "quantitative",
"title": "Nombre de thèses"
}
]
},
"layer": [
{
"transform": [
{
"filter": "datum.source == 'Soutenue'"
}
],
"mark": {
"type": "area",
"interpolate": "monotone",
"point": {
"filled": true,
"size": 75,
"fill": "#ffeb6e",
"stroke": "#00284b",
"strokeWidth": 2
},
"line": {
"color": "#00284b",
"strokeWidth": 3
},
"color": {
"x1": 1,
"y1": 1,
"x2": 1,
"y2": 0,
"gradient": "linear",
"stops": [
{
"offset": 0,
"color": "white"
},
{
"offset": 1,
"color": "#0798d6"
}
]
}
}
},
{
"transform": [
{
"filter": "datum.source == 'En cours'"
}
],
"mark": {
"type": "area",
"interpolate": "monotone",
"point": {
"filled": true,
"size": 75,
"fill": "white",
"stroke": "#6941eb",
"strokeWidth": 2
},
"line": {
"color": "#6941eb",
"strokeWidth": 3,
"strokeDash": [
7,
5
]
},
"color": {
"x1": 1,
"y1": 1,
"x2": 1,
"y2": 0,
"gradient": "linear",
"stops": [
{
"offset": 0,
"color": "white"
},
{
"offset": 1,
"color": "#6941eb"
}
]
},
"opacity": 0.35
}
},
{
"mark": {
"type": "point",
"opacity": 0
},
"encoding": {
"color": {
"field": "source",
"type": "nominal",
"title": "Statut de la thèse",
"scale": {
"domain": [
"Soutenue",
"En cours"
],
"range": [
"#0798d6",
"#6941eb"
]
},
"legend": {
"orient": "top",
"direction": "horizontal",
"titleFontSize": 14,
"titleFontWeight": "bold",
"labelFontSize": 13,
"symbolType": "circle",
"symbolSize": 120
}
}
}
}
]
}
Adapter le graphique à vos données
Pour réutiliser cette recette avec d’autres données, les principales modifications concernent les valeurs du champ source, les axes et l’apparence de chacune des séries.
Choisir les séries à représenter
Chaque aire est créée dans une couche distincte et sélectionnée à l’aide d’un filtre.
La première aire correspond ici aux thèses soutenues :
"transform": [
{
"filter": "datum.source == 'Soutenue'"
}
]
La seconde correspond aux thèses en cours :
"transform": [
{
"filter": "datum.source == 'En cours'"
}
]
Remplacez Soutenue et En cours par les valeurs du champ source que vous souhaitez comparer.
source ne seront donc pas affichées.
Adapter l’axe temporel
Les valeurs du champ target correspondent ici à des années. Le script commence par écarter les valeurs absentes ou non exploitables :
{
"filter": "datum.target != null && datum.target != '' && datum.target != '?'"
}
Elles sont ensuite converties en nombres dans un nouveau champ year :
{
"calculate": "toNumber(datum.target)",
"as": "year"
}
Ce champ est ensuite utilisé sur l’axe horizontal :
"x": {
"field": "year",
"type": "ordinal",
"title": "Année de référence",
"sort": "ascending"
}
Si votre champ target contient également des années, vous pouvez conserver ce fonctionnement et simplement adapter le titre de l’axe.
Modifier le titre des axes
Le titre de l’axe horizontal est défini ici :
"title": "Année de référence"
Celui de l’axe vertical est défini ici :
"title": "Nombre de thèses"
Remplacez ces intitulés par ceux correspondant à vos données.
Modifier les couleurs et les dégradés
Chaque aire peut utiliser son propre dégradé. Pour la série Soutenue, il est défini ici :
"color": {
"x1": 1,
"y1": 1,
"x2": 1,
"y2": 0,
"gradient": "linear",
"stops": [
{
"offset": 0,
"color": "white"
},
{
"offset": 1,
"color": "#0798d6"
}
]
}
La seconde série utilise le même principe avec la couleur #6941eb.
Vous pouvez remplacer ces couleurs par celles de votre choix. Les deux valeurs définies dans stops déterminent les extrémités du dégradé.
Modifier l’apparence des lignes
La ligne de la série Soutenue est continue :
"line": {
"color": "#00284b",
"strokeWidth": 3
}
Celle de la série En cours est en pointillés :
"line": {
"color": "#6941eb",
"strokeWidth": 3,
"strokeDash": [
7,
5
]
}
La propriété strokeWidth permet de modifier l’épaisseur de la ligne. La propriété strokeDash permet de créer une ligne discontinue.
Modifier les points
Des points sont affichés sur les valeurs de chaque série. Leur apparence est définie dans la propriété point.
Pour la série Soutenue, par exemple :
"point": {
"filled": true,
"size": 75,
"fill": "#ffeb6e",
"stroke": "#00284b",
"strokeWidth": 2
}
sizedétermine la taille du point ;filldétermine sa couleur intérieure ;strokedétermine la couleur de son contour ;strokeWidthdétermine l’épaisseur du contour.
Modifier la transparence
Afin que les différentes aires restent visibles lorsqu’elles se superposent, la série En cours utilise une transparence :
"opacity": 0.35
Une valeur proche de 0 rend l’aire plus transparente, tandis qu’une valeur proche de 1 la rend plus opaque.
Modifier la forme des courbes
Les deux séries utilisent l’interpolation monotone :
"interpolate": "monotone"
Cette interpolation permet d’obtenir des transitions arrondies entre les différents points.
Modifier la légende
La légende est créée à partir du champ source. Les valeurs et les couleurs associées sont définies ici :
"scale": {
"domain": [
"Soutenue",
"En cours"
],
"range": [
"#0798d6",
"#6941eb"
]
}
Si vous modifiez les séries représentées, adaptez également les valeurs du tableau domain et les couleurs correspondantes dans range.
Le titre de la légende peut être modifié ici :
"title": "Statut de la thèse"
Modifier les informations affichées au survol
Les infobulles affichent actuellement le statut, l’année et le nombre de thèses :
"tooltip": [
{
"field": "source",
"type": "nominal",
"title": "Statut"
},
{
"field": "year",
"type": "ordinal",
"title": "Année"
},
{
"field": "weight",
"type": "quantitative",
"title": "Nombre de thèses"
}
]
Vous pouvez modifier les propriétés title pour adapter les intitulés au contenu de votre graphique.
source, target et weight afin de comparer l’évolution de plusieurs séries sur un même axe. Elle peut par exemple servir à comparer des types de documents, des catégories de projets, des statuts, des établissements ou des disciplines au cours du temps.
Formatage français des dates et des nombres
Vega-Lite permet de convertir l’affichage des dates et des nombres en français en s’appuyant sur une locale adaptée.
En configurant correctement cette locale et en l’utilisant avec les formats appropriés, il est notamment possible d’afficher :
- les mois et les jours en français ;
- des dates lisibles, par exemple
01 janvier 2025; - des nombres conformes aux conventions françaises, par exemple
11 951.
Trois éléments interviennent dans ce formatage : la locale, le type du champ et le format appliqué à son affichage.
Définir une locale française
La première étape consiste à définir une locale. Celle-ci décrit les règles linguistiques et typographiques utilisées lors du formatage, comme les séparateurs numériques ou les noms des mois et des jours.
Dans Vega-Lite, la locale se définit dans la section config.locale de la spécification :
{
"config": {
"locale": {
"number": {
"decimal": ",",
"thousands": " ",
"grouping": [3],
"currency": ["", " €"],
"percent": " %"
},
"time": {
"days": [
"dimanche",
"lundi",
"mardi",
"mercredi",
"jeudi",
"vendredi",
"samedi"
],
"shortDays": [
"dim.",
"lun.",
"mar.",
"mer.",
"jeu.",
"ven.",
"sam."
],
"months": [
"janvier",
"février",
"mars",
"avril",
"mai",
"juin",
"juillet",
"août",
"septembre",
"octobre",
"novembre",
"décembre"
],
"shortMonths": [
"janv.",
"févr.",
"mars",
"avr.",
"mai",
"juin",
"juil.",
"août",
"sept.",
"oct.",
"nov.",
"déc."
]
}
}
}
}
Cette configuration indique à Vega-Lite :
- quel caractère utiliser comme séparateur décimal et comme séparateur de milliers ;
- comment afficher les pourcentages et les monnaies ;
- quels libellés utiliser pour les jours et les mois, en version longue ou abrégée.
format déterminent ensuite où ce formatage doit être appliqué.
Définir correctement le type des données
Pour appliquer le formatage approprié, Vega-Lite doit savoir comment interpréter les données.
Deux types sont particulièrement importants :
temporalpour les dates et les heures ;quantitativepour les valeurs numériques.
Dates : utiliser le type temporal
Un champ contenant une date doit être déclaré avec le type temporal :
{
"field": "date",
"type": "temporal"
}
Nombres : utiliser le type quantitative
De la même manière, un champ numérique doit être déclaré avec le type quantitative :
{
"field": "value",
"type": "quantitative"
}
La locale définit donc les règles de présentation, tandis que le type indique à Vega-Lite quel moteur de formatage utiliser.
Appliquer un format
Une fois la locale définie et le type du champ correctement renseigné, la propriété format permet de préciser la manière dont la valeur doit être affichée.
Formater une date
Les dates utilisent une syntaxe issue de d3-time-format. Pour afficher une date sous la forme 01 janvier 2025, utilisez par exemple :
{
"axis": {
"format": "%d %B %Y"
}
}
Dans ce format :
%dcorrespond au jour du mois sur deux chiffres ;%Bcorrespond au nom du mois en toutes lettres ;%Ycorrespond à l’année sur quatre chiffres.
Ainsi :
2025-01-01 → 01 janvier 2025
Le nom janvier provient directement de la liste définie dans config.locale.time.months.
Formater un nombre
Le format des nombres utilise la syntaxe de d3-format. Pour afficher un entier avec un séparateur de milliers :
{
"format": ",d"
}
Dans ce format :
,active le groupement des milliers ;dindique que la valeur doit être affichée comme un entier.
Le caractère utilisé comme séparateur de milliers est ensuite déterminé par la locale française :
1250000 → 1 250 000
Exemple : afficher des dates en français

Dans cet exemple, les valeurs du champ _id sont converties en dates, puis affichées avec le nom du mois en français.
{
"background": "transparent",
"mark": {
"type": "bar"
},
"transform": [
{
"calculate": "toDate(datum._id)",
"as": "date"
}
],
"encoding": {
"x": {
"field": "date",
"type": "temporal",
"title": "",
"axis": {
"labelAngle": 0,
"format": "%d %B %Y"
}
},
"y": {
"field": "value",
"type": "quantitative",
"title": "",
"axis": {
"labelAngle": 0,
"format": ",d"
},
"scale": {
"type": "linear"
}
},
"tooltip": [
{
"field": "date",
"type": "temporal",
"title": "Date",
"format": "%d %B %Y"
},
{
"field": "value",
"type": "quantitative",
"title": "Nombre",
"format": ",d"
}
]
},
"padding": 18,
"width": "container",
"height": "container",
"autosize": {
"type": "fit",
"contains": "padding"
},
"config": {
"view": {
"strokeWidth": 0
},
"locale": {
"number": {
"decimal": ",",
"thousands": " ",
"grouping": [3],
"currency": ["", " €"],
"percent": " %"
},
"time": {
"dateTime": "%A %e %B %Y, %X",
"date": "%d/%m/%Y",
"time": "%H:%M:%S",
"periods": ["AM", "PM"],
"days": [
"dimanche",
"lundi",
"mardi",
"mercredi",
"jeudi",
"vendredi",
"samedi"
],
"shortDays": [
"dim.",
"lun.",
"mar.",
"mer.",
"jeu.",
"ven.",
"sam."
],
"months": [
"janvier",
"février",
"mars",
"avril",
"mai",
"juin",
"juillet",
"août",
"septembre",
"octobre",
"novembre",
"décembre"
],
"shortMonths": [
"janv.",
"févr.",
"mars",
"avr.",
"mai",
"juin",
"juil.",
"août",
"sept.",
"oct.",
"nov.",
"déc."
]
}
}
}
}
Trois éléments sont particulièrement importants dans cet exemple :
toDate(datum._id)convertit la valeur d’origine en date exploitable par Vega-Lite ;"type": "temporal"indique qu’il s’agit d’une donnée temporelle ;"format": "%d %B %Y"applique le format souhaité en utilisant les mois définis dans la locale française.
axis et dans tooltip.
Exemple : afficher des nombres au format français

Dans cet exemple, les valeurs numériques sont affichées avec un séparateur de milliers conforme à la locale française.
{
"params": [
{
"name": "highlight",
"select": {
"type": "point",
"on": "pointerover"
}
},
{
"name": "select",
"select": "point",
"value": null
}
],
"background": "transparent",
"mark": {
"type": "bar",
"cursor": "pointer",
"stroke": "black"
},
"encoding": {
"x": {
"field": "value",
"type": "quantitative",
"axis": {
"labelAngle": 0,
"tickMinStep": 1,
"format": ",d"
},
"scale": {
"type": "linear"
},
"title": "",
"sort": null
},
"y": {
"field": "_id",
"type": "nominal",
"axis": {
"labelAngle": 0,
"tickMinStep": 1
},
"title": "",
"sort": null
},
"color": {
"field": "_id",
"scale": {
"range": ["#AB8EE2"]
},
"type": "nominal",
"legend": null
},
"fillOpacity": {
"condition": [
{
"param": "select",
"value": 1
},
{
"param": "highlight",
"empty": false,
"value": 1
}
],
"value": 0.3
},
"strokeWidth": {
"condition": [
{
"param": "select",
"empty": false,
"value": 2
},
{
"param": "highlight",
"empty": false,
"value": 1
}
],
"value": 0
},
"tooltip": [
{
"field": "_id",
"type": "nominal",
"title": "Catégorie"
},
{
"field": "value",
"type": "quantitative",
"title": "Valeur",
"format": ",d"
}
]
},
"padding": 18,
"width": "container",
"height": {
"step": "30"
},
"autosize": {
"type": "fit",
"contains": "padding"
},
"config": {
"locale": {
"number": {
"decimal": ",",
"thousands": " ",
"grouping": [3],
"currency": ["", " €"],
"percent": " %"
}
},
"view": {
"strokeWidth": 0
}
}
}
Ici, le champ value est déclaré en quantitative et le format ,d est appliqué à l’axe :
"axis": {
"labelAngle": 0,
"tickMinStep": 1,
"format": ",d"
}
Le même format est également appliqué dans l’infobulle :
{
"field": "value",
"type": "quantitative",
"title": "Valeur",
"format": ",d"
}
config.locale et les propriétés format dans vos propres visualisations.
Ajouter un sélecteur à un graphique Vega-Lite

Un graphique peut contenir plusieurs catégories de données que l’on souhaite pouvoir afficher séparément, sans avoir à créer plusieurs visualisations.
Vega-Lite permet d’ajouter un sélecteur afin que l’utilisateur choisisse les données qu’il souhaite afficher.
Dans cet exemple, nous partons d’un diagramme en barres et souhaitons proposer trois choix :
positifnégatifni positif ni négatif
Nous partons de ce diagramme en barres classique :
{
"$schema": "https://vega.github.io/schema/vega-lite/v5.json",
"background": "transparent",
"transform": [
{"filter": "datum._id != 'non concerné'"},
{"joinaggregate": [{"op": "sum", "field": "value", "as": "total"}]},
{"calculate": "datum.value / datum.total * 100", "as": "pourcentage"}
],
"layer": [
{
"mark": {"type": "bar"},
"encoding": {
"x": {
"field": "value",
"type": "quantitative",
"axis": {"labelAngle": 0, "tickMinStep": 1},
"scale": {"type": "linear"},
"title": "",
"sort": null
},
"y": {
"field": "_id",
"type": "nominal",
"axis": {"labelAngle": 0, "tickMinStep": 1},
"title": "",
"sort": null
},
"color": {
"field": "_id",
"scale": {
"range": ["#d7191c", "#fdae61", "#ffffbf", "#abdda4", "#2b83ba"]
},
"type": "nominal",
"legend": null
},
"tooltip": [
{"field": "_id", "type": "nominal", "title": "Catégorie"},
{"field": "value", "type": "quantitative", "title": "Valeur"},
{"field": "total", "type": "quantitative", "title": "Sur"},
{
"field": "pourcentage",
"type": "quantitative",
"format": ".0f",
"title": "Pourcentage (%)"
}
]
}
},
{
"mark": {
"type": "text",
"color": "black",
"fontSize": 10,
"fontWeight": "bold",
"baseline": "middle",
"align": "left",
"dx": 4,
"dy": 0
},
"encoding": {
"x": {
"field": "value",
"type": "quantitative",
"axis": null,
"sort": null
},
"y": {"field": "_id", "type": "nominal", "title": "", "sort": null},
"text": {"field": "value", "type": "quantitative"}
}
}
],
"padding": 18,
"config": {"view": {"strokeWidth": 0}},
"width": "container",
"height": {"step": 20},
"autosize": {"type": "fit", "contains": "padding"},
"data": {
"values": [
{
"_id": "programme positif",
"value": 28
},
{
"_id": "international positif",
"value": 18
},
{
"_id": "financement positif",
"value": 12
},
{
"_id": "reconnaissance positif",
"value": 8
},
{
"_id": "programme négatif",
"value": 15
},
{
"_id": "international négatif",
"value": 10
},
{
"_id": "financement négatif",
"value": 21
},
{
"_id": "reconnaissance négatif",
"value": 14
},
{
"_id": "programme ni positif ni négatif",
"value": 40
},
{
"_id": "international ni positif ni négatif",
"value": 32
},
{
"_id": "financement ni positif ni négatif",
"value": 25
},
{
"_id": "reconnaissance ni positif ni négatif",
"value": 16
}
]
}
}
ℹ️Le principe présenté ici n’est toutefois pas spécifique aux diagrammes en barres. Le sélecteur agit sur les données avant leur représentation et peut donc être utilisé avec d’autres types de graphiques Vega-Lite.
Préparer les données utilisées par le graphique
Pour pouvoir utiliser le sélecteur, chaque valeur doit contenir à la fois :
- le libellé qui sera utilisé dans le graphique
- la catégorie qui permettra de filtrer les données.
Une solution consiste à regrouper ces deux informations dans une même chaîne en utilisant un séparateur.
Dans notre exemple, nous utilisons :
programme : positif
programme : négatif
international : positif
international : négatif
financement : ni positif ni négatif
La structure est donc toujours la même :
libellé : catégorie
La partie située avant : correspond au libellé qui sera utilisé par le graphique.
La partie située après : correspond à la catégorie utilisée par le sélecteur.
Préparer ses données
Selon la structure du corpus d’origine, il peut être nécessaire de transformer les données avant de créer le graphique.
Par exemple, une valeur telle queFinancement Négatifpeut être transformée en
Financement : négatif.Cette préparation permet ensuite à Vega-Lite de distinguer facilement le libellé de la catégorie utilisée par le sélecteur.
Un exemple de script Lodash permettant de réaliser cette transformation est disponible ici :
Structurer une chaîne de caractères pour distinguer un libellé et une catégorie
Après application de l’enrichissement, puis de la routine, les données transmises au graphique ont cette forme :
[
{
"_id": "programme : positif",
"value": 28
},
{
"_id": "international : positif",
"value": 18
},
{
"_id": "programme : négatif",
"value": 15
},
{
"_id": "international : négatif",
"value": 10
}
]
La propriété _id contient les deux informations nécessaires tandis que value contient le nombre d’occurrences calculé par la routine.
Ajouter le sélecteur
Le sélecteur est déclaré dans la propriété params de la spécification Vega-Lite.
"params": [
{
"name": "selectcategorie",
"value": "positif",
"bind": {
"input": "select",
"options": [
"positif",
"négatif",
"ni positif ni négatif"
],
"name": "Afficher : "
}
}
]
Ce bloc crée une liste déroulante permettant de sélectionner la catégorie à afficher.
Nommer le sélecteur
"name": "selectcategorie"
La propriété name définit le nom interne du paramètre.
Ce nom sera ensuite utilisé dans le filtre afin de récupérer la valeur actuellement choisie par l’utilisateur.
Définir la valeur sélectionnée par défaut
"value": "positif"
La propriété value définit la valeur sélectionnée lors du premier affichage du graphique.
Dans cet exemple, le graphique affiche donc initialement les données appartenant à la catégorie positif.
Créer une liste déroulante
"bind": {
"input": "select"
}
La propriété bind permet d’associer le paramètre à un élément d’interface.
Avec "input": "select", Vega-Lite crée une liste déroulante.
Définir les valeurs proposées
"options": [
"positif",
"négatif",
"ni positif ni négatif"
]
La propriété options contient les différentes valeurs proposées dans le sélecteur.
Ces valeurs doivent correspondre exactement aux catégories présentes dans les données.
À modifier
Adaptez la propriétéoptionsaux catégories présentes dans votre propre corpus.
Par exemple :
"options": [
"article",
"ouvrage",
"chapitre"
]
ou :
"options": [
"2024",
"2025",
"2026"
]
Séparer le libellé et la catégorie dans Vega-Lite
Les données reçues par Vega-Lite contiennent actuellement une chaîne unique :
international : positif
Nous devons récupérer séparément :
libelle → international
categorie → positif
Pour cela, deux transformations sont ajoutées :
{
"calculate": "split(datum._id, ' : ')[0]",
"as": "libelle"
},
{
"calculate": "split(datum._id, ' : ')[1]",
"as": "categorie"
}
La fonction split découpe la chaîne en utilisant : comme séparateur.
Ainsi :
international : positif
est découpé conceptuellement de cette manière :
["international", "positif"]
Le premier élément est récupéré avec [0] et enregistré dans un nouveau champ appelé libelle.
Le second élément est récupéré avec [1] et enregistré dans un nouveau champ appelé categorie.
international : positif
│ │
▼ ▼
libelle categorie
│ │
▼ ▼
international positif
À modifier
Si vous utilisez un autre séparateur dans vos données, remplacez' : 'dans les deux expressionssplit.
Relier le sélecteur aux données
Nous disposons maintenant :
- d’un champ
categoriedans les données ; - d’un paramètre
selectcategoriecontenant le choix effectué par l’utilisateur.
Il suffit alors de comparer les deux valeurs avec un filtre :
{
"filter": "datum.categorie == selectcategorie"
}
Pour chaque donnée, Vega-Lite compare donc :
datum.categorie
avec :
selectcategorie
Si l’utilisateur choisit négatif, seules les données dont la catégorie vaut négatif sont conservées.
programme : positif ✕
international : positif ✕
programme : négatif ✓
international : négatif ✓
financement : négatif ✓
Le graphique est automatiquement mis à jour lorsque l’utilisateur modifie la valeur du sélecteur.
Utiliser le nouveau libellé dans le graphique
Dans le graphique initial, la propriété _id pouvait être utilisée directement comme libellé.
Mais _id contient désormais :
programme : positif
Nous souhaitons uniquement afficher :
programme
Il faut donc utiliser le nouveau champ libelle dans l’encodage du graphique :
"y": {
"field": "libelle",
"type": "nominal",
"axis": {
"labelAngle": 0,
"tickMinStep": 1
},
"title": "",
"sort": null
}
Le même principe peut être appliqué partout où le libellé doit être utilisé, par exemple pour la couleur :
"color": {
"field": "libelle",
"scale": {
"range": [
"#d7191c",
"#fdae61",
"#ffffbf",
"#abdda4",
"#2b83ba"
]
},
"type": "nominal",
"legend": null
}
Adapter l’infobulle
Les deux informations peuvent également être affichées séparément dans l’infobulle.
"tooltip": [
{
"field": "libelle",
"type": "nominal",
"title": "Libellé"
},
{
"field": "categorie",
"type": "nominal",
"title": "Catégorie"
},
{
"field": "value",
"type": "quantitative",
"title": "Valeur"
},
{
"field": "total",
"type": "quantitative",
"title": "Sur"
},
{
"field": "pourcentage",
"type": "quantitative",
"format": ".0f",
"title": "Pourcentage (%)"
}
]
Pour une donnée telle que :
financement : négatif
l’infobulle peut ainsi présenter séparément le libellé, la catégorie et la valeur.
Calculer le total après le filtrage
Dans notre exemple, le graphique calcule également un total et un pourcentage.
Le bloc complet des transformations est :
"transform": [
{
"calculate": "split(datum._id, ' : ')[0]",
"as": "libelle"
},
{
"calculate": "split(datum._id, ' : ')[1]",
"as": "categorie"
},
{
"filter": "datum.categorie == selectcategorie"
},
{
"joinaggregate": [
{
"op": "sum",
"field": "value",
"as": "total"
}
]
},
{
"calculate": "datum.value / datum.total * 100",
"as": "pourcentage"
}
]
L’ordre des transformations est important.
Séparation du libellé et de la catégorie
↓
choix dans le sélecteur
↓
filtrage
↓
calcul du total sélectionné
↓
calcul des pourcentages
↓
affichage du graphique
Le filtre est appliqué avant le calcul du total.
Si l’utilisateur sélectionne positif, le total est donc calculé uniquement à partir des valeurs positives.
S’il sélectionne négatif, le total est recalculé à partir des valeurs négatives.
Le code complet du graphique avec sélecteur
{
"$schema": "https://vega.github.io/schema/vega-lite/v5.json",
"background": "transparent",
"params": [
{
"name": "selectcategorie",
"value": "positif",
"bind": {
"input": "select",
"options": [
"positif",
"négatif",
"ni positif ni négatif"
],
"name": "Afficher : "
}
}
],
"transform": [
{
"calculate": "split(datum._id, ' : ')[0]",
"as": "libelle"
},
{
"calculate": "split(datum._id, ' : ')[1]",
"as": "categorie"
},
{
"filter": "datum.categorie == selectcategorie"
},
{
"joinaggregate": [
{
"op": "sum",
"field": "value",
"as": "total"
}
]
},
{
"calculate": "datum.value / datum.total * 100",
"as": "pourcentage"
}
],
"layer": [
{
"mark": {
"type": "bar"
},
"encoding": {
"x": {
"field": "value",
"type": "quantitative",
"axis": {
"labelAngle": 0,
"tickMinStep": 1
},
"scale": {
"type": "linear"
},
"title": "",
"sort": null
},
"y": {
"field": "libelle",
"type": "nominal",
"axis": {
"labelAngle": 0,
"tickMinStep": 1
},
"title": "",
"sort": null
},
"color": {
"field": "libelle",
"scale": {
"range": [
"#d7191c",
"#fdae61",
"#ffffbf",
"#abdda4",
"#2b83ba"
]
},
"type": "nominal",
"legend": null
},
"tooltip": [
{
"field": "libelle",
"type": "nominal",
"title": "Catégorie"
},
{
"field": "categorie",
"type": "nominal",
"title": "Catégorie"
},
{
"field": "value",
"type": "quantitative",
"title": "Valeur"
},
{
"field": "total",
"type": "quantitative",
"title": "Sur"
},
{
"field": "pourcentage",
"type": "quantitative",
"format": ".0f",
"title": "Pourcentage (%)"
}
]
}
},
{
"mark": {
"type": "text",
"color": "black",
"fontSize": 10,
"fontWeight": "bold",
"baseline": "middle",
"align": "left",
"dx": 4,
"dy": 0
},
"encoding": {
"x": {
"field": "value",
"type": "quantitative",
"axis": null,
"sort": null
},
"y": {
"field": "libelle",
"type": "nominal",
"title": "",
"sort": null
},
"text": {
"field": "value",
"type": "quantitative"
}
}
}
],
"padding": 18,
"config": {
"view": {
"strokeWidth": 0
}
},
"width": "container",
"height": {
"step": 20
},
"autosize": {
"type": "fit",
"contains": "padding"
},
"data": {
"values": [
{
"_id": "programme : positif",
"value": 28
},
{
"_id": "international : positif",
"value": 18
},
{
"_id": "financement : positif",
"value": 12
},
{
"_id": "reconnaissance : positif",
"value": 8
},
{
"_id": "programme : négatif",
"value": 15
},
{
"_id": "international : négatif",
"value": 10
},
{
"_id": "financement : négatif",
"value": 21
},
{
"_id": "reconnaissance : négatif",
"value": 14
},
{
"_id": "programme : ni positif ni négatif",
"value": 40
},
{
"_id": "international : ni positif ni négatif",
"value": 32
},
{
"_id": "financement : ni positif ni négatif",
"value": 25
},
{
"_id": "reconnaissance : ni positif ni négatif",
"value": 16
}
]
}
}
Utiliser un sélecteur avec d’autres types de graphiques
Dans cet exemple, le sélecteur est utilisé avec un diagramme en barres, mais son fonctionnement n’est pas lié à ce type de représentation.
Le sélecteur intervient dans les transformations Vega-Lite :
{
"filter": "datum.categorie == selectcategorie"
}
Le filtrage est donc effectué sur les données avant leur représentation graphique.
Données
↓
Sélection d'une catégorie
↓
Filtrage des données
↓
Transformations éventuelles
↓
Représentation graphique
Le même mécanisme peut ainsi être utilisé avec différents types de visualisations Vega-Lite : courbes, graphiques en aires, nuages de points, donuts ou encore graphiques combinés.
Par exemple, des données structurées ainsi :
2024 : France
2025 : France
2026 : France
2024 : Allemagne
2025 : Allemagne
2026 : Allemagne
pourraient utiliser la première partie comme information représentée sur l’axe temporel et la seconde comme catégorie permettant de sélectionner le pays.
Le principe reste le même :
split(...)[0] → information utilisée par le graphique
split(...)[1] → information utilisée par le sélecteur
Seuls les champs utilisés dans les propriétés encoding doivent ensuite être adaptés au type de représentation choisi.
À retenir
Le sélecteur est indépendant du type de graphique. Il filtre les données transmises à la visualisation. Une fois le filtre appliqué, Vega-Lite construit le graphique avec les seules données correspondant au choix effectué par l’utilisateur.
Les trois modifications essentielles
Pour ajouter un sélecteur à un graphique existant, trois modifications principales sont nécessaires.
1. Ajouter le sélecteur
"params": [
{
"name": "selectcategorie",
"value": "positif",
"bind": {
"input": "select",
"options": [
"positif",
"négatif",
"ni positif ni négatif"
],
"name": "Afficher : "
}
}
]
2. Créer les champs et appliquer le filtre
{
"calculate": "split(datum._id, ' : ')[0]",
"as": "libelle"
},
{
"calculate": "split(datum._id, ' : ')[1]",
"as": "categorie"
},
{
"filter": "datum.categorie == selectcategorie"
}
3. Utiliser le nouveau champ pour l’affichage
Dans les différentes parties du graphique qui doivent afficher le libellé, utilisez :
"field": "libelle"
à la place de :
"field": "_id"
Principe général
Cette méthode ne se limite pas aux catégories positif et négatif.
Elle repose simplement sur des données structurées selon le modèle :
libellé : catégorie
Par exemple :
Article scientifique : français
Article scientifique : anglais
Université de Lorraine : 2025
Université de Lorraine : 2026
Publication : ouverte
Publication : fermée
Dans tous les cas, Vega-Lite peut récupérer séparément les deux informations :
split(...)[0] → information utilisée dans le graphique
split(...)[1] → information utilisée par le sélecteur
À retenir
Lorsque plusieurs informations sont regroupées dans une chaîne structurée, par exemplelibellé : catégorie, la fonctionsplitpermet de les séparer directement dans Vega-Lite. L’une peut alors servir à construire la visualisation et l’autre à filtrer les données grâce à un sélecteur.