Visualization VocabularyDataviz vocabulary
Diagram: ternary plot
Drawing: Adrien Taudière (CC0)
ggplot2 example: ternary plot
Adrien Taudière (CC0); R code ↓; data: Aitchison 1986, via compositions (van den Boogaart, Tolosana-Delgado & Bren 2025) (GPL)

chart

ternary plot

Scatterplot drawn in a triangle, where each point's position gives the shares of three components of a single whole.

Classification

  • chart
  • points and bubbles › scatterplots
  • part-to-whole

Channels

Attestation and synonyms

Scientific literature

OpenAlex: 760 papers since 1968, 36% in the last five years; mostly in Earth and Planetary Sciences, Environmental Science, Agricultural and Biological Sciences; Wikidata

Seminal references

R packages

R code of the ggplot2 example

library(ggplot2)

## Sand, silt and clay of 39 sediment samples taken at different water depths
## in an Arctic lake (Aitchison 1986). Plain ggplot2: each composition is
## projected into an equilateral triangle, sand bottom left, silt bottom
## right, clay on top.
data(ArcticLake, package = "compositions")
lake <- as.data.frame(ArcticLake)
lake[c("sand", "silt", "clay")] <- lake[c("sand", "silt", "clay")] / rowSums(lake[c("sand", "silt", "clay")])

to_xy <- function(sand, silt, clay) {
  data.frame(x = silt + clay / 2, y = clay * sqrt(3) / 2)
}
lake <- cbind(lake, to_xy(lake$sand, lake$silt, lake$clay))

## Grid lines every 20%, one family per component. Each line ends on the
## side where it is read, and a short tick prolongs it outside the triangle:
## clay on the left side, sand at the bottom, silt on the right side.
s <- seq(0.2, 0.8, by = 0.2)
ends <- function(read_at, other_end) {
  setNames(cbind(read_at, other_end), c("x", "y", "xend", "yend"))
}
grid_lines <- rbind(
  ends(to_xy(1 - s, 0, s), to_xy(0, 1 - s, s)),  # clay
  ends(to_xy(s, 1 - s, 0), to_xy(s, 0, 1 - s)),  # sand
  ends(to_xy(0, s, 1 - s), to_xy(1 - s, s, 0))   # silt
)
grid_lines$hj <- rep(c(1, 0, 0), each = length(s))
grid_lines$vj <- rep(c(0.5, 1, 0), each = length(s))
grid_lines$label <- paste0(s * 100, "%")
## Outward direction of each line at the end where it is read.
len <- with(grid_lines, sqrt((x - xend)^2 + (y - yend)^2))
grid_lines$dx <- with(grid_lines, (x - xend) / len)
grid_lines$dy <- with(grid_lines, (y - yend) / len)
tick <- 0.035

frame <- to_xy(c(1, 0, 0, 1), c(0, 1, 0, 0), c(0, 0, 1, 0))
vertices <- cbind(to_xy(c(1, 0, 0), c(0, 1, 0), c(0, 0, 1)),
                  label = c("Sand", "Silt", "Clay"),
                  hj = c(1.15, -0.15, 0.5), vj = c(0.5, 0.5, -0.6))

p <- ggplot(lake, aes(x, y)) +
  geom_segment(data = grid_lines, aes(xend = xend, yend = yend),
               colour = "#d6d6d6", linewidth = 0.25) +
  geom_segment(data = grid_lines, aes(xend = x + tick * dx, yend = y + tick * dy),
               colour = "#535353", linewidth = 0.3) +
  geom_text(data = grid_lines, aes(x + 1.3 * tick * dx, y + 1.3 * tick * dy,
                                   label = label, hjust = hj, vjust = vj),
            colour = "#7d7d7d", size = 2.3) +
  geom_path(data = frame, colour = "#535353", linewidth = 0.5) +
  geom_point(aes(fill = depth), shape = 21, size = 2, colour = "#535353", stroke = 0.25) +
  geom_text(data = vertices, aes(label = label, hjust = hj, vjust = vj),
            colour = "#535353", size = 3.2, fontface = "bold") +
  scale_fill_gradientn(colours = idest_seq, labels = lex_number) +
  coord_equal(xlim = c(-0.55, 1.55), ylim = c(-0.08, 0.9), clip = "off") +
  labs(title = "Sediments hold more clay and less sand in deeper water",
       subtitle = "39 samples from an Arctic lake, 10 to 104 m deep; median sand: 53% shallower than 30 m, 6% deeper than 70 m",
       fill = "Water\ndepth (m)",
       caption = "Data: Aitchison 1986, via the compositions R package") +
  theme_lex_viz(grid = "", arrows = "") +
  theme(axis.text = element_blank(), axis.title = element_blank(),
        legend.position = "inside", legend.position.inside = c(0, 1),
        legend.justification.inside = c(0, 1), legend.key.height = unit(5, "mm"),
        legend.key.width = unit(3, "mm"))

Sources (11)

10 occurrences in the corpus; indexed by 2 books

Show the 11 sources

Cite this entry

Stable addresshttps://dataviz.adrientaudiere.com/en-only/term/ternary-plot.html

ReferenceTaudière Adrien. 2026. ternary plot. In Visualization Vocabulary, version 1.0.0. IdEst. https://dataviz.adrientaudiere.com/en-only/term/ternary-plot.html

BibTeX
@incollection{taudiere2026-ternary-plot,
  author    = {Taudière, Adrien},
  title     = {ternary plot},
  booktitle = {Visualization Vocabulary},
  year      = {2026},
  version   = {1.0.0},
  publisher = {IdEst},
  url       = {https://dataviz.adrientaudiere.com/en-only/term/ternary-plot.html},
  note      = {CC0 1.0}
}

Page created on 2026-11-09. Text last changed on 2026-11-10. Images last changed on 2026-11-11. Numbers computed on 2026-10-22.