R + Claude: Getting Publication-Ready ggplot2 Figures from a Plain-Language Description
A publication-ready ggplot2 figure has a specification most researchers never write down: resolution, font family, colour palette, axis-label style, and the exact comparison the plot is meant to carry. Ask an AI model for "a box plot of my data" and you get defaults — screen resolution, a rainbow palette, and axis titles lifted straight from your column names. The distance between that and a figure an editor accepts sits almost entirely in the prompt.
Describe the data frame, not the picture
The model cannot see your data. Start by stating the schema: column names, types, and what one row represents. group is a factor with two levels; score is numeric, ranging zero to ten; each row is one patient. This single step removes most of the back-and-forth, because the model stops guessing at your structure and starts writing against it.
State the journal's figure spec first
Journals publish figure requirements: resolution in dpi, accepted fonts, maximum width, and increasingly a requirement for colour-blind-safe palettes. Put those in the opening prompt, not the fifth. The ggplot2 documentation covers the theme() and ggsave() controls for all of them, and a model that knows the target writes ggsave(dpi = 600, width = 180, units = "mm") instead of leaving it to a default. Naming the spec once also stops the slow drift where each iteration fixes one thing and breaks another.
Name the comparison
A figure makes one argument. Before asking for the plot, say what that argument is: the difference between arms at the primary endpoint, the trend across follow-up, the spread within each group. The model then picks geoms that serve it — individual points over a box summary when the sample is small, a reference line at the null, facets instead of an overplotted single panel. Without that instruction it optimises for looking like a generic result, which is how you end up with a bar chart where a scatter would have told the reader more.
Three figure types that hold up
Box-and-whisker with individual points. Ask for geom_boxplot(outlier.shape = NA) under geom_jitter(), so the reader sees the distribution and not only the summary.
Kaplan-Meier. Give the survfit object structure and ask for a risk table aligned under the x-axis. survminer::ggsurvplot() is the usual route, and the model should default to it rather than rebuilding the curve by hand.
Grouped bar with error bars. State whether the bars show standard deviation, standard error, or a confidence interval. The model will otherwise choose one silently, and reviewers ask which it is. Ask for the underlying values to be printed to the console as well, so the figure and the results table can be checked against each other.
The figure is code you have to read
A figure that looks right can still be wrong: error bars plotting the wrong statistic, an axis that starts above zero, a data point hidden behind the legend. Read the generated code the way you would read generated analysis code — a habit covered in AI-generated statistical code failure modes. Then cross-check the plotted values against your summary table, the same output check described in statistical assumption check with Claude, before the figure goes into the manuscript.
Getting to spec
Reaching a journal-spec figure is a prompt-structure problem, not a design-talent one: schema, spec, comparison, all in the first message. AI for Academic's peer-review stress test at aiforacademic.world flags results-reporting gaps — error bars with no defined statistic, a missing analysed sample size on a figure — before submission. Free to start.