ggplot2 scale_linetype() in R: Map Factor to Line Patterns
The scale_linetype() function in ggplot2 maps a discrete (factor) variable to line patterns, so each group draws with a different dash style. It is the core scale behind any chart that uses the linetype aesthetic to separate trends without color.
scale_linetype() # default discrete palette scale_linetype(name = "Group") # tune legend title scale_linetype_manual(values = c("dashed", "dotted")) # pick patterns by name scale_linetype_manual(values = c("A" = "solid", "B" = "dashed")) # named values scale_linetype_manual(values = c(1, 2, 4)) # integer codes 0 to 6 scale_linetype_identity() # column values ARE the linetype scale_linetype(na.value = "blank") # hide NA group
Need explanation? Read on for examples and pitfalls.
What scale_linetype() does in one sentence
scale_linetype() maps each level of a discrete variable to a unique dash pattern so groups stay visually separable without color. ggplot2 picks from the 6 named patterns ("solid", "dashed", "dotted", "dotdash", "longdash", "twodash") plus "blank" in a fixed cycle, with the option to pass custom hex strings for unlimited dash designs.
Syntax and arguments
scale_linetype(name = waiver(), breaks = waiver(), labels = waiver(), limits = NULL, na.value = "blank", guide = "legend"). The na.value argument controls how missing groups draw; default "blank" hides them. There is no values argument on scale_linetype() itself; to pick specific patterns use scale_linetype_manual().
The linetype = cyl mapping inside aes() tells ggplot which variable controls the dash style. scale_linetype() then auto-picks one pattern per factor level. With three cyl levels, ggplot assigns "solid", "dashed", "dotted" in order.
linewidth = 0.5 makes short dashes and dots look almost identical, especially on retina displays or in thumbnails. Bump to 1 or 1.2 inside geom_line() for legibility.Five common patterns
1. Default scale_linetype() with a factor
The mapping linetype = cyl is enough to trigger scale_linetype() implicitly. You only call scale_linetype() directly when you want to tune the legend, the breaks, or the NA value. For full control over which pattern each level gets, jump to scale_linetype_manual() in pattern 2.
2. Manual patterns with scale_linetype_manual()
Use scale_linetype_manual() whenever you need a specific pattern per group. Valid values are the named strings ("solid", "dashed", "dotted", "dotdash", "longdash", "twodash"), integer codes 0 to 6, or custom hex strings like "1F" (1 unit on, 15 off).
3. Custom dash patterns with hex strings
Hex strings encode the on-off pattern: "1F" is 1 unit on, 15 off (sparse dots), "62" is 6 on, 2 off (long dash). Each character (0 to 9, A to F) is a hex unit of pen up or down, alternating. This unlocks unlimited custom patterns past the 6 named ones.
4. linetype plus color for double-encoding
When linetype and color both map to the same variable, ggplot merges the two legends into one. This double-encoding is best for print or grayscale fallback: the line stays readable when color is lost in photocopy or for color-blind readers.
aes(linetype = mpg) triggers "A continuous variable cannot be mapped to the linetype aesthetic." Cast to a factor first with factor(cut(mpg, 3)), or use scale_linetype_binned() to bin automatically.5. Tidy legend with custom labels
The name argument renames the legend header. The labels argument relabels each factor level for display, useful for engineering units, scientific notation, or shorter display strings without rewriting the underlying factor.
scale_linetype() vs scale_linetype_manual() vs scale_linetype_identity()
| Function | Source of pattern | Use when |
|---|---|---|
scale_linetype() |
Auto picks from 6 named patterns | Up to 6 groups, any pattern works |
scale_linetype_manual() |
You pass values = c(...) |
Specific pattern per group needed |
scale_linetype_identity() |
Column itself holds "solid", "dashed", or codes | Data already encodes the pattern |
scale_linetype_discrete() |
Alias for scale_linetype() |
Legacy code or explicit clarity |
scale_linetype_binned() |
Continuous variable binned into patterns | Linetype by numeric range |
Common pitfalls
Pitfall 1: more than 6 levels. scale_linetype() warns and recycles patterns once you push past the named palette. Use scale_linetype_manual() with hex strings to extend, or switch the encoding to color or faceting.
Pitfall 2: forgot group =. Mapping linetype to a factor usually creates the grouping automatically, but if you ALSO map color to a different variable, ggplot may not split the line. Add group = interaction(grp1, grp2) to be explicit.
Pitfall 3: NA rows draw as solid lines. The default na.value = "blank" hides them, but if a user override changes that default and NA groups exist, they appear as solid lines next to your real groups. Drop NA rows before plotting or set na.value = "blank" explicitly.
Try it yourself
Try it: Plot the built-in Loblolly data with age on x, height on y, and Seed (as a factor) controlling line type. Limit to three seeds, use scale_linetype_manual() to assign solid, dashed, and dotted, and save the plot to ex_lt.
Click to reveal solution
Explanation: subset() keeps only three Seed levels so the manual mapping has exact matches for values. scale_linetype_manual(values = ...) then assigns one named pattern per Seed, and name = sets the legend header.
Related ggplot2 functions
After mastering scale_linetype(), look at:
geom_line(): the main geom that uses the linetype aestheticscale_linetype_manual(): pick specific patterns per levelscale_linetype_identity(): when the data column holds pattern names directlyscale_color_brewer(): pair color with linetype for accessible group encodingaes(): where you maplinetype = variablein the first place
For the full reference, see the official ggplot2 scale_linetype page.
FAQ
What line types does ggplot2 support?
ggplot2 supports 6 named patterns plus "blank": "solid" (1), "dashed" (2), "dotted" (3), "dotdash" (4), "longdash" (5), "twodash" (6), and "blank" (0). You can pass either the names or the integer codes anywhere linetype = ... is accepted, including fixed values in geom_line(linetype = ...) and mapped values in scale_linetype_manual(values = ...). For unlimited custom patterns, pass hex strings like "1F" or "62" that encode the on-off pen sequence.
How do I change line type in ggplot2 without mapping a variable?
Set linetype as a constant inside the geom call, not inside aes(). For example, geom_line(linetype = "dashed") makes every line dashed regardless of data. The key distinction: linetype = "dashed" inside aes() would treat the literal string "dashed" as a one-level factor, which is rarely what you want. Outside aes(), the value is a fixed graphical setting that applies to all lines drawn by that geom.
What is the difference between scale_linetype and scale_linetype_manual?
scale_linetype() auto-assigns patterns from the fixed palette of 6 named line types. scale_linetype_manual() lets you specify exactly which pattern each factor level gets via values = c(...). Use scale_linetype() for quick exploratory plots where any clear separation suffices, and scale_linetype_manual() for publication plots where the pattern-to-group mapping must be deliberate, reproducible, and consistent across figures in a paper.
Can I map a continuous variable to linetype in ggplot2?
Not directly. ggplot2 errors with "A continuous variable cannot be mapped to the linetype aesthetic" because linetype is inherently discrete. Two workarounds: bin the variable into 3 to 5 categories with cut(x, 4) and map the result, or use scale_linetype_binned() which does the binning for you. For continuous trend encoding, prefer linewidth (line thickness) or alpha (line opacity), both of which handle continuous mappings natively.
Why do my dashed and dotted lines look the same?
The default linewidth = 0.5 makes short dashes and dots visually indistinguishable, especially on retina displays or when the chart is small. Bump linewidth to 1 or 1.2 inside geom_line() and the gaps render large enough to read. If lines still merge, switch to higher-contrast patterns like "longdash" and "twodash", or double-encode with color so the chart stays readable even at thumbnail size.