{"spec_id":"column-stratigraphic","library":"ggplot2","language":"r","code":"#' anyplot.ai\n#' column-stratigraphic: Stratigraphic Column with Lithology Patterns\n#' Library: ggplot2 3.5.1 | R 4.4.1\n#' Quality: 93/100 | Created: 2026-06-17\n\nlibrary(ggplot2)\nlibrary(dplyr)\nlibrary(tibble)\nlibrary(ragg)\n\nset.seed(42)\n\n# --- Theme tokens -----------------------------------------------------------\nTHEME       <- Sys.getenv(\"ANYPLOT_THEME\", \"light\")\nPAGE_BG     <- if (THEME == \"light\") \"#FAF8F1\" else \"#1A1A17\"\nELEVATED_BG <- if (THEME == \"light\") \"#FFFDF6\" else \"#242420\"\nINK         <- if (THEME == \"light\") \"#1A1A17\" else \"#F0EFE8\"\nINK_SOFT    <- if (THEME == \"light\") \"#4A4A44\" else \"#B8B7B0\"\nGRID        <- if (THEME == \"light\") \"#D8D5CC\" else \"#33332E\"\n\n# Imprint palette — canonical order, first series ALWAYS #009E73.\n# Lithology is encoded primarily by the FGDC/USGS-style fill pattern; the colour\n# is a secondary tint, so the categories take the Imprint palette in order.\nLITH_COLORS <- c(\n  Sandstone    = \"#009E73\",  # 1 — brand green (first series)\n  Shale        = \"#C475FD\",  # 2 — lavender\n  Limestone    = \"#4467A3\",  # 3 — blue\n  Siltstone    = \"#BD8233\",  # 4 — ochre\n  Conglomerate = \"#AE3030\"   # 5 — matte red\n)\n\n# --- Data: a synthetic borehole section (depth increases downward) ----------\nlayers <- tibble(\n  top       = c(0,   26,  54,  86,  112, 150, 176, 214),\n  bottom    = c(26,  54,  86,  112, 150, 176, 214, 250),\n  lithology = c(\"Sandstone\", \"Shale\", \"Limestone\", \"Siltstone\",\n                \"Sandstone\", \"Conglomerate\", \"Shale\", \"Limestone\"),\n  formation = c(\"Belly River Fm\", \"Wapiabi Fm\", \"Greenhorn Fm\", \"Joli Fou Fm\",\n                \"Viking Fm\", \"Cadomin Fm\", \"Nikanassin Fm\", \"Fernie Fm\"),\n  age       = c(\"Campanian\", \"Santonian\", \"Cenomanian\", \"Albian\",\n                \"Albian\", \"Aptian\", \"Tithonian\", \"Toarcian\")\n)\nlayers$lithology <- factor(layers$lithology, levels = names(LITH_COLORS))\n\n# A sub-Cretaceous unconformity (Aptian conglomerate over Tithonian shale).\nUNCONFORMITY <- 176\n\n# --- Build the lithology patterns natively (line / dot / clast primitives) ---\n# ggplot2 has no native fill-texture geom, so each rock type's standard symbol\n# is composed from segments, points and open circles laid inside the layer box.\nseg_rows <- list(); dot_rows <- list(); clast_rows <- list()\nsi <- 0L; di <- 0L; ci <- 0L\n\nfor (i in seq_len(nrow(layers))) {\n    t <- layers$top[i]; b <- layers$bottom[i]\n    lit <- as.character(layers$lithology[i])\n\n    if (lit == \"Limestone\") {\n        # Brick: full-width courses with staggered vertical joints.\n        courses <- seq(t + 7, b - 3, by = 9)\n        si <- si + 1L\n        seg_rows[[si]] <- tibble(x = 0.0, xend = 1.0, y = courses, yend = courses)\n        if (length(courses) >= 2) {\n            for (j in seq_len(length(courses) - 1)) {\n                xv <- if (j %% 2 == 0) c(0.34, 0.67) else c(0.2, 0.5, 0.8)\n                si <- si + 1L\n                seg_rows[[si]] <- tibble(x = xv, xend = xv,\n                                         y = courses[j], yend = courses[j + 1])\n            }\n        }\n    } else if (lit == \"Shale\") {\n        # Continuous, closely spaced horizontal laminae.\n        lines_y <- seq(t + 4, b - 3, by = 4.5)\n        si <- si + 1L\n        seg_rows[[si]] <- tibble(x = 0.05, xend = 0.95, y = lines_y, yend = lines_y)\n    } else if (lit == \"Siltstone\") {\n        # Broken (dashed) horizontal lines, staggered between rows.\n        rows <- seq(t + 4, b - 3, by = 5)\n        for (j in seq_along(rows)) {\n            xo <- if (j %% 2 == 0) 0.13 else 0\n            xs <- seq(0.1 + xo, 0.82, by = 0.26)\n            si <- si + 1L\n            seg_rows[[si]] <- tibble(x = xs, xend = xs + 0.14,\n                                     y = rows[j], yend = rows[j])\n        }\n    } else if (lit == \"Sandstone\") {\n        # Stipple: regular dot grid, offset on alternate rows.\n        rows <- seq(t + 4, b - 3, by = 5.5)\n        for (j in seq_along(rows)) {\n            xo <- if (j %% 2 == 0) 0.065 else 0\n            xs <- seq(0.1 + xo, 0.93, by = 0.13)\n            di <- di + 1L\n            dot_rows[[di]] <- tibble(x = xs, y = rep(rows[j], length(xs)))\n        }\n    } else if (lit == \"Conglomerate\") {\n        # Scattered clasts as open circles of varying size.\n        n <- max(8L, round((b - t) * 0.7))\n        ci <- ci + 1L\n        clast_rows[[ci]] <- tibble(\n            x = runif(n, 0.13, 0.87),\n            y = runif(n, t + 4, b - 4),\n            r = runif(n, 2.0, 5.5)\n        )\n    }\n}\nseg_df   <- bind_rows(seg_rows)\ndot_df   <- bind_rows(dot_rows)\nclast_df <- bind_rows(clast_rows)\n\n# Wavy line marking the unconformity contact.\nwave <- tibble(x = seq(0, 1, length.out = 160))\nwave$y <- UNCONFORMITY + 1.8 * sin(wave$x * 2 * pi * 7)\n\n# --- Plot -------------------------------------------------------------------\np <- ggplot() +\n    geom_rect(data = layers,\n              aes(xmin = 0, xmax = 1, ymin = top, ymax = bottom, fill = lithology),\n              color = NA, alpha = 0.62) +\n    geom_segment(data = seg_df, aes(x = x, xend = xend, y = y, yend = yend),\n                 color = INK, linewidth = 0.35) +\n    geom_point(data = dot_df, aes(x = x, y = y), color = INK, size = 0.9) +\n    geom_point(data = clast_df, aes(x = x, y = y, size = r),\n               shape = 1, stroke = 0.5, color = INK) +\n    scale_size_identity() +\n    geom_rect(data = layers,\n              aes(xmin = 0, xmax = 1, ymin = top, ymax = bottom),\n              fill = NA, color = INK_SOFT, linewidth = 0.5) +\n    geom_path(data = wave, aes(x = x, y = y), color = INK, linewidth = 0.9) +\n    annotate(\"text\", x = -0.12, y = UNCONFORMITY, label = \"unconformity\",\n             hjust = 1, fontface = \"italic\", size = 2.8, color = INK_SOFT) +\n    geom_text(data = layers,\n              aes(x = 1.1, y = (top + bottom) / 2 - 3.8, label = formation),\n              hjust = 0, fontface = \"bold\", size = 3.3, color = INK) +\n    geom_text(data = layers,\n              aes(x = 1.1, y = (top + bottom) / 2 + 4.8, label = lithology),\n              hjust = 0, fontface = \"italic\", size = 2.9, color = INK_SOFT) +\n    geom_text(data = layers,\n              aes(x = -0.08, y = (top + bottom) / 2, label = age),\n              hjust = 1, size = 3.0, color = INK_SOFT) +\n    scale_fill_manual(values = LITH_COLORS, name = \"Lithology\",\n                      breaks = names(LITH_COLORS)) +\n    scale_y_reverse(breaks = seq(0, 250, 25),\n                    expand = expansion(mult = c(0.03, 0.03))) +\n    coord_cartesian(xlim = c(-1.5, 2.6), clip = \"off\") +\n    guides(fill = guide_legend(override.aes = list(alpha = 0.62))) +\n    labs(title = \"column-stratigraphic · r · ggplot2 · anyplot.ai\",\n         y = \"Depth (m)\", x = NULL) +\n    theme_minimal(base_size = 9) +\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         = element_blank(),\n        panel.grid.major.y = element_line(color = GRID, linewidth = 0.25),\n        axis.title.y       = element_text(color = INK, size = 11),\n        axis.text.y        = element_text(color = INK_SOFT, size = 9),\n        axis.title.x       = element_blank(),\n        axis.text.x        = element_blank(),\n        axis.ticks.x       = element_blank(),\n        axis.ticks.y       = element_line(color = INK_SOFT, linewidth = 0.3),\n        plot.title         = element_text(color = INK, size = 13, face = \"bold\",\n                                          margin = margin(b = 10)),\n        legend.position    = \"right\",\n        legend.title       = element_text(color = INK, size = 11),\n        legend.text        = element_text(color = INK_SOFT, size = 9),\n        legend.background   = element_rect(fill = ELEVATED_BG, color = INK_SOFT,\n                                          linewidth = 0.3),\n        legend.key         = element_rect(fill = ELEVATED_BG, color = NA),\n        plot.margin        = margin(t = 14, r = 16, b = 14, l = 16)\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"}