Written and maintained by CASRAI Editorial Board
Last updated
Stata builds scatterplots with the twoway scatter command, and adds a fitted regression line to the same graph by layering a second twoway element — lfit for a straight line, qfit for a quadratic curve — inside the same command rather than as a separate step. Because every twoway plot type follows the same building-block syntax, the pattern you learn for a scatter-plus-fit-line graph extends directly to combining any number of scatter, fit, and grouping elements in one call.
This page covers the graphing command itself: twoway scatter syntax, the lfit/qfit overlay, and combining multiple twoway elements. For the statistics behind the fitted line — ordinary least squares, residuals, and what a linear fit assumes about the data — see CASRAI’s regression analysis guide; for running the equivalent t-test procedure in Stata, see running a t-test in Stata, and for the software itself, see CASRAI’s SPSS overview and the R vs. Stata comparison if you’re deciding which package to learn.
The basic twoway scatter command
twoway is Stata’s general-purpose two-dimensional graphing command. Every plot it draws — scatter, line, bar, fitted curve — is a “plot type” specified as the first word after twoway, followed by a y-variable and an x-variable:
twoway scatter mpg weight
using Stata’s built-in auto dataset (sysuse auto) as a stand-in, this plots one point per observation, fuel economy (mpg) on the y-axis against vehicle weight (weight) on the x-axis. That two-variable, y-then-x argument order is the same for every plot type in the twoway family, which is what makes combining them predictable once you know the pattern.
Common scatter-level options control how the points look, not what’s plotted:
msymbol()— marker shape (circle, diamond, triangle, and so on)mcolor()— marker colormsize()— marker sizemlabel(varname)— prints a text label next to each point, drawn from another variable (e.g.mlabel(make)to label each car by name)
These go inside the same command, after the variable list: twoway scatter mpg weight, mlabel(make) msymbol(oh).
Adding a fitted line: lfit and qfit
A raw scatterplot shows the relationship; a fit line summarizes it. Stata provides this as its own twoway plot type rather than a separate two-step process — you don’t need to run regress first. lfit fits a straight (linear, OLS) line across the range of the x-variable in your data; qfit fits a quadratic (curved) line by including a squared term internally. Both compute their own regression at graph time purely for plotting, and neither one saves new variables or estimation results to your dataset the way running regress separately would.
twoway lfit mpg weight
twoway qfit mpg weight
On their own, each of these draws only the fitted line with no points — useful for the syntax pattern, less useful as a finished graph. The overlay you actually want combines the fit line with the scatter of raw points in a single command (next section).
Two related plot types worth knowing:
lfitci/qfitci— the same fit, drawn with a shaded confidence-interval band around the linelowess— a locally-weighted, non-parametric smooth rather than a single global line or curve, useful when you suspect the relationship isn’t well described by either a straight line or a simple quadratic
Choosing between lfit and qfit is a judgment call about the data, not a syntax question: lfit assumes a straight-line relationship; reach for qfit when the scatter visibly curves and a straight line would systematically miss the pattern at one or both ends of the range.
Combining multiple twoway elements in one graph command
This is the core mechanic: a single twoway command can layer any number of plot types by wrapping each one in parentheses, one after another, with no comma between the parenthesized groups. Stata draws them in the order listed, each on top of the last:
twoway (scatter mpg weight) (lfit mpg weight)
Each parenthesized element can carry its own options, scoped to just that element — for example, giving the scatter a marker style and the fit line a color, without one affecting the other:
twoway (scatter mpg weight, mcolor(gray)) (lfit mpg weight, lcolor(red))
Overall graph-level options — the ones that apply to the whole combined graph rather than to a single element, such as title(), ytitle(), xtitle(), legend(), or by() — go once, after a final comma, outside every parenthesized group:
twoway (scatter mpg weight) (lfit mpg weight), ///
title("Fuel economy by weight") legend(order(1 "Observed" 2 "Linear fit"))
An older, equivalent syntax joins elements with a double pipe instead of parentheses (twoway scatter mpg weight || lfit mpg weight). It still works, but the parenthesized form is the clearer and more commonly taught style once options are attached to individual elements, since it’s unambiguous which options belong to which plot.
The same pattern scales past two elements. A scatter, a linear fit, and a confidence band together is simply three parenthesized groups in one command:
twoway (scatter mpg weight) (lfit mpg weight) (lfitci mpg weight)
Faceting with by(): one scatter-and-fit panel per group
by(groupvar) is also a graph-level option, so it goes after the final comma alongside title() and legend(). It splits the combined scatter-plus-fit graph into one small panel per value of a categorical variable, each panel with its own fitted line computed from just that group’s data:
twoway (scatter mpg weight) (lfit mpg weight), by(foreign)
This is the fastest way to check whether a relationship holds consistently across groups, or whether the fitted line for one subgroup looks meaningfully different from another — a visual companion to running the regression separately by group.
Saving or exporting the graph
Once a twoway command runs, the graph opens in Stata’s Graph window. Two commands turn it into a file:
graph export filename.png, replace— exports a static image (PNG, PDF, EPS, SVG, and others depending on platform) for a paper, slide deck, or reportgraph save filename.gph, replace— saves it as a native Stata graph file, editable later in Stata’s own Graph Editor without re-running the command
Frequently asked questions
Does lfit require running regress first?
No. lfit (and qfit) compute their own regression internally, purely to draw the line — they don’t require a prior regress command and don’t leave estimation results behind the way regress does. If you already ran regress for the actual analysis and want the identical fitted line Stata used there, you can alternatively predict fitted values and plot them with twoway line, but for a quick visual overlay lfit/qfit is simpler and is what most Stata documentation and teaching materials use.
What’s the difference between lfit and qfit?
lfit draws a straight-line (linear) fit; qfit draws a curved (quadratic) fit by adding a squared term to the underlying regression. Use qfit when the scatter shows a visible curve that a straight line wouldn’t track well.
How do I label individual points on a Stata scatterplot?
Add mlabel(varname) to the scatter element, naming a variable that holds the text you want next to each point — for example mlabel(make) to label each observation by name. Combine with mlabpos() to control label placement relative to the marker.
Can I combine a scatterplot with more than one type of fit line?
Yes — add as many parenthesized elements as you need in the same twoway command, for example a scatter plus both an lfit and a qfit line, so you can visually compare a straight-line and a curved fit on the same graph.
How do I remove the legend or change its labels?
The legend() graph-level option, placed after the final comma, controls this: legend(off) removes it entirely, and legend(order(1 "label one" 2 "label two")) relabels and reorders the entries to match the order your parenthesized elements were listed in.








