This source did not publish a separate summary. Review SKILL.md before using the skill.
SKILL.md
Publication-Quality Figures Skill
This skill generates figure code that meets the formatting standards of top economics journals (AER, QJE, ReStud, Econometrica, JPE). It covers the most common econometric figure types with precise control over fonts, colors, dimensions, and export formats.
# Python — overlapping density plot
from scipy.stats import gaussian_kde
def plot_density(groups, labels, xlabel="Value", title=""):
fig, ax = plt.subplots(figsize=(7, 4.5))
for i, (data, label) in enumerate(zip(groups, labels)):
kde = gaussian_kde(data, bw_method='silverman')
x_grid = np.linspace(data.min() - data.std(), data.max() + data.std(), 300)
ax.plot(x_grid, kde(x_grid), color=COLORS[i], linewidth=1.5, label=label)
ax.fill_between(x_grid, kde(x_grid), alpha=0.1, color=COLORS[i])
ax.set_xlabel(xlabel)
ax.set_ylabel("Density")
ax.set_title(title)
ax.legend(frameon=False)
plt.tight_layout()
plt.savefig("density.pdf")
# R — density comparison
ggplot(df, aes(x = outcome, fill = group, color = group)) +
geom_density(alpha = 0.15, linewidth = 0.8) +
scale_fill_manual(values = econ_colors[1:2]) +
scale_color_manual(values = econ_colors[1:2]) +
labs(x = "Outcome", y = "Density",
title = "Distribution by Group") +
theme_econ()
* Stata — density comparison
twoway (kdensity outcome if group == 0, lcolor(navy) lwidth(medthick)) ///
(kdensity outcome if group == 1, lcolor(cranberry) lwidth(medthick) ///
lpattern(dash)), ///
legend(label(1 "Control") label(2 "Treatment")) ///
ytitle("Density") xtitle("Outcome") ///
title("Distribution by Group") ///
$graph_opts
graph export "density.pdf", as(pdf) replace
6. Time Series / Trend Plot
# Python — time series with shaded recession bars
def plot_timeseries(dates, series_dict, recessions=None,
ylabel="", title=""):
fig, ax = plt.subplots(figsize=(7, 4.5))
for i, (label, values) in enumerate(series_dict.items()):
ax.plot(dates, values, color=COLORS[i], linewidth=1.5,
linestyle=LINESTYLES[i], label=label)
if recessions:
for start, end in recessions:
ax.axvspan(start, end, alpha=0.08, color='grey')
ax.set_ylabel(ylabel)
ax.set_title(title)
ax.legend(frameon=False, loc='best')
fig.autofmt_xdate()
plt.tight_layout()
plt.savefig("timeseries.pdf")
# R — time series with recession shading
library(ggplot2)
ggplot(df, aes(x = date, y = value)) +
geom_rect(data = recessions,
aes(xmin = start, xmax = end, ymin = -Inf, ymax = Inf),
inherit.aes = FALSE, fill = "grey", alpha = 0.1) +
geom_line(aes(color = series, linetype = series), linewidth = 0.8) +
scale_color_manual(values = econ_colors) +
labs(x = "", y = "Value", title = "Time Series Comparison") +
theme_econ()
* Stata — multi-panel with graph combine
graph combine panel_a panel_b panel_c panel_d, ///
rows(2) cols(2) ///
title("Figure 1: Main Results") ///
$graph_opts
graph export "multipanel.pdf", as(pdf) replace
Formatting Checklist
Before submitting to a journal, verify:
Vector format: Exported as PDF (not PNG/JPG) for line plots
Readable in grayscale: Print in B&W to check
Font consistency: Same font family as paper body text
Axis labels: Descriptive, with units (e.g., "Income (1000 USD)")
No chartjunk: Remove gridlines, borders, and unnecessary decoration
Proper aspect ratio: Not stretched or compressed
Legend placement: Inside plot if space allows; below otherwise
Panel labels: (a), (b), (c) for multi-panel figures
Notes below figure: Data source, sample, key definitions
CI/SE shown: For any estimated quantities (coefficients, treatment effects)
Reference lines: Zero line for coefficient plots; cutoff for RDD; treatment date for event study
Common Pitfalls
Using default matplotlib/ggplot themes: They look unprofessional — always customize
Raster exports for line plots: Use PDF/EPS, not PNG, for any plot with lines or text
Too many colors: Limit to 3–4 distinguishable colors; use linestyle for additional series
Tiny axis labels: Minimum 8pt after scaling to final size in the paper
Missing confidence intervals: Never show point estimates without uncertainty
3D plots: Almost never appropriate in economics — use 2D alternatives
Pie charts: Never use in academic economics papers
Output File Management
Consistent figure naming and directory layout prevents the most common assembly problem: the paper's \includegraphics{} calls pointing to files that don't exist or are scattered across subdirectories (data/bartik/, data/results/, output/, etc.).
Standard Convention
Save all figures to a single figures/ directory at the project root. Use zero-padded sequential prefixes:
The numeric prefix (fig01_, fig02_, ...) makes insertion order explicit and survives alphabetical sorting. The descriptive suffix means you can identify the figure without opening it.
Python Helper
Add this to any figure-generating script to enforce the convention:
% In preamble — point to figures/ once:
\graphicspath{{../figures/}}
% In the paper body — no path needed in each call:
\begin{figure}[htbp]
\centering
\includegraphics[width=0.9\textwidth]{fig03_event_study_wages}
\caption{Event Study: Effect of AI Exposure on Log Wages}
\label{fig:event_study}
\end{figure}
When multiple scripts generate figures (e.g., main analysis, robustness, heterogeneity), add a comment block at the top of each script listing which figure numbers it produces. This prevents two scripts overwriting the same file.
Related Skills & Commands
/plot: Command that generates visualization code for specific analyses
stats: Summary statistics that inform what to visualize
table: Companion tables that present the same results numerically
did-analysis: Event study plots are the key figure for DID papers
rdd-analysis: RDD binned scatter is essential for discontinuity papers
synthetic-control: Gap plots and placebo plots for SCM papers