Ternary Plots in GGPLOT/R


Ternary Plot using ggplot2

>DOWNLOAD THE TEMPLATE<

Ternary plots are great for displaying trivariate data (or more), and are used a lot in geochemistry. R is a great tool for plotting data and has built-in capabilities for dealing with trivariate data:

Many people, however, use the ggplot2 package for R which sadly has no native ternary plotting capability. A hack is provided by Sean Mulcahy, but the code here deals with an alternative, somewhat adapted way of achieving similar results.

How does it work? Basically the code takes 3 variables (A, B, C) and converts it into XY data. The ternary plot is actually plotted on a [hidden] X-Y plot, where the X values are corrected for Y thus allowing ternary data to be plotted onto the XY plot area.

Features of the template

  • Lists of common customisation parameters (colour, size etc) built into the preamble to make visual changes quick and correct
  • Automatic correction of ABC data into ternary plotting coordinates
  • Systematically commented allowing you to understand what’s doing what.

What next? I’m working on a set of templates for common geochemical discrimination diagrams which will allow you to simply import and display your data and discriminate between your samples.

# Load Packages
	
	library (cwhmisc)
	library (ggplot2)
	library (grid)
	library (scales)

# Select Data Source 
	
	# Select csv file
	data = mtcars	
	
	# Define apices
	#t = top, l = left, r = right
	data$l = data$mpg		# e.g. data$t = data$a*100
	data$t = data$wt*10
	data$r = data$hp/5


# Plot customisation
	
	# Customise: Colours
	colour.1 = "white"		# Panel background colour
	colour.2 = "white"		# Plot area background colour
	colour.3 = "black"		# Outer text colour
	colour.4 = "black"		# Plot outline colour
	colour.5 = "lightgrey"		# Gridline colour
	colour.6 = "white"		# Legend box outline colour
	
	# Customise: Font sizes
	fs.r = 1.168
	fs.1 = 6
	fs.2 = (fs.1*2) * (fs.r^4)
	fs.3 = fs.1 * (fs.r^5)
	
	# Labels & Title
	title = "Ternary Template v.09.13"
	apices = c("MPG", "Horse Power", "Weight (x10)") 	# Left, Right, Top

	# Other
	gridlines = F		# Turn gridlines on/off with T/F






##################################################################################

# Convert data to %
	data$total = data$l+data$r+data$t
	data$t = (data$t/data$total)*100
	data$l = (data$l/data$total)*100
	data$r = (data$r/data$total)*100

# Convert abc into xy
	data$x = (100-((data$t/2)+((100-data$t)*(data$l/(data$l+data$r)))))
	data$y = data$t

	#if t = 100 then x should be 50 
	n = nrow (data)
	for (i in 1:n) {
		temp = data[i,]
		if (temp$y == 100) {temp$x = 50}
		data[i,] = temp	
	}

# Coordinates for triangle
	tri = data.frame (c(0, 100, 50, 0), c(0, 0, 100, 0))
	colnames(tri) = c("x", "y")

# Coordinates for grid
	x1 = seq (10, 90, 10)
	x2 = seq (5, 45, 5)
	x3 = seq (55, 95, 5)
	x4 = seq (45, 5, -5)
	y1 = 0
	y2 = seq (10, 90, 10)
	y3 = seq (90, 10, -10)
	grid = data.frame (x1, x2, x3, x4, y1, y2, y3)


# Open new quartz window
	dev.new (height = 10*0.866025, width = 10)
	if (gridlines == T) {gridalpha = 1} else {gridalpha = 0}


	
	
ggplot (data = data, aes (x = x, y = y)) +
	
	# Shapes, lines, text
	geom_polygon (data = tri, fill = colour.2) +
	
	geom_segment (data = grid, 
		aes (x = x1, y = y1, xend = x2, yend = y2), 
		linetype = "dashed", size = 0.5, colour = colour.5, alpha = gridalpha) +
	geom_segment (data = grid, 
		aes (x = x1, y = y1, xend = x3, yend = y3), 
		linetype = "dashed", size = 0.5, colour = colour.5, alpha = gridalpha) +
	geom_segment (data = grid, 
		aes (x = x4, y = y3, xend = x3, yend = y3), 
		linetype = "dashed", size = 0.5, colour = colour.5, alpha = gridalpha) +
	annotate ("text", label = apices, x = c(-5, 105, 50), y = c(-5, -5, 105), size = fs.1, colour = colour.3) +
	labs (title  = title, colour = "No Cylinders") +
	geom_path (data = tri, size = 0.5, colour = colour.4) +
	
	# Appearance controls
	coord_fixed (ratio = 0.866025) +
	scale_x_continuous (limits = c(-20, 120), expand = c(0,0)) +
	scale_y_continuous (limits = c(-20, 120), expand = c(0,0)) +
	theme (
		
		# Panel and plot attributes
		plot.title = element_text (size = fs.2, colour = colour.3), 	# Plot title
		plot.margin = unit (c(3, 4, 3, 3), "lines"), 					# Plot margins
		plot.background = element_rect (colour = F, fill = colour.1),
		panel.border = element_rect (colour = F, fill = F, size = 1), 	# Axis colours
		panel.grid.major = element_blank (), 							# Remove major grid
		panel.grid.minor = element_blank (), 							# Remove minor grid
		panel.background = element_rect (fill = colour.1), 				
		
		# Legend attributes
		legend.background = element_rect (colour = colour.6, size = 0.3, fill = "white"),
		legend.justification = c(1, 1),
		legend.position = c(0.9, 0.9), 				# Put the legend INSIDE the plot area
		legend.key = element_blank (), # switch off the rectangle around symbols in the legend
		legend.box.just = "bottom",
		legend.box = "horizontal",
		legend.title = element_text (size = fs.3, colour = colour.3), # switch off the legend title
		legend.text = element_text (size = fs.3, colour = colour.3), #sets the attributes of the legend text
		
		# Axis attributes
		axis.title.x = element_blank (),
		axis.title.y = element_blank (),
		axis.text.x = element_blank (),
		axis.text.y = element_blank (),
		axis.ticks = element_blank ()
		) +
	
	# Data layer
	geom_point (aes(colour = factor(cyl)),size = 6)

	
ggsave ("/Users/s0679701/Desktop/ternary.png", dpi = 100)
	

Update: Basic R Template


wilkinson_r_basic_template

Here is an update to my basic template for R using ggplot2.

Updates include

  • Added size scaling, using golden ratios
  • Updated padding
  • Updated aspect ratio fixing

Click here to download the R file.

The code is displayed below:

# R Template v.09.13
# Compiled by Darren J Wilkinson
# The University of Edinburgh, Scotland
# d.j.wilkinson@ed.ac.uk

# Packages to load
library (ggplot2)
library (grid)
library (scales)

# Easy customisation parameters

	# Text/Line/Fill Colours
	colour.1 = "black"		# Text, outside plot area
	colour.2 = "white"		# Fill, outside plot area
	colour.3 = "white"		# Fill, plot area
	colour.5 = "black"		# Text, inside plot area
	colour.6 = "black"		# Outlines

	# Line Widths
	lw.r = 1.1618			# Scaling ratio
	lw.1 = 1.5				# Plot area
	lw.2 = lw.1/(lw.r^7)	# Axis ticks
	lw.3 = lw.1/(lw.r^8)	# Legend box

	# Font Sizes
	fs.r = 1.1618				# Scaling ratio
	fs.1 = 12					# Axis Labels
	fs.2 = fs.1 * (fs.r^2)		# Axis title
	fs.3 = fs.1 * (fs.r^3)		# Plot title
	fs.4 = fs.1 / (fs.r^2)		# Legend
	fs.5 = fs.1 / (fs.r^4)		# Legend title

# Plot Code

	# Define the plot
	ggplot (
		data = mtcars, 
		aes (
			x = wt,
			y = mpg
			)
		) +

	# Data layers
	geom_point (
		aes(
			colour = hp
			), 
		size = 4
		) +

	# Customise: Scales
	scale_x_continuous (name = "Mass (Tonnes)") +
	scale_y_continuous (name = "Miles per Gallon (MPG)") +	

	# Customise: Labels
	labs (
		title = "Template v.09.13",
		colour = "Horse\nPower (HP)"
		) +

		scale_colour_gradient (high = "red", low = "grey") +

	# Customise: Appearance
	theme (
		# Plot Attributes
		plot.title = element_text (vjust = 3, size = fs.3, colour = colour.5),
		plot.margin = unit (c(5, 2, 5, 3), "lines"), 								# Plot padding
		plot.background = element_rect (fill = colour.2, colour = F),

		# Panel Attributes
		panel.border = element_rect (colour = colour.6, fill = F, size = lw.1), 		
		panel.grid.major = element_blank (), 										# Removes major grid
		panel.grid.minor = element_blank (),  										# Removes minor grid
		panel.background = element_rect (fill = colour.3, colour = colour.2), 		

		#Legend Attributes
		legend.background = element_rect (colour = colour.6, size = lw.3, fill = colour.3),
		#legend.justification = c(0, 0),							# (1/2) Uncomment to place lnd inside plot area
		#legend.position = c(0, 0), 								# (2/2) Uncomment to place lnd inside plot area
		legend.key = element_blank (), 									# Remove bkgrd for legend elements
		legend.title = element_text (size = fs.4, colour = colour.1),
		legend.text = element_text (size = fs.5, colour = colour.1),	

		# Axis Attributes
		axis.title.x = element_text (vjust = -2, size = fs.2, colour = colour.5), 
		axis.title.y = element_text (vjust = -0.1, angle = 90, size = fs.2, colour = colour.5), 
		axis.text.x = element_text (size = fs.1, vjust = -0.25, colour = colour.5), 
		axis.text.y = element_text (size = fs.1, hjust = 1, colour = colour.5), 
		axis.ticks = element_line (colour = "black", size = lw.3),
		axis.ticks.length = unit(-(0.5/(1.168^4)) , "cm"), 
		axis.ticks.margin = unit(0.5, "cm"),

		# Other Attributes
		aspect.ratio = 1/1.168
		)