Sign in

Mwavu Kennedy

@mwavu.com
230 followers 147 following 144 posts

i write r for fun & profit. neovim, btw. arch, btw. site: mwavu.com

PostsRepliesMedia
Mwavu Kennedy @mwavu.com · 03/07/2026
financial times also has one of the coolest i've seen so far.
2135
Mwavu Kennedy @mwavu.com · 07/06/2026
010
Mwavu Kennedy @mwavu.com · 03/06/2026
> Anyone has an idea why? i do... claude is stupid & outdated.
110
Mwavu Kennedy @mwavu.com · 30/04/2026
i'm having a field day with the tidyverse today.
the "car sales man slaps roof of car" meme.

* slaps {tidyverse} *
this bad boy can fit so many R packages in it
0251
Mwavu Kennedy @mwavu.com · 30/04/2026
you guys work? i thought we were all doing side projects!
template of the meme "you guys are getting paid?"
020
Mwavu Kennedy @mwavu.com · 30/04/2026
installing the tidyverse just to feel something.
~/Projects ❯ R

R version 4.5.3 (2026-03-11) -- "Reassured Reassurer"
Copyright (C) 2026 The R Foundation for Statistical Computing
Platform: x86_64-pc-linux-gnu

R is free software and comes with ABSOLUTELY NO WARRANTY.
You are welcome to redistribute it under certain conditions.
Type 'license()' or 'licence()' for distribution details.

  Natural language support but running in an English locale

R is a collaborative project with many contributors.
Type 'contributors()' for more information and
'citation()' on how to cite R or R packages in publications.

Type 'demo()' for some demos, 'help()' for on-line help, or
'help.start()' for an HTML browser interface to help.
Type 'q()' to quit R.

> install.packages("tidyverse")
080
Mwavu Kennedy @mwavu.com · 20/04/2026
{hypertext} 1.2.0 is out on CRAN. we've added support for trailing commas in tags. quite a small feature but makes for great UX. check it out: github.com/sigflux/hype... #rstats
page <- function(...) {
  content <- tag_list(
    doctype(),
    tags$html(),
    tags$head(
      tags$meta(
        charset = "utf-8"
      )
    ),
    tags$body(
      tags$main(
        class = "main",
        ...,
      ),
    ),
  )

  render(content)
}

home_ui <- function() {
  content <- tags$div(
    tags$h3("hello, world"),
    tags$p("trailing commas, yeeey!"),
    tags$small("hypertext 1.2.0"),
  )

  page(content)
}
1133
Mwavu Kennedy @mwavu.com · 09/04/2026
#rstats
0120
Mwavu Kennedy @mwavu.com · 13/03/2026
anon: R is a terrible language and an absolute disaster. me: correct. anon: so you agree? me: completely. anon: then why do you use it? me: *shares attached screenshot* anon: *furiously typing... deleting... typing...* #rstats
 “There are only two kinds of languages: the ones people complain about and the ones nobody uses.”
― Bjarne Stroustrup, The C++ Programming Language
2447
Mwavu Kennedy @mwavu.com · 10/03/2026
{hypertext} 1.1.0 is out on CRAN. many new features, the most important is probably creation of custom tags via, well, `tag()`. github.com/sigflux/hype... #rstats
library(hypertext)

content <- tag(
  tag_name = "calcite-action-bar",
  layout = "horizontal"
)

render(content)
#> [1] "<calcite-action-bar layout=\"horizontal\"></calcite-action-bar>"
0112
Mwavu Kennedy @mwavu.com · 08/03/2026
i've spent the entire day trying to figure out why my server was sending escaped html to the frontend (needed the raw html). after hours of debugging, i've finally discovered the culprit... it was me. i escaped it :(
0171
Mwavu Kennedy @mwavu.com · 07/03/2026
010
Mwavu Kennedy @mwavu.com · 05/03/2026
all this can be avoided by being unemployed.
020
Mwavu Kennedy @mwavu.com · 03/03/2026
sometimes i sit and wonder whether partial matching was introduced as a real feature or as an accidental by-product. #rstats
1191
Mwavu Kennedy @mwavu.com · 03/03/2026
010
Mwavu Kennedy @mwavu.com · 01/03/2026
just realized LoTR has mount doom, and you said non-doom content.
030
Mwavu Kennedy @mwavu.com · 28/02/2026
#rstats
0523
Mwavu Kennedy @mwavu.com · 28/02/2026
{hypertext} is a DSL for building HTML in R. it's similar to {htmltools}, but with 2 deliberate differences: - it is *framework-agnostic* - it has *zero dependencies* we now have more web frameworks in R than ever before. {hypertext} works with all of them, and independently of them. #rstats
library(hypertext)

page <- tags$html(
  tags$head(
    tags$title("hypertext")
  ),
  tags$body(
    tags$h1("Hello"),
    tags$p(
      class = c("lead", "mb-2"),
      "Server-side HTML."
    ),
    tags$input(
      type = "text",
      placeholder = "enter your nickname"
    ),
    tags$button(
      "Click"
    )
  )
)

render(page)
0192
Mwavu Kennedy @mwavu.com · 21/02/2026
#rstats
4393
Mwavu Kennedy @mwavu.com · 06/02/2026
well...
010
Mwavu Kennedy @mwavu.com · 05/12/2025
{ambiorix} v2.2.2 is rolling out: cran.r-project.org/web/packages... you can now hand an endpoint a {mirai} and let it resolve when it feels like it.
library(ambiorix)
library(mirai)

daemons(2)

app <- Ambiorix$new()

#' Handle GET at '/now'
#'
#' @export
get_time_now <- function(req, res) {
  res$json(
    list(time = Sys.time())
  )
}

#' Handle GET at '/slow'
#'
#' @export
get_time_slow <- function(req, res) {
  mirai(
    .expr = {
      Sys.sleep(10)
      res$json(
        list(time = Sys.time())
      )
    },
    res = res
  )
}

app$get("/now", get_time_now)
app$get("/slow", get_time_slow)

app$start(port = 5000L)
020
Mwavu Kennedy @mwavu.com · 07/11/2025
you can just do things, btw.
010
Mwavu Kennedy @mwavu.com · 21/10/2025
you're to be feared.
010
Mwavu Kennedy @mwavu.com · 01/10/2025
so stoked about this caffeine chalice! thanks @posit.co @libbyheeren.bsky.social
110
Mwavu Kennedy @mwavu.com · 25/08/2025
comment annotations would serve you well. eg. # TODO: some plans for later # NOTE: this is a note pretty sure most IDEs would pick up on these:
# a normal comment
# just vibes, no urgency

# TODO: some plans for later
# future you will hate present you for this

# NOTE: explain edge cases & design choices
# "dear diary, here's why I did this dumb thing"

# WARNING: do not change this part of the code
# touch this and you summon production demons

# FIXME: this is a known bug
# duct tape, but digital

# BUG: another known bug
# congratulations, you found the landmine

# HACK: ugly/temporary workaround
# might need rethinking

# XXX: questionable or dangerous code
# works on my machine, breaks in prod

# OPTIMIZE: potential performance improvements
# could be more efficient
020
Mwavu Kennedy @mwavu.com · 21/08/2025
coincidentally, the catchphrase on my website is...
030
Mwavu Kennedy @mwavu.com · 14/07/2025
010
Mwavu Kennedy @mwavu.com · 04/05/2025
000
Mwavu Kennedy @mwavu.com · 25/04/2025
i'm with you on this one.
count_ones <- \(x, ...) {
  cols <- match.call(expand.dots = FALSE)[["..."]] |>
    vapply(FUN = deparse, FUN.VALUE = character(1))

  colSums(x[cols] == 1)
}
100
Mwavu Kennedy @mwavu.com · 21/04/2025
every visionary walks alone. van gogh had no buyers, tesla died broke, and now… this.
020
Mwavu Kennedy @mwavu.com · 13/04/2025
this one had me in the first half, ngl. apparently, R discards empty *formal* arguments. inspection via `browser()` shows that the call is f(a = 3, b = 2), meaning that after discarding of `a = ` & `b = `, 3 and 2 ended up being matched by position. haven't found any official docs on this though.
> f <- \(a = 1, b) {
  browser()
  b
}
> f(a = , 3, 2, b = )
Called from: f(a = , 3, 2, b = )
Browse[1]> match.call()
f(a = 3, b = 2)
110
Mwavu Kennedy @mwavu.com · 09/04/2025
070
Mwavu Kennedy @mwavu.com · 17/03/2025
i use {box}. that way, i can have files/functions with the same name but in different "R modules". helps a lot when building a large app, as file & function names rarely get long. plus explicit name imports. pure bliss! have a look at this example: github.com/ambiorix-web...
120
Mwavu Kennedy @mwavu.com · 01/12/2024
you can speed up the R version by a *huge* factor by iterating only on items present in both groups.
bench::mark(
  a = {
    g1 <- input$group1[input$group1 %in% input$group2] |> unique()
    g2 <- input$group2[input$group2 %in% g1]
    n <- sapply(g1, \(i) sum(i == g2))
    sum(g1 * n)
  },
  b = {
    sum(input$group1 * table(input$group2)[as.character(input$group1)], na.rm = TRUE)
  }
)

# # A tibble: 2 × 13
#   expression      min median `itr/sec` mem_alloc `gc/sec` n_itr  n_gc total_time
#   <bch:expr> <bch:tm> <bch:>     <dbl> <bch:byt>    <dbl> <int> <dbl>   <bch:tm>
# 1 a             122µs  129µs     7398.     123KB    37.5   3155    16      426ms
# 2 b             503µs  522µs     1843.     215KB     8.23   896     4      486ms
# # ℹ 4 more variables: result <list>, memory <list>, time <list>, gc <list>
010
Mwavu Kennedy @mwavu.com · 31/10/2024
apparently, `c()` does too! x <- c(5, 7, 11) y <- c(x) when will i learn R?
x <- c(5, 7, 11)
y <- c(x)

lobstr::obj_addr(x) # "0x63bb2e495cc8"
lobstr::obj_addr(y) # "0x63bb2e495c78"
100
Mwavu Kennedy @mwavu.com · 31/10/2024
well, copy & modify :) on a serious note though, `[` seems to make a deep copy: x <- c(5, 7, 11) y <- x[]
x <- c(5, 7, 11)
tracemem(x)
# [1] "<0x5ed28a507cc8>"

y <- x[] # deep copy
# tracemem[0x5ed28a507cc8 -> 0x5ed28a507c28]:

lobstr::obj_addr(x) # "0x5ed28a507cc8"
lobstr::obj_addr(y) # "0x5ed28a507c28"
121