## ----setup, include = FALSE---------------------------------------------------
knitr::opts_chunk$set(
  collapse = TRUE,
  comment = "#>",
  fig.width = 7,
  fig.height = 5,
  fig.align = 'center',
  dev = "png",
  warning = FALSE,
  message = FALSE
)

## ----libraries----------------------------------------------------------------
library(ggmosaic2)
library(vcdExtra)
library(dplyr)

## ----theme-setup, include = FALSE---------------------------------------------
# Set theme globally to avoid repetition
theme_set(theme_mosaic())

## ----table-form---------------------------------------------------------------
# HairEyeColor is already in table form
str(HairEyeColor)
class(HairEyeColor)

# Examine the 3-way table structure
HairEyeColor

# Total observations
sum(HairEyeColor)

## ----color-table--------------------------------------------------------------
color_table(HairEyeColor, shade = "freq")

## ----frequency-form-----------------------------------------------------------
# Convert table to frequency form
hair_freq <- as.data.frame(HairEyeColor)
head(hair_freq, 10)
nrow(hair_freq)  # 32 cells in the 4 × 4 × 2 table

# Verify totals match
sum(hair_freq$Freq)

## ----case-form----------------------------------------------------------------
# Convert frequency form to case form using vcdExtra::expand.dft()
hair_case <- expand.dft(hair_freq, freq = "Freq")
head(hair_case, 10)
nrow(hair_case)  # 592 individual observations

# Structure
str(hair_case)

## ----conversions--------------------------------------------------------------
# Case → Frequency (count occurrences)
hair_case |>
  count(Hair, Eye, Sex, name = "Freq") |>
  head()

# Frequency → Table
hair_table <- xtabs(Freq ~ Hair + Eye + Sex, data = hair_freq)
identical(hair_table, HairEyeColor)

# Table → Frequency (already shown)
# Frequency → Case (already shown)

## ----mosaic-3way-frequency, fig.height=5--------------------------------------
# From frequency form (most common)
ggplot(data = hair_freq,
       aes(weight = Freq, x = product(Hair, Eye, Sex), fill = Eye)) +
  geom_mosaic() +
  labs(title = "Three-Way Mosaic: Hair × Eye × Sex",
       subtitle = "Frequency form with weight aesthetic")

## ----mosaic-3way-case, fig.height=5-------------------------------------------
# From case form
ggplot(data = hair_case,
       aes(x = product(Hair, Eye, Sex), fill = Eye)) +
  geom_mosaic() +
  labs(title = "Three-Way Mosaic: Hair × Eye × Sex",
       subtitle = "Case form without weight")

## ----mosaic-conds, fig.height=5-----------------------------------------------
# Condition on Sex
ggplot(data = hair_freq,
       aes(weight = Freq,
           x = product(Hair, Eye),
           conds = product(Sex),
           fill = Eye)) +
  geom_mosaic() +
  labs(title = "Hair × Eye | Sex",
       subtitle = "Conditioned on Sex")

## ----default-shading----------------------------------------------------------
ggplot(data = hair_freq,
       aes(weight = Freq, x = product(Hair, Eye), fill = Eye)) +
  geom_mosaic() +
  labs(title = "Hair × Eye Color: Default Shading",
       subtitle = "Fill shows Eye color levels")

## ----residual-2way------------------------------------------------------------
ggplot(data = hair_freq,
       aes(weight = Freq, x = product(Hair, Eye))) +
  geom_mosaic(expected = "independence") +
  scale_fill_residual() +
  labs(title = "Hair × Eye Color: Independence Model",
       subtitle = "Blue = more than expected, Red = fewer than expected")

## ----residual-labels----------------------------------------------------------
ggplot(data = hair_freq,
       aes(weight = Freq, x = product(Hair, Eye))) +
  mosaic_settings(expected = "independence") +
  geom_mosaic() +
  scale_fill_residual() +
  geom_mosaic_text(display_values = "residual",
                   format_digits = 1,
                   size = 3.5,
                   colour = "black") +
  labs(title = "Hair × Eye Independence Model with Residual Values",
       subtitle = "Numbers show Pearson residuals")

## ----residual-3way------------------------------------------------------------
ggplot(data = hair_freq,
       aes(weight = Freq, x = product(Hair, Eye, Sex))) +
  geom_mosaic(expected = "independence") +
  scale_fill_residual() +
  labs(title = "Hair × Eye × Sex: Complete Independence",
       subtitle = "Model: ~ Hair + Eye + Sex (no interactions)")

## ----custom-model-------------------------------------------------------------
# Model: Hair and Eye are associated, but independent of Sex
ggplot(data = hair_freq,
       aes(weight = Freq, x = product(Hair, Eye, Sex))) +
  geom_mosaic(expected = ~ Hair * Eye + Sex) +
  scale_fill_residual() +
  labs(title = "Model: (Hair × Eye) Independent of Sex",
       subtitle = "~ Hair * Eye + Sex")

## ----expected-values----------------------------------------------------------
ggplot(data = hair_freq,
       aes(weight = Freq, x = product(Hair, Eye))) +
  mosaic_settings(expected = "independence") +
  geom_mosaic() +
  scale_fill_residual() +
  geom_mosaic_text(display_values = "expected",
                   format_digits = 1,
                   size = 3.5,
                   colour = "black") +
  labs(title = "Expected Frequencies Under Independence",
       subtitle = "Compare with observed to see associations")

## ----observed-values----------------------------------------------------------
ggplot(data = hair_freq,
       aes(weight = Freq, x = product(Hair, Eye))) +
  geom_mosaic(aes(fill = Eye)) +
  geom_mosaic_text(display_values = "observed",
                   format_digits = 0,
                   size = 3.5,
                   colour = "white") +
  labs(title = "Observed Frequencies",
       subtitle = "Actual counts in each cell")

## ----session-info-------------------------------------------------------------
sessionInfo()

