---
title: "Introduction to ggtaichi"
author: |
Youzhi Yu
University of Chicago
date: "`r Sys.Date()`"
output: rmarkdown::html_vignette
vignette: >
%\VignetteIndexEntry{Introduction to ggtaichi}
%\VignetteEngine{knitr::rmarkdown}
%\VignetteEncoding{UTF-8}
---
```{r setup, include = FALSE}
knitr::opts_chunk$set(
collapse = TRUE,
comment = "#>",
warning = FALSE,
message = FALSE,
fig.width = 7,
fig.height = 7,
fig.align = "center",
dpi = 120
)
```
## Why taichi?
A heat map drawn with `ggplot2::geom_tile()` carries three dimensions of
information: the `x` position, the `y` position, and a single value mapped to
fill. That is plenty when there is one number per cell, but it forces you to
*facet* (or to draw two separate maps) the moment you want to compare two data
sources on the same footing.
`ggtaichi` removes that limitation by replacing each cell with a **taichi**
(yin-yang) diagram. The symbol is a circle split by an S-curve into two
interlocking "fish":
- the **yang** (light) fish is shaded by one data source, and
- the **yin** (dark) fish is shaded by the other.
Because both fish live in the same cell, a single `geom_taichi()` layer encodes
**four** dimensions at once: `x`, `y`, `yin`, and `yang`. The two sources keep
their own color scales and legends, so they can be read independently while
still being compared side by side. There are no decorative eyes or markers --
every drop of ink on the plot is mapped to data.
```{r}
library(ggtaichi)
library(ggplot2)
```
## Reading a single symbol
It is worth zooming in on one cell to see the anatomy of the glyph. The yang
fish (its bulb at the bottom) carries one source; the yin fish (its bulb at the
top) carries the other. Each half is filled by its own gradient, so a lighter or
darker shade is a smaller or larger value.
```{r, fig.width = 4.5, fig.height = 4.5}
one <- data.frame(x = 1, y = 1, google = 7, twitter = 3)
ggplot(one, aes(x, y)) +
geom_taichi(yin = twitter, yang = google) +
coord_fixed() +
theme_taichi()
```
Here the yang (red) fish reads `7` and the yin (grey) fish reads `3`; the deeper
the ink, the larger the number relative to the rest of the data.
## The example data
`ggtaichi` ships with the same data sets used by its foundational package
`ggDoubleHeat`. `pitts_tg` records the 30-week COVID-related Google and Twitter
incidence rates for 9 categories in the Pittsburgh Metropolitan Statistical
Area (MSA).
```{r}
head(pitts_tg)
```
`states_tg` is the larger sibling, repeating the same measurements across four
states, and `pitts_emojis` holds the most popular weekly emoji per category.
See `?pitts_tg`, `?states_tg`, and `?pitts_emojis` for the full descriptions.
## A first taichi grid
The two value columns are passed to the `yin` and `yang` arguments. Everything
else -- the `x`/`y` mapping, faceting, titles -- is plain `ggplot2`. The legend
titles default to the column names you supplied (`Twitter` and `Google` here).
```{r, fig.height = 6}
ggplot(pitts_tg, aes(x = week, y = category)) +
geom_taichi(yin = Twitter, yang = Google) +
theme_taichi() +
ggtitle("Pittsburgh Google & Twitter Incidence Rate (%)")
```
Each symbol stays round regardless of the panel's aspect ratio, so you do **not**
need `coord_fixed()`. The shape is sized in square units, like the radius of a
`grid::circleGrob()`.
## Fewer cells, bigger glyphs
Thirty weeks across nine categories is a lot of ink in one panel. When the goal
is to *read* individual symbols rather than scan an overall texture, subset the
data: fewer cells means each taichi is drawn larger.
```{r, fig.height = 8}
pitts_small <- subset(pitts_tg, week <= 6)
ggplot(pitts_small, aes(x = week, y = category)) +
geom_taichi(yin = Twitter, yang = Google) +
theme_taichi() +
ggtitle("The first six weeks, drawn large")
```
## Which source should be yin?
`yin` defaults to a grey (luminance) ramp and `yang` to a red ramp, echoing the
"ink and seal" look of a classic taichi. The choice is yours, but a useful rule
of thumb is to put the source you want to read as *intensity* on `yin` (the eye
reads darkness quickly) and the source you want to read as *warmth* on `yang`.
## Customizing the color scales
Each fish gets its own gradient. `yang_colors` and `yin_colors` accept any color
vector (usually hex codes), and `yang_name` / `yin_name` relabel the legends.
Any extra argument is forwarded to `ggplot2::scale_fill_gradientn()`, so you can,
for example, set common `limits` so both legends share a scale, or pass an
`na.value`.
```{r, fig.height = 8}
ggplot(pitts_small, aes(x = week, y = category)) +
geom_taichi(
yin = Twitter, yin_name = "Twitter (%)",
yin_colors = c("#deebf7", "#3182bd", "#08306b"),
yang = Google, yang_name = "Google (%)",
yang_colors = c("#fee6ce", "#e6550d", "#7f2704")
) +
theme_taichi()
```
## Removing the panel padding
`ggplot2` leaves a margin around discrete and continuous scales, which can make
a taichi grid look like it is floating. `remove_padding()` trims it; tell it
whether each axis is continuous (`"c"`) or discrete (`"d"`).
```{r, fig.height = 8}
ggplot(pitts_small, aes(x = week, y = category)) +
geom_taichi(yin = Twitter, yang = Google) +
remove_padding(x = "c", y = "d") +
theme_taichi()
```
## Comparing places with facets
Because `geom_taichi()` is an ordinary layer, faceting works out of the box. The
`states_tg` data set carries the same measurements across four states; pairing
two of them over a few weeks keeps every glyph large and legible.
```{r, fig.height = 8}
two_states <- subset(states_tg, state %in% c("New York", "Texas") & week <= 6)
ggplot(two_states, aes(x = week, y = category)) +
geom_taichi(yin = Twitter, yang = Google) +
facet_wrap(~ state, ncol = 1) +
remove_padding(x = "c", y = "d") +
theme_taichi() +
ggtitle("New York vs Texas, weeks 1-6")
```
## Theming
`theme_taichi()` is a light, off-white companion theme that bottoms the legends,
drops the panel grid and ticks, and emphasizes the axis labels. It is a normal
`ggplot2` theme, so you can override any element afterwards, or skip it entirely
and bring your own.
```{r, fig.height = 6}
ggplot(pitts_small, aes(x = week, y = category)) +
geom_taichi(yin = Twitter, yang = Google) +
theme_taichi() +
theme(plot.background = element_rect(fill = "white")) +
ggtitle("theme_taichi(), then tweaked")
```
## Acknowledgement
`ggtaichi` stands on the shoulders of the
[`ggDoubleHeat`](https://CRAN.R-project.org/package=ggDoubleHeat) package, which
pioneered the two-source "double" heat map through its `geom_heat_*()` family
and supplies the example data used throughout this vignette. Please cite it
alongside `ggtaichi`:
> Yu Y, Buskirk T (2025). *ggDoubleHeat: A Heatmap-Like Visualization Tool*.
> R package version 0.1.3. CRAN:
> , GitHub:
>