## ----setup, include = FALSE---------------------------------------------------
knitr::opts_chunk$set(
  collapse = TRUE,
  comment = "##",
  warning = FALSE,
  message = FALSE,
  fig.width = 7,
  fig.height = 5
)
library(HistData)
library(ggplot2)

## ----arbuthnot-duplicate------------------------------------------------------
data(Arbuthnot)
Arbuthnot$Christenings <- Arbuthnot$Males + Arbuthnot$Females
Arbuthnot[Arbuthnot$Year %in% c(1674, 1704),
          c("Year", "Males", "Females", "Christenings", "Ratio")]

## ----arbuthnot-plot-----------------------------------------------------------
copy_level <- Arbuthnot$Christenings[Arbuthnot$Year == 1704]

ggplot(Arbuthnot, aes(x = Year, y = Christenings)) +
  geom_line(color = "grey50") +
  geom_point(color = "grey50") +
  geom_hline(yintercept = copy_level, linetype = "dotted", color = "black") +
  annotate(
    "segment", x = 1677, xend = 1701, y = copy_level, yend = copy_level,
    color = "darkred", linewidth = 1.3,
    arrow = arrow(length = unit(0.3, "cm"), type = "closed")
  ) +
  geom_point(
    data = subset(Arbuthnot, Year %in% c(1674, 1704)),
    color = "firebrick", size = 4
  ) +
  labs(
    title = "Arbuthnot's annual christenings in London, 1629-1710",
    subtitle = "1674 and 1704 (red) are identical -- likely a copying error",
    y = "Christenings (Males + Females)"
  ) +
  theme_minimal()

## ----minard-ggplot, fig.height = 3.5------------------------------------------
data(Minard.cities); data(Minard.troops)

ggplot(Minard.troops, aes(x = long, y = lat)) +
  geom_path(aes(linewidth = survivors, colour = direction, group = group),
            lineend = "round") +
  scale_linewidth(range = c(0.5, 15), guide = "none") +
  scale_colour_manual(values = c(A = "grey50", R = "firebrick"), guide = "none") +
  geom_point(data = Minard.cities, size = 1.2) +
  geom_text(data = Minard.cities, aes(label = city), vjust = 1.5, hjust = 0.5, size = 3) +
  labs(title = "Napoleon's Russian campaign of 1812", x = NULL, y = NULL) +
  theme_minimal() +
  theme(axis.text = element_blank(), panel.grid = element_blank())

## ----perozzo-setup------------------------------------------------------------
data(Perozzo)
Pmat <- xtabs(Survivors ~ Year + Age, data = Perozzo)
years <- as.numeric(rownames(Pmat))
ages  <- as.numeric(colnames(Pmat))

## ----perozzo-base, fig.height = 5---------------------------------------------
ages_rev <- -rev(ages)
Pmat_rev <- Pmat[, rev(seq_along(ages))]
persp(years, ages_rev, Pmat_rev,
      xlab = "Year", ylab = "Age", zlab = "Survivors",
      theta = 0, phi = 25, expand = 0.6,
      col = adjustcolor("lightblue", alpha.f = 0.5), shade = 0.5)

## ----perozzo-enhanced, fig.height = 6-----------------------------------------
colnames(Pmat_rev) <- as.character(ages_rev)  # match column names to ages_rev's sign flip

# re-angled to bring the Age = 0 "wall" of large young-survivor counts forward
pmat <- persp(years, ages_rev, Pmat_rev,
      xlab = "Year", ylab = "Age", zlab = "Survivors",
      theta = -30, phi = 20, expand = 0.6, r = 4,
      col = adjustcolor("lightblue", alpha.f = 0.4), shade = 0.5)

# red: highlight both cross-section families -- Survivors-by-Age at each Year,
# and Survivors-by-Year at each Age -- every 25 years/years-of-age
hi_years <- years[years %% 25 == 0]
for (yr in hi_years) {
  z <- Pmat_rev[as.character(yr), ]
  lines(trans3d(rep(yr, length(ages_rev)), ages_rev, z, pmat), col = "red", lwd = 2)
}
hi_ages <- ages[ages %% 25 == 0]
for (ag in hi_ages) {
  z <- Pmat_rev[, as.character(-ag)]
  lines(trans3d(years, rep(-ag, length(years)), z, pmat), col = "red", lwd = 2)
}

# blue: birth-cohort diagonals -- Year = birth year + Age -- every 25 years,
# starting from the Age = 0 edge (cohorts born during the observation window)
# and the Year = 1750 edge (cohorts already alive when it starts)
cohort_starts <- rbind(
  data.frame(year0 = years[years %% 25 == 0], age0 = 0),
  data.frame(year0 = 1750, age0 = ages[ages %% 25 == 0 & ages > 0])
)
for (i in seq_len(nrow(cohort_starts))) {
  b  <- cohort_starts$year0[i]
  a0 <- cohort_starts$age0[i]
  k  <- 0:((100 - a0) / 5)
  Y  <- b + 5 * k
  A  <- a0 + 5 * k
  keep <- Y >= min(years) & Y <= max(years) & A <= 100
  Y <- Y[keep]; A <- A[keep]
  if (length(Y) < 2) next
  z <- mapply(function(y, a) Pmat[as.character(y), as.character(a)], Y, A)
  lines(trans3d(Y, -A, z, pmat), col = "blue", lwd = 2)
}

## ----perozzo-ggplot-contour---------------------------------------------------
ggplot(Perozzo, aes(x = Year, y = Age, z = Survivors)) +
  geom_raster(aes(fill = Survivors)) +
  geom_contour(color = "white", alpha = 0.6) +
  scale_fill_distiller(palette = "Blues", direction = 1) +
  scale_y_reverse() +
  labs(title = "Perozzo's survivorship grid, as a heatmap") +
  theme_minimal()

## ----perozzo-isometric--------------------------------------------------------
shear <- 0.6   # horizontal points per year of age; tune to taste
lift  <- 400   # vertical Survivors-units per year of age

Perozzo_iso <- transform(Perozzo,
  x_iso = Year + shear * Age,
  y_iso = Survivors + lift * Age
)

ggplot(Perozzo_iso, aes(x = x_iso, y = y_iso, group = Age, color = Age)) +
  geom_line() +
  scale_color_distiller(palette = "Blues", direction = 1) +
  labs(
    title = "Perozzo's stereogram as a 2D isometric shear",
    x = "Year (sheared by Age)", y = "Survivors (lifted by Age)"
  ) +
  theme_minimal() +
  theme(axis.text.x = element_blank(), axis.text.y = element_blank())

## ----perozzo-plotly-----------------------------------------------------------
library(plotly)
plot_ly(x = ~years, y = ~ages, z = ~Pmat, type = "surface") |>
  layout(scene = list(
    xaxis = list(title = "Year"),
    yaxis = list(title = "Age"),
    zaxis = list(title = "Survivors")
  ))

## ----snow-density-------------------------------------------------------------
data(Snow.deaths); data(Snow.pumps); data(Snow.streets)

ggplot(Snow.deaths, aes(x = x, y = y)) +
  geom_line(data = Snow.streets, aes(x = x, y = y, group = street),
            color = "black", linewidth = 0.5) +
  geom_point(alpha = 0.6) +
  geom_density_2d_filled(bins = 4, show.legend = FALSE) +
  geom_density_2d(bins = 4, color = "black", alpha = 0.6) +
  scale_fill_manual(values = c("#FFFFFF00", "#F0808030", "#FF000030", "#8B000080")) +
  geom_label(data = Snow.pumps, aes(x = x, y = y, label = label),
             size = 3, color = "grey20", fill = "lightblue", alpha = 0.9) +
  theme_void() +
  labs(
    title = "John Snow's Cholera Map",
    subtitle = "With contour lines showing densities of death",
    caption = "Data: HistData::Snow.deaths / Snow.pumps / Snow.streets"
  )

