Atelier Quarto - Exercice 3

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 arquero et un peu de javascript pour gérer l’interactivité !

La doc arquero

Introduction à Arquero
Un cookbook
Illustration en image des verbes d’arquero
Doc complète

Chargement des librairies, csv, tableau

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.

Afficher le code
import { aq, op } from '@uwdata/arquero' // le dplyr ou pandas du javascript

// la donnée sera un dataframe au format arquero, ce format est compatible directement avec la librairie plot intégré de ojs (sinon il est nécessaire de retransformer la donnée en object javascript pour les autres librairies)
myData = aq.loadCSV("./data/donnees_combined.csv");
Inputs.table(myData)

Filtre pour sélectionner les indicateurs tranche d’âge

Un simple filtre permet de sélectionner tous les indicateurs relatifs aux tranches d’âge.

Afficher le code
myDataTrancheAge = myData
                    .filter(d => op.includes(d.indicateur, '_ans'))
                    
// Afficher la donnée
Inputs.table(myDataTrancheAge)

Ensuite, OJS contient tous les input de base, voici un exemple avec un slider

Afficher le code
viewof myQuartier = Inputs.range([1, 342], {step: 1, label: "Choisir un quartier"})

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.

Afficher le code
myDataQuartier = myDataTrancheAge
                  .filter(aq.escape(d => d.id== myQuartier && d.echelle == 'recoquartier'))

// Afficher la donnée
Inputs.table(myDataQuartier)

Et pour avoir un graphe interactif, il suffit de prendre entrée la variable filtrée selon le input.

Afficher le code
Plot.plot({
  marginLeft: 45,
  color: {legend: true },
  marks: [
    Plot.barX(
      myDataQuartier,
        { x: "valeur" , y : "id", fill: "indicateur"}
    )
  ]
})

Exemple plus complet de texte, tableau et graphe

Préparation des données pour le Inputs.select

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.

Afficher le code
dataSelectQ = myData
                .select('id','indicateur','valeur')
                .filter(aq.escape(d => d.indicateur == 'commune' || d.indicateur == 'nom_iris'))
                .groupby('id')
                .pivot('indicateur', 'valeur')

// Afficher la donnée
Inputs.table(dataSelectQ)

Données quartier avec référent régional, stackBar

Afficher le code
// Le menu déroulant
viewof Q = Inputs.select(dataSelectQ, {label: "Choisir un quartier", format: d => `n° ${d.id}-${d.commune} (${d.nom_iris})` })

Vous avez sélectionner le quartier 🏢 n° situé sur la commune de (IRIS : )

Les données étant au format long, il suffit de filtrer :

  • selon l’identifiant du quartier
  • selon la valeur de l’échelle géographique (avec un ou qui s’écrit || en javascript)
  • selon les libellés des indicateurs que l’on veut représenter
Afficher le code
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 à la volée
Inputs.table(
  myDataGrapheStackBar.groupby('indicateur').pivot('echelle','valeur'), {
  header: {
    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.

Afficher le code
// Des stack bar série               
Plot.plot({
  marginLeft: 45,
  marginBottom: 60,
  marginTop: 60,
  style: {fontSize: "25px"},
  color: {legend: true },
  marks: [
    Plot.barY(
      myDataGrapheStackBar,
        { x : "echelle" ,y: "valeur" , fill: "indicateur", offset: "normalize", tip: true}
    )
  ]
})

Boîtes à moustache + symboles

Afficher le code
myDataBoxPlot = myData
                  .filter( d => d.echelle == 'recoquartier')
                  .filter( d => op.includes(d.indicateur, '_ans') )
                  .derive({
                    valeurNumber: aq.escape(d => parseFloat(d.valeur))
                  })
                  .select('id','echelle','indicateur','valeurNumber')

myDataBoxPlotQ = myDataBoxPlot.filter(aq.escape(d => d.id == Q.id))

//Inputs.table(myDataBoxPlotQ)

Plot.plot({
  caption: "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
    Plot.boxY(myDataBoxPlot, {x: "indicateur", y: "valeurNumber", fill:"indicateur"}),

    // et un symbole pour positionner le quartier sélectionné
    Plot.dot(myDataBoxPlotQ, {
      x: "indicateur", 
      y: "valeurNumber", 
      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
        }
      }
    })
  ]
})