Written and maintained by CASRAI Editorial Board
Last updated
To plot a line in R, call plot(x, y, type = "l") in base R or add geom_line() to a ggplot2 chart; to add a second line to an existing plot, call lines(x, y). “Plot a line” is used for three different jobs, and each has a different function: connecting data points in order (this page), adding a line to a plot that already exists, and drawing a straight or fitted line through a scatterplot.
Which one do you need? Connecting measurements across time, dose or distance is covered below. A straight reference or regression line over a scatterplot is a different task, covered in CASRAI’s Scatterplots in R guide (base R’s abline() is the function documented for “drawing (single) straight lines”). A distribution rather than a trend belongs in a histogram, and categories belong in a bar plot. For a wider chooser, see Types of Graphs in Statistics.
The example data below are small vectors written into the code so you can paste and run them; they are illustrative values, not measurements from any study.
What it is used for in research
A line plot joins observations in order so the reader sees change: a time course, a growth curve, a dose-response series, a measurement repeated at fixed intervals. The joining is the claim the figure makes, so it is only appropriate when the x values have a meaningful order and the step between neighbouring points is something you are willing to interpolate over. For two unordered variables use a scatterplot; for modelling serial dependence in the data, see ARIMA Models for Research Time Series.
Install or access
Base R plotting needs no extra package: plot() and lines() belong to the graphics package that ships with R. R itself is downloaded from the Comprehensive R Archive Network (CRAN) at cran.r-project.org. ggplot2 is installed from within R:
install.packages("ggplot2")
library(ggplot2)
The ggplot2 documentation also shows install.packages("tidyverse") as the easiest route, since it installs ggplot2 along with the rest of the tidyverse. If you are new to the environment, CASRAI’s How to Use RStudio and What Is R Programming Used For cover the basics.
Step-by-step: plot a line
1. Base R: plot() with type = “l”
The default plot type is points (type = "p"). The documented one-character type codes include "l" for lines, "b" for both points and lines, "o" for points and lines overplotted, "s" and "S" for stair steps, "h" for histogram-like vertical lines, and "n" for no points or lines.
- Put the x values and y values in two vectors of equal length, with x in the order you want them joined.
- Call
plot()withtype = "l":
hours <- c(0, 2, 4, 6, 8, 10)
signal <- c(1.0, 2.1, 3.9, 5.2, 5.8, 6.1)
plot(hours, signal, type = "l",
xlab = "Time (h)", ylab = "Signal (arbitrary units)",
main = "Signal over time")
- Style the line with
col(colour),lty(line type) andlwd(line width), for exampleplot(hours, signal, type = "b", col = "blue", lty = 2, lwd = 2). Usetype = "b"when readers should see where the actual measurements are, not only the joins between them.
2. Add a second line with lines()
lines() is documented as a generic function that takes coordinates and joins the points with line segments; its default method is lines(x, y = NULL, type = "l", ...). It draws on the current plot and does not rescale the axes, so set the y range on the first call to cover every series:
signal2 <- c(0.8, 1.4, 2.0, 2.4, 3.1, 3.3)
plot(hours, signal, type = "l", col = "black",
ylim = range(c(signal, signal2)),
xlab = "Time (h)", ylab = "Signal (arbitrary units)")
lines(hours, signal2, col = "red", lty = 2)
legend("topleft", legend = c("Group A", "Group B"),
col = c("black", "red"), lty = c(1, 2))
If you do not want the first series to draw anything, plot(hours, signal, type = "n") sets up the axes without drawing points or lines, and every series is then added with lines().
3. ggplot2: geom_line()
ggplot2 expects a data frame with one row per observation. geom_line() “connects them in order of the variable on the x axis”:
library(ggplot2)
df <- data.frame(
hours = rep(c(0, 2, 4, 6, 8, 10), times = 2),
signal = c(1.0, 2.1, 3.9, 5.2, 5.8, 6.1,
0.8, 1.4, 2.0, 2.4, 3.1, 3.3),
group = rep(c("A", "B"), each = 6)
)
ggplot(df, aes(x = hours, y = signal, colour = group)) +
geom_line(linewidth = 1) +
labs(x = "Time (h)", y = "Signal (arbitrary units)")
Two lines are drawn because colour = group maps a grouping variable; ggplot2’s documentation states that “the group aesthetic determines which cases are connected together.” Line width is the linewidth aesthetic (for example linewidth = 3, colour = "red" in the documentation’s own examples). A single-series example from the documentation is ggplot(economics, aes(date, unemploy)) + geom_line(), using the economics data that ships with ggplot2.
Output and how to read it
Each line segment joins two adjacent observations, so the slope of a segment is the average rate of change between those two measurements and says nothing about what happened between them. Read the figure with three checks:
- Axis range. In base R, the y axis is fixed by the first call; a line added with
lines()that runs off the plot area meansylimwas too narrow. - Markers. A line with no point markers hides how many observations exist.
type = "b"or ageom_point()layer shows the sampling. - Legend and line type. If the figure may be printed in black and white, distinguish series by
lty(base R) orlinetype(ggplot2) as well as colour.
Troubleshooting
The line zigzags back and forth
Points are joined in the order the function uses. With plot(x, y, type = "l") that is the order of the rows you supplied, so unsorted x values produce a tangle. Sort first, for example o <- order(hours); plot(hours[o], signal[o], type = "l"). In ggplot2, geom_line() sorts by x for you, whereas geom_path() “connects the observations in the order in which they appear in the data.” Choose geom_path() deliberately, for a trajectory where the order of rows is the information; use geom_line() for a function of x.
There are gaps in the line
In base R, “if a point contains NA in either its x or y value, it is omitted from the plot,” and the documentation notes that “missing values can be used to achieve breaks in lines.” A gap therefore means a missing value, which is sometimes what you want (an instrument outage) and sometimes a data problem to fix upstream; count the NAs with sum(is.na(signal)) before deciding.
ggplot2 draws no line, only points or nothing
When a grouping variable puts every group at a single x value, there is nothing to connect. Check that each group has at least two observations, and that the variable you mapped to colour or group is not unique per row.
The second line is missing or clipped
lines() adds to the current plot and does not open a new one. Call it after plot(), not before, and widen ylim (and xlim if needed) on the first call.
Alternatives within R
| Approach | What it does | Use it when |
|---|---|---|
plot(x, y, type = "l") |
Draws a new plot and joins the points with lines (base R, graphics package). |
You want a quick line with no extra package. |
lines(x, y) |
Joins points with line segments on an existing plot. | You are adding a second or later series. |
plot(x, y, type = "s") |
Stair-step plot. | The value holds constant between observations. |
ggplot2::geom_line() |
Connects observations in order of the x variable. | You want grouping, colour mapping and automatic legends from one mapping. |
ggplot2::geom_path() |
Connects observations in the order they appear in the data. | Row order is meaningful, as in a trajectory. |
ggplot2::geom_step() |
Creates a stairstep plot, highlighting exactly when changes occur. | You need to show when a value changes rather than a smooth join. |
FAQ
What is the difference between plot a line and line plot in R?
Nothing in the code: line plot, line graph and “plot a line” are all searched for the same output, a chart of joined points. In base R that is plot(x, y, type = "l"); in ggplot2 it is geom_line(). A straight line over a scatterplot is a different function; see the scatterplots guide.
How do I plot multiple lines in R?
In base R, call plot() for the first series with a ylim that covers all of them, then call lines() once per further series. In ggplot2, put all series in one data frame and map a grouping column to colour or group.
How do I plot a line and points together?
Use type = "b" (points and lines) or type = "o" (overplotted points and lines) in base R, or add geom_point() to a geom_line() chart.
Why does my line plot have breaks in it?
A missing value in x or y is omitted and breaks the line in base R; see the troubleshooting section above. To compare the same measurements as a distribution per group instead, see Box Plots in R.
Sources (official documentation)
- R Core Team, plot.default: The Default Scatterplot Function (R documentation, graphics package), checked 2026-10-29.
- R Core Team, lines: Add Connected Line Segments to a Plot (R documentation, graphics package), checked 2026-10-29.
- ggplot2 documentation, Connect observations: geom_path, geom_line, geom_step, checked 2026-10-29.
- ggplot2 documentation, Installation, checked 2026-10-29.
- The Comprehensive R Archive Network, cran.r-project.org, checked 2026-10-29.








