---
title: 'Static R Graphics: A Brief Introduction'
author: Deepayan Sarkar
bibliography: references.bib
---



```{r opts, echo = FALSE, results = "hide", warning = FALSE, message = FALSE}
opts_chunk$set(cache = TRUE, cache.path='~/knitr-cache/nehu-rgraphics-static/', autodep = TRUE,
               comment = "", warning = TRUE, message = TRUE,
               knitr.table.format = "html",
			   dev.args = list(pointsize = 16),
               fig.width = 15, fig.height = 6, dpi = 120, fig.path='figures/rgraphics-static')
library(ggplot2)
library(lattice)
library(latticeExtra)
## lattice.options(default.args = list(as.table = FALSE),
##                default.theme = list(grid.pars = list(cex = 1.5)))
options(warnPartialMatchDollar = FALSE, width = 120)
```



## R graphics

* R has a reputation for being a good system for graphics

* This is mainly based on its ability to produce good
  publication-quality statistical plots

. . .

* R actually has two largely independent graphics subsystems
  
    * Traditional graphics
    
        * Available in R from the beginning
        * Rich collection of tools
        * Not very flexible
    
    * Grid graphics
    
        * Relatively recent (2000)
        * Low-level tool, highly flexible
    

## Grid graphics, __lattice__ and __ggplot2__

* Grid graphics is not usually used directly by the user

* But it forms the basis of two high-level graphics systems:
  
    * __lattice__: based on Trellis graphics (Cleveland)

    * __ggplot2__: inspired by _"Grammar of Graphics"_ (Wilkinson)

. . .

* These represent two very different philosophical approaches to graphics

* __lattice__ is in many ways a natural successor to traditional graphics

* __ggplot2__ represents a completely different _declarative_ approach


\pagebreak


## An example: Anscombe's quartet

* I will try to illustrate this with an example

* @anscombe1973graphs introduced four artificial bivariate datasets to
  emphasize the importance of graphics

* The datasets all had the same means, standard deviations, and correlation


```{r}
str(anscombe)
```

## An example: Anscombe's quartet

```{r}
sapply(anscombe, mean)
sapply(anscombe, sd)
with(anscombe, c(cor(x1, y1), cor(x2, y2), cor(x3, y3), cor(x4, y4)))
```
\


. . .

* How can we plot all four datasets together?



\pagebreak


## Anscombe's quartet using traditional graphics

* Traditional graphics thinks of this as four different data sets

* The function to create scatter plots is `plot()`

* Multiple plots can be put in the same figure using `par(mfrow = ...)`

* Several ways of specifying variable names inside dataset:

```r
plot(anscombe$x1, anscombe$y1)     # ugly and error-prone

with(anscombe, plot(x1, y1))       # temporarily attach dataset

plot(y1 ~ x1, data = anscombe)     # formula-data interface (also used in modeling)
```

<!--
. . .

* Another possibility is to use a function called `attach()`

	* This is often suggested, especially in online tutorials / examples
	
	* Useful in some contexts, but has potential to introduce difficult-to-find errors 
	
	* I would strongly discourage its use

-->


## Anscombe's quartet using traditional graphics

```{r, fig.height=5}
par(mfrow = c(1, 4))
plot(y1 ~ x1, data = anscombe, pch = 16)
plot(y2 ~ x2, data = anscombe, pch = 16)
plot(y3 ~ x3, data = anscombe, pch = 16)
plot(y4 ~ x4, data = anscombe, pch = 16)
```
\


## Anscombe's quartet using traditional graphics

```{r, fig.height=5}
xrng <- with(anscombe, range(x1, x2, x3, x4))
yrng <- with(anscombe, range(y1, y2, y3, y4))   ## common axis limits
par(mfrow = c(1, 4))
plot(y1 ~ x1, data = anscombe, pch = 16, xlim = xrng, ylim = yrng)
plot(y2 ~ x2, data = anscombe, pch = 16, xlim = xrng, ylim = yrng)
plot(y3 ~ x3, data = anscombe, pch = 16, xlim = xrng, ylim = yrng)
plot(y4 ~ x4, data = anscombe, pch = 16, xlim = xrng, ylim = yrng)
```
\



## Anscombe's quartet using __lattice__ and __ggplot2__

* Both __lattice__ and __ggplot2__ are capable of producing a single plot
  with all four datasets

* But this requires the dataset to be in the "long format" (one row per data point)

```{r}
anscombe.long <- 
    with(anscombe, data.frame(x = c(x1, x2, x3, x4), 
	                          y = c(y1, y2, y3, y4),
						      which = rep(c("1", "2", "3", "4"), each = 11)))
str(anscombe.long)
```


## Anscombe's quartet using __lattice__

```{r, fig.height=5}
library(package = "lattice")
xyplot(y ~ x | which, data = anscombe.long, layout = c(4, 1), pch = 16)
```
\


## Anscombe's quartet using __ggplot2__

```{r, fig.height=4}
library(package = "ggplot2")
ggplot(data = anscombe.long) + geom_point(aes(x = x, y = y)) + facet_grid( ~ which)
```
\


## Anscombe's quartet using __lattice__ and __ggplot2__

* The approaches share many common features

* Both Capable of plotting subsets of data (indexed by categorical variables)

	* This idea is known by several names: _small multiples, conditioning, facetting_

* Both makes efficient use of available space (common scales, common axes)

* Different visual appearance, but that is superficial (different default themes)


## Anscombe's quartet using __lattice__ and __ggplot2__

* However, the way in which we _specify_ the display is very different

	* __lattice__ uses an extension of the formula-data interface (with
      function `xyplot()` instead of `plot()`)
	
	* __ggplot2__ specifies _type_ of rendering (geom)
      and _mapping_ of variables to coordinates (aesthetics)

. . .


* The differences become clearer if we try to customize the display further

* A natural modification in this example is to add a linear regression
  line to each scatter plot

## Anscombe's quartet with regression lines

```{r, fig.height=4.5}
xrng <- with(anscombe, range(x1, x2, x3, x4))
yrng <- with(anscombe, range(y1, y2, y3, y4))
par(mfrow = c(1, 4))
plot(y1 ~ x1, anscombe, pch = 16, xlim = xrng, ylim = yrng)
abline(lm(y1 ~ x1, anscombe))  ## lm() fits regression line, abline() adds the line to current plot
plot(y2 ~ x2, anscombe, pch = 16, xlim = xrng, ylim = yrng) 
abline(lm(y2 ~ x2, anscombe))
plot(y3 ~ x3, anscombe, pch = 16, xlim = xrng, ylim = yrng)
abline(lm(y3 ~ x3, anscombe))
plot(y4 ~ x4, anscombe, pch = 16, xlim = xrng, ylim = yrng)
abline(lm(y4 ~ x4, anscombe))
```
\


## Anscombe's quartet with regression lines

* The traditional graphics approach is to _add_ the line after the plot is drawn

* In general, a plot is never _finished_, you can always add more points, lines, text, ...

. . .

* This is possible because there is _only one plot_ !

* __lattice__ and __ggplot2__ need alternative solutions

* The __ggplot2__ solution is to allow plots to have multiple _layers_

* The __lattice__ solution is to allow user to fully specify the
  _procedure_ used to display data
  



## Regression lines: the __ggplot2__ solution

* Plot with points only

```{r, fig.height=4}
ggplot(data = anscombe.long) + facet_grid( ~ which) + geom_point(aes(x = x, y = y))
```
\



## Regression lines: the __ggplot2__ solution

* Plot with regression line only

```{r, fig.height=4}
ggplot(data = anscombe.long) + facet_grid( ~ which) + 
                          geom_smooth(aes(x = x, y = y), method = "lm", se = FALSE)
```
\


## Regression lines: the __ggplot2__ solution

* Plot with both points and regression lines

```{r, fig.height=4}
ggplot(data = anscombe.long) + facet_grid( ~ which) + geom_point(aes(x = x, y = y)) + 
                          geom_smooth(aes(x = x, y = y), method = "lm", se = FALSE)
```
\



\pagebreak


## Regression lines: the __lattice__ solution

* The __lattice__ solution is actually very similar to the traditional graphics solution

* Basically, we want to do the following for each data subset `x, y`:

	* Draw points at `(x, y)`
	
	* Draw the linear regression line through `x, y`
	
* For __lattice__, we need to encapsulate this _procedure_ into a function

```{r}
displayFunction <- function(x, y) {
    panel.grid(h = -1, v = -1)               ## add a reference grid
	panel.points(x, y, pch = 16)             ## draw the points
	panel.abline(lm(y ~ x), col = "grey50")  ## draw linear regression line
}
```

* This function is then supplied to the `xyplot()` function as the `panel` argument

## Regression lines: the __lattice__ solution

* Plot with points only

```{r, fig.height=5}
xyplot(y ~ x | which, data = anscombe.long, layout = c(4, 1), panel = panel.points, pch = 16)
```
\


## Regression lines: the __lattice__ solution

* Plot with grid, points, and regression line

```{r, fig.height=5}
xyplot(y ~ x | which, data = anscombe.long, layout = c(4, 1), panel = displayFunction)
```
\



## Regression lines: the __lattice__ solution

* __lattice__ also supports a layering mechanism similar to __ggplot2__

```{r, fig.height=5, message=FALSE}
library(package = "latticeExtra")
xyplot(y ~ x | which, data = anscombe.long, layout = c(4, 1), pch = 16) + 
                      layer_(panel.grid(h = -1, v = -1)) + layer(panel.abline(lm(y ~ x)))
```
\



## Regression lines: the __lattice__ solution

* Common customizations like these are also supported directly through optional arguments

```{r, fig.height=5, results="hide"}
library(package = "latticeExtra")
xyplot(y ~ x | which, data = anscombe.long, layout = c(4, 1), pch = 16, 
       grid = TRUE, type = c("p", "r"))
```
\



## Brief history of R graphics

* R is an Open Source / Free Software re-implementation / dialect of S

	- Freely available from [CRAN](https://cran.r-project.org)
	
	- Available on all major platforms (Windows / UNIX / Linux / Mac)


* The _original_ implementation, available commercially as S-PLUS, was
  developed at Bell Labs

* Both traditional graphics and Trellis graphics were _part of the original S_

* Remembering this helps in understanding the design of graphics in R


## Origins of the graphics model

- The abstract graphics model in S may be described as a "painter's model":

	- a graphic is built out of a small set of primitives such as line
	  segments, polygons, text, etc., and

	- later elements are drawn on top of earlier ones

	- no provision for deleting an element once it was drawn

	- except to start a completely new graphic

- Advantage: both input and output could be abstracted

- Graphics functions called by users would internally call these
  primitives

- For output, the primitives could be implemented differently
  depending on the target "device"
  

## This leads to a concept of graphics devices

- Postscript or PDF files for printing,

- Hardware devices such as pen plotters, 

- On-screen devices for interactive viewing (different for Windows / Linux / Mac)
	
- Image files (JPG / PNG) for inclusion in a web page

. . .

- Device-specific implementations of the primitives are known as
  device drivers

- New drivers can be written to support new kinds of output formats

- See `?Devices` for more details.

- This is how R has solved the problem of cross-platform consistency for graphics

- The drawback is that more advanced / interactive features are not available


## Traditional graphics

- The core of the traditional R graphics system is the suite of
functions available in the __graphics__ package, 

- Various add-on packages providing further functionality.

- The full list of functions can be seen using

```r
library(help = graphics)
```

- The listed functions can be roughly categorized into two groups: 

	- __High-level functions__ are intended to produce a complete plot
	  by themselves

	- __Low-level functions__ are intended to add elements to existing
	  plots



## Commonly used high-level traditional graphics functions

--------------------------------------------------------------------
Function           Default Display
----------------   -------------------------------------------------
`plot()`           Scatter Plot, Time-series Plot (with `type="l"`)

`boxplot()`        Comparative Box-and-Whisker Plots

`barplot()`        Bar Plot

`dotchart()`       Cleveland Dot Plot

`hist()`           Histogram

`plot(density())`  Kernel Density Plot

`qqnorm()`         Normal Quantile-Quantile Plot

`qqplot()`         Two-sample Quantile-Quantile Plot

`stripchart()`     Stripchart (Comparative 1-D Scatter Plots)

`pairs()`          Scatter-Plot Matrix
--------------------------------------------------------------------



## __lattice__ defines analogous functions with different names

--------------------------------------------------------------------
Function           Default Display
----------------   -------------------------------------------------
`xyplot()`         Scatter Plot, Time-series Plot (with `type="l"`)

`bwplot()`         Comparative Box-and-Whisker Plots 

`barchart()`       Bar Plot

`dotplot()`        Cleveland Dot Plot 

`histogram()`      Histogram 

`densityplot()`    Kernel Density Plot 

`qqmath()`         Normal Quantile-Quantile Plot

`qq()`             Two-sample Quantile-Quantile Plot 

`stripplot()`      Stripchart (Comparative 1-D Scatter Plots) 

`splom()`          Scatter-Plot Matrix 
--------------------------------------------------------------------




## Grammar of graphics

* Traditional and trellis graphics both have the same basic approach:

	- Functions are written to implement specific graphical designs

	- Usually these are designs that have been established as being useful

	- Customization is achieved through a procedural approach


* The __ggplot2__ package takes a different declarative approach:

	- Defines a "layered grammar" for defining graphical designs

	- Final display is a composition of various components

	- A systematic grammar is used to specify the composition

	- Can be used to create novel displays easily

	- Plots consist of one or more layers (e.g., raw data could be one
      layer, model fits another)



## Grammar of graphics: Main components

* _Aesthetic mappings_ that map data values to some aspect in the
  displayed graph, such as
	  
	- coordinate positions
	- color, shape, size
	- group, ...

* _geometric types_ used to render the mapped data, e.g., 

	- points, lines, polygons
	- more complex types such as a box-and-whisker plot

* statistical transformations that are applied to the data beforehand,
  such as
	  
	- binning for histograms
	- computation of kernel density estimates.

* Scales that give a visual indication of the aesthetic mappings, e.g., 
	
	- axis annotation for position mapping
	- legends for mapping to color, size, etc.

* Faceting (conditioning) to produce small multiples



## Grammar of graphics - built-in geoms and stats

* Geoms

```{r}
grep("^geom_", ls("package:ggplot2"), value = TRUE)
```
\


* Stats

```{r}
grep("^stat_", ls("package:ggplot2"), value = TRUE)
```


## Parting comments

* We don't have time to go into details of any of these systems

* Lots of help easily available on the internet

* If you primarily use R / Python for your analysis, I would also suggest learning about

	- [pandoc](https://pandoc.org)

	- [knitr](https://yihui.org/knitr)

* Together, these form a convenient basis for "literate documents"
  combining text and code

* [This talk](rgraphics-static.rmd) is an example

* Very good support available in [R Studio](https://rstudio.com), the
  best interface to R for beginners


## References


