Version 1.0.0 | 2026-10-26
Quick Start · Installation · Key Options · Gallery · Stata-Tools · Report a bug
eplot creates forest plots and coefficient plots from variables, estimation results, matrices, or graph-ready frames. It gives applied Stata users one plotting workflow for effect sizes, confidence intervals, model comparison, and publication-oriented annotations.
Quick Start
After installing, draw a meta-analysis forest plot with weighted boxes, prediction intervals, a values column, and direction labels from study-level results typed in as data:
clear
input str20 study double(es lci uci pi_lci pi_uci weight) byte type
"Smith 2018" -0.42 -0.78 -0.06 -1.15 0.31 12.3 1
"Jones 2019" -0.31 -0.58 -0.04 -1.04 0.42 16.8 1
"Brown 2020" -0.18 -0.41 0.05 -0.91 0.55 21.5 1
"Lee 2021" -0.55 -0.93 -0.17 -1.28 0.18 10.2 1
"Garcia 2022" -0.27 -0.49 -0.05 -1.00 0.46 19.1 1
"Patel 2023" -0.09 -0.35 0.17 -0.82 0.64 20.1 1
"Overall" -0.28 -0.41 -0.15 . . . 5
end
eplot es lci uci, labels(study) weights(weight) type(type) ///
values vformat(%4.2f) ///
pi(pi_lci pi_uci) ///
i2("42.1%") tau2("0.021") qstat("8.63, df=5, p=0.125") ///
effect("Mean Difference (95% CI)") ///
favors("Favors Treatment" "Favors Control")

Drawn by demo/demo_eplot.do, which also sets the white_tableau scheme from the tc_schemes package and adds title("Meta-Analysis with Prediction Intervals").
For a coefficient plot of the model you just fitted, eplot . reads the active estimation results:
sysuse auto, clear
regress price mpg weight foreign
eplot ., drop(_cons) cicap
Features
- Four inputs, one vocabulary. Variables in memory, active or stored estimates, a matrix, or a frame share one set of selection, labelling, transform, and display options; the Key Options tables mark the few that are mode-specific.
- Meta-analysis layouts.
type()marks headers, pooled subgroup and overall rows (drawn as diamonds), heterogeneity rows, and spacers;weights()sizes the boxes,pi()adds prediction-interval whiskers, andi2(),tau2(), andqstat()print heterogeneity text you supply (it is not computed). - Intervals that match Stata's tables. Estimates mode uses the t distribution with
e(df_r), or parameter-specific degrees of freedom aftermi estimate, postandmixed, dfmethod(), andeformexponentiates only the equations Stata's owneformrule covers. - Publication annotations. A values column with its own header, size, and format,
favors()direction labels, labelledxline()reference lines,logscaleaxes, and journal presets throughstyle(). - No silent drops. A
keep()ordrop()name that matches nothing exits with r(198), and a data row with a missing estimate is left out with a note naming it.
Requirements
- Stata 16 or later
- No required external packages
- The optional
tabtoolscompanion-frame workflow requires siblingtabtools; itsregtab,effecttab,comptab, andhrcomptabcommands require Stata 17 or later
Installation
Install the released package from Stata-Tools:
capture ado uninstall eplot
net install eplot, from("https://raw.githubusercontent.com/tpcopeland/Stata-Tools/main/eplot") replace
For a local Stata-Tools checkout, replace the URL with the package directory:
capture ado uninstall eplot
net install eplot, from("/path/to/Stata-Tools/eplot") replace
Commands
| Command | Description |
|---|---|
eplot |
Draw forest and coefficient plots from data, estimates, matrices, or frames |
How It Works
eplot selects an input mode from the call and then applies a shared plotting vocabulary to the resulting effects and confidence limits.
| Calling convention | Mode | Use it when |
|---|---|---|
eplot esvar lcivar ucivar [if] [in], ... |
Data | Point estimates and confidence limits are variables in the active dataset |
eplot [namelist], ... |
Estimates | Plot active estimates with eplot . or compare stored models |
eplot, matrix(matname) ... |
Matrix | Results are assembled in a Stata matrix |
eplot [if] [in], frame(framename) ... |
Frame | A graph-ready result table is stored in a Stata frame |
Mode detection checks explicit matrix() first, then frame(). With no namelist or with . it uses active estimation results; a call with three leading numeric variables selects data mode, and estimate names select estimates mode. Use an explicit selector when a variable name and stored estimate name could be confused.
Data mode uses the three variables as estimate, lower confidence limit, and upper confidence limit. Optional type() values identify headers, regular effects, pooled subgroup/overall effects, heterogeneity rows, and blank spacers. Matrix mode accepts either two columns (b, se) or three columns (b, ll, ul); all required cells must be nonmissing, and row names supply plot labels when present.
Frame mode requires numeric estimate, ll, and ul variables unless estimate(), ll(), and ul() override those names. It automatically uses string label, numeric or string rowtype or type, numeric weight or weights, and numeric pvalue variables when they are present; type() and rowtype() are mutually exclusive. Frame mode reuses the data-mode plotting options, including groups, headers, pooled rows, weights, prediction intervals, and heterogeneity notes.
The optional tabtools bridge lets regtab, effecttab, comptab, and hrcomptab produce companion frames for eplot, frame(). The repository demo documents that workflow and requires sibling tabtools and tc_schemes packages, the _data/ fixtures, and Stata 17 or later.
Worked Examples
1. Data mode: forest plot from variables
Use data mode when point estimates and confidence limits already exist in the dataset.
clear
input str20 study double es lci uci weight byte type
"Study A" -.16 -.36 .03 15.2 1
"Study B" -.33 -.54 -.12 18.4 1
"Study C" -.09 -.25 .06 22.1 1
"Overall" -.24 -.34 -.13 . 5
end
eplot es lci uci, labels(study) weights(weight) type(type) values ///
effect("Mean Difference (95% CI)")
The type-5 row is drawn as a pooled diamond, while the study rows use weight-proportional boxes.
2. Estimates mode: compare stored models
Store models in the order you want them shown, then supply their names and optional legend labels.
sysuse auto, clear
quietly regress price mpg weight foreign
estimates store base
quietly regress price mpg weight length headroom foreign
estimates store extended
eplot base extended, drop(_cons) ///
modellabels("Base" "Extended") cicap
A single active model uses eplot .; multiple single-equation models share coefficient rows and receive separate legend entries. Multi-equation estimates retain equation prefixes when coefficient names repeat, and plotting named estimates preserves the caller’s active estimation state. Confidence intervals and p-values use the t distribution when a model provides positive residual degrees of freedom and the normal distribution otherwise, evaluated separately for each model.
3. Matrix mode: exponentiated effects with stars
A two-column matrix is interpreted as b and se, so confidence limits and p-values can be computed.
matrix R = (0.20, 0.10 \ -0.10, 0.08 \ 0.30, 0.12)
matrix rownames R = Treatment_A Treatment_B Treatment_C
eplot, matrix(R) eform values stars ///
effect("Odds Ratio (95% CI)")
Use a three-column matrix when the second and third columns are already the lower and upper confidence limits.
4. Frame mode: plot a graph-ready frame
Frame mode can consume a custom frame directly and auto-detect its pvalue variable for stars.
clear
input str12 label double estimate ll ul pvalue byte rowtype
"Age" 1.12 1.04 1.20 0.004 1
"Sex" 0.86 0.70 1.06 0.150 1
"Overall" 1.03 0.97 1.10 0.320 5
end
frame put label estimate ll ul pvalue rowtype, into(effects)
eplot, frame(effects) values stars rowtype(rowtype) ///
effect("Odds Ratio (95% CI)") null(1)
frame drop effects
The active dataset is restored after the frame is copied and plotted.
5. Estimates mode: eform, grouping, and style
Use eform for log-scale model output; explicit labels and groups can be layered over a journal preset.
sysuse auto, clear
logit foreign mpg weight length headroom trunk turn
eplot ., noconstant eform style(lancet) values ///
groups(mpg weight = "Efficiency and mass" ///
length headroom trunk turn = "Vehicle dimensions") ///
gap(.5)
In estimates mode, eform sets the null line to 1 and suppresses _cons automatically.
6. Publication forest plot: values column, labelled reference line, and favors
Subgroup time ratios on a log axis, with the values printed at the row-label size and an extra reference line at the overall estimate (synthetic data).
clear
input str20 group double(tr lci uci) byte type
"Men" . . . 0
" 18-39" 1.21 1.04 1.41 1
" 40-59" 1.09 0.97 1.22 1
" 60-79" 1.03 0.94 1.13 1
" 80+" . . . 2
"" . . . 6
"Women" . . . 0
" 18-39" 1.34 1.16 1.55 1
" 40-59" 1.12 1.01 1.24 1
" 60-79" 0.97 0.88 1.07 1
" 80+" 0.88 0.73 1.06 1
"" . . . 6
"All participants" 1.08 1.03 1.13 5
end
eplot tr lci uci, labels(group) type(type) logscale ///
values vformat(%4.2f) vsize(small) vcolor(black) ///
effect("Time ratio (log scale)") vtitle("Time ratio (95% CI)") ///
xlabel(0.7 "0.7" 0.8 "0.8" 1 "1.0" 1.25 "1.25" 1.5 "1.5") ///
xscale(lcolor(black) lwidth(medthin) fextend) ///
xline(1.08, lcolor(gs8) lpattern(dash) label("Overall 1.08")) ///
favors("Favors SSRI" "Favors SNRI", ends arrows)

The type 2 row prints Not estimated in the values column (vmissing() changes the text). effect() titles the axis while vtitle() heads the values column, and vsize(small) matches the default row-label size (labsize() sets the labels). The xline() label sits at the top of the plot (a row above the values header), favors(..., ends arrows) anchors the direction labels at the ends of the effect range, and xscale() styles the axis line without touching the range eplot computes. Because xlabel() is user-supplied, no grid is drawn unless it asks for one with xlabel(..., grid); with default ticks, nogrid removes the grid.
7. Consistent panels: shared axis styling
Keep the styling options for a multi-panel figure in one local so the panels cannot drift apart.
local shared `"logscale xlabel(0.7 "0.7" 1 "1.0" 1.4 "1.4") xscale(lcolor(black) lwidth(medthin) fextend) values vformat(%4.2f) vsize(small) vcolor(black) labsize(small) effect("Hazard ratio") vtitle("HR (95% CI)") vmissing("Too few events") favors("Favors SNRI" "Favors SSRI", below arrows)"'
* ... load panel A results (hr lci uci subgroup type) ...
eplot hr lci uci, labels(subgroup) type(type) `shared' ///
title("A. Cardiovascular event", size(medium)) name(panel_cv, replace) nodraw
* ... load panel B results ...
eplot hr lci uci, labels(subgroup) type(type) `shared' ///
title("B. Gastrointestinal bleeding", size(medium)) name(panel_gi, replace) nodraw
graph combine panel_cv panel_gi, cols(2) xsize(12) ysize(5)

Each panel computes its own effect-axis range from its data, so choose ticks that fall within the data of every panel. The full data for both panels are in demo/demo_eplot.do.
Gallery
The ten core figures below are reproducible from a repository checkout; run demo/demo_eplot.do from the repository root to regenerate them (it draws them in the white_tableau scheme from the sibling tc_schemes package). Run demo/demo_tabtools_eplot.do to regenerate the two bridge figures; that optional integration workflow also needs sibling tabtools and tc_schemes, the repository _data/ fixtures, and Stata 17 or later. These demos are checkout workflows and are not part of the net install payload.
| Output | Command focus |
|---|---|
![]() |
values after a single regression |
![]() |
comptab forest bridge |
![]() |
regtab to eplot, frame() |
![]() |
type(), weights(), pooled rows, and vsize(small) values |
![]() |
groups() and eform |
![]() |
style(lancet) |
![]() |
Three-column matrix() input with null(1) |
![]() |
pi(), i2(), tau2(), and qstat() |
![]() |
modellabels() and palette() |
![]() |
Shared xlabel(), xscale(), text sizes, vmissing(), and favors(, below arrows) across panels |
![]() |
sigcolors, sigcolor(), and insigncolor() |
![]() |
logscale, vtitle(), vsize(), labelled xline(), and favors(, ends arrows) |
Key Options
Availability tags are D = data, E = estimates, M = matrix, and F = frame. Frame mode accepts the data-mode plotting options after its frame selector. Options not marked with a mode are accepted in all four modes; additional twoway graph options are passed through.
Input and row structure
| Option | Modes | Contract and default |
|---|---|---|
matrix(matname) |
M | Selects a two- or three-column matrix |
frame(framename) |
F | Selects a graph-ready frame |
estimate(varname), ll(varname), ul(varname) |
F | Override frame variables; defaults are estimate, ll, and ul |
labels(varname) |
D, F | String row labels; data mode defaults to Row 1, Row 2, and so on; frame mode auto-detects label |
weights(varname) |
D, F | Numeric marker/box weights; frame mode auto-detects weight, then weights. Unless nobox is specified, every plotted type-1 row must carry a nonmissing, positive weight |
type(varname) |
D, F | Row-role variable; omitted rows are regular effects |
rowtype(varname) |
F | Frame synonym for type(); auto-detected when present |
pvalue(varname) |
D, F | Numeric p-values in [0, 1] for stars and r(pvalues); frame mode auto-detects pvalue |
pi(lci_var uci_var) |
D, F | Complete, ordered prediction-limit pairs drawn as dashed whiskers behind confidence intervals |
Data/frame type() values are 0 = header, 1 = regular effect, 2 = missing/excluded, 3 = subgroup pooled effect, 4 = heterogeneity row, 5 = overall pooled effect, and 6 = blank spacer. String values effect/regular, header/section, missing/reference, subgroup, hetinfo, overall, and blank are also recognized; unknown values are rejected.
Selection and labeling
| Option | Modes | Contract and default |
|---|---|---|
keep(coeflist) |
D, E, M, F | Keep only listed names; * and ? wildcards are supported; estimates/matrix modes also match eq:name; data/frame modes match the source labels() values, including structural rows; a name or pattern that matches nothing exits with r(198) |
drop(coeflist) |
D, E, M, F | Drop listed names, matched as in keep(); a name or pattern that matches no coefficient of the model exits with r(198) (_cons, and names already removed by keep() or omitted, are exempt); selection leaving no plottable effect row is an error |
rename(spec) |
E | Rename matched estimates for display before labels/groups are applied; all mappings apply at once to the original names, so swaps and chains work |
noconstant |
D, E, M, F | Drop _cons; not an error when there is no constant |
coeflabels(spec) |
D, E, M, F | Replace matched coefficient/effect labels using well-formed mappings; applied after keep(), drop(), order(), groups(), and headers(), all of which key on the original names |
groups(spec) |
D, E single, F | Insert bold group headers; members are gathered, in display order, at the group's first member; every named effect must match, and a coefficient may belong to one group only |
headers(spec) / headings(spec) |
D, E single, F | Insert a header before a matched effect; headings() is an alias |
gap(#) |
D, E single, F | Nonmissing, nonnegative extra group spacing; default is 0 |
Transform, reference lines, and intervals
| Option | Modes | Contract and default |
|---|---|---|
eform |
D, E, M, F | Exponentiate estimates and limits; the null defaults to 1 instead of 0 |
logscale |
D, E, M, F | Draw the effect axis on a logarithmic scale with multiplicative padding and decade ticks; all plotted values, null(), and xline() positions must be positive, and the null defaults to 1 |
rescale(#) |
D, E, M, F | Nonmissing, nonzero multiplier for estimates and limits on the estimation scale (with eform, rescale(10) plots exp(10*b)); negative factors preserve lower/upper ordering; default is 1 |
xline(numlist[, line_options label(strlist[, size() color() placement()])]) |
D, E, M, F | Add reference lines; repeatable, one style per occurrence; bare positions use a light dashed style; label() gives one label per line, drawn at the top of the plot beside the line (left of it in the right half of the axis; a row above the header with values; beside the first row in vertical layout) |
xlabel(spec) |
D, E, M, F | Set effect-axis ticks in either orientation; the axis range extends to every numeric tick; draws no grid (including a scheme grid) unless its suboptions include grid |
nogrid |
D, E, M, F | Suppress the grid eplot draws with its default ticks |
null(#[, line_options]) |
D, E, M, F | Nonmissing null line position; default is 0, or 1 with eform; line options replace the dashed gray style; not drawn when off the axis |
nonull |
D, E, M, F | Suppress the null line |
level(#) |
D, E, M, F | Confidence level for constructed intervals; default is current c(level), normally 95; in data/frame mode it only labels the default title, which reads 95 without it |
noci |
D, E, M, F | Suppress all interval geometry: whiskers are omitted and data/frame pooled rows are drawn as markers rather than diamonds; the axis ranges on the point estimates |
cicap |
D, E, M, F | Use capped rcap intervals instead of rspike |
Display, significance, and meta-analysis
| Option | Modes | Contract and default |
|---|---|---|
dp(#) |
D, E, M, F | Nonnegative decimal places for values; default is 2 |
effect(string[, atnull]) |
D, E, M, F | Effect-axis title, and the values header unless vtitle() is set; atnull centres the title under the null on its own row (size and color from xtitle()); data/frame default to Estimate (95% CI) or Effect (95% CI) with eform, while estimates/matrix use the current CI level |
values |
D, E single, M, F | Annotate rows with estimate and interval text; requires horizontal layout |
vformat(fmt) |
D, E, M, F | Numeric values format; default is %24.2f, or %w.dpf with w = dp + 22; fixed formats round half away from zero on the decimal value, never print -0.00, and show a row in exponent notation when any of its numbers is too wide |
vsize(textsizestyle), vcolor(colorstyle) |
D, E single, M, F | values text size and color; defaults are vsmall and gs4; vsize(small) matches the row labels |
vtitle(string) |
D, E single, M, F | Header above the values column; default is the effect() text |
vgap(#) |
D, E single, M, F | Nonmissing, nonnegative gap between the effect axis and the values column, as a fraction of the axis span (of its log span under logscale); default is 0.15. The column starts right of the widest interval, the null line when drawn, and the last labelled tick |
vmissing(string) |
D, F | values text on type 2 (missing/excluded) rows; default is Not estimated; vmissing("") leaves them blank; string reference rows stay blank |
baselevels, vreference(string) |
E single | Show factor base levels as reference rows (no marker); values text 1.00 (reference) with eform, 0.00 (reference) otherwise, or vreference(); not in r(k)/r(table) |
labsize(textsizestyle) |
D, E, M, F | Row-label size; default is small |
stars |
D, E single, M 2-column, F | Append p-value stars to values; data mode requires pvalue(), while frame mode uses pvalue() or an auto-detected pvalue variable |
sigcolors |
D, E single, M, F | Color single-model effects by whether the interval excludes null(); multi-model estimates use palette() colors |
sigcolor(color) |
D, E single, M, F | Significant-effect color when sigcolors is set; default is cranberry |
insigncolor(color) |
D, E single, M, F | Non-significant-effect color when sigcolors is set; default is gs10 |
favors(left right[, ends below arrows size() color() gap()]) |
D, E, M, F | Directional labels for a horizontal effect axis, anchored at the null and reading outward from it (gap() sets the gap, default 1.5), in the tick-label size; ends at the axis ends, below under the tick labels, arrows adds direction arrows, size()/color() style the text; a null not strictly inside the tick span moves the labels to the ends |
i2(string), tau2(string), qstat(string) |
D, F | Add supplied heterogeneity text as-is to the graph note; values are not computed |
hetrow |
D, F | Show the heterogeneity text as a row (I² = …, τ² = …, Q = …) under the last overall row instead of in the note |
style(name) |
D, E, M, F | Presets: forest, coef, lancet, jama, nejm, and bmj; explicit options override preset defaults |
Layout and model comparison
| Option | Modes | Contract and default |
|---|---|---|
horizontal / vertical |
D, E, M, F | Horizontal is the default; the two orientations are mutually exclusive |
sort |
D, E, M, F | Sort regular effects by estimate within their block (between header, pooled, and blank rows, and within each groups() list); global without such rows; may not be combined with order() |
order(coeflist) |
D, E, M, F | Explicit order; unlisted rows follow in their original order; a name that matches nothing exits with r(198); may not be combined with sort |
modellabels(strlist) |
E multi | Exactly one legend label per model |
offset(#) |
E multi | Nonmissing, nonnegative vertical model spacing; default is 0.15, reduced with more than five models so a coefficient's models span at most 0.6 rows |
palette(colorlist) |
E multi | Exactly one color per model; the default palette navy cranberry forest_green dkorange purple teal maroon olive_teal cycles for a ninth model onward |
legendopts(string) |
E multi | Additional legend options; default is rows(1) pos(6) size(small) |
Markers and graph options
| Option | Modes | Contract and default |
|---|---|---|
mcolor(color) |
D, E, M, F | Marker color; default is navy in single-model plots, while multi-model estimates use palette() colors |
msymbol(symbol) |
D, E, M, F | Marker symbol (any symbolstyle, case-sensitive); default is O. An unknown name, or a list outside multi-model estimates mode, exits with r(198). With multiple models, one symbol for every model or exactly one per model, e.g. msymbol(O D T), so models differ by shape as well as color |
msize(size) |
D, E, M, F | Marker size; default is medium, or medsmall for multi-model estimates |
boxscale(#) |
D, F | Nonmissing, positive weighted-box scaling; default is 100 percent |
nobox |
D, F | Replace weight-proportional squares with standard markers |
nodiamonds |
D, F | Replace pooled-effect diamonds with standard markers |
diamondcolor(overall [subgroup]) |
D, F | Diamond outline colors; default black and maroon |
cicolor(color) |
D, E, M, F | CI line color; default follows mcolor() in single-model plots, while multi-model estimates use palette() colors |
ciwidth(lwstyle) |
D, E, M, F | CI line width; default is medium |
title(string), subtitle(string), note(string) |
D, E, M, F | Graph title, subtitle, and note |
name(string), saving(filename), scheme(schemename) |
D, E, M, F | Graph name, saved graph path, and scheme |
plotregion(options), graphregion(options), aspect(#) |
D, E, M, F | Standard Stata graph-region and aspect options; with values, plotregion() is merged with the values-column margin |
export(frame[, replace]) |
D, E, M, F | Write the plotted rows (label, estimate, ll, ul, pos, and type, weight, model_id, pvalue, values where available) to a frame that eplot, frame() reads back; the values are as plotted, so add null(1) (and logscale) after eform |
xscale(), yscale() |
D, E, M, F | Axis style suboptions such as lcolor(), lwidth(), fextend, line are merged into the axes eplot builds; range(), log, nolog, reverse, noreverse, and axis() exit with r(198) |
twoway options |
D, E, M, F | Other options are appended to the generated twoway command |
Stored Results
After a successful call, eplot returns r-class results. Use return list and matrix list r(table) to inspect them.
| Result | Type | Meaning |
|---|---|---|
r(N) |
Scalar | Number of display rows: effect rows plus generated groups()/headers() header rows, gap() spacer rows, baselevels reference rows, and the hetrow row; in data and frame modes, non-effect rows retained through type() are also included |
r(k) |
Scalar | Number of regular plotted effects; pooled rows and headers are excluded where applicable |
r(n_models) |
Scalar | Number of models in estimates mode; not returned for other modes |
r(cmd) |
Local macro | Full generated twoway command |
r(table) |
Matrix | b, ll, and ul columns; multi-model estimates use b_1 ll_1 ul_1 ... |
r(pvalues) |
Matrix | P-values when supplied in data/frame mode, available for one-model estimates, or requested for a two-column matrix with stars |
For a single estimates model or a matrix, r(table) is k × 3. For multiple estimates it is k × (3 × number of models), with three columns per model. Data- and frame-mode pooled subgroup and overall rows appear in r(table) even though r(k) counts regular type-1 rows. Returned matrices use plotted labels as row names when Stata permits them; otherwise they fall back to row1, row2, and so on without truncating the graph labels.
Assumptions and Limits
- Data and frame modes take confidence limits from supplied variables;
level()is only for intervals constructed in estimates and matrix modes. - In data and frame modes an effect row needs an estimate and both limits. A row with no estimate, or with neither limit, is left out of the plot with a note naming it; give it
type()code 2 to keep it as a labelled row. A row with exactly one missing limit exits withr(198). - Estimates-mode intervals and p-values use the t distribution with
e(df_r), or with parameter-specific degrees of freedom when the estimator posts them (e(df_mi)aftermi estimate, post;e(df)aftermixed, dfmethod()), and the normal distribution otherwise. Parameters in the/equation and the variance components ofmixed(its equations after the firste(k_f)fixed-effect coefficients) are omitted with a note. Omitted and base-level terms (exactly zero variance) are not plotted. - Supplied lower confidence limits may not exceed upper limits; prediction limits must be complete ordered pairs; two-column matrix standard errors must be nonnegative; and all required matrix cells must be nonmissing.
- Data/frame effect titles therefore default to 95% CI wording; estimates/matrix titles use the current
c(level), and single-model estimates-modeeformlabels the axis with the name the command's own table gives the exponentiated column (odds, hazard, time, risk, and relative-risk ratios, IRR, SHR), falling back to "Effect" where Stata's table readsexp(b). - Matrix mode requires exactly two columns (
b,se) or three columns (b,ll,ul); two-column input is the only matrix form that supportsstars. valuesandfavors()require horizontal layout;values,stars,sigcolors,sigcolor(), andinsigncolor()are single-model-only in estimates mode, and a multi-model call that explicitly supplies them exits withr(198).groups(),headers(), andgap()apply to data/frame mode and single-model estimates; multi-model-only options (modellabels(),offset(),palette(), andlegendopts()) require multiple estimates.eformexponentiates supplied values, sets the null to 1, and suppresses_consautomatically in estimates and matrix modes.logscalerequires strictly positive values; a non-positive plotted value,null(), orxline()position exits withr(198)rather than drawing a collapsed axis. Ticks sit on a decade lattice (for example0.5 1 2 5 10 20); a range wider than twelve decades labels every kth decade, at most twelve ticks, and a range narrower than threefold that contains the null gets ticks null·r^k (for the smallest r of 1.1, 1.25, 1.5, and 2 giving 4 to 9 ticks), symmetric about the null.eplotcomputes each axis range itself.xscale()andyscale()accept style suboptions only;range(),log,reverse,axis(), and their negations exit withr(198). Uselogscalefor a logarithmic effect axis.- In data mode, three leading numeric variables win mode detection even if their names also match stored estimates; use
eplot .,matrix(), orframe()to disambiguate. - In multi-model estimates, models are told apart by color unless
msymbol()gives each its own symbol; for greyscale print or color-vision-deficient readers, pass one symbol per model.palette()sets per-model colors by default.mcolor()andcicolor()each take one color for every model or exactly one color per model (quote RGB triplets in a list);mcolor()may not be combined withpalette(), andsigcolorsis single-model-only. Astyle()preset's colors yield to the palette. The default palette cycles for a ninth model onward, so model m uses colormod(m-1, 8) + 1. - Style presets supply defaults only; explicitly supplied options take precedence, and a preset's
valuescomponent applies only wherevaluesitself does. keep(),drop(),order(),groups(), andheaders()key on the original coefficient orlabels()values in every mode;coeflabels()is applied last, so relabeling and grouping compose.
References
Estimates mode follows the rules in these Stata manual entries:
- StataCorp. [P] ereturn — Post the estimation results. Stata Programming Reference Manual. t statistics with
e(df_r)degrees of freedom when it is posted, normal statistics otherwise. - StataCorp. [ME] mixed — Multilevel mixed-effects linear regression. Stata Multilevel Mixed-Effects Reference Manual. Parameter-specific
e(df)afterdfmethod(), ande(V_df)afterdfmethod(kroger). - StataCorp. [MI] mi estimate — Estimation using multiple imputations. Stata Multiple-Imputation Reference Manual. Parameter-specific
e(df_mi);e(b)ande(V)are stored only withpost. - StataCorp. [R] ml — Maximum likelihood estimation, options for use with
ml display. Stata Base Reference Manual.eformexponentiates only the firste(k_eform)equations, by default the first.
Related commands:
- coefplot by Ben Jann — a comprehensive coefficient-plot command available from SSC
- metan — a user-written meta-analysis command available from SSC
meta forestplot— the official meta-analysis forest-plot command
QA
QA suites and how to run them are documented in qa/README.md.
Author
Timothy P Copeland, Karolinska Institutet
Questions and bug reports: GitHub issues. Please include the first line of which eplot and your Stata version.
To cite: Copeland TP. eplot: Forest and coefficient plots from any source. Stata-Tools, https://github.com/tpcopeland/Stata-Tools/tree/main/eplot. Please give the version you used (which eplot prints it).
License
MIT (see LICENSE)








