Afficher le code
= DuckDBClient.of({
db donnees_combined : FileAttachment("data/donnees_combined.csv")
})
= db.sql`SELECT * FROM donnees_combined`
myData .table(myData) Inputs
Observable JavaScript avec WidgetHTML : tableau, graphe, carte, inline code
L’exemple qui suit est complexe : il va falloir charger un csv avec des données au “format long” et les manipuler avec duckdb et un peu de javascript pour gérer l’interactivité !
à compléter
Ici les données ont été préparées au “format long”, c’est un format très pratique pour simplement faire des filtres par la suite et pouvoir représenter des “séries” de données.
La donnée est complexe : elle comprend à la queuleuleue les données des quartiers mais aussi les données des quartiers agrégées à la commune, département, région.
Duckdb est intégré à observable javascript, dans cet exemple on ne charge aucune librairie !
= DuckDBClient.of({
db donnees_combined : FileAttachment("data/donnees_combined.csv")
})
= db.sql`SELECT * FROM donnees_combined`
myData .table(myData) Inputs
Un simple filtre permet de sélectionner tous les indicateurs relatifs aux tranches d’âge.
= db.sql`SELECT * FROM donnees_combined where indicateur ilike 'ind%ans%'`
myDataTrancheAge // Afficher la donnée
.table(myDataTrancheAge) Inputs
Ensuite, OJS contient tous les input
de base, voici un exemple avec un slider
= Inputs.range([1, 342], {step: 1, label: "Choisir un quartier"}) viewof myQuartier
On peut lier cet input à un filtre. Dès que l’on change la valeur du input, cela recalcule tous les blocs de code qui contiennent myQuartier
.
= db.sql`
myDataQuartier SELECT * FROM donnees_combined where id=${myQuartier} and echelle = 'recoquartier' and indicateur ilike 'ind%ans%'
`
// Afficher la donnée
.table(myDataQuartier) Inputs
Et pour avoir un graphe interactif, il suffit de prendre entrée la variable filtrée selon le input.
.plot({
PlotmarginLeft: 45,
color: {legend: true },
marks: [
.barX(
Plot,
myDataQuartierx: "valeur" , y : "id", fill: "indicateur"}
{
)
] })
Au préalable, on prépare des données sur mesure pour notre Input pour choisir un quartier et on formate ça aux petits oignons : selection de colonnes, filtre, pivot.
= db.sql`
dataSelectQ SELECT
id,
MIN(CASE WHEN indicateur = 'commune' THEN valeur END) AS commune,
MIN(CASE WHEN indicateur = 'nom_iris' THEN valeur END) AS nom_iris
FROM donnees_combined
WHERE indicateur IN ('commune', 'nom_iris')
GROUP BY id;
`
.table(dataSelectQ) Inputs
// Le menu déroulant
= Inputs.select(dataSelectQ, {label: "Choisir un quartier", format: d => `n° ${d.id}-${d.commune} (${d.nom_iris})` }) viewof Q
Vous avez sélectionner le quartier 🏢 n° situé sur la commune de (IRIS : )
Les données étant au format long, il suffit de filtrer :
= db.sql`
myDataGrapheStackBar SELECT echelle, indicateur, valeur
FROM donnees_combined
WHERE
indicateur ilike '%ind%ans%'
and
(
(id = ${Q.id} and echelle='recoquartier' )
or
echelle = 'multi_recoquartiers_region'
)
`
/*
myDataGrapheStackBar = myData
.filter( aq.escape(d => (d.id== Q.id && d.echelle == 'recoquartier') || d.echelle == 'multi_recoquartiers_region' ) )
.filter( d => op.includes(d.indicateur, '_ans') )
.select('echelle','indicateur','valeur')
*/
// Un tableau sur 2 colonnes en faisant un pivot à part (plus compliqué et moins lisible qu'avec arquero...)
= db.sql`
myData2columns SELECT indicateur,
MIN(CASE WHEN echelle = 'multi_recoquartiers_region' THEN valeur END) as multi_recoquartiers_region,
MIN(CASE WHEN echelle = 'recoquartier' THEN valeur END) as recoquartier
FROM donnees_combined
WHERE
indicateur ilike '%ind%ans%'
and
(
(id = ${Q.id} and echelle='recoquartier' )
or
echelle = 'multi_recoquartiers_region'
)
group by indicateur
`
.table(
Inputs, {
myData2columnsheader: {
multi_recoquartiers_region: "Ensemble des RecoQ",
recoquartier: `RecoQ n° ${Q.id}`
,
}align: {
multi_recoquartiers_region: "center",
recoquartier: "center"
} })
La librairie plot permet de créer la plupart des graphes. Très élégante dans sa conception, elle est un peu difficile à prendre en main… mais une fois la logique comprise elle permet de faire des graphes sur mesure complètement responsive design.
// Des stack bar série
.plot({
PlotmarginLeft: 45,
marginBottom: 60,
marginTop: 60,
style: {fontSize: "25px"},
color: {legend: true },
marks: [
.barY(
Plot,
myDataGrapheStackBarx : "echelle" ,y: "valeur" , fill: "indicateur", offset: "normalize", tip: true}
{
)
] })
= db.sql`
myDataBoxPlot SELECT id, echelle, indicateur, valeur
FROM donnees_combined
WHERE
indicateur ilike '%ind%ans%'
and
echelle='recoquartier'
`
// valeur du quartier sélectionné
= db.sql`
myDataBoxPlotQ SELECT id, echelle, indicateur, valeur
FROM donnees_combined
WHERE
id = ${Q.id}
and
indicateur ilike '%ind%ans%'
and
echelle='recoquartier'
`
//Inputs.table(myDataBoxPlotQ)
// Comme avec arquero, le graphe en boxplot ne reconnaît pas directement que valeur est un nombre, on lui force la main avec d => parseFloat(d.valeur) au lieu de simplement "valeur"
.plot({
Plotcaption: "Les boîtes à moustache représentent la dispersion des valeurs de l'ensemble des quartiers par tranche d'âge, les symboles représentent les valeurs du quartier sélectionné",
y: {
grid: true
,
}color: {legend:true, style: {fontSize: "14px"}},
symbol: {legend: true, style: {fontSize: "14px"}},
style: {fontSize: "14px"},
marginBottom: 40,
marginTop: 20,
marks: [
// boîte à moustache en série pour réprésenter l'ensemble des quartiers
.boxY(myDataBoxPlot, {x: "indicateur", y: d => parseFloat(d.valeur), fill:"indicateur"}),
Plot
// et un symbole pour positionner le quartier sélectionné
.dot(myDataBoxPlotQ, {
Plotx: "indicateur",
y: d => parseFloat(d.valeur),
fill: "white",
stroke:"black",
r: 5,
symbol: "indicateur",
// un canal permet de rajouter des informations sur mesure à partir des données
channels: {
quartier: {
value: "id",
label: "Quartier n°"
,
},
}tip: {
format: {
quartier: true,
id:true,
indicateur: true,
y: (d) => `${d*100} %`,
stroke: false
}
}
})
] })