Ziyi Li (ziyi.li@emory.edu)


Content

1. Foundations: parameters

The par function is used to specific global graphics parameters that affect all plots in an R session. These parameters can often be overriden as arguments to specific plotting functions.

1.1 pch

  • pch: the plotting symbol (default is open circle)
par("pch")
## [1] 1

1.2 lty

  • lty: the line type (default is solid line), can be dashed, dotted, etc.
par("lty")
## [1] "solid"
par(mfrow = c(4,1), mar=c(1,2.1,1,1) )
x = 1:5
y = 1:5
plot(x, y, lty = 1, main = "lty = 1", type="l")
plot(x, y, lty = 2, main = "lty = 1",  type="l")
plot(x, y, lty = 3, main = "lty = 1", type="l")
plot(x, y, lty = 4, main = "lty = 1", type="l")

1.3 lwd

  • lwd: the line width, specified as an integer multiple
par("lwd")
## [1] 1
par(mfrow = c(4,1), mar=c(1,2.1,1,1))
plot(x, y, lwd = 0.5, main = "lwd = 0.5", type="l")
plot(x, y, lwd = 1, main = "lwd = 1", type="l")
plot(x, y, lwd = 3, main = "lwd = 3", type="l")
plot(x, y, lwd = 5, main = "lwd = 5", type="l")

1.4 col

  • col: the plotting color specified as a number, string, or hex code; The colors function gives you a vector of colors by name
par("col")
## [1] "black"
par(mfrow = c(4,1), mar=c(1,2.1,1,1))
plot(x, y, col = 1, main = "col = 1", type="l")
plot(x, y, col = 2, main = "col = 2", type="l")
plot(x, y, col = 3, main = "col = 3", type="l")
plot(x, y, col = 4, main = "col = 4", type="l")

1.5 bg

  • bg: the background color
par("bg")
## [1] "white"
par(mfrow = c(2,1), bg="pink", mar=c(1,2.1,1,1))
x = 1:10
y = rnorm(10)
plot(x, y, col = 1, main = "col = 1")
plot(x, y, col = 2, main = "col = 2")

1.6 mar

  • mar: the margins

<ref: http://rgraphics.limnology.wisc.edu/rmargins_sf.php>

par("mar")
## [1] 5.1 4.1 4.1 2.1
x = 1:10
y = rnorm(10)
plot(x, y)

par(mar = c(0.5,0.5,0.5,0.5))
plot(x, y)

2. Panels

How can I get two plots to be on the same page ?

par(mfrow=c(1,2)) # One row and two columns
plot(mtcars$mpg, main="MPG", type="l", xlab="Car Number",ylab="MPG")
plot(mtcars$mpg, main="MPG", type="b", xlab="Car Number",ylab="MPG")

par(mfrow=c(2,2))  # Two rows and two columns
plot(mtcars$mpg,main="MPG",xlab="Car",ylab="MPG",type="p")
plot(mtcars$mpg,main="MPG",xlab="Car",ylab="MPG",type="l")
plot(mtcars$mpg,main="MPG",xlab="Car",ylab="MPG",type="h")
plot(mtcars$mpg,main="MPG",xlab="Car",ylab="MPG",type="o")
legend("topleft",legend=c("Test Legend"),cex=0.8)

Example:

We usually take this approach when we want to plot data across different categories. Like the mpg vs weight across cylinder types. We have three unique cylinder values:

unique(mtcars$cyl) # We have three categories so create 3 plots
## [1] 6 4 8
par(mfrow=c(1,3)) # One row and three columns

fourcyl <- mtcars[mtcars$cyl == 4,]
sixcyl <- mtcars[mtcars$cyl == 6,]
eightcyl <- mtcars[mtcars$cyl == 8,]

plot(fourcyl$wt, fourcyl$mpg, main = "MPG vs Wt 4 Cyl", ylim=c(0,40))
plot(sixcyl$wt, sixcyl$mpg, main = "MPG vs Wt 6 Cyl", ylim=c(0,40))
plot(eightcyl$wt, eightcyl$mpg, main = "MPG vs Wt 8 Cyl", ylim=c(0,40))

par(mfrow=c(1,1)) # Reset the plot window

3. Annotation

par(mfrow=c(1,2)) # One row and three columns

fourcyl <- mtcars[mtcars$cyl == 4,]

plot(fourcyl$wt, fourcyl$mpg, main = "MPG vs Wt 4 Cyl", ylim=c(0,40), 
     xlab = "my wt", ylab = "my mpg")
legend("bottomright", inset=0.05, "This is data", pch=1, col="black")

plot(fourcyl$wt, fourcyl$mpg, main = "MPG vs Wt 4 Cyl", ylim=c(0,40), 
     xlab = "my wt", ylab = "my mpg")
legend("bottomright", "This is data", pch=1, col="black")

We could put up our own grid using some “primitive” graphics functions:

plot(mtcars$wt, mtcars$mpg, xlab = "Weight / 1,000", main = "MPG vs. WT")

# Draws vertical dashed lines at 2,3,4,5
abline(v=c(2,3,4,5),lty=2,col="gray90")
# Draws horizontal dashed lines at 10,15,20,25,30
abline(h=c(10,15,20,25,30), lty=2, col="gray90")

We can also add text to our plot with no problem.

plot(mtcars$wt, mtcars$mpg, main="Mileage vs. Car Weight",
     xlab="Weight", ylab="Mileage", pch=18, col="blue")

text(mtcars$wt, mtcars$mpg, # We cannot use the formula in text
     row.names(mtcars), # Get the row names
     cex=0.6, # Scaling of the font size
     pos=4, # 1=below, 2=left, 3=above, 4=right
     col="red")

The text label is too long. We can shorten them:

plot(mtcars$wt, mtcars$mpg, main="Mileage vs. Car Weight",
     xlab="Weight", ylab="Mileage", pch=18, col="blue")

carlabs <- sapply(strsplit(row.names(mtcars)," "),
               function(x) x[[1]])

text(mtcars$wt, mtcars$mpg, # Note we cannot use the formula in text
     carlabs, # Get the row names
     cex=0.6, # Scaling of the font size
     pos=4, # 1=below, 2=left, 3=above, 4=right
     col="red")

Advanced annotation (optional)

Let’s look at a more involved annotation example. We’ll use the same data:

plot(mtcars$mpg ~ mtcars$wt,cex=0.8, pch=21,col="blue",bg="red",
     xlab="Wt in Lbs/1,000", ylab="Miles Per Gallon")

title(main="The mtcars data set wt vs. MPG")

# Next draw a vertical line at the mean of the weight
abline(v=mean(mtcars$wt),lty=2,col="blue")

# Next draw a horizontal line at the man of the MPG
abline(h=mean(mtcars$mpg),lty=2,col="blue")

points(mean(mtcars$wt), # Draws a diamond at the common mean
       mean(mtcars$mpg),
       pch=23,col="black",
       bg="brown", cex=2)

# Let's put some custom text on the graph to indicate the mean.
text(mean(mtcars$wt),min(mtcars$mpg),
     paste("Mean:",round(mean(mtcars$wt),2)),pos=4)

text(min(mtcars$wt),mean(mtcars$mpg),
     paste("Mean:",round(mean(mtcars$mpg),2)),adj=c(0,1))

4. Layered plot

We could also use information from a data frame to help us print different characters based on value. Like in mtcars. Let’s plot MPG vs Weight but pick a different plot character based on Transmission Type. Here is one way to do it:

  1. Create a blank plot that sets the limits and title
  2. Extract records for automatic transmission into a data frame
  3. Extract records for manual transmission into a data frame
  4. Use the points command to plot these two different groups using a different pch value
# A null plot
plot(mtcars$wt, mtcars$mpg, type="n", main="MPG vs. Weight")

auto <- mtcars[mtcars$am == 0,]
manu <- mtcars[mtcars$am == 1,]

points(auto$wt, auto$mpg, pch = 0)
points(manu$wt, manu$mpg, pch = 1)

legend("topright", inset=0.05, c("manual","auto"), pch = c(1,0))

An easier way is

# A null plot
mtcars$am
##  [1] 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 1 1 1 1 1 1 1
# We see that am is 0 or 1 which just 
# so happen to also represent
# valid print characters

plot(mtcars$wt, mtcars$mpg, pch=mtcars$am, main="MPG vs. Weight", sub="Different plot chars")

legend("topright", inset=0.05, c("manual","auto"), pch = unique(mtcars$am))

Example:

It is also possible to build a plot in layers. We initialize a “blank” plot using the plot command but we specify a type of “n”.

Let’s plot wt vs MPG and do it such that the records with a weight below the mean weight are in red and those above the mean weight are in blue

plot(mtcars$wt,mtcars$mpg,type="n", xlab="Weight in lbs/1,000",
     ylab="MPG", main="MPG vs. Weight")

How is this useful ? Well we can add points or lines in stages. This allows us to plot things on an existing plot using specific colors or print characters.

plot(mtcars$wt,mtcars$mpg,type="n",xlab="Weight in lbs/1,000",
     ylab="MPG", main="MPG vs. Weight")

# Let's get records for each category
above.mean <- mtcars[mtcars$wt >= mean(mtcars$wt),]
below.mean <- mtcars[mtcars$wt < mean(mtcars$wt),]

# Use the points command to plot each group
points(below.mean$wt,below.mean$mpg,col="red")
points(above.mean$wt,above.mean$mpg,col="blue")

# Draw a vertical line where the mean(wt) is
abline(v=mean(mtcars$wt),lty=2,col="gray90")

5. Custom axis

Sometimes we want to draw an axis ourselves because R’s defaults aren’t what we want. Imagine a set of observations over time such as stock market activity.

Here is a data frame you can read in that tracks actual stock market performance for Microsoft, (MSFT), for each trading day of the year 2014.

url <- "https://www.dropbox.com/s/kkohm0vcgzbj136/stock.data.14.csv?dl=1"
msft <- read.csv(url)
head(msft)
##         Date  Open  High   Low Close   Volume Adj.Close
## 1 2014-01-02 37.35 37.40 37.10 37.16 30632200     36.17
## 2 2014-01-03 37.20 37.22 36.60 36.91 31134800     35.93
## 3 2014-01-06 36.85 36.89 36.11 36.13 43603700     35.17
## 4 2014-01-07 36.33 36.49 36.21 36.41 35802800     35.44
## 5 2014-01-08 36.00 36.14 35.58 35.76 59971700     34.81
## 6 2014-01-09 35.88 35.91 35.40 35.53 36516300     34.58
plot(msft$High,type="l",main="High MSFT Price", xlab="Day of Year",ylab="Price in $")
mtext("2014",3)

The day number is okay but we could also the actual dates as labels. But that could be a problem. First, we use the xaxt argument to suppress the printing of the x-axis

plot(msft$High,type="l",main="High MSFT Price", 
     xlab="Day of Year",ylab="Price in $", xaxt="n")

axis(1,at=1:nrow(msft),labels=msft$Date)

That wasn’t so good because the X-axis got really crowded. We can print labels for the x-axis every 30 days or so using this approach. We could alter this to accommodate an arbitrary number of days and labels. Notice how we generate sequence that we then use to index into the Dates.

plot(msft$High,type="l", main="High MSFT Price",
     xlab="Day of Year",ylab="Price in $", xaxt="n")

mtext("2014",3)

dseq <- seq(1,nrow(msft),30)

axislabs <- substr(msft$Date[dseq],6,10)
axis(1, at=dseq, labels=axislabs, cex.axis=0.8)

6. Colors

length(colors()) # The colors function returns a vector of colors
## [1] 657
colors()[1:5]
## [1] "white"         "aliceblue"     "antiquewhite"  "antiquewhite1"
## [5] "antiquewhite2"
grep("yellow",colors(),value=TRUE)
##  [1] "greenyellow"          "lightgoldenrodyellow" "lightyellow"         
##  [4] "lightyellow1"         "lightyellow2"         "lightyellow3"        
##  [7] "lightyellow4"         "yellow"               "yellow1"             
## [10] "yellow2"              "yellow3"              "yellow4"             
## [13] "yellowgreen"
grep("purple",colors(),value=TRUE)
##  [1] "mediumpurple"  "mediumpurple1" "mediumpurple2" "mediumpurple3"
##  [5] "mediumpurple4" "purple"        "purple1"       "purple2"      
##  [9] "purple3"       "purple4"

Strongly recommend R color cheatsheet.

Example

library("colorspace")
## Warning: package 'colorspace' was built under R version 3.5.2
par(mfrow = c(1,2))

plot_it <- function(cols){
     y <- sort(runif(500,0,10))
     x <- rep(1:5, each=100) + rnorm(500,0,0.5)
     x_ind <- rep(1:5, each=100)
     plot(x, y, pch = 19, col = cols[x_ind])
}

mycols <- rainbow_hcl(5)
plot_it(mycols)

mycols <- heat_hcl(5)
plot_it(mycols)