---
title: "glyph vs ggplot2: Side-by-Side Comparison"
output: rmarkdown::html_vignette
vignette: >
  %\VignetteIndexEntry{glyph vs ggplot2: Side-by-Side Comparison}
  %\VignetteEngine{knitr::rmarkdown}
---

## 1. Basic Scatterplot

**ggplot2:**
```r
ggplot(mtcars, aes(x = wt, y = mpg, color = factor(cyl))) +
  geom_point(size = 3) +
  scale_color_brewer(palette = "Set2") +
  labs(
    title = "Motor Trend Cars",
    x = "Weight (1000 lbs)",
    y = "Miles per Gallon",
    color = "Cylinders"
  ) +
  theme_minimal()
```

**glyph:**
```r
glyph(mtcars, x = wt, y = mpg) |>
  mark_point(color = cyl, style = list(size = 6)) |>
  scale_color("Set2") |>
  scale("x", label = "Weight (1000 lbs)") |>
  scale("y", label = "Miles per Gallon") |>
  titles(title = "Motor Trend Cars") |>
  theme_tokens(preset = "minimal")
```

**What changed:** No `aes()`, no `factor()` coercion, no `+` operator.
Pipeline reads left-to-right with `|>`. Color scale is one function call.

---

## 2. Interactive Exploration

**ggplot2 + plotly:**
```r
library(plotly)

p <- ggplot(mtcars, aes(x = wt, y = mpg, color = factor(cyl),
                         text = paste("Car:", rownames(mtcars),
                                      "<br>MPG:", mpg,
                                      "<br>Weight:", wt))) +
  geom_point(size = 3)

ggplotly(p, tooltip = "text")
# Note: loses theme, some formatting; no brush-to-filter
```

**glyph:**
```r
glyph(mtcars, x = wt, y = mpg) |>
  mark_point(color = cyl) |>
  interact(
    tooltip = "Car: {.rownames}\nMPG: {mpg}\nWeight: {wt}",
    zoom = TRUE,
    brush = TRUE,
    hover = "enlarge"
  )
# Theme, formatting, all interactions preserved — no conversion step
```

**What changed:** No lossy ggplotly() conversion. Interactions are part
of the spec, not a post-hoc wrapper. Tooltip template is a simple string,
not a paste() call inside aes().

---

## 3. Animated Bar Chart

**ggplot2 + gganimate:**
```r
library(gganimate)

p <- ggplot(gapminder, aes(x = continent, y = lifeExp, fill = continent)) +
  geom_col(stat = "summary", fun = "mean") +
  transition_states(year, transition_length = 2, state_length = 1) +
  labs(title = "Year: {closest_state}") +
  theme_minimal() +
  enter_grow() +
  ease_aes("bounce-out")

animate(p, fps = 20, width = 600, height = 400)
# Renders to GIF (not interactive)
```

**glyph:**
```r
glyph(gapminder, x = continent, y = lifeExp) |>
  mark_bar() |>
  animate(by = year, transition = "morph", easing = "bounce") |>
  interact(tooltip = TRUE) |>
  titles(title = "Life Expectancy by Continent") |>
  theme_tokens(preset = "minimal")
# Renders as interactive HTML with playback controls
```

**What changed:** Animation is one function call in the pipeline, not a
separate package. Output is interactive HTML (play/pause/scrub), not a
static GIF. Tooltips work during animation.

---

## 4. Multi-Panel Dashboard

**ggplot2 + patchwork:**
```r
library(patchwork)

p1 <- ggplot(mtcars, aes(wt, mpg)) + geom_point() + theme_minimal()
p2 <- ggplot(mtcars, aes(hp, mpg)) + geom_point() + theme_minimal()
p3 <- ggplot(mtcars, aes(factor(cyl), mpg)) + geom_boxplot() + theme_minimal()

(p1 | p2) / p3 +
  plot_annotation(title = "Motor Trend Dashboard")
# No linked interactions between panels
```

**glyph:**
```r
p1 <- glyph(mtcars, x = wt, y = mpg) |>
  mark_point(color = cyl) |>
  interact(brush = TRUE)

p2 <- glyph(mtcars, x = hp, y = mpg) |>
  mark_point(color = cyl) |>
  interact(brush = TRUE)

p3 <- glyph(mtcars, x = cyl, y = mpg) |>
  mark_bar()

compose(p1, p2, p3,
        type = "wrap",
        linked_selections = TRUE,
        title = "Motor Trend Dashboard")
# Brushing in p1 highlights the same cars in p2 and p3
```

**What changed:** No extra package. Linked selections across panels
via `linked_selections = TRUE`. Brush in one panel cross-filters the others.

---

## 5. Marginal Distributions

**ggplot2 + ggExtra:**
```r
library(ggExtra)

p <- ggplot(mtcars, aes(wt, mpg, color = factor(cyl))) +
  geom_point() +
  theme_minimal()

ggMarginal(p, type = "histogram", groupColour = TRUE)
```

**glyph:**
```r
glyph(mtcars, x = wt, y = mpg) |>
  mark_point(color = cyl) |>
  marginals(x = "histogram", y = "density", size = 0.2)
```

**What changed:** Built-in. One function call. Size is configurable.

---

## 6. Dark Theme

**ggplot2:**
```r
ggplot(mtcars, aes(wt, mpg)) +
  geom_point(color = "#6ec6ff") +
  theme(
    plot.background = element_rect(fill = "#1a1a2e"),
    panel.background = element_rect(fill = "#1a1a2e"),
    panel.grid.major = element_line(color = "#2a2a4a"),
    panel.grid.minor = element_blank(),
    axis.text = element_text(color = "#e0e0e0"),
    axis.title = element_text(color = "#e0e0e0"),
    text = element_text(color = "#e0e0e0")
  )
# 9 lines of theme overrides
```

**glyph:**
```r
glyph(mtcars, x = wt, y = mpg) |>
  mark_point() |>
  theme_tokens(preset = "dark")
# 1 line. All contrast/grid/text colors auto-derived.
```

Or with custom colors:
```r
glyph(mtcars, x = wt, y = mpg) |>
  mark_point() |>
  theme_tokens(bg = "#1a1a2e")
  # fg, grid_color, accent all adapt automatically
```

---

## 7. Export Flexibility

**ggplot2:**
```r
ggsave("plot.png", width = 8, height = 6)   # static only
ggsave("plot.pdf", width = 8, height = 6)   # static only
ggsave("plot.svg", width = 8, height = 6)   # static only
# No interactive HTML export. No spec export.
```

**glyph:**
```r
spec <- glyph(mtcars, x = wt, y = mpg) |>
  mark_point() |>
  interact(tooltip = TRUE, zoom = TRUE)

export(spec, "plot.html")              # interactive HTML
export(spec, "plot.svg")               # static SVG
export(spec, "plot.json")             # raw spec (inspect/debug)
cat(to_vegalite(spec))                 # Vega-Lite JSON (use in Python/JS)
```

---

## Summary: When to Use Which

**Use ggplot2 when:**
- You need a specific extension (ggridges, ggalluvial, etc.)
- You're producing static plots for print/PDF
- You want maximum community support and StackOverflow answers
- Statistical transforms (smooth, density2d) are central to your workflow

**Use glyph when:**
- Interactivity is part of the deliverable (dashboards, reports, exploration)
- You want linked views without Shiny
- Animation is important (presentations, storytelling)
- You're working with large datasets (>10K points)
- You want a cleaner, more composable API
- You need to export specs to JavaScript (Vega-Lite, D3)
- Theme consistency across many plots matters (token system)
