{"spec_id":"sequence-logo-basic","library":"ggplot2","language":"r","code":"#' anyplot.ai\n#' sequence-logo-basic: Sequence Logo for Motif Visualization\n#' Library: ggplot2 3.5.1 | R 4.4.1\n#' Quality: 89/100 | Created: 2026-06-02\n\nlibrary(ggplot2)\nlibrary(dplyr)\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\"\n\n# DNA color scheme — Imprint palette with semantic mapping\n# Bioinformatics convention: A=green, C=blue, G=ochre/yellow, T=red\nDNA_COLORS <- c(\n  \"A\" = \"#009E73\",  # Imprint position 1 - green\n  \"C\" = \"#4467A3\",  # Imprint position 3 - blue\n  \"G\" = \"#BD8233\",  # Imprint position 4 - ochre\n  \"T\" = \"#AE3030\"   # Imprint position 5 - matte red\n)\n\n# TATA-box transcription factor binding site motif (12 positions)\n# Positions 2-8 represent the conserved TATAAATA core\nmotif_df <- data.frame(\n  position = rep(1:12, each = 4),\n  letter   = rep(c(\"A\", \"C\", \"G\", \"T\"), times = 12),\n  frequency = c(\n    # Pos 1: low information (upstream flank)\n    0.22, 0.28, 0.28, 0.22,\n    # Pos 2: T-conserved\n    0.03, 0.04, 0.04, 0.89,\n    # Pos 3: A-conserved\n    0.88, 0.04, 0.04, 0.04,\n    # Pos 4: T-conserved\n    0.04, 0.04, 0.04, 0.88,\n    # Pos 5: A-conserved\n    0.86, 0.04, 0.05, 0.05,\n    # Pos 6: A-conserved\n    0.84, 0.05, 0.06, 0.05,\n    # Pos 7: T-conserved\n    0.04, 0.05, 0.04, 0.87,\n    # Pos 8: A-conserved\n    0.80, 0.07, 0.07, 0.06,\n    # Pos 9: moderate T (downstream)\n    0.12, 0.15, 0.13, 0.60,\n    # Pos 10: moderate A/G\n    0.40, 0.15, 0.30, 0.15,\n    # Pos 11: nearly uniform\n    0.26, 0.24, 0.26, 0.24,\n    # Pos 12: low information\n    0.24, 0.28, 0.24, 0.24\n  )\n)\n\n# Information content per position: IC = 2 - H, H = -sum(f * log2(f))\n# Letter height within stack = frequency * IC\nmotif_df <- motif_df %>%\n  group_by(position) %>%\n  mutate(\n    H      = -sum(ifelse(frequency > 0, frequency * log2(frequency), 0)),\n    IC     = 2 - H,\n    height = frequency * IC\n  ) %>%\n  ungroup() %>%\n  # Sort ascending by frequency: lowest at bottom, highest on top\n  arrange(position, frequency) %>%\n  group_by(position) %>%\n  mutate(\n    y_bottom = cumsum(lag(height, default = 0)),\n    y_top    = cumsum(height),\n    y_mid    = (y_bottom + y_top) / 2,\n    # Scale text size proportional to bar height; ~14 maps bits to mm units\n    # while keeping character width within the 0.9-unit bar slot (~13mm)\n    letter_size = pmax(2.0, height * 14)\n  ) %>%\n  ungroup()\n\n# Title — 46 chars < 67 baseline so no size shrinkage needed\ntitle_str <- \"sequence-logo-basic · r · ggplot2 · anyplot.ai\"\n\n# Plot\np <- ggplot(motif_df) +\n  geom_rect(\n    aes(\n      xmin = position - 0.45,\n      xmax = position + 0.45,\n      ymin = y_bottom,\n      ymax = y_top,\n      fill = letter\n    ),\n    color = NA\n  ) +\n  # Overlay letter glyphs — skips letters too small to read\n  geom_text(\n    data = dplyr::filter(motif_df, height > 0.04),\n    aes(\n      x     = position,\n      y     = y_mid,\n      label = letter,\n      size  = letter_size\n    ),\n    color       = \"white\",\n    fontface    = \"bold\",\n    show.legend = FALSE\n  ) +\n  scale_fill_manual(\n    values = DNA_COLORS,\n    name   = \"Nucleotide\"\n  ) +\n  scale_size_identity(guide = \"none\") +\n  scale_x_continuous(\n    breaks = 1:12,\n    expand = c(0.025, 0)\n  ) +\n  scale_y_continuous(\n    limits = c(0, 2.05),\n    expand = c(0, 0),\n    breaks = seq(0, 2, by = 0.5)\n  ) +\n  labs(\n    x     = \"Position\",\n    y     = \"Information content (bits)\",\n    title = title_str\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.y = element_line(color = INK_SOFT,  linewidth = 0.15),\n    panel.grid.major.x = element_blank(),\n    panel.grid.minor   = element_blank(),\n    panel.border       = element_blank(),\n    axis.line          = element_line(color = INK_SOFT,  linewidth = 0.4),\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                                      face = \"bold\", margin = margin(b = 8)),\n    legend.background  = element_rect(fill = ELEVATED_BG, color = INK_SOFT,\n                                      linewidth = 0.3),\n    legend.text        = element_text(color = INK_SOFT,  size = 8),\n    legend.title       = element_text(color = INK,       size = 10),\n    legend.position    = \"right\",\n    legend.key.size    = unit(12, \"pt\"),\n    plot.margin        = margin(12, 12, 8, 8, \"pt\")\n  )\n\n# Save — ragg device, exact canvas 3200 x 1800 px\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"}