ggplot2 element_line() in R: Style Lines and Gridlines
The element_line() function in ggplot2 styles every line on a plot, axis lines, gridlines, tick marks, and panel borders. You pass it inside theme() with arguments like color, linewidth, linetype, lineend, and arrow.
element_line(color = "grey80") # subtle gridlines element_line(linewidth = 0.8) # thicker line element_line(linetype = "dashed") # dashed style element_line(color = "black", linewidth = 0.5) # crisp axis line element_line(color = NA) # invisible but reserves space element_line(arrow = arrow(length = unit(2, "mm"))) # axis arrows element_line(color = "grey90", linetype = "dotted") # dotted minor grid
Need explanation? Read on for examples and pitfalls.
What element_line() does in ggplot2
element_line() builds a line-styling specification that ggplot2 plugs into any line slot. It does not draw a line by itself. You always pass the result to theme() as the value of a line argument, like panel.grid.major = element_line(color = "grey80").
Every line element in a ggplot2 plot has a name: axis.line, axis.ticks, panel.grid.major, panel.grid.minor. Each one accepts an element_line() value. Specific slots like axis.line.x and panel.grid.major.y let you target one direction at a time. Settings cascade, line = element_line(color = "blue") propagates to every line slot, then specific slots override the cascade.
element_line() is a specification, not a drawn line. ggplot2 stores the spec, then applies it when rendering. This is why one base theme can restyle every gridline across 50 plots at once.Syntax and arguments
element_line(color, linewidth, linetype, lineend, arrow, inherit.blank) covers every line styling need. Each argument has a sensible default, so you only specify what you want to change.
The default theme_grey() draws white major gridlines on a grey panel, no axis lines, and short black tick marks. Every line you see can be restyled with one element_line() per slot.
| Argument | Type | Common values |
|---|---|---|
color (or colour) |
character | "black", "grey80", "#1f77b4", NA |
linewidth |
numeric | 0.25 to 2 (mm); 0.5 is the default |
linetype |
character or integer | "solid", "dashed", "dotted", "dotdash", "longdash" |
lineend |
character | "butt" (default), "round", "square" |
arrow |
grid::arrow() | arrow(length = unit(2, "mm")) |
inherit.blank |
logical | TRUE inherits element_blank() from parent slot |
linewidth replaced size in ggplot2 3.4.0. Older tutorials use element_line(size = 1). New code should use linewidth; size still works for backward compatibility but throws a deprecation warning.Seven styling patterns with element_line()
1. Subtle major gridlines
A white background with grey85 major gridlines is the cleanest baseline. Setting panel.grid.minor = element_blank() removes the fine minor grid entirely; readers focus on the major breaks.
2. Dashed gridlines
linetype accepts six string presets or integers 0 through 6. Mixing dashed major and dotted minor gridlines visually separates the two without color clash.
3. Add visible axis lines
axis.line is hidden by default in theme_grey(). Adding element_line(color = "black") mimics a base R plot. panel.grid = element_blank() is shorthand that hides both major and minor gridlines at once.
4. Thicker, colored axis lines
linewidth is in millimeters. Values above 1 read as bold; values below 0.3 disappear on most screens. Match axis.ticks to axis.line for visual unity.
axis.line = element_line(linewidth = 0.5) plus axis.ticks = element_line(linewidth = 0.4).5. Different styles for x and y
panel.grid.major.x controls vertical gridlines; panel.grid.major.y controls horizontal ones. Pairing them with element_blank() and element_line() makes one axis primary.
6. Arrows on axes
arrow() comes from the grid package. length sets the arrowhead size; type = "closed" fills the arrowhead. Use this for textbook diagrams or schematic plots.
7. Invisible but space-preserving
color = NA draws nothing but keeps the layout slot allocated. This differs from element_blank(), which fully drops the element. The difference matters when aligning multiple plots with patchwork; an empty element_blank() can shift panel sizes.
element_line(color = NA) and element_blank() are not interchangeable. Both look empty, but NA reserves space; element_blank() removes it. Pick element_blank() when you want every plot pixel back; pick NA when alignment with sibling plots matters.element_line() vs the other element_*() helpers
Each line slot accepts only element_line() or element_blank(). Passing element_text() or element_rect() to a line slot throws an error.
| Helper | Used for | Example slot | Returns |
|---|---|---|---|
element_line() |
Lines and axes | axis.line, panel.grid | Line spec |
element_text() |
Text styling | plot.title, axis.text | Text spec |
element_rect() |
Filled rectangles | panel.background, plot.background | Rect spec |
element_blank() |
Hide an element | any slot | Empty spec |
If you assign element_text() to panel.grid.major, R errors with 'panel.grid.major' must be an element_line object. Match the helper to the slot.
Common pitfalls
Pitfall 1: Using size instead of linewidth. In ggplot2 3.4 and later, element_line(size = 1) triggers a deprecation warning. Use linewidth = 1 for line thickness; size now applies only to point and text elements.
Pitfall 2: Confusing element_blank() with element_line(color = NA). Both hide the line, but element_blank() removes the layout slot while element_line(color = NA) preserves it. Plot alignment in patchwork breaks if you mix them.
Pitfall 3: Wrong slot name. Use panel.grid.major.x, not panel.grid.major_x or panel.grid.x.major. Type ?theme for the canonical slot list; misnamed slots fail silently in older ggplot2 and error in newer versions.
Pitfall 4: Forgetting theme(). element_line(color = "red") on its own does nothing. Always wrap it: + theme(panel.grid.major = element_line(color = "red")).
Try it yourself
Try it: Build a scatter of mpg vs wt from mtcars. Make the major gridlines dashed grey, hide the minor gridlines, add black axis lines, and use a white panel background. Save the result to ex_lined.
Click to reveal solution
Explanation: Each line slot gets its own element_line() call. The white panel.background lets the grey gridlines show; element_blank() removes the minor grid entirely; the black axis.line adds visible axes that theme_grey() hides by default.
Related ggplot2 functions
After mastering element_line(), explore these companions:
theme(): the wrapper that accepts every element_*() specelement_text(),element_rect(),element_blank(): matching helpers for text, rectangles, and hidden elementsarrow()from thegridpackage: build arrowhead specs for axis linestheme_minimal(),theme_classic(),theme_bw(): pre-built themes with distinct line styling defaultscoord_cartesian(): pair with axis lines to control where they meet the panel edgescale_x_continuous(): set tick break positions that gridlines follow
For the canonical argument list, see the ggplot2 element reference.
FAQ
How do I remove gridlines in ggplot2?
Set panel.grid = element_blank() inside theme() to remove both major and minor gridlines. To remove only one set, target the specific slot: panel.grid.minor = element_blank() keeps the major grid while dropping the minor. To remove gridlines on one axis only, use panel.grid.major.x = element_blank() or panel.grid.major.y = element_blank(). The element_blank() helper drops both the line and the layout space.
What is the difference between linewidth and size in element_line?
linewidth is the modern argument for line thickness in ggplot2 3.4 and later; size was deprecated for line elements because it overloaded with point and text sizing. Both still work, but size issues a deprecation warning. New code should use linewidth = 0.5 (the default) and reserve size for geom_point() and geom_text() calls.
Can I use element_line() to draw lines inside the plot?
No. element_line() only styles theme slots, axis lines, ticks, gridlines, and panel borders. To draw lines inside the plot panel, use geom_hline(), geom_vline(), geom_abline(), or geom_segment(). These geoms accept their own color, linewidth, and linetype arguments directly, without element_line().
How do I make gridlines dashed in ggplot2?
Pass linetype = "dashed" to element_line() for the grid slot you want to restyle. For example, panel.grid.major = element_line(linetype = "dashed", color = "grey70") makes the major gridlines dashed grey. The full set of presets is "solid", "dashed", "dotted", "dotdash", "longdash", and "twodash". Integer codes 0 through 6 also work.
Why are my axis lines not showing in ggplot2?
The default theme_grey() hides axis.line because it relies on the panel border to delimit the plot. Add theme(axis.line = element_line(color = "black")) to make them visible. If you want axes but no panel border, also set panel.border = element_blank(). Built-in themes like theme_classic() enable axis lines automatically.