Last active
June 18, 2026 15:13
-
-
Save mcanouil/d149ba403b63d356dbcabcc07f476bc1 to your computer and use it in GitHub Desktop.
Adaptation of Cara Thompson's code from https://www.cararthompson.com/talks/rencontresr-2026-beau-graphique/
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #import "@preview/gribouille:0.3.0": * | |
| #set page("a4", margin: 2.5cm) | |
| // === Data management: reproduce `creations` === | |
| #let challenges = csv("bakeoff-challenges.csv", row-type: dictionary) | |
| // grepl patterns -> ingredient names (French labels match the R script). | |
| #let ingredients = ( | |
| chocolat: regex("[Cc]hocolat"), | |
| framboise: regex("[Rr]aspberr"), | |
| orange: regex("[Oo]range"), | |
| ) | |
| // Distinct series in order of first appearance. | |
| #let series-list = () | |
| #for row in challenges { | |
| let s = int(row.series) | |
| if s not in series-list { series-list.push(s) } | |
| } | |
| // pivot_longer(signature, showstopper) + grepl + sum, grouped by series. | |
| #let counts = (:) | |
| #for s in series-list { | |
| counts.insert(str(s), (chocolat: 0, framboise: 0, orange: 0)) | |
| } | |
| #for row in challenges { | |
| let s = str(int(row.series)) | |
| for col in ("signature", "showstopper") { | |
| let value = row.at(col) | |
| for (ingredient, pattern) in ingredients { | |
| if value.contains(pattern) { | |
| counts.at(s).at(ingredient) += 1 | |
| } | |
| } | |
| } | |
| } | |
| // pivot_longer(-series) + rank(-value, ties="min") within series + mary_berry. | |
| #let creations = () | |
| #for s in series-list { | |
| let row-counts = counts.at(str(s)) | |
| for (ingredient, value) in row-counts { | |
| let rank = 1 | |
| for (_, other) in row-counts { | |
| if other > value { rank += 1 } | |
| } | |
| creations.push(( | |
| series: s, | |
| ingredient: ingredient, | |
| value: value, | |
| rank: rank, | |
| mary-berry: if s < 8 { "oui" } else { "non" }, | |
| )) | |
| } | |
| } | |
| // === Plot: reproduce the ggplot from bakeoff === | |
| #let couleurs-accessibles = ( | |
| chocolat: rgb("#5F1C34"), | |
| orange: rgb("#DCA113"), | |
| framboise: rgb("#d33b66"), | |
| mary: rgb("#F2CAE4"), | |
| ) | |
| #let my-plot = plot( | |
| data: creations, | |
| mapping: aes( | |
| x: "series", | |
| y: "value", | |
| colour: "ingredient", | |
| fill: "ingredient", | |
| shape: "ingredient", | |
| ), | |
| layers: ( | |
| geom-rect( | |
| data: ((xmin: 0.5, xmax: 7.5, ymin: 0, ymax: 32),), | |
| mapping: aes(xmin: "xmin", xmax: "xmax", ymin: "ymin", ymax: "ymax"), | |
| inherit-aes: false, | |
| fill: couleurs-accessibles.mary, | |
| alpha: 0.3, | |
| ), | |
| geom-line(), | |
| geom-vline(xintercept: 7.5, stroke: 0.2pt, colour: rgb("#ca3e8c")), | |
| geom-typst( | |
| data: ((x: 7.5, y: 31, label: "*Les années Mary Berry*"),), | |
| mapping: aes(x: "x", y: "y", label: "label"), | |
| inherit-aes: false, | |
| anchor: "east", | |
| colour: rgb("#3f4a57"), | |
| ), | |
| geom-point(size: 8pt, colour: rgb("#3f4a57")), | |
| ), | |
| scales: ( | |
| scale-shape-manual( | |
| values: ("diamond", "triangle", "circle"), | |
| limits: ("chocolat", "framboise", "orange"), | |
| ), | |
| scale-fill-manual( | |
| values: (couleurs-accessibles.chocolat, couleurs-accessibles.framboise, couleurs-accessibles.orange), | |
| limits: ("chocolat", "framboise", "orange"), | |
| ), | |
| scale-colour-manual( | |
| values: (couleurs-accessibles.chocolat, couleurs-accessibles.framboise, couleurs-accessibles.orange), | |
| limits: ("chocolat", "framboise", "orange"), | |
| ), | |
| scale-x-continuous(breaks: range(1, 11), expand: (0pt, 12pt)), | |
| scale-y-continuous(limits: (0, 31), expand: (0pt, 0pt)), | |
| ), | |
| guides: guides(default: guide-legend(position: "bottom")), | |
| labs: labs( | |
| title: "Le chocolat demeure l'ingrédient le plus utilisé, même s'il s'est fait brièvement doubler par les oranges en Saison 8", | |
| subtitle: "Le nombre de créations incluant du chocolat était bien plus élevé pendant que Mary Berry était dans le jury. On anticipe d'avoir besoin de deux fois plus de chocolat la saison prochaine si elle revient.", | |
| x: "Saison", | |
| y: "Nombre de créations", | |
| ), | |
| theme: theme-minimal( | |
| ink: rgb("#3f4a57"), | |
| legend-title: element-blank(), | |
| text: element-text(font: "Inclusive Sans", size: 12pt, colour: rgb("#3f4a57")), | |
| plot-title: element-text( | |
| font: "Inclusive Sans", | |
| weight: "bold", | |
| size: 19.2pt, | |
| colour: rgb("#071526"), | |
| margin: margin(top: 12pt, bottom: 18pt), | |
| ), | |
| plot-subtitle: element-text( | |
| font: "Inclusive Sans", | |
| size: 14.4pt, | |
| colour: rgb("#3f4a57"), | |
| margin: margin(top: 12pt, bottom: 24pt), | |
| ), | |
| plot-background: element-rect( | |
| fill: rgb("#f8f8f8"), | |
| inset: margin(top: 24pt, right: 24pt, bottom: 24pt, left: 24pt), | |
| ), | |
| axis-title: element-text(size: 12pt), | |
| axis-text: element-text(size: 12pt), | |
| legend-text: element-text(size: 12pt), | |
| ), | |
| width: 16cm, | |
| height: 20cm, | |
| ) | |
| #show heading.where(level: 1): set text(size: 20pt) | |
| = Bien plus qu'un beau graphique : Creativité et accessibilité avec ggplot2 | |
| _By Cara Thompson._ | |
| Date: The 17th of June, 2026 | |
| Original version: #link("https://www.cararthompson.com/talks/rencontresr-2026-beau-graphique/")[www.cararthompson.com/talks/rencontresr-2026-beau-graphique] | |
| == Typst Version with Gribouille | |
| #align(center)[ | |
| #my-plot | |
| ] | |
| #place(dx: 68%, dy: 5pt)[ | |
| Typst code by #link("https://mickael.canouil.fr")[Mickaël Canouil]. | |
| ] |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.