Teun van den Brand's Avatar

Teun van den Brand

@teunbrand.bsky.social

GitHub: https://github.com/teunbrand

952 Followers  |  93 Following  |  160 Posts  |  Joined: 28.12.2023
Posts Following

Posts by Teun van den Brand (@teunbrand.bsky.social)

A screenshot of two reply messages on bluesky commenting on the same post. The reply on top is very negative about the data.table package, saying 'it was just the worst'. The bottom reply instead claims that data.table's syntax is the best thing produced in #rstats.

A screenshot of two reply messages on bluesky commenting on the same post. The reply on top is very negative about the data.table package, saying 'it was just the worst'. The bottom reply instead claims that data.table's syntax is the best thing produced in #rstats.

Never change #rstats, never change

27.02.2026 17:22 β€” πŸ‘ 48    πŸ” 3    πŸ’¬ 0    πŸ“Œ 0

I've been charmed recently by ggiraph. It feels well-integrated and mostly works with extensions even if doesn't wrap them in interactivity. ggplotly sort of 'translates' ggplot figures and some of the more niche settings or extensions don't have a natural translation.

27.02.2026 17:17 β€” πŸ‘ 0    πŸ” 0    πŸ’¬ 1    πŸ“Œ 0

PDF has a horrible habit messing up font stuff. I'm an SVG enthusiast myself and I use ggrastr when my plot has too many points.

25.02.2026 21:38 β€” πŸ‘ 0    πŸ” 0    πŸ’¬ 1    πŸ“Œ 0

A humble suggestion:

```
`%xtab%` <- function(x, y) {
table(x, y, dnn = list(
deparse(substitute(x)),
deparse(substitute(y))
))
}
```

24.02.2026 17:15 β€” πŸ‘ 5    πŸ” 1    πŸ’¬ 0    πŸ“Œ 0
Post image

How can you say this when theme_barbie() exists? (cc @matthewbjane.bsky.social)

23.02.2026 12:09 β€” πŸ‘ 6    πŸ” 1    πŸ’¬ 1    πŸ“Œ 0
Post image

'ignored positional aesthetics' are so handy and cool, wanted to share on bsky! (as seen on mastodon πŸ™ƒ) #rstats #ggplot2

11.02.2026 20:46 β€” πŸ‘ 15    πŸ” 1    πŸ’¬ 0    πŸ“Œ 0
Preview
ggplot2 styling This post discusses one function in ggplot2: `theme()`. Find out about the glamour of graphics in this deep-dive article.

You can use this instead of your `update_geom_defaults()`:
```
theme(geom = element_geom(linewidth = 0.25, borderwidth = 0.25, pointsize = 0.5))
```
And you can use `set_theme()` to globally apply a theme as the default theme.

I wrote some additional tricks here: tidyverse.org/blog/2025/10...

10.02.2026 10:31 β€” πŸ‘ 3    πŸ” 1    πŸ’¬ 0    πŸ“Œ 0

ONE OF US, ONE OF US, ONE OF US ✨https://github.com/ggplot2-extenders/ggplot-extension-club ✨

05.02.2026 17:21 β€” πŸ‘ 2    πŸ” 0    πŸ’¬ 0    πŸ“Œ 0

Look the use of the word 'extension' was very deliberate to absolve ggplot2 from having to absorb more functionality than it already does πŸ˜…

05.02.2026 17:07 β€” πŸ‘ 3    πŸ” 0    πŸ’¬ 1    πŸ“Œ 0

I like this use case for a facet extension!

05.02.2026 16:41 β€” πŸ‘ 0    πŸ” 0    πŸ’¬ 1    πŸ“Œ 0

I think this may come from Afrikaans/Dutch and means 'red forest', so bois (woods) wasn't too far of 🀷

05.02.2026 12:18 β€” πŸ‘ 1    πŸ” 0    πŸ’¬ 0    πŸ“Œ 0
Preview
dplyr 1.2.0 dplyr 1.2.0 fills in some important gaps in dplyr's API: we've added a new complement to `filter()` focused on dropping rows, and we've expanded the `case_when()` family with three new recoding and re...

dplyr 1.2.0 is out now and we are SO excited!

- `filter_out()` for dropping rows

- `recode_values()`, `replace_values()`, and `replace_when()` that join `case_when()` as a complete family of recoding/replacing tools

These are huge quality of life wins for #rstats!

tidyverse.org/blog/2026/02...

04.02.2026 11:39 β€” πŸ‘ 464    πŸ” 134    πŸ’¬ 12    πŸ“Œ 14

# pretty slick
l <- c(mpg = "Miles per gallon", wt = "Weight (1,000 lbs)", `mpg/2` = "yes this works")
ggplot(mtcars, aes(mpg, wt)) + labs(dictionary = l)
ggplot(mtcars, aes(wt, mpg)) + labs(dictionary = l)
ggplot(mtcars, aes(wt, mpg/2)) + labs(dictionary = l)

29.01.2026 21:43 β€” πŸ‘ 38    πŸ” 6    πŸ’¬ 2    πŸ“Œ 1

This is a very good primer on why we encounter breaking changes whenever ggplot2 has a meaningful update πŸ™ƒ

21.01.2026 20:31 β€” πŸ‘ 9    πŸ” 0    πŸ’¬ 1    πŸ“Œ 0

A second crime is not putting these on the y-axis and displaying the names horizontally.

21.01.2026 19:48 β€” πŸ‘ 0    πŸ” 0    πŸ’¬ 1    πŸ“Œ 0

It is a (relatively) new thing πŸŽ‰

19.01.2026 22:08 β€” πŸ‘ 1    πŸ” 0    πŸ’¬ 1    πŸ“Œ 0

You can specify relative position in ggplot with I(x) I(y).

E.g. annotate("text", x = I(.5), y = I(.5), label = "hello!") will place the text in the middle of the plot.
This, combined with alignment arguments is like 87% of the magic for me.

26.12.2025 07:05 β€” πŸ‘ 111    πŸ” 29    πŸ’¬ 3    πŸ“Œ 5

They're alright if you have mutually inclusive categories, mostly as an alternative for large venn-diagram like data. Here, KO/WT are mutually exclusive and 8h/24h/48h are mutually exclusive. I'd opt for other ways of emphasising the experimental conditions.

09.01.2026 21:57 β€” πŸ‘ 1    πŸ” 0    πŸ’¬ 0    πŸ“Œ 0

Where'd be the artistry in deftly replacing `theme_gray()` with something more sensible? You gotta give the people some sense of accomplishment for free.

09.01.2026 21:46 β€” πŸ‘ 1    πŸ” 0    πŸ’¬ 0    πŸ“Œ 0

lukewarm take, but plotly is uggy and ggplotly should generally be avoided for disrespecting your static ggplot2 formatting (use ggiraph instead)

05.01.2026 19:52 β€” πŸ‘ 9    πŸ” 2    πŸ’¬ 2    πŸ“Œ 0

If there is a fear that some undocumented behaviour you rely on may break on accident, one thing you could do is PR a unit test for the behaviour. At least then, it'll only be broken purposefully πŸ™ƒ

15.12.2025 11:25 β€” πŸ‘ 2    πŸ” 0    πŸ’¬ 1    πŸ“Œ 0
Side-by-side comparison of two multi-panel bubble charts faceted by world region. The left column shows the default facet labels placed above each panel (β€œAfrica”, β€œAmericas”, β€œAsia”, β€œEurope”, β€œOceania”). The right column shows the same charts, but the facet labels are moved inside each panel at the top-left using a negative margin. In the center, there is a title reading β€œWant to place your facet labels inside each panel?” with an arrow pointing right, followed by a short ggplot2 theme code snippet demonstrating how to move strip text inside the panel.

Side-by-side comparison of two multi-panel bubble charts faceted by world region. The left column shows the default facet labels placed above each panel (β€œAfrica”, β€œAmericas”, β€œAsia”, β€œEurope”, β€œOceania”). The right column shows the same charts, but the facet labels are moved inside each panel at the top-left using a negative margin. In the center, there is a title reading β€œWant to place your facet labels inside each panel?” with an arrow pointing right, followed by a short ggplot2 theme code snippet demonstrating how to move strip text inside the panel.

I ignored the strip.clip argument in #ggplot2 for way too long 😲

Combined with a small negative margin tweak, you can place facet labels inside each panel. A tiny trick that makes small multiples feel so much cleaner.

πŸ”΅ no manual coordinates
πŸ”΅ inherits theme styling
πŸ”΅ scales nicely when resizing

12.12.2025 12:51 β€” πŸ‘ 239    πŸ” 40    πŸ’¬ 7    πŸ“Œ 4
Post image

You can use character glyphs as shapes too. That includes emoji.

```
library(ggplot2)

ggplot(mpg, aes(displ, hwy, shape = fl)) +
geom_point(size = 5) +
scale_shape_manual(values = c("πŸ«›", "πŸ“", "πŸ₯•", "πŸ‹", "πŸ‡"))
```

11.12.2025 12:21 β€” πŸ‘ 4    πŸ” 0    πŸ’¬ 1    πŸ“Œ 0
Preview
Point Paths β€” geom_pointpath The point path geom is used to make a scatterplot wherein the points are connected with lines in some order. This geom intends to mimic the type = 'b' style of base R line plots.

I made a geom that can do this, but it had a different purpose in mind, so you have to use `mult = 0`. You can use:

```r
stat_summary(
geom = ggh4x::GeomPointpath, fun = mean, color = "red",
mult = 0
)
```

teunbrand.github.io/ggh4x/refere...

09.12.2025 16:22 β€” πŸ‘ 2    πŸ” 0    πŸ’¬ 1    πŸ“Œ 0

``` r
func <- function(x) deparse(substitute(x))

mtcars |> func()
#> [1] "mtcars"
mtcars |> dplyr::select(hp, mpg) |> func()
#> [1] "dplyr::select(mtcars, hp, mpg)"
```

28.11.2025 15:48 β€” πŸ‘ 6    πŸ” 0    πŸ’¬ 0    πŸ“Œ 0
Preview
tidyr: Tidy Messy Data Tools to help to create tidy data, where each column is a variable, each row is an observation, and each cell contains a single value. 'tidyr' contains tools for changing the shape (pivoting) and hier...

Also, packages on CRAN come with a DOI that can be included: doi.org/10.32614/CRA...

25.11.2025 11:45 β€” πŸ‘ 0    πŸ” 0    πŸ’¬ 0    πŸ“Œ 0
Purrrfectly parallel, purrrfectly distributed (Charlie Gao, Posit) | posit::conf(2025)
YouTube video by Posit PBC Purrrfectly parallel, purrrfectly distributed (Charlie Gao, Posit) | posit::conf(2025)

Everyone can now view my posit::conf 2025 talk "purrrfectly parallel, purrrfectly distributed"!

{purrr} now lets you access the magic of {mirai} directly, as the modern way to make things faster through parallel computation in #rstats.

youtu.be/j1yHjMvbnQM?...

17.11.2025 11:30 β€” πŸ‘ 27    πŸ” 3    πŸ’¬ 1    πŸ“Œ 0
Preview
testthat 3.3.0 testthat 3.3.0 brings improved expectations with better error messages, new expectations for common testing patterns, and lifecycle changes including the removal of `local_mock()` and `with_mock()`. I...

testthat 3.3.0 out now! This is a massive release with tons of improvements including better failure messages, new expectations, improved snapshotting, new vignettes, and much much more: tidyverse.org/blog/2025/11... Post includes some thoughts on developing an #rstats package with Claude Code.

13.11.2025 17:24 β€” πŸ‘ 91    πŸ” 15    πŸ’¬ 1    πŸ“Œ 0

Yes, I can confirm ggplot2 has changed default binning. This difference is why it is listed as a breaking change.

13.11.2025 09:22 β€” πŸ‘ 1    πŸ” 0    πŸ’¬ 0    πŸ“Œ 0

Factors and strings are treated at discrete

12.11.2025 16:00 β€” πŸ‘ 2    πŸ” 0    πŸ’¬ 1    πŸ“Œ 0