Comment transformer le visuel d'un dashboard en R Shiny

DESIGN - UX - LANCEMENT PUBLIC

Dans le cadre du lancement public d'une application R Shiny, DATA CHAMP’ est intervenu pour améliorer l'esthétique, optimiser l'expérience utilisateur et développer de nouvelles fonctionnalités.

Objectif : maximiser la communication autour de l'outil.

L'OFCE (Observatoire Français des Conjonctures Économiques) a récemment créé l'application Debtwatch afin de simuler les trajectoires économiques et échanger autour de la soutenabilité de la dette. Un outil a priori idéal en prévision des élections 2022 !

A priori seulement car l'application n'allait pas être prête dans les temps. Et surtout, il manquait un détail important : un design qui donne envie aux utilisateurs de revenir, de partager et d'en parler autour d'eux.

Dans cette étude de cas, on va voir comment DATA CHAMP’ est intervenu pour remplir deux objectifs majeurs :

  1. Réussir un lancement public sans accroc
  2. Transformer les utilisateurs en ambassadeurs de l'outil

Le point de départ de l’application

Quand Xavier Timbeau m’a montré l’application pour la première fois, j’ai vu un dashboard des plus classiques.

Une barre latérale qui contient des paramètres et des filtres.

Une série de graphiques qui se mettent à jour quand on change les filtres.

Dans les coulisses, des modèles macro-économiques assez balèzes qui tournent et simulent des scénarios.

Plutôt la base pour une application Shiny.

Le point de départ de l’application Appli basique

DebtwatchR : Améliorer l'UI/UX d'une application grand public

Objectif : Maximiser la communication autour de l'outil.

Secteur :

Client : Observateur Français des Conjonctures Économiques (OFCE)

Dans le cadre du lancement public d'une application R Shiny, DATA CHAMP’ est intervenu pour améliorer l'esthétique, optimiser l'expérience utilisateur et développer de nouvelles fonctionnalités.

Xavier m’a amené 2 problématiques :

1. Ajouter des nouvelles fonctionnalités

Ces nouvelles fonctionnalités portaient notamment sur l’ajout de boutons sociaux, la gestion des paramètres dans la barre latérale ou le multi-langue.

A priori, rien qui ne résistait à Xavier. Clairement, il avait déjà codé une application très fonctionnelle. Les features manquantes n’étaient pas particulièrement difficiles à mettre en place.

C’était plutôt un problème de timing. La date de lancement était déjà prévue. Elle approchait à grand pas.

2. Améliorer l’esthétique

Et si on regarde l’esthétique (voir le screenshot au-dessus)… Disons que l’application de base n’était pas moche.

C’était sobre. Propre. C’était acceptable. Enfin, pour une application interne peut-être.

Sauf que là, l’outil se destinait au grand public. On voulait que l’application soit agréable à visiter et facile à utiliser. On voulait aussi pouvoir reconnaître l’identité visuelle de l’OFCE.

Et là, pour le coup, j’ai vite vu que le design c’était pas le truc de Xavier.

Comment choisir la bonne technologie de base ?

Quand on veut créer un tableau de bord en Shiny, on peut gagner du temps en utilisant certaines librairies. Et la question qui turlupinait Xavier, c’était de connaître la librairie la plus adaptée. On devrait prendre shinyBS, shinydashboard, bs4dash, ou shiny.react ?

bsdash vs shinydashboard

Toutes de très bonnes solutions pour construire une interface en Shiny. D’ailleurs, il y en a encore plein d’autres. En 2021, c’était pas vraiment ce qui manquait. Sauf que… si la question était complètement légitime, ce n’était pas la bonne approche.

Quel que soit le choix qu’on allait faire, on allait toujours avoir le même résultat.

C’est-à-dire une interface neutre.

Sobre. Propre. Agréable à utiliser. Certes.

Mais aussi…

Neutre. Générique. Fade. Sans personnalité.

Et c’est normal ! C’est du one-size-fits-all. C’est censé être utilisé par n’importe qui, dans n’importe quel contexte.

Sauf que nous, on voulait donner une vraie identité à l’application.

On voulait maximiser la communication autour de l’outil.

Un des moyens d’y parvenir, c’était de transformer les utilisateurs de notre application en ambassadeurs de notre produit.

Et pour ça, il fallait davantage qu’un outil sobre, propre et neutre.

Il fallait :

Préparer une maquette graphique

Le design se découpe en deux parties : l’UI et l’UX.

L’UI, pour User Interface, c’est créer l’interface et la rendre jolie.

L’UX, pour User eXperience, c’est tout ce qui a trait à la manière dont l’utilisateur va interagir avec l’application.

En gros, on veut un truc qui soit beau ET pratique. C’est comme ça qu’on maximise l’adoption de l’outil.

L’UI et l’UX, c’est un vrai métier.

Et c’est clairement pas le mien. Je n’ai aucun goût artistique, aucune capacité à me projeter dans un autre design.

Pour ces problématiques, je fais appel à une experte : Cécile Uzel, graphiste et fondatrice de l’Atelier Qui Fait Mouche.

Je lui ai présenté l’application, comment elle fonctionnait et l’objectif qu’on avait.

Je n’avais aucune idée de ce à quoi l’application allait ressembler.

Mais quand j’ai vu la maquette, je me suis tout de suite dit : « Bah oui ! Mais c’était sûr en fait ! »

On reconnaît instantanément la charte graphique de l’OFCE :

Maquette v1 Maquette

Je vous remets le lien vers le site de l’OFCE pour comparer : Lien

Il ne restait plus qu’à intégrer tout ça dans un code en R Shiny.

Et là…

La question du « shinyBS ou shinydashboard ? » a été vite répondue.

Aucun des deux.

C’est finalement beaucoup plus simple de repartir de zéro en construisant les blocs avec du HTML et du CSS.

Créer la structure en HTML d’une application Shiny

On pourrait penser que c’est une perte de temps de tout recoder en HTML au lieu d’utiliser un package comme shinydashboard.

En fait, pas tant que ça.

Le HTML, c’est la partie la plus facile.

Comme Shiny utilise Bootstrap par défaut, on ne part pas tout à fait de zéro.

En fait, Bootstrap donne déjà énormément d’outils.

Par exemple, la possibilité d’utiliser une grille avec le système de colonnes avec les fonctions fluidRow() et column().

Voici comme reconstituer une structure de dashboard :

fluidPage(
  fluidRow(
    id = "title_panel",
    # Contenu de l'en-tête
  ),
  fluidRow(
    id = "body",
    column(
      id = "sidebar_panel",
      width = 3,
      div(
        # Contenu de la barre latérale
      )
    ),
    column(
      id = "main_panel",
      width = 9,
      div(
        # Contenu du corps principal
      )
    )
  )
)

Et c’est tout ! Pour le reste, on ajoute le contenu.

Si vous êtes curieux, voici le code de l’interface : Lien vers le dépôt Github

Notez l’utilisation du paramètre id.

Les id seront beaucoup utilisés ensuite en CSS pour personnaliser l’apparence. Ils permettent de créer ce qu’on appelle des sélecteurs.

Parce qu’en effet, par défaut, ça va être un peu moche.

Si on utilise un package comme shinydashboard, on va par défaut avoir une apparence correcte. Mais elle sera non personnalisée et sans identité marquée. Ceci convient bien dans certains cas. Mais pas dans le nôtre.

Il ne reste plus qu’à coder la partie visuelle ! Et pour ça, il faut faire du CSS.

Le package sass pour écrire du CSS facilement

Mon outil préféré pour tout ce qui touche au graphisme, c’est le package sass.

sass, pour Syntactically Awesome Style Sheets, est une sorte de d’extension de CSS.

Je l’utilise principalement pour hiérarchiser mon code CSS, ce qui est plus facile à lire et à écrire.

Par exemple :

#main_panel {
  
  padding: 50px 7%;
  
  .introduction {
    
    position: relative;
    background-color: white;
    padding: 10px 25px 30px 25px;
    margin-bottom: 20px;
    
    h3 {
      font-size: 20px;
      color: $red;
      text-transform: uppercase;
    }
  }
}

Alors qu’en CSS, ça donne :

#main_panel {  
  padding: 50px 7%;
}
  
#main_panel .introduction {    
  position: relative;
  background-color: white;
  padding: 10px 25px 30px 25px;
  margin-bottom: 20px;
}
    
#main_panel .introduction h3 {
  font-size: 20px;
  color: $red;
  text-transform: uppercase;
}

C’est pas forcément super flagrant. Mais le fichier CSS n’a aucune structure et les sélecteurs sont beaucoup plus longs. Sur ce petit exemple, ça va encore. Par contre, quand on a des centaines de lignes, on est content de pouvoir structurer et hiérarchiser les sélecteurs !

Là aussi, si vous êtes curieux, le code est disponible sur le dépôt Github : Lien vers les fichiers SASS.

Au final, la maquette n’était pas très compliquée à intégrer.

Sauf un petit détail…

Comment créer ses propres widgets en Shiny

Un challenge qu’on a dû résoudre était celui de pouvoir afficher les paramètres sur la gauche d’une manière qui soit à la fois :

Clairement, la solution d’origine ne permettait pas tous ces points.

Elle utilisait bsCollapse pour la partie condensée. On ne comprenait pas bien qu’il s’agissait de boîtes qu’on pouvait déplier. Et surtout, on n’avait pas d’accès facile aux valeurs sélectionnées.

Autre problème : le design du sliderInput de Shiny.

Il prend énormément de place !

Comparez avec ce qui était prévu par la maquette :

Slider 1 : sliderInput

Slider 2 : sliderInput2

Au-delà même de l’aspect visuel et des couleurs, il y a pas mal de problèmes à résoudre :

J’ai vite compris que j’allais devoir recoder un widget.

Créer un nouveau widget, quand on ne l’a jamais fait avant, c’est pas une mince affaire.

La documentation sur le sujet est par ailleurs assez légère.

RStudio propose deux articles :

Ce sont des bons articles introductifs… mais c’est tout. Il manque des parties importantes si on veut coder un widget pleinement fonctionnel.

En fait, ils écrivent :

“In addition to the previously discussed methods, several other JavaScript methods can be added to your input binding object, notably; getId, getState, getRatePolicy, receiveMessage and unsubscribe. These are discussed in the various references provided and are not further discussed here.

En français : il y a plein d’autres méthodes qui sont discutées dans d’autres articles, allez voir les références.

Oui, ben en fait, non, pas vraiment.

Les références qu’ils mentionnent, c’est l’autre article que j’ai cité et qui reste lui aussi introductif. Sinon on a des liens vers des exemples sur Github.

Donc, en gros, le message c’est : « Débrouillez-vous pour le reste. »

Bref.

Au final, des recherches supplémentaires m’ont conduit vers :

Et puis après, bah… Le meilleur moyen, c’est encore de creuser dans le code.

Je suis allé voir le code de la fonction originelle sliderInput. Je me suis aussi aidé de ce qui a été fait dans le package shinyWidgets.

Et au bout d’un moment, on s’en sort.

Le widget créé n’est pas parfait, notamment il ne se généralise pas très bien à d’autres applications. Mais il marche. Il fait exactement ce que la maquette avait prévu :

Pour les curieux, voici le code :

Il y a aussi un bout de code en plus pour mettre à jour la valeur dans le “contenant” du slider.

Bref, c’est pas très généralisable.

Au final, une fois passés les premiers errements sur la documentation, la création d’un nouveau widget s’est faite assez facilement.

Objectifs accomplis !

L'application a été lancée lors d'une conférence de presse en octobre 2021.

Elle a connu un franc succès dès sa publication. Environ 10 000 scénarios ont été simulés pendant les 2 premières semaines.

Ensuite, le trafic est naturellement redescendu. Mais il suit maintenant une pente légèrement croissante grâce aux nombreux outils mis en place facilitant le partage de graphiques ou de simulations sur les réseaux sociaux.

Nous entrons donc dans une phase d'amélioration continue de l'application. Notre objectif : améliorer encore l'expérience utilisateur via la prise en compte des retours utilisateurs. Nous travaillons, par exemple, sur la possibilité de retrouver facilement les scénarios simulés d'une fois sur l'autre.

Avez-vous un projet ?