diff --git a/plots/scatter-connected-temporal/implementations/r/ggplot2.R b/plots/scatter-connected-temporal/implementations/r/ggplot2.R new file mode 100644 index 0000000000..f4dcccefca --- /dev/null +++ b/plots/scatter-connected-temporal/implementations/r/ggplot2.R @@ -0,0 +1,145 @@ +#' anyplot.ai +#' scatter-connected-temporal: Connected Scatter Plot with Temporal Path +#' Library: ggplot2 3.5.1 | R 4.4.1 +#' Quality: 89/100 | Created: 2026-06-09 + +library(ggplot2) +library(scales) +library(ragg) + +set.seed(42) + +# Theme tokens (Imprint palette, theme-adaptive chrome) +THEME <- Sys.getenv("ANYPLOT_THEME", "light") +PAGE_BG <- if (THEME == "light") "#FAF8F1" else "#1A1A17" +ELEVATED_BG <- if (THEME == "light") "#FFFDF6" else "#242420" +INK <- if (THEME == "light") "#1A1A17" else "#F0EFE8" +INK_SOFT <- if (THEME == "light") "#4A4A44" else "#B8B7B0" +INK_MUTED <- if (THEME == "light") "#6B6A63" else "#A8A79F" +IMPRINT_PALETTE <- c( + "#009E73", "#C475FD", "#4467A3", "#BD8233", + "#AE3030", "#2ABCCD", "#954477", "#99B314" +) + +# Data: unemployment vs inflation (Phillips curve dynamics), 1980-2019 +years <- 1980:2019 +unemployment <- c( + 7.2, 7.6, 9.7, 9.6, 7.5, 7.2, 7.0, 6.2, 5.5, 5.3, + 5.6, 6.8, 7.5, 6.9, 6.1, 5.6, 5.4, 4.9, 4.5, 4.2, + 4.0, 4.7, 5.8, 6.0, 5.5, 5.1, 4.6, 4.6, 5.8, 9.3, + 9.6, 8.9, 8.1, 7.4, 6.2, 5.3, 4.9, 4.4, 3.9, 3.5 +) +inflation <- c( + 13.5, 10.3, 6.2, 3.2, 4.3, 3.6, 1.9, 3.6, 4.1, 4.8, + 5.4, 4.2, 3.0, 3.0, 2.6, 2.8, 2.9, 2.3, 1.6, 2.2, + 3.4, 2.8, 1.6, 2.3, 2.7, 3.4, 3.2, 2.9, 3.8, -0.4, + 1.6, 3.2, 2.1, 1.5, 1.6, 0.1, 1.3, 2.1, 2.4, 2.3 +) + +df <- data.frame( + year = years, + unemployment = unemployment, + inflation = inflation +) + +key_years <- c(1980, 1990, 2000, 2010, 2019) +df_labels <- df[df$year %in% key_years, ] + +# Per-label positions to avoid crowding (2000 nudged left, 2019 nudged higher) +df_labels$lbl_x <- df_labels$unemployment + c( 0.2, 0.2, -0.3, 0.2, 0.2) +df_labels$lbl_y <- df_labels$inflation + c( 0.6, 0.5, 0.5, 0.5, 0.7) + +# Arrow segment: from start point toward first step for temporal direction cue +arrow_start <- df[df$year == 1980, ] +arrow_end <- df[df$year == 1981, ] + +# Title: scale fontsize for long title (80 chars -> size 10) +plot_title <- "Phillips Curve Dynamics · scatter-connected-temporal · r · ggplot2 · anyplot.ai" +title_size <- max(8L, round(12 * 67 / nchar(plot_title))) + +# Plot +p <- ggplot(df, aes(x = unemployment, y = inflation)) + + geom_path( + aes(color = year), + linewidth = 1.0, + alpha = 0.85, + lineend = "round", + linejoin = "round" + ) + + # Start-of-path arrow to reinforce temporal direction + geom_segment( + data = data.frame( + x = arrow_start$unemployment, + y = arrow_start$inflation, + xend = arrow_end$unemployment, + yend = arrow_end$inflation + ), + aes(x = x, y = y, xend = xend, yend = yend), + color = IMPRINT_PALETTE[1], + linewidth = 1.2, + arrow = arrow(length = unit(0.18, "cm"), type = "closed") + ) + + geom_point( + aes(color = year), + size = 3.5, + alpha = 0.95 + ) + + geom_text( + data = df_labels, + aes(x = lbl_x, y = lbl_y, label = year), + color = INK, + size = 3.2, + fontface = "bold" + ) + + scale_color_gradient( + low = IMPRINT_PALETTE[1], + high = IMPRINT_PALETTE[3], + name = "Year", + guide = guide_colorbar( + barwidth = 8, + barheight = 0.5, + title.position = "top", + title.hjust = 0.5 + ) + ) + + scale_x_continuous( + labels = label_number(suffix = "%"), + expand = expansion(mult = c(0.05, 0.08)) + ) + + scale_y_continuous( + labels = label_number(suffix = "%"), + expand = expansion(mult = c(0.05, 0.15)) + ) + + labs( + x = "Unemployment Rate", + y = "Inflation Rate", + title = plot_title + ) + + theme_minimal(base_size = 8) + + theme( + plot.background = element_rect(fill = PAGE_BG, color = PAGE_BG), + panel.background = element_rect(fill = PAGE_BG, color = NA), + panel.grid.major = element_line(color = INK_MUTED, linewidth = 0.15), + panel.grid.minor = element_blank(), + panel.border = element_blank(), + axis.line = element_line(color = INK_SOFT, linewidth = 0.4), + axis.title = element_text(color = INK, size = 10), + axis.text = element_text(color = INK_SOFT, size = 8), + plot.title = element_text(color = INK, size = title_size, face = "bold"), + legend.position = "bottom", + legend.background = element_rect(fill = ELEVATED_BG, color = NA), + legend.text = element_text(color = INK_SOFT, size = 8), + legend.title = element_text(color = INK, size = 9), + plot.margin = margin(20, 20, 10, 20) + ) + +# Save +ggsave( + filename = sprintf("plot-%s.png", THEME), + plot = p, + device = ragg::agg_png, + width = 8, + height = 4.5, + units = "in", + dpi = 400 +) diff --git a/plots/scatter-connected-temporal/metadata/r/ggplot2.yaml b/plots/scatter-connected-temporal/metadata/r/ggplot2.yaml new file mode 100644 index 0000000000..a3cc78ce2f --- /dev/null +++ b/plots/scatter-connected-temporal/metadata/r/ggplot2.yaml @@ -0,0 +1,272 @@ +library: ggplot2 +language: r +specification_id: scatter-connected-temporal +created: '2026-06-09T23:28:54Z' +updated: '2026-06-09T23:51:13Z' +generated_by: claude-sonnet +workflow_run: 27242295762 +issue: 4675 +language_version: 4.4.1 +library_version: 3.5.1 +preview_url_light: https://storage.googleapis.com/anyplot-images/plots/scatter-connected-temporal/r/ggplot2/plot-light.png +preview_url_dark: https://storage.googleapis.com/anyplot-images/plots/scatter-connected-temporal/r/ggplot2/plot-dark.png +preview_html_light: null +preview_html_dark: null +quality_score: 89 +review: + strengths: + - Correct use of geom_path() (not geom_line) preserves temporal order — idiomatic + ggplot2 for connected scatter + - 'imprint_seq gradient (green #009E73 → blue #4467A3) elegantly encodes temporal + progression along both path and points' + - Arrow overlay (geom_segment with arrow parameter) reinforces time direction without + cluttering the chart + - 'Full theme-adaptive chrome: PAGE_BG, INK, INK_SOFT, INK_MUTED all correctly toggled + between light and dark' + - Title font scaling formula correctly handles the 80-character mandated title (size + capped at 10pt via linear formula) + - Real historical Phillips curve data (1980–2019) with accurate economic values + provides compelling real-world context + - guide_colorbar with barwidth/barheight customization makes the continuous legend + compact and well-positioned + - Panel border removed, minor grid disabled, axis lines added — clean L-shaped frame + without full box + weaknesses: + - 'Label overlap: ''2000'' and ''2019'' are nearly co-located (lbl_x both = 3.7%, + lbl_y = 3.1 vs 3.0 — only 0.1% separation on a 17%-range axis, ~8 source-px gap + vs ~50px text height). Labels overlap in both renders. Fix: increase y-offset + for ''2019'' to at least inflation + 1.5 or nudge x for one of the two labels.' + - 'Year colorbar legend (1980–2010) is truncated — the colorbar ticks show 1980, + 1990, 2000, 2010 but not 2019. Minor cosmetic issue: the max scale value (2019) + is cut off. Widen barwidth or set breaks explicitly to include 2019.' + image_description: |- + Light render (plot-light.png): + Background: Warm off-white (#FAF8F1) — correctly set, not pure white. + Chrome: Title "Phillips Curve Dynamics · scatter-connected-temporal · r · ggplot2 · anyplot.ai" renders at ~10pt (scaled from default 12pt for 80-char title), bold, dark ink — readable. X-axis label "Unemployment Rate" and Y-axis label "Inflation Rate" both at 10pt in dark ink — readable. Tick labels (3%, 4%, ... 10% on x; 0%, 5%, 10%, 15% on y) at 8pt in INK_SOFT — readable. Bottom legend "Year" colorbar shows gradient from green to blue across 1980–2010 range. + Data: Path and points graduate from brand green #009E73 (1980, high-inflation/high-unemployment region, upper-right) through teal/mid-green to blue #4467A3 (recent years, lower-left cluster). Small arrow at start (1980→1981) in green reinforces temporal direction. Year labels "1980", "1990", "2010" are well-spaced; "2000" and "2019" appear nearly stacked (overlapping vertically) in the lower-left of the scatter. + Legibility verdict: PASS overall. Minor readability issue: "2000" and "2019" labels nearly overlap. + + Dark render (plot-dark.png): + Background: Warm near-black (#1A1A17) — correctly set, not pure black. + Chrome: Title, axis labels, and tick labels all render in light-colored ink (#F0EFE8 / #B8B7B0) — clearly readable against the dark background. No dark-on-dark failures observed. Legend text and title in appropriate light tones. + Data: Path and point colors are identical to the light render — green #009E73 through to blue #4467A3 gradient. Arrow at start visible. Year annotation labels appear in INK (#F0EFE8 in dark mode) — readable against the dark background. The "2000"/"2019" overlap issue persists identically in the dark render. + Legibility verdict: PASS. Data colors identical to light render (only chrome flipped). No dark-on-dark failures. + criteria_checklist: + visual_quality: + score: 26 + max: 30 + items: + - id: VQ-01 + name: Text Legibility + score: 7 + max: 8 + passed: true + comment: All font sizes explicitly set (axis.title=10, axis.text=8, title_size=10, + legend.text=8, legend.title=9). Readable in both themes. Minor deduction + for the 2000/2019 proximity causing readability concern. + - id: VQ-02 + name: No Overlap + score: 3 + max: 6 + passed: false + comment: '''2000'' and ''2019'' labels nearly co-located (lbl_y = 3.1 vs 3.0 + — only 0.1% gap on 17%-range axis). Labels overlap in both renders.' + - id: VQ-03 + name: Element Visibility + score: 6 + max: 6 + passed: true + comment: 40 data points, size=3.5 markers with alpha=0.95, linewidth=1.0 path. + Well-adapted to medium density connected scatter. + - id: VQ-04 + name: Color Accessibility + score: 2 + max: 2 + passed: true + comment: Green-to-blue imprint_seq gradient is CVD-safe. No red-green reliance. + - id: VQ-05 + name: Layout & Canvas + score: 4 + max: 4 + passed: true + comment: 3200x1800 landscape (8x4.5in at dpi=400). Good canvas utilization, + legend at bottom, generous margins. + - id: VQ-06 + name: Axis Labels & Title + score: 2 + max: 2 + passed: true + comment: Descriptive labels 'Unemployment Rate' and 'Inflation Rate'; % shown + in tick labels via label_number(suffix='%'). + - id: VQ-07 + name: Palette Compliance + score: 2 + max: 2 + passed: true + comment: 'Uses imprint_seq gradient (low=#009E73, high=#4467A3) for continuous + temporal variable. Backgrounds #FAF8F1 / #1A1A17 correctly set. All chrome + theme-adaptive.' + design_excellence: + score: 14 + max: 20 + items: + - id: DE-01 + name: Aesthetic Sophistication + score: 6 + max: 8 + passed: true + comment: 'Strong design: gradient along the temporal path is visually striking + and informative. Arrow cue adds clarity. Clean minimal chrome. Clearly above + library defaults.' + - id: DE-02 + name: Visual Refinement + score: 4 + max: 6 + passed: true + comment: Subtle grid (linewidth=0.15, INK_MUTED), minor grid disabled, panel + border removed, axis lines added for L-shape frame. Good refinement. + - id: DE-03 + name: Data Storytelling + score: 4 + max: 6 + passed: true + comment: Gradient + arrow + year annotations create clear temporal narrative. + Viewer follows the economic path from high-inflation 1980s to lower-inflation + 2010s. Good visual hierarchy. + spec_compliance: + score: 15 + max: 15 + items: + - id: SC-01 + name: Plot Type + score: 5 + max: 5 + passed: true + comment: Connected scatter with temporal path. geom_path for connections, + geom_point for markers — correct plot type fully implemented. + - id: SC-02 + name: Required Features + score: 4 + max: 4 + passed: true + comment: 'All required features present: chronological connection (geom_path), + key time point annotations (1980/1990/2000/2010/2019), arrow for direction + (geom_segment with arrow), color gradient for temporal progression, visible + markers (geom_point).' + - id: SC-03 + name: Data Mapping + score: 3 + max: 3 + passed: true + comment: X=unemployment rate, Y=inflation rate, time encoded via color gradient. + All axes show full data range. + - id: SC-04 + name: Title & Legend + score: 3 + max: 3 + passed: true + comment: Title 'Phillips Curve Dynamics · scatter-connected-temporal · r · + ggplot2 · anyplot.ai' matches required format with optional descriptive + prefix. Year colorbar legend appropriate. + data_quality: + score: 15 + max: 15 + items: + - id: DQ-01 + name: Feature Coverage + score: 6 + max: 6 + passed: true + comment: 'Shows full complexity of connected scatter: looping paths, direction + changes, clustering in 2000s, extreme 1980 outlier, 2008 recession excursion + to high unemployment.' + - id: DQ-02 + name: Realistic Context + score: 5 + max: 5 + passed: true + comment: Classic Phillips curve (US unemployment vs inflation 1980-2019). + Real, comprehensible, neutral economic data. Well-known academic and journalistic + visualization context. + - id: DQ-03 + name: Appropriate Scale + score: 4 + max: 4 + passed: true + comment: Unemployment 3.5-9.7%, inflation -0.4% to 13.5% — accurate historical + US values. The data reflects actual economic patterns including the 1980-81 + disinflation and 2008-09 recession. + code_quality: + score: 10 + max: 10 + items: + - id: CQ-01 + name: KISS Structure + score: 3 + max: 3 + passed: true + comment: 'Clean linear flow: theme tokens → data → plot layers → save. No + functions or classes.' + - id: CQ-02 + name: Reproducibility + score: 2 + max: 2 + passed: true + comment: set.seed(42) present; data is hardcoded historical values (fully + deterministic). + - id: CQ-03 + name: Clean Imports + score: 2 + max: 2 + passed: true + comment: ggplot2 (plot), scales (label_number), ragg (agg_png device) — all + three used. + - id: CQ-04 + name: Code Elegance + score: 2 + max: 2 + passed: true + comment: Per-label nudge offsets are thoughtful. Title-size scaling formula + is appropriate. No over-engineering. + - id: CQ-05 + name: Output & API + score: 1 + max: 1 + passed: true + comment: Saves as sprintf('plot-%s.png', THEME) → plot-light.png / plot-dark.png. + Uses ragg::agg_png device. Correct. + library_mastery: + score: 9 + max: 10 + items: + - id: LM-01 + name: Idiomatic Usage + score: 5 + max: 5 + passed: true + comment: 'Expert ggplot2: aes(color=year) with scale_color_gradient for continuous + mapping on path AND points simultaneously, guide_colorbar customization, + geom_path for temporal ordering (not geom_line which sorts by x), proper + theme inheritance from theme_minimal.' + - id: LM-02 + name: Distinctive Features + score: 4 + max: 5 + passed: true + comment: geom_path temporal ordering, continuous aesthetic mapping across + multiple geom layers, guide_colorbar with custom dimensions, geom_segment + arrow — all distinctively ggplot2 patterns. One point deducted as no faceting + or advanced grammar technique. + verdict: APPROVED +impl_tags: + dependencies: [] + techniques: + - annotations + - colorbar + - layer-composition + patterns: + - data-generation + dataprep: [] + styling: + - alpha-blending + - custom-colormap