RSSAmplifier

Blog

Home on Nan Xiao | 肖楠

Recent content in Home on Nan Xiao | 肖楠

nanx.meRSS feed ↗125 posts

Latest posts

Żmij for R: Floating-point to string conversion with round-trip guarantees

Photo by Claire Satera. Stylized with Paper Shaders halftone dots filter. I’m glad to share that zmij is now on CRAN. zmij converts doubles to decimal strings and back, using the fewest digits needed to recover the original values. It brings Victor Zverovich’s zmij algorithm to R, via David Tolnay’s Rust zmij port, wrapped in a vectorized interface with extendr.
You can install it from CRAN…

Introducing ggsci for Rust

Photo by Rémi Müller. Welcome to the latest post of the “Introducing X for Y” series.
Today I’m happy to share that ggsci is now available for Rust. You can add the crates to your Rust project with Cargo:
cargo add ggsci cargo add ggsci-ratatui cargo add ggsci-ggsql ggsci for R started ten years ago as a small collection of color palettes inspired by scientific journals and science…

Building a Homebrew tap to distribute my software

TL;DR: I built a Homebrew tap so you can install my fonts and CLI tools with a single brew install: https://github.com/nanxstats/homebrew-tap
I can’t find a good photo of beer tap so here is a kitchen tap instead.
Photo by Clay Banks. Until this week, I distributed my software the artisanal way: command line tools on PyPI and crates.io, fonts as zip files attached to GitHub releases. This…

Introducing bisectrunk: Parallel Git bisection for real-world regressions

The Broad, Los Angeles. Photo by Logan DeBorde. I’m delighted to announce the first public release of bisectrunk, a Rust CLI for parallel Git bisection of real-world software regressions.
You give it a known-good revision, a known-bad revision, and a few shell hooks that describe how your ecosystem installs and tests a commit. It then finds the commit that changed the result by evaluating…

Two small Python automation tools: asciilint and playwright-byob

Bright sunroom with plants and dining table. Photo by Clay Banks. In the past week, besides fully indulging myself in the food scene and outdoor activities of the SF Bay Area, I started building a few new personal automation and developer tooling projects. This post shares two of them: asciilint checks that your text files contain only the characters you want, and playwright-byob lets Playwright…

Anthrosevka Mono: Custom Iosevka build inspired by Anthropic Mono

I’m happy to share Anthrosevka Mono, a custom build of Iosevka inspired by the look and feel of Anthropic Mono. Prebuilt TTFs are available from the GitHub releases, and there is a microsite with specimen and code samples if you’d like to see it first.
This is the 4th entry in my coding font series, after DM Mono, Noto Sans Mono, and Paper Mono. The first three were all Fira Code ligatures…

ggsci 5.0.0 and py-ggsci 2.0.0: Generative Color Scales from Gephi

San Francisco 1.4. Photo by Pine Watt. After the last major version update in September 2025, I am happy to announce the release of ggsci 5.0.0 and ggsci for Python 2.0.0.
You can install the R package ggsci from CRAN:
install.packages("ggsci") And install the Python package from PyPI:
pip install ggsci What’s new Every color palette in ggsci until now has been a fixed list: someone…

Paper Mono with Fira Code ligatures

TL;DR: This is the third entry in the ligaturized font series, after DM Mono and Noto Sans Mono. This time it’s Paper Mono, patched with ligatures and a slashed zero promoted to default. Download from GitHub: nanxstats/paper-mono-ligaturized.
Liga Paper Mono in Ghostty, configured with adjust-cell-height = 8. Why Paper Mono Paper Mono is built by Paper and released under the SIL Open Font…

Why AI Feels Useless at Work

My father worked at a local branch of a railway company in his entire professional career. For a bureaucratic institution, it adopted new technology surprisingly fast. Or, more precisely, it was fast at buying the machines.
I remember those unofficial “take your child to work” days in the 1990s. Windows 3.1 was already out, so I could open Paintbrush, draw the nine (now eight) planets of our…

Becoming a Vibe Maintainer

Back in 2018, I started awesome-shiny-extensions, a curated list of Shiny extension packages in R (and now +Python). What began as a small collection of around 130 packages has grown into something much bigger than I expected: nearly 500 packages and 1.6k GitHub stars. But I will be honest: for the last couple of years, I have been what you might call “vibe maintaining” this list. I update it when…

Intellectual Minimalism

Over the weekend, I gave this site a new look. The Hugo theme has been migrated from Bootstrap to Tailwind CSS, but honestly, the framework change was the least interesting part. The interesting part was the excuse it gave me to rethink what a personal site should feel like in the age of intelligence abundance.
A wall with dried flowers and a straw hat. Photo by Olivie Strauss. What do I want…

Noto Sans Mono with Fira Code ligatures

Following my ligaturized DM Mono project, I’ve applied the same idea to Noto Sans Mono. You can download it from GitHub: nanxstats/noto-sans-mono-ligaturized.
Liga Noto Sans Mono in action: Running brew info in Ghostty. Theme: Dracula+. Why Noto Sans Mono? Noto Sans Mono is designed by Steve Matteson and is the monospaced member of the Noto type family. Its design is closely related to Open…

Introducing pytest-r-snapshot: Verifying Python code against R outputs at scale

An earthy, minimalist display blending textured art with dried and fresh botanicals.
Photo by Toa Heftiba. First package in the new year: I’m glad to announce pytest-r-snapshot, a pytest plugin for snapshot testing Python code against reference outputs generated by R.
You can install it from PyPI:
pip install pytest-r-snapshot If your project uses uv, add it as a development…

revdeprun 2.1.0: hunting bottlenecks and a new speedrun record

A race car pit crew in action during a pit stop. Photo by Paul Krüger. I’m excited to announce revdeprun 2.1.0, a major update to my Rust CLI tool for automating R package reverse dependency checks. This release is really two updates in one: version 2.0.0 accelerated dependency installation, while 2.1.0 addressed two more bottlenecks I discovered during testing. The combined result is a much…

DM Mono with Fira Code ligatures

I’ve created a ligaturized version of DM Mono by adding Fira Code ligatures. You can download it from GitHub: https://github.com/nanxstats/dm-mono-ligaturized.
Ligaturized DM Mono in action: Running Homebrew in Ghostty. Theme: Dracula+. Why ligatures? I’ll confess: I can’t start real work until I’ve found a coding font that fits the vibe of the day. My dotfiles are fairly basic, but they…

Reverse dependency check speedrun: a data.table case study

Monument Valley Navajo Tribal Park. Photo by Elvis Liang. A week ago, I announced revdeprun, a Rust CLI tool for automating R package reverse dependency checks. Since then, I have been iterating rapidly: 16 crates.io releases in a week! These updates focused on both correctness and speed. The tool has evolved from its initial v0.1.0 to v1.4.2, and the workflow now leverages pak for dependency…

revdeprun: Rust CLI for R package reverse dependency check automation

Smoke and speed: a race car mid-drift on the track. Photo by Jack Stapleton. Update (2025-10-31): revdeprun 1.0.0 switched to using a custom workflow to pre-install binary dependencies for checking reverse dependencies, and run parallel checks using xfun::rev_check(). This significantly improves performance and reliability. Read the release notes here. This post has been updated to reflect these…

ggsci 4.0.0: 400+ new color palettes

Cozy autumn vibes: a warm drink, a good book, and colorful leaves. Photo by Alisa Anton. After the last update in June 2024, I am excited to announce the release of ggsci 4.0.0 and ggsci for Python 1.0.0. You can install the R package ggsci from CRAN:
install.packages("ggsci") And install the Python package from PyPI:
pip install ggsci This update brings over 400 new discrete color…

Introducing py-ggsci: ggsci color palettes for plotnine in Python

Cliff Walk at Pourville (1882) by Claude Monet: two women on a grassy cliff above the sea under a bright sky. Public domain. Source: Art Institute of Chicago. I’m thrilled to announce the release of py-ggsci, a Python package that brings the popular ggsci color palettes from R’s ggplot2 ecosystem to Python’s plotnine library.
You can install py-ggsci from PyPI:
pip install ggsci Here is a…

The trash can has become the trashed can

A Vanitas Still Life with a Flag, Candlestick, Musical Instruments, Books, Writing Paraphernalia, Globes, and Hourglass, 1662. Edwaert Collier (Dutch, 1642–1708).
Scan from the Art Institute of Chicago. I have posted exclusively technical content on this blog for the past five years. Today, I want to write something different.
I have been using a 45-liter step trash can with a soft-close…

Markdown Stupefy: Tidy AI Text in VS Code

The extension name was inspired by the “stupefy mode” described in the SmartyPants project written by John Gruber, the creator of Markdown. If you copy AI responses into Markdown, you will often get curly quotes, em dashes, emojis, and other smart punctuation. They look fine, but they are Unicode characters that can trip linters and clutter diffs. So I built a tiny tool to fix that.
Automate…

Refactoring the GPU Selector App with Claude Code: A Vibe Coding Experiment

Desk setup with plants. Photo by Amari James. In January 2023, I built a basic, interactive deep learning GPU selector app inspired by Tim Dettmers’ popular guide. The original project was a pure HTML + JavaScript + CSS “vibe coding” experiment, driven by chat with GPT-3.5, which was the SOTA at the time. While the core logic worked, I did not focus much on its UI or UX.
Now, two and a half…

My First PyCon Experience

A flamingo peeking through the plants. National Aviary, Pittsburgh, PA. Photo by Adam Custer. I attended PyCon US 2025 in Pittsburgh, Pennsylvania from May 16–18, 2025. As my first Python conference, I wanted to document the most interesting things I learned.
Why a statistician goes to PyCon? It might seem odd for a statistician to focus on any particular programming language. But I’m not your…

pkgdown.offline: Build pkgdown websites without an internet connection

On the grid but off the line. Logo font: Founders Grotesk Condensed Semibold. I’m pleased to announce that the R package pkgdown.offline is now available on CRAN. You can install it with:
install.packages("pkgdown.offline") pkgdown.offline enables you to build pkgdown websites in environments without internet access, such as private, restricted development workflows or CI/CD pipelines. It…

Customizing Inter with alternative optical sizing presets

A cylinder casting a circular and rectangular shadow on two perpendicular planes, showing how perspective shapes interpretation of a single form. 3D render by Daniels Joffe. Since its open source release in 2017, Inter has become a widely adopted sans-serif font, especially popular for web content and user interfaces that benefit from a clean, neo-grotesque style. Thoughtful glyph redesigns in…

Optimize R foreach loops for parallelism: avoid the .combine argument

Cute boat in a glass bottle. Art generated by FLUX.1 [dev] + cozy-book-800 LoRA adapter. The benchmarking script used in this post is available as a GitHub Gist.
This post recommends avoiding the use of foreach(.combine = 'rbind') in parallel loops in R. Instead, manually combine the results after the foreach() call using functions like data.table::rbindlist() or…

R packages using Rust

TL;DR: I’m curating a list of CRAN R packages that use Rust: nanxstats/r-rust-pkgs.
Dirt bike. Photo by POWERING OFFROAD. Rust in R packages Rust has been the most admired programming language for nearly a decade. CRAN, the largest public repository for R packages, has also supported integrating Rust in R packages for several years. What’s the magic behind the language?
To me, Rust is a…

Introducing rtflite for Python

Touring in the clouds. Photo by Clement Delhaye. This is a guest post generously contributed by Yilong Zhang, a biostatistician at Meta.
It is my pleasure to introduce rtflite, a new Python package for generating RTF documents. A preview version is now available on PyPI. You can install it with:
pip install rtflite The ultimate goal of rtflite is to provide a lightweight solution for…

Prevent RStudio 2024.12.0 from adding ProjectID to .Rproj files

Git diff showing the ProjectID field added by RStudio 2024.12.0.
Terminal: Ghostty. Theme: Dracula+. Font family: Iosevka Term. Update (2025-02-13): The issue still exists in RStudio 2024.12.1. The fix still applies.
Update (2025-03-05): The issue has been fixed in RStudio >= 2025.04.0+323.
TL;DR: The fix The following script detects newly added ProjectID lines in .Rproj files using…

Introducing pkglite for Python

Les Menuires, France. Photo by Yann Allegre. I am pleased to introduce pkglite for Python, now available on PyPI. pkglite for Python provides a minimalist framework for packing source packages written in any programming language into a text file and restoring them to their original directory structure. You can install it with:
pip install pkglite For installation as a global command-line tool,…

Customize testthat snapshot directory with monkey patching

Memories instant photo. Photo by Kelly Sikkema. Problem Snapshot testing has been supported in testthat since testthat 3.0.0. By default, snapshot files are saved to a hardcoded directory:
tests/testthat/_snaps/ Unfortunately, testthat does not provide a public API to customize this directory. This question has been raised in issues like r-lib/testthat#1623, suggesting that customizing the…

Skip RStudio splash screen

Skating at Venice Beach, Los Angeles. Photo by Josh Hild. Update (2025-05-05): RStudio release planned for August 2025 will include a global option to turn off the splash screen and support click-to-close behavior.
Starting with RStudio IDE version 2024.12.0+467, a redesigned splash screen replaces the previous app logo. This change was introduced in rstudio/rstudio#15347 and it looks like…

tinyvdiff: Minimalist visual regression testing plugin for pytest

Hummingbirds. Photo by Zdeněk Macháček. I’m delighted to announce my second Python package, tinyvdiff, now available on PyPI. It offers a lightweight pytest plugin for detecting appearance changes in visual content, such as figures or documents. You can install it with:
pip install tinyvdiff Setup and usage Here is an example test for matplotlib graphics, from the tinyvdiff demo…

tinytopics: GPU-accelerated topic modeling via constrained neural Poisson NMF

Downhill mountain biking. Photo by Tim Foster. I’m excited to share that my first Python package, tinytopics, is now available on PyPI. You can install it using
pip install tinytopics tinytopics is a minimalist solution designed to scale up topic modeling tasks on CPUs and GPUs using PyTorch.
Motivation Fitting topic models at scale using classical algorithms on CPUs can be slow.…

FLUX.1 + LoRA for styled image generation

Technical line drawing generated by Flux1.dev + LoRA adapter.
Prompt: techlinedrawing, a drawing of a glass-heavy, modern architecture that Californian venture capital firms like, with fine details and mountains in the back, white background. Besides playing the Elden Ring: Shadow of the Erdtree DLC and Black Myth: Wukong on my gaming rig, I’ve also been playing with open weights generative AI…

Group sequential trials in industry: a 30-year perspective

Photo by Estée Janssens. Update (May 11, 2025): The paper discussed in this post has been selected as one of the recipients of the 2025 Best Paper Award from Statistics in Biopharmaceutical Research (SBR)! It is a wonderful honor to see our work recognized by the journal.
I’m delighted to share that our paper, Some Group Sequential Trials From Industry Over the Last 30 Years, has been…

R command-line tool paths on Windows

Mirror House. Photo by Karsten Winegeart. I’m glad to share a new repository that documents the essential R command-line tool paths on Windows: https://github.com/nanxstats/r-windows-paths.
Motivation As an R developer, I frequently set up new development and testing environments for my R packages on Windows. This process often involves installing several command-line tools alongside R,…

ssw is on CRAN

Cape Cod sand dunes on a cloudy day. Photo by Nicholas Bartos. I’m excited to share that my R package ssw is now available on CRAN. This package began as a weekend project in 2020. ssw offers an R interface for SSW (Zhao et al. 2013), a high-performance C/C++ implementation of the Smith-Waterman algorithm for sequence alignment using SIMD.
You can install ssw from CRAN…

ggsci 3.2.0: new color palettes from Observable, Bootstrap, and Tailwind CSS

Villa in Zurich, perspective view. From “Moderne Architektur” (Modern Architecture), edited by Lambert & Stahl, Stuttgart, 1891. Scan from Europeana. I am delighted to announce the release of ggsci 3.2.0. The R package ggsci was first released in 2016. It offers a range of ggplot2 color scales drawn from various sources, including scientific publications, data visualization tools, sci-fi movies,…

You should (maybe) enable font ligatures when building with GPT models

Parts of a typewriter. Photo by Florian Klauer. The token <|endoftext|> is a special token used as a document separator for OpenAI GPT models. It has become quite prevalent if you look closely:&#xA;It has been used since GPT-2 and remains present in the OpenAI API for their latest models. Their tokenizer package, tiktoken, includes logic to process text with these special tokens. The markup <| and…

ggsci 3.1.0, ggsurvfit example, and reverse dependency check

Photo by Elena Mozhvilo. I am excited to announce the release of ggsci 3.1.0. ggsci is an R package that provides a collection of color palettes inspired by colors used in scientific journals, data visualization libraries, science fiction movies, and TV shows.&#xA;To install ggsci from CRAN, run:&#xA;install.packages("ggsci") This release introduces a new color scale and brings documentation…

msaenet 3.1.2 and a sparse survival modeling example

Father-Son Tennis. Photo by Lucas Davies. I’m pleased to announce that msaenet 3.1.2 is now available on CRAN.&#xA;You can install msaenet with:&#xA;install.packages("msaenet") If you frequently build sparse linear models, msaenet can help you generate more parsimonious solutions with adaptive estimations. It supports any number of adaptive estimation steps, flexible initialization methods,…

stackgbm is on CRAN

A group of sheep on Faroe Islands. Photo by Dylan Shaw. I’m happy to announce that stackgbm, a minimalist R package for tree model stacking, is now on CRAN. Model stacking is an ensemble learning method that combines the predictions from multiple base learners to improve overall performance. stackgbm makes it easy to stack gradient boosting decision tree (GBDT) models, which are particularly…

R Package Release Notes: ggsci, protr, and msaenet (Spring 2024)

Cute market in Rome, Italy. Photo by Mark Pecar. Maintaining R packages is a significant time and effort commitment. The Releasing to CRAN chapter of the R Packages book provides an excellent overview of the many responsibilities package authors face. Henrik’s CRANhaven also helps me appreciate the efforts made by both CRAN maintainers and package maintainers to keep a consistent, high standard on…

Prompt LLMs with R Package Source Code Using pkglite

Illustration from Google DeepMind. Artist: Martina Stiftinger. Sometimes, large language models (LLMs) answer coding questions by making up software behaviors or APIs that don’t exist. A simple but effective strategy to minimize such hallucination problems is to feed the exact, complete source code as context in the prompt. For code organized in R packages, it is tedious to copy the file contents…

Use STIX Fonts in R Markdown and Quarto for Readability

Seashore with Shipwreck by Moonlight by Caspar David Friedrich. I have been playing a lot of Elden Ring lately. After investing 200 (!) hours into it, I learned three valuable lessons:&#xA;Life is hard. Something that seems unachievable today doesn’t mean it will be tomorrow. Explore, learn, practice, and with efforts, and perhaps a little luck, suddenly, you’ve done it. Life is unfair. You can…

protr 1.7-0

3D render from Google DeepMind. Artist: Wes Cockx. I am glad to announce the release of protr 1.7-0. Install it from CRAN with:&#xA;install.packages("protr") You can also install it from conda-forge in Python.&#xA;First released in 2012, protr was my very first open source R package. The package generates representations for protein sequences such as numerical features and similarity measures.…

9 Questions About Adaptive Design

Muir Woods trails. Photo by Caleb Jones. For someone who has worked in the industry for years, one thing I miss about school is the Socratic method of teaching used by some professors. It involves asking and answering questions to encourage critical thinking. By engaging in thoughtful Q&A sessions, I often find myself understanding the core elements of complex topics better compared to reading…

Base R Shortcuts: A Repository of Efficient Base R Coding Patterns

TL;DR: Please help me extend this GitHub repo by adding your own base R programming idioms: https://github.com/nanxstats/r-base-shortcuts.&#xA;Snowboarder on a cloudy hill. Photo by Boba Jovanovic. For a long time, I’ve told people that I am not an R expert. I don’t know too much about R. I just happen to write software that encounters the least resistance when implemented in R. I’m shy. I’d…

Create Engaging Word Cloud Visualizations from Your Research

Many outstanding researchers and labs have created visualizations of their research using word clouds. In this post, I present a simple, automated “paper2wordcloud” workflow to create eye-catching word cloud visualizations. It combines the efficiency of automation with the power of human intuition and aesthetic sense. The figure below was created using my published papers.&#xA;A word cloud…