## ----setup, include = FALSE---------------------------------------------------
knitr::opts_chunk$set(
  collapse  = TRUE,
  comment   = "#>",
  dev       = "ragg_png",
  dpi       = 300,
  fig.asp   = 0.618,
  fig.width = 6,
  fig.height = 3,
  fig.align = "center",
  out.width = "80%"
)

## ----setup-theme, warning=FALSE-----------------------------------------------
library(ggpointless)

# set consistent theme for all plots
cols <- c("#311dfc", "#a84dbd", "#d77e7b", "#f4ae1b")
theme_set(
  theme_minimal() + 
    theme(legend.position = "bottom") +
    theme(geom = element_geom(fill = cols[1])) +
    theme(palette.fill.discrete = c(cols[1], cols[3])) +
    theme(palette.colour.discrete = cols)
  )

## ----area-fade-economics------------------------------------------------------
ggplot(economics, aes(date, unemploy)) +
  geom_area_fade()

## ----area-fade-alpha, fig.height = 3------------------------------------------
ggplot(economics, aes(date, unemploy)) +
  geom_area_fade(alpha = 0.75, alpha_fade_to = 0.1)

## ----geom-area-fade-reverse, warning=FALSE------------------------------------
ggplot(economics, aes(date, unemploy)) +
  geom_area_fade(alpha = 0, alpha_fade_to = 1)

## ----area-fade-2d, fig.height = 3---------------------------------------------
set.seed(42)
ggplot(economics, aes(date, unemploy)) +
  geom_area_fade(aes(fill = uempmed), colour = cols[1]) +
  scale_fill_continuous(palette = scales::colour_ramp(cols))

## ----geom-area-fade-multiple-groups-basic, warning=FALSE----------------------
df1 <- data.frame(
  g = c("a", "a", "a", "b", "b", "b"),
  x = c(1, 3, 5, 2, 4, 6),
  y = c(2, 5, 1, 3, 6, 7)
)

ggplot(df1, aes(x, y, fill = g)) +
  geom_area_fade()

## ----geom-area-fade-global, warning=FALSE-------------------------------------
df_alpha_scope <- data.frame(
  g = c("a", "a", "a", "b", "b", "b"),
  x = c(1, 3, 5, 2, 4, 6),
  y = c(1, 2, 1, 9, 10, 8)
)
p <- ggplot(df_alpha_scope, aes(x, y, fill = g))
p + geom_area_fade(
  alpha_scope = "global", # default
  position = "identity"
)

## ----geom-area-fade-group, warning=FALSE--------------------------------------
p <- ggplot(df_alpha_scope, aes(x, y, fill = g))

# alpha_scope = "group": each group uses the alpha range independently
p + geom_area_fade(
  alpha_scope = "group", 
  position = "identity"
  )

## ----arch-basic, fig.height = 3-----------------------------------------------
ggplot(data.frame(x = 1:2, y = c(0, 0)), aes(x, y)) +
  geom_arch(arch_height = 0.6)

## ----stat-arch-compare, fig.height = 3.5--------------------------------------
ggplot(data.frame(x = c(0, 2), y = c(0, 0)), aes(x, y)) +
  stat_arch(arch_height = 0.5, aes(colour = "arch_height = 0.5")) +
  stat_arch(arch_height = 1.5, aes(colour = "arch_height = 1.5")) +
  stat_arch(arch_height = 3.0, aes(colour = "arch_height = 3"))

## ----rice-house, fig.height = 3-----------------------------------------------
rice_house <- data.frame(
  x = c(0, 1.5, 2.5, 3.5, 5),
  y = c(0, 1, 1, 1, 0)
)

ggplot(rice_house, aes(x, y)) +
  geom_arch(arch_height = 0.15, linewidth = 2, colour = "#333333") +
  geom_segment(aes(xend = x, yend = 0), colour = "#333333") +
  geom_hline(yintercept = 0, colour = "#4a7c59", linewidth = 3) +
  coord_equal() +
  theme_void() +
  labs(caption = "Rice House, Eltham (simplified catenary cross-section)")

## ----catenary-basic, fig.height = 3-------------------------------------------
set.seed(1)
ggplot(data.frame(x = 1:6, y = sample(6)), aes(x, y)) +
  geom_catenary() +
  geom_point(size = 3, colour = "#333333")

## ----catenary-chain-length, fig.height = 3------------------------------------
ggplot(data.frame(x = c(0, 1), y = c(1, 1)), aes(x, y)) +
  lapply(c(1.5, 1.75, 2), \(cl) {
    geom_catenary(chain_length = cl)
  }) +
  ylim(0, 1.05) +
  labs(title = "Increasing chain_length adds more sag")

## ----catenary-sag, fig.height = 3---------------------------------------------
df_sag <- data.frame(x = c(0, 2, 4, 6), y = c(1, 1, 1, 1))

ggplot(df_sag, aes(x, y)) +
  geom_catenary(sag = c(0.1, 0.5, 1.2)) +
  geom_point(size = 3, colour = "#333333") +
  labs(title = "sag = 0.1, 0.5, 1.2 (left to right)")

## ----catenary-sag-vs-chain-length, fig.height = 3-----------------------------
df_sag <- data.frame(x = c(0, 2, 4, 6), y = c(1, 1, 1, 1))

ggplot(df_sag, aes(x, y)) +
  geom_catenary(
    chain_length = c(2, NA, 3),
    sag = c(0.1, 0.5, NA)
  ) +
  geom_point(size = 3, colour = "#333333") +
  labs(title = "sag wins over chain_length") +
  ylim(c(-.25, 1))

## ----chaikin-basic, fig.height = 3--------------------------------------------
set.seed(42)
dat <- data.frame(x = seq.int(10), y = sample(15:30, 10))

ggplot(dat, aes(x, y)) +
  geom_line(linetype = "dashed", colour = "#333333") +
  geom_chaikin(colour = cols[1])

## ----chaikin-ratio, fig.height = 3--------------------------------------------
triangle <- data.frame(x = c(0, 0.5, 1), y = c(0, 1, 0))

ggplot(triangle, aes(x, y)) +
  geom_polygon(fill = NA, colour = "grey70", linetype = "dashed") +
  geom_chaikin(ratio = 0.10, mode = "closed", aes(colour = "ratio = 0.10")) +
  geom_chaikin(ratio = 0.25, mode = "closed", aes(colour = "ratio = 0.25")) +
  geom_chaikin(ratio = 0.50, mode = "closed", aes(colour = "ratio = 0.50")) +
  coord_equal()

## ----chaikin-iterations-gif, echo=FALSE, out.width="60%", eval=identical(Sys.getenv("IN_PKGDOWN"), "true")----
# knitr::include_graphics("../man/figures/chaikin_iterations.gif")

## ----chaikin-iterations-static, echo=FALSE, fig.height = 3, fig.align="center", eval=!identical(Sys.getenv("IN_PKGDOWN"), "true")----
n_pts   <- 5L
outer_r <- 1
inner_r <- 0.38
ang_out <- seq(pi / 2, pi / 2 + 2 * pi, length.out = n_pts + 1L)[seq_len(n_pts)]
ang_in  <- ang_out + pi / n_pts
star <- data.frame(
  x = c(rbind(outer_r * cos(ang_out), inner_r * cos(ang_in))),
  y = c(rbind(outer_r * sin(ang_out), inner_r * sin(ang_in)))
)

ggplot(star, aes(x, y)) +
  geom_polygon(
    fill = NA, colour = "#333333", linetype = "dotted", linewidth = 0.55
  ) +
  stat_chaikin(
    geom = "polygon", mode = "closed", iterations = 3,
    fill = "#311dfc", alpha = 0.20, colour = "#311dfc", linewidth = 0.8
  ) +
  coord_equal(clip = "off") +
  labs(x = NULL, y = NULL) +
  theme_minimal() +
  theme(
    panel.grid = element_line(linetype = "dotted"),
    axis.text  = element_blank(),
    axis.ticks = element_blank()
  )

## ----chaikin-polygon, fig.height = 3.5----------------------------------------
# An irregular hexagon
hex <- data.frame(
  x = c(0.0, 0.4, 1.0, 1.2, 0.9, 0.1),
  y = c(0.2, 1.0, 0.9, 0.3, -0.2, 0.0)
)

ggplot(hex, aes(x, y)) +
  geom_polygon(fill = "grey95", colour = "#333333", linetype = "dashed") +
  stat_chaikin(geom = "polygon", mode = "closed", fill = cols[1], colour = NA) +
  coord_equal() +
  labs(title = "Original polygon (dashed) with smoothed fill (purple)")

## ----fourier-harmonics, fig.height = 3.5--------------------------------------
set.seed(42)
n <- 150
df_f <- data.frame(
  x = seq(0, 2 * pi, length.out = n),
  y = sin(seq(0, 2 * pi, length.out = n)) +
    0.4 * sin(3 * seq(0, 2 * pi, length.out = n)) +
    rnorm(n, sd = 0.25)
)

ggplot(df_f, aes(x, y)) +
  geom_point(alpha = 0.25) +
  geom_fourier(aes(colour = "n_harmonics = 1"), n_harmonics = 1) +
  geom_fourier(aes(colour = "n_harmonics = 3"), n_harmonics = 3)

## ----fourier-detrend, fig.height = 3.5----------------------------------------
set.seed(3)
x_d <- seq(0, 4 * pi, length.out = 100)
df_d <- data.frame(
  x = x_d,
  y = sin(x_d) + x_d * 0.4 + rnorm(100, sd = 0.2)
)

ggplot(df_d, aes(x, y)) +
  geom_point(alpha = 0.35) +
  geom_fourier(aes(colour = "as is"),
    n_harmonics = 3
  ) +
  geom_fourier(
    aes(colour = "detrend = 'lm'"),
    n_harmonics = 3,
    detrend = "lm") +
  labs(
    title = "geom_fourier() w/wo detrending",
    x = NULL, y = NULL
  )

## ----fourier-dates-irregular-spacing, fig.height = 3.5------------------------
df_gap <- data.frame(
  x = c(1:10, 19:20),
  y = sin(seq_len(12))
  )
ggplot(df_gap, aes(x, y)) + 
  geom_fourier()

## ----lexis-basic, fig.height = 3.5--------------------------------------------
df_l <- data.frame(
  key  = c("A", "B", "B", "C", "D"),
  x    = c(0, 1, 6, 5, 6),
  xend = c(5, 4, 10, 8, 10)
)

p <- ggplot(df_l, aes(x = x, xend = xend, colour = key)) +
  coord_equal()

p + geom_lexis()

## ----lexis-gap, fig.height = 3.5----------------------------------------------
p + geom_lexis(gap_filler = FALSE)

## ----lexis-type, fig.height = 3.5---------------------------------------------
p +
  stat_lexis(
    aes(linetype = after_stat(type)),
    point_colour = "#333333",
    shape        = 21,
    fill         = "white",
    size         = 2.5,
    stroke       = 0.8
  ) +
  scale_linetype_identity()

## ----lexis-dates, fig.height = 3.5--------------------------------------------
df_dates <- data.frame(
  key   = c("A", "B"),
  start = c(2019, 2021),
  end   = c(2022, 2022)
)
df_dates[, c("start", "end")] <- lapply(
  df_dates[, c("start", "end")],
  \(i) as.Date(paste0(i, "-01-01"))
)

ggplot(df_dates, aes(x = start, xend = end, group = key)) +
  geom_lexis() +
  scale_y_continuous(
    breaks = 0:3 * 365.25,
    labels = \(i) paste0(floor(i / 365.25), " yr")
  ) +
  coord_fixed() +
  labs(y = "Duration")

## ----point-glow-basic, fig.height = 3.5---------------------------------------
# Basic usage
ggplot(mtcars, aes(wt, mpg, colour = factor(cyl))) +
   geom_point_glow()

## ----point-glow-overwrite-params, fig.height = 3.5----------------------------
# Customizing glow parameters (fixed for all points)
ggplot(mtcars, aes(wt, mpg, colour = factor(cyl))) +
  geom_point_glow(
    glow_alpha = 0.25,
    glow_colour = "#0833F5",
    glow_size = 5
    )

## ----big-dipper, fig.height = 5, fig.width = 7.5, echo = FALSE----------------
# source: https://de.wikipedia.org/wiki/Gro%C3%9Fer_B%C3%A4r#Sterne
# colours, coordinates all approximations of course
big_dipper <- data.frame(
  star = c(
    "Megrez",
    "Dubhe",
    "Merak",
    "Phecda",
    "Megrez",
    "Alioth",
    "Mizar",
    "Alkaid"
  ),
  ra_h = c(12.257, 11.062, 11.031, 11.897, 12.257, 12.900, 13.399, 13.792),
  dec_d = c(57.03, 61.75, 56.38, 53.70, 57.03, 55.96, 54.93, 49.31),
  mag = c(3.32, 1.81, 2.34, 2.41, 3.32, 1.77, 2.23, 1.86),
  colour = c("#CFDDFF", "#FFDBBF", "#C7D9FF", "#C8D9FF", "#CFDDFF", "#C7D9FF", "#CBDBFF", "#BAD0FF")
)

big_dipper$x <- -big_dipper$ra_h
big_dipper$y <- big_dipper$dec_d

# Linear size mapping: brighter (lower mag) → larger point
mag_to_size <- \(m) pmax(0.7, (5.5 - m) * 1.0)

ggplot(big_dipper, aes(x = x, y = y)) +
  geom_path(colour = "#F5F5F5", linewidth = 0.6, alpha = .6) +
  geom_point_glow(
    data = big_dipper[-1L, ], # don't plot Megrez a second time
    aes(x = -ra_h, y = dec_d, size = mag_to_size(mag), colour = colour,
        alpha = mag),
    shape = 8,
    glow_alpha = 0.75
  ) +
  scale_alpha_continuous(range = c(1, 0.4), guide = "none") +
  scale_size_identity() +
  scale_colour_identity() +
  geom_text(
    aes(x = -ra_h, y = dec_d, label = star),
    colour = "#bbccdd",
    vjust = -1.5,
    size = 2.5,
    check_overlap = TRUE
  ) +
  scale_x_continuous(
    breaks = seq(-14, -8, by = 1),
    labels = \(x) paste0(abs(x), "h")
  ) +
  scale_y_continuous(labels = \(x) paste0(x, "°")) +
  labs(
    title = "Big Dipper",
    x = NULL,
    y = NULL
  ) +
  coord_cartesian(clip = 'off') +
  theme(
    panel.background = element_rect(fill = grid::linearGradient(colours = c("#1D2180", "#081849")), colour = NA),
    plot.background = element_rect(fill = grid::linearGradient(colours = c("#1D2180", "#081849")), colour = NA),
    panel.grid = element_blank(),
    text = element_text(colour = "#344B73"),
    plot.title = element_text(size = 18, face = "bold")
  )

## ----big-dipper-code, eval = FALSE--------------------------------------------
# # source: https://de.wikipedia.org/wiki/Gro%C3%9Fer_B%C3%A4r#Sterne
# # colours, coordinates all approximations of course
# big_dipper <- data.frame(
#   star = c(
#     "Megrez",
#     "Dubhe",
#     "Merak",
#     "Phecda",
#     "Megrez",
#     "Alioth",
#     "Mizar",
#     "Alkaid"
#   ),
#   ra_h = c(12.257, 11.062, 11.031, 11.897, 12.257, 12.900, 13.399, 13.792),
#   dec_d = c(57.03, 61.75, 56.38, 53.70, 57.03, 55.96, 54.93, 49.31),
#   mag = c(3.32, 1.81, 2.34, 2.41, 3.32, 1.77, 2.23, 1.86),
#   colour = c("#CFDDFF", "#FFDBBF", "#C7D9FF", "#C8D9FF", "#CFDDFF", "#C7D9FF", "#CBDBFF", "#BAD0FF")
# )
# 
# big_dipper$x <- -big_dipper$ra_h
# big_dipper$y <- big_dipper$dec_d
# 
# # Linear size mapping: brighter (lower mag) → larger point
# mag_to_size <- \(m) pmax(0.7, (5.5 - m) * 1.0)
# 
# ggplot(big_dipper, aes(x = x, y = y)) +
#   geom_path(colour = "#F5F5F5", linewidth = 0.6, alpha = .6) +
#   geom_point_glow(
#     data = big_dipper[-1L, ], # don't plot Megrez a second time
#     aes(x = -ra_h, y = dec_d, size = mag_to_size(mag), colour = colour,
#         alpha = mag),
#     shape = 8,
#     glow_alpha = 0.75
#   ) +
#   scale_alpha_continuous(range = c(1, 0.4), guide = "none") +
#   scale_size_identity() +
#   scale_colour_identity() +
#   geom_text(
#     aes(x = -ra_h, y = dec_d, label = star),
#     colour = "#bbccdd",
#     vjust = -1.5,
#     size = 2.5,
#     check_overlap = TRUE
#   ) +
#   scale_x_continuous(
#     breaks = seq(-14, -8, by = 1),
#     labels = \(x) paste0(abs(x), "h")
#   ) +
#   scale_y_continuous(labels = \(x) paste0(x, "°")) +
#   labs(title = "Big Dipper", x = NULL, y = NULL) +
#   coord_cartesian(clip = 'off') +
#   theme(
#     panel.background = element_rect(fill = grid::linearGradient(colours = c("#1D2180", "#081849")), colour = NA),
#     plot.background = element_rect(fill = grid::linearGradient(colours = c("#1D2180", "#081849")), colour = NA),
#     panel.grid = element_blank(),
#     text = element_text(colour = "#344B73"),
#     plot.title = element_text(size = 18, face = "bold")
#   )

## ----pointless-basic, fig.height = 3------------------------------------------
x <- seq(-pi, pi, length.out = 100)
df1 <- data.frame(var1 = x, var2 = rowSums(outer(x, 1:5, \(x, y) sin(x * y))))

p <- ggplot(df1, aes(x = var1, y = var2)) +
  geom_line()

p + geom_pointless(location = "all", size = 3)

## ----pointless-colour, fig.height = 3-----------------------------------------
p +
  geom_pointless(
    aes(colour = after_stat(location)),
    location = "all",
    size = 3
  ) +
  theme(legend.position = "bottom")

## ----pointless-spiral, fig.height = 3.5, fig.show = 'hold'--------------------
x <- seq(5, -1, length.out = 1000) * pi
spiral <- data.frame(var1 = sin(x) * 1:1000, var2 = cos(x) * 1:1000)

p_spi <- ggplot(spiral) +
  geom_path() +
  coord_equal(xlim = c(-1000, 1000), ylim = c(-1000, 1000))

p_spi +
  aes(x = var1, y = var2) +
  geom_pointless(aes(colour = after_stat(location)), location = "all", size = 3) +
  labs(subtitle = "orientation = 'x'")

p_spi +
  aes(y = var1, x = var2) +
  geom_pointless(aes(colour = after_stat(location)), location = "all", size = 3) +
  labs(subtitle = "orientation = 'y'")

## ----pointless-order, fig.height = 3, fig.show = 'hold'-----------------------
df2 <- data.frame(x = 1:2, y = 1:2)
p2 <- ggplot(df2, aes(x, y)) +
  geom_path() +
  coord_equal()

p2 + geom_pointless(aes(colour = after_stat(location)),
  location = c("first", "last", "minimum", "maximum"), size = 4
) +
  labs(subtitle = "first on top")

p2 + geom_pointless(aes(colour = after_stat(location)),
  location = c("maximum", "minimum", "last", "first"), size = 4
) +
  labs(subtitle = "maximum on top")

## ----pointless-facets, fig.height = 7-----------------------------------------
ggplot(
  subset(economics_long, variable %in% c("psavert", "unemploy")),
  aes(x = date, y = value)
) +
  geom_line(colour = "#333333") +
  geom_pointless(
    aes(colour = after_stat(location)),
    location = c("minimum", "maximum"),
    size = 3
  ) +
  stat_pointless(
    geom = "text",
    aes(label = after_stat(y)),
    location = c("minimum", "maximum"),
    hjust = -.55) +
  facet_wrap(vars(variable), ncol = 1, scales = "free_y") +
  theme(legend.position = "bottom") +
  labs(x = NULL, y = NULL, colour = NULL)

## ----pointless-hline, fig.height = 3------------------------------------------
set.seed(42)
df3 <- data.frame(x = 1:10, y = sample(10))

ggplot(df3, aes(x, y)) +
  geom_line() +
  stat_pointless(
    aes(yintercept = y, colour = after_stat(location)),
    location = c("minimum", "maximum"),
    geom = "hline"
  ) +
  theme(legend.position = "bottom")

