{"spec_id":"ice-basic","library":"ggplot2","language":"r","code":"#' anyplot.ai\n#' ice-basic: Individual Conditional Expectation (ICE) Plot\n#' Library: ggplot2 3.5.1 | R 4.4.1\n#' Quality: 92/100 | Created: 2026-08-17\n\nlibrary(ggplot2)\nlibrary(dplyr)\nlibrary(tidyr)\nlibrary(scales)\nlibrary(ragg)\n\nset.seed(42)\n\n# --- Theme tokens -------------------------------------------------------\nTHEME       <- Sys.getenv(\"ANYPLOT_THEME\", \"light\")\nPAGE_BG     <- if (THEME == \"light\") \"#FAF8F1\" else \"#1A1A17\"\nINK         <- if (THEME == \"light\") \"#1A1A17\" else \"#F0EFE8\"\nINK_SOFT    <- if (THEME == \"light\") \"#4A4A44\" else \"#B8B7B0\"\nIMPRINT_PALETTE <- c(\"#009E73\", \"#C475FD\", \"#4467A3\", \"#BD8233\",\n                     \"#AE3030\", \"#2ABCCD\", \"#954477\", \"#99B314\")\n\n# --- Data -----------------------------------------------------------------\n# ICE curves from a house-price model: predicted sale price as home size\n# varies, one curve per house. Two age cohorts reveal a feature interaction —\n# older homes plateau above a size threshold, newer homes keep climbing.\nn_houses <- 100\nn_grid <- 70\n\nage_levels <- c(\"Newer build (<15 yr)\", \"Older build (15+ yr)\")\nhouse_age <- factor(\n  sample(age_levels, n_houses, replace = TRUE, prob = c(0.45, 0.55)),\n  levels = age_levels\n)\n\nsqft_grid <- seq(800, 3500, length.out = n_grid)\n\nbase_price      <- rnorm(n_houses, mean = 180000, sd = 22000)\nprice_per_sqft  <- ifelse(house_age == \"Newer build (<15 yr)\",\n                           rnorm(n_houses, mean = 148, sd = 14),\n                           rnorm(n_houses, mean = 96, sd = 18))\nplateau_sqft    <- ifelse(house_age == \"Older build (15+ yr)\",\n                           rnorm(n_houses, mean = 2200, sd = 150), Inf)\nwiggle_amplitude <- rnorm(n_houses, mean = 0, sd = 9000)\nwiggle_phase     <- runif(n_houses, 0, 2 * pi)\n\nhouse_params <- tibble::tibble(\n  observation_id   = seq_len(n_houses),\n  house_age        = house_age,\n  base_price       = base_price,\n  price_per_sqft   = price_per_sqft,\n  plateau_sqft     = plateau_sqft,\n  wiggle_amplitude = wiggle_amplitude,\n  wiggle_phase     = wiggle_phase\n)\n\nice_df <- expand_grid(observation_id = seq_len(n_houses), feature_value = sqft_grid) %>%\n  left_join(house_params, by = \"observation_id\") %>%\n  mutate(\n    effective_sqft = pmin(feature_value, plateau_sqft) +\n      0.18 * pmax(feature_value - plateau_sqft, 0),\n    prediction = base_price + price_per_sqft * effective_sqft +\n      wiggle_amplitude * sin(feature_value / 650 + wiggle_phase)\n  ) %>%\n  select(observation_id, house_age, feature_value, prediction)\n\npdp_df <- ice_df %>%\n  group_by(feature_value) %>%\n  summarize(prediction = mean(prediction), .groups = \"drop\")\n\nobserved_sqft <- tibble::tibble(\n  feature_value = pmin(pmax(rnorm(n_houses, 1900, 480), 800), 3500)\n)\n\n# --- Plot -------------------------------------------------------------------\np <- ggplot() +\n  geom_line(\n    data = ice_df,\n    aes(x = feature_value, y = prediction, group = observation_id, color = house_age),\n    alpha = 0.12, linewidth = 0.35\n  ) +\n  geom_rug(\n    data = observed_sqft,\n    aes(x = feature_value),\n    sides = \"b\", color = INK_SOFT, alpha = 0.35, linewidth = 0.3\n  ) +\n  geom_line(\n    data = pdp_df,\n    aes(x = feature_value, y = prediction),\n    color = INK, linewidth = 1.6\n  ) +\n  scale_color_manual(values = IMPRINT_PALETTE[1:2]) +\n  scale_y_continuous(labels = label_dollar(scale = 1e-3, suffix = \"K\")) +\n  guides(color = guide_legend(override.aes = list(alpha = 1, linewidth = 2))) +\n  labs(\n    title = \"ice-basic · r · ggplot2 · anyplot.ai\",\n    x = \"Home Size (sq ft)\",\n    y = \"Predicted Sale Price\",\n    color = \"House Age\"\n  ) +\n  theme_minimal(base_size = 8) +\n  theme(\n    plot.background     = element_rect(fill = PAGE_BG, color = PAGE_BG),\n    panel.background    = element_rect(fill = PAGE_BG, color = NA),\n    panel.grid.major.x  = element_blank(),\n    panel.grid.minor    = element_blank(),\n    panel.grid.major.y  = element_line(color = INK_SOFT, linewidth = 0.2),\n    axis.line           = element_line(color = INK_SOFT),\n    axis.title          = element_text(color = INK, size = 10),\n    axis.text           = element_text(color = INK_SOFT, size = 8),\n    plot.title          = element_text(color = INK, size = 12),\n    legend.background   = element_blank(),\n    legend.key          = element_blank(),\n    legend.text         = element_text(color = INK_SOFT, size = 8),\n    legend.title        = element_text(color = INK, size = 10)\n  )\n\n# --- Save -------------------------------------------------------------------\nggsave(\n  filename = sprintf(\"plot-%s.png\", THEME),\n  plot     = p,\n  device   = ragg::agg_png,\n  width    = 8,\n  height   = 4.5,\n  units    = \"in\",\n  dpi      = 400\n)\n"}