# Surfaces in ternary plots

January 31, 2012
By

(This article was first published on Software for Exploratory Data Analysis and Statistical Modelling » R Environment, and kindly contributed to R-bloggers)

In mixture experiments there is a constraint that the variables are the proportions of components that are mixed together with the consequence that these proportions sum to one. When fitting regression models to data from mixture experiments we may be interested in reprenting the fitted model with a surface plot.

The constraint on proportions means that the mixture data can be described in one dimension lower than the total number of components. For example when there are three mixture components a two dimension plot can be used to represent the mixture within an equilateral triangle.

To create a surface within the mixture triangle we can create a grid of points and then convert these pairs of points into mixture triples.

``` mygrid = rbind( expand.grid( x = seq(0, 1.0, length.out = 500), y = seq(0, sqrt(3)/2, length.out = 500) ) ) ```

The conversion formulae are shown below:

``` mygrid\$a = (sqrt(3) * (mygrid\$x - 0.5) + (mygrid\$y - 0.5 * sqrt(3))) / (- sqrt(3) - 0.5 * sqrt(3)) mygrid\$b = (- sqrt(3) * (mygrid\$x - 0.5) + (mygrid\$y - 0.5 * sqrt(3))) / (- sqrt(3) - 0.5 * sqrt(3)) mygrid\$c = 1 - mygrid\$a - mygrid\$b ```

The next step is to calculate our surface values, a trivial example of which is:

``` mygrid\$z = 10 + 4 * mygrid\$a + 3 * mygrid\$b ```

We then need to trick the plotting function by setting all invalid mixture combinations to be missing values.

``` mygrid\$z[mygrid\$a < 0 | mygrid\$b < 0 | mygrid\$c < 0] = NA mygrid\$z[mygrid\$a > 1 | mygrid\$b > 1 | mygrid\$c > 1] = NA ```

Lastly we use the levelplot function in the lattice package.

``` trellis.par.set("axis.line",list(col=NA,lty=1,lwd=1)) levelplot(z ~ x*y, data = mygrid, col.regions = gray(101:0/101), scales = list(draw=FALSE), xlab = "", ylab = "", panel = function(x, y, z, ...) { panel.levelplot(x, y, z, ...) panel.lines(c(0,1), c(0,0), col = "black") panel.lines(c(0,0.5), c(0,sqrt(3)/2), col = "black") panel.lines(c(0.5,1), c(sqrt(3)/2,0), col = "black") panel.text(0.5, sqrt(3)/2, "C", pos=3) panel.text(0, 0, "A", pos=2) panel.text(1, 0, "B", pos=4) }, xlim = c(-0.2,1.2), ylim = c(-0.2, 0.2+sqrt(3)/2) ) ```

This forms the basis of a ternary surface plot and various adjustments can be easily made to customise the plot.

Example of a surface plot in a ternary diagram

Other useful resources are provided on the Supplementary Material page.

R-bloggers.com offers daily e-mail updates about R news and tutorials on topics such as: Data science, Big Data, R jobs, visualization (ggplot2, Boxplots, maps, animation), programming (RStudio, Sweave, LaTeX, SQL, Eclipse, git, hadoop, Web Scraping) statistics (regression, PCA, time series, trading) and more...