---
title: "350.graphics"
author: "William Revelle"
date: "`r Sys.Date()`"
output: html_document
---

```{r setup, include=FALSE}
knitr::opts_chunk$set(echo = TRUE)
options(width=100)
```

```{r}
library(psych)
library(psychTools)
```

# Adventures in simple graphics

Graphic displays are among the most useful tools in R.  Some of the basic graphic tools have been used in the `psych` package for displays of factor/cluster structures, models of linear regressions, etc. These all take advantage of some basic graphic tools.

The most basic function is `plot` which creates a graphic window with certain parameters (arguments).


## From the plot help file

Arguments to be passed to methods, such as graphical parameters (see par). Many methods will accept the following arguments:

type     what type of plot should be drawn. Possible types are

"p" for points,

"l" for lines,

"b" for both,

"c" for the lines part alone of "b",

"o" for both ‘overplotted’,

"h" for ‘histogram’ like (or ‘high-density’) vertical lines, 

"s" for stair steps,

"S" for other steps, 

see ‘Details’ below,

"n" for no plotting.

All other types give a warning or an error; using, e.g., type = "punkte" being equivalent to type = "p" for S compatibility.

Note that some methods, e.g. plot.factor, do not accept this.

Other parameters passed to plot

xlim The size of the x axis ylim The size of the y axis

xlab The label for the x axis ylab The label for the y axis

main A title for the figure

axes Show the axes (defaults to TRUE)

frame.plot Show the frame (defaults to TRUE)

cex The size of the characters

pch Which plot character to use for data points

```{r}
plot(0, type="n")

plot(x=1:10,y=10:1, xlab="X variable" , ylab= "Y variable", main="A title for this plot")
```

### the text function will add text at an x, y location

```{r}
plot(x=1:10,y=10:1, xlab="X variable" , ylab= "Y variable", main="A title for this plot")
text(2,4,"some text")
text(8,6, "more informative text")
```
# Psych graphics use core R graphics

`tidyverse` makes use of `ggplot` which is more powerful.

`psych` has two broad classes of graphics: those that draw diagrams and those that plot data.

We will examine the code behind the various diagram functions.  `fa.diagram`, `iclust.diagram`, `lmDiagram` call the primitive functions in the diagram.

These primitives `dia.rect`, `dia.ellipse`, `dia.arrow`, `dia.curved.arrow` may be combined to make complex diagrams.

To use these functions, we first must initialize the plot function with margins.


## Consider a simple figure

```{r}
xlim=c(-2,10);   ylim=c(0,10)
#initiate plot
plot(NA,xlim=xlim,ylim=ylim,main="Demonstration of diagram functions", axes=FALSE, xlab="", ylab="")
```
That just creates an empty page.  We do this again, with some shapes.  We specify where on the page we want the shapes. 

```{r}
#first set up the margins and initiate the plot
xlim=c(-2,10);   ylim=c(0,10)
plot(NA,xlim=xlim,ylim=ylim,main="Demonstration of diagram functions",
axes=FALSE,xlab="",ylab="")
#place and name the objects
ul <- dia.rect(1,9,labels="upper left",xlim=xlim,ylim=ylim)
ml <- dia.rect(1,6,"middle left",xlim=xlim,ylim=ylim)
ll <- dia.rect(1,3,labels="lower left",xlim=xlim,ylim=ylim)
bl <- dia.rect(1,1,"bottom left",xlim=xlim,ylim=ylim)
lr <- dia.ellipse(7,3,"lower right",xlim=xlim,ylim=ylim,e.size=.07)
ur <- dia.ellipse(7,9,"upper right",xlim=xlim,ylim=ylim,e.size=.07)
mr <- dia.ellipse(7,6,"middle right",xlim=xlim,ylim=ylim,e.size=.07)
lm <- dia.triangle(4,1,"Lower Middle",xlim=xlim,ylim=ylim)
br <- dia.rect(9,1,"bottom right",xlim=xlim,ylim=ylim) 

```

Now, we want to connect these objects with curves and arrows.  


```{r a figure}
#first set up the margins and initiate the plot
xlim=c(-2,10);   ylim=c(0,10)
plot(NA,xlim=xlim,ylim=ylim,main="Demonstration of diagram functions",
axes=FALSE,xlab="",ylab="")
#place and name the objects
ul <- dia.rect(1,9,labels="upper left",xlim=xlim,ylim=ylim)
ml <- dia.rect(1,6,"middle left",xlim=xlim,ylim=ylim)
ll <- dia.rect(1,3,labels="lower left",xlim=xlim,ylim=ylim)
bl <- dia.rect(1,1,"bottom left",xlim=xlim,ylim=ylim)
lr <- dia.ellipse(7,3,"lower right",xlim=xlim,ylim=ylim,e.size=.07)
ur <- dia.ellipse(7,9,"upper right",xlim=xlim,ylim=ylim,e.size=.07)
mr <- dia.ellipse(7,6,"middle right",xlim=xlim,ylim=ylim,e.size=.07)
lm <- dia.triangle(4,1,"Lower Middle",xlim=xlim,ylim=ylim)
br <- dia.rect(9,1,"bottom right",xlim=xlim,ylim=ylim) 
#connect them
dia.curve(from=ul$left,to=bl$left,"double headed",scale=-1)
dia.arrow(from=lr,to=ul$right,labels="right to left")
dia.arrow(from=ul,to=ur,labels="left to right")
dia.curved.arrow(from=lr,to=ll,labels ="right to left")
dia.curved.arrow(to=ur,from=ul,labels ="left to right")
dia.curve(ll$top,ul$bottom,"right",pos=4)  #for rectangles, specify where to point 
dia.arrow(from=lm, to= lr, "lower middle to lower right")
dia.curve(ur$right,lr$right,"top down",scale =2) #scale is size and curvature
dia.curve(ur$right,mr$right,"top down",scale =1) #scale is size and curvature
```
That is better, but lets clean it up a bit by changing the size, as well as fixing some of the text.

```{r}

#first set up the margins and initiate the plot
xlim=c(-1,10);      ylim=c(1,10)
plot(NA,xlim=xlim,ylim=ylim,main="Demonstration of diagram functions",
      axes=FALSE,xlab="",ylab="")
#place and name the objects
ul <- dia.rect(1,9,labels="upper left",xlim=xlim,ylim=ylim)
ml <- dia.rect(1,6,"middle left",xlim=xlim,ylim=ylim)
ll <- dia.rect(1,3,labels="lower left",xlim=xlim,ylim=ylim)
bl <- dia.rect(1,1,"bottom left",xlim=xlim,ylim=ylim)
lr <- dia.ellipse(7,3,"lower right",xlim=xlim,ylim=ylim,e.size=.09)
ur <- dia.ellipse(7,9,"upper right",xlim=xlim,ylim=ylim,e.size=.08)
mr <- dia.ellipse(7,6,"middle right",xlim=xlim,ylim=ylim,e.size=.07) #too small
lm <- dia.triangle(4,1,"Lower Middle",xlim=xlim,ylim=ylim)
br <- dia.rect(9,1,"bottom right",xlim=xlim,ylim=ylim) 
#now connect the shapes
dia.curve(from=ul$left,to=bl$left,"double\nheaded",scale=-.8)
dia.arrow(from=lr,to=ul$right,labels="right to left")
dia.arrow(from=ul,to=ur,labels="left to\n right",gap.size=.25)
dia.curved.arrow(from=lr,to=ll,labels ="right to\n left")
dia.curved.arrow(to=ur,from=ul,labels ="left to right")
dia.curve(ll$top,ul$bottom,"right",pos=4)  #for rectangles, specify where to point 
dia.arrow(from=lm, to= lr, "lower middle to \nlower right")#use \n for new line
dia.curve(ur$right,lr$right,"top down",scale =2) #scale is size and curvature
dia.curve(ur$right,mr$right,"top down",scale =1) #scale is size and curvature

```
This figure is a bit squased.  Can we increase the y dimension.

```{r}
#first set up the margins and initiate the plot
xlim=c(-1,10);      ylim=c(0,10)
plot(NA,xlim=xlim,ylim=ylim,main="Demonstration of diagram functions",
      axes=FALSE,xlab="",ylab="")
#place and name the objects
ul <- dia.rect(1,9,labels="upper left",xlim=xlim,ylim=ylim)
ml <- dia.rect(1,6,"middle left",xlim=xlim,ylim=ylim)
ll <- dia.rect(1,3,labels="lower left",xlim=xlim,ylim=ylim)
bl <- dia.rect(1,1,"bottom left",xlim=xlim,ylim=ylim)
lr <- dia.ellipse(7,3,"lower right",xlim=xlim,ylim=ylim,e.size=.09)
ur <- dia.ellipse(7,9,"upper right",xlim=xlim,ylim=ylim,e.size=.08)
mr <- dia.ellipse(7,6,"middle right",xlim=xlim,ylim=ylim,e.size=.07) #too small
lm <- dia.triangle(4,1,"Lower Middle",xlim=xlim,ylim=ylim)
br <- dia.rect(9,1,"bottom right",xlim=xlim,ylim=ylim) 
#now connect the shapes
dia.curve(from=ul$left,to=bl$left,"double\nheaded",scale=-.8)
dia.arrow(from=lr,to=ul$right,labels="right to left")
dia.arrow(from=ul,to=ur,labels="left to\n right",gap.size=.25)
dia.curved.arrow(from=lr,to=ll,labels ="right to\n left")
dia.curved.arrow(to=ur,from=ul,labels ="left to right")
dia.curve(ll$top,ul$bottom,"right",pos=4)  #for rectangles, specify where to point 
dia.arrow(from=lm, to= lr, "lower middle to \nlower right")#use \n for new line
dia.curve(ur$right,lr$right,"top down",scale =2) #scale is size and curvature
dia.curve(ur$right,mr$right,"top down",scale =1) #scale is size and curvature
```

This is not pretty.  It looks better if we don't run this in R studio.

# Developing functions to do graphics

Take examples from the help pages and modify them.

Consider the help page for `layout'. This discusses how to create multiple sub windows in one window.

We use their example and their example data:

```{r layout}
def.par <- par(no.readonly = TRUE) # save default, for resetting...
##-- Create a scatterplot with marginal histograms -----

x <- pmin(3, pmax(-3, stats::rnorm(50)))
y <- pmin(3, pmax(-3, stats::rnorm(50)))
xhist <- hist(x, breaks = seq(-3,3,0.5), plot = FALSE)
yhist <- hist(y, breaks = seq(-3,3,0.5), plot = FALSE)
top <- max(c(xhist$counts, yhist$counts))
xrange <- c(-3, 3)
yrange <- c(-3, 3)
nf <- layout(matrix(c(2,0,1,3),2,2,byrow = TRUE), c(3,1), c(1,3), TRUE)
layout.show(nf)

par(mar = c(3,3,1,1))
plot(x, y, xlim = xrange, ylim = yrange, xlab = "", ylab = "")
par(mar = c(0,3,1,1))
barplot(xhist$counts, axes = FALSE, ylim = c(0, top), space = 0)
par(mar = c(3,0,1,1))
barplot(yhist$counts, axes = FALSE, xlim = c(0, top), space = 0, horiz = TRUE)

par(def.par)  #- reset to default
```

Use those same x and y data, and draw it again, with `scatterHist` from `psych`.  `scatterHist` took the basic concepts from layout, and then added some bells and whistles.

```{r scatterHist}
scatterHist(x,y, main="data from layout example")
```

## From `pairs` to `pairs.panels`

Learn to read the `help` pages for each function.  Then Try the examples.  

The `pairs` function in core R has a very helpful help menu with examples.

```{r}
pairs(iris[1:4], main = "Anderson's Iris Data -- 3 species",
      pch = 21, bg = c("red", "green3", "blue")[unclass(iris$Species)])
```


## Examine the code

To see the code for particular functions, you can try just typing the name of the function.  If it is a `method` then you can ask for the various versions of that method.

```{r}
pairs  #either show the code or show that it is a method
methods(pairs) #show all the methods using `pairs`
```

We can then examine the code for any of those methods by calling `getAnywhere` with the name of the method.  e.g.
`getAnywhere(pairs.default)`  (not run)
 
 This was done to create `pairs.panels` function.
 
From help menu:

The various examples from the help page for `pairs` can be incorporated in one function `pairs.panels` for psych.'

Shamelessly adapted from the pairs help page. Uses panel.cor, panel.cor.scale, and panel.hist, all taken from the help pages for pairs. Also adapts the ellipse function from John Fox's car package.

pairs.panels is most useful when the number of variables to plot is less than about 6-10. It is particularly useful for an initial overview of the data.

To show different groups with different colors, use a plot character (pch) between 21 and 25 and then set the background color to vary by group. (See the second example).


```{r}
pairs.panels(iris[1:4],bg=c("red","yellow","blue")[iris$Species],
  pch=21+as.numeric(iris$Species),main="Fisher Iris data by Species",hist.col="red") 
```



