# Plotting simplexes using R

crumb /

In evolutionary game theory and related fields, one often needs to visualize the dynamics of three-dimensional systems, e.g. competition between three strategies $$x_1$$, $$x_2$$ and $$x_3$$ for which $$x_1 + x_2 + x_3 = 1$$. This is most conveniently done on a 2-simplex (ternary plot, de Finetti diagram), and the following code snippet defines a minimal way of visualizing data on a 2-simplex using R base graphics.

The function takes a minimum of four arguments: x and y are vectors holding the $$x_1$$ and $$x_2$$ values (it is not necessary to input the remaining, third value, as $$x_3 = 1 - x_1 - x_2$$); label is a vector of length 3 giving labels for the vertices of the simplex. Additional arguments are passed to the base plot function.

simplex <- function(x,
y,
label = expression(italic(x)[1], italic(x)[2], italic(x)[3]),
...) {
# empty plot
op <- par(mar=c(1,0,0,0) + 0.1, pty="s")
plot(x=c(-0.2,1.2), y=c(-0.2,1.2), type="n", axes=FALSE, xlab="", ylab="")

# triangle (borders)
points(x=c(0,0.5,1,0), y=c(0,0.5*sqrt(3),0,0), type="l")

# transform the points
xx <- 0.5*(1-x+y)
yy <- 0.5*sqrt(3)*(1-x-y)

# plot points
points(x=xx, y=yy, ...)

# labels
if (!is.null(label)) {
text(x=0.5, y=0.5*sqrt(3), pos=3, labels=label[3])
text(x=0.0, y=0.0, pos=2, labels=label[1])
text(x=1.0, y=0.0, pos=4, labels=label[2])
}

# restore plotting parameters
par(op)
}

Here’s a demo:

x <- seq(from=0, to=1, length.out=100)^2
y <- 0.5*(1-x) + rnorm(length(x), 0, 0.05*(1-x))
simplex(x=x, y=y, type="l", lwd=2, col="red")

This minimal procedure can easily be extended in the obvious ways, as in the following state diagram with vector field: