---
title: "User Guide: 1 Grammar of Graphics"
subtitle: "'ggspectra' `r packageVersion('ggspectra')`"
author: "Pedro J. Aphalo"
date: "`r Sys.Date()`"
output: 
  rmarkdown::html_vignette:
    toc: yes
vignette: >
  %\VignetteIndexEntry{User Guide: 1 Grammar of Graphics}
  %\VignetteEngine{knitr::rmarkdown}
  %\VignetteEncoding{UTF-8}
---

## Introduction

Package `ggspectra` extends `ggplot2` with stats, geoms, scales and annotations suitable for light spectra. It also defines `ggplot()` and  `plot()` methods specialized for the classes defined in package `photobiology` for storing different types of spectral data. The `plot()` methods are described separately in vignette 'Plot Methods'.

The new elements can be freely combined with methods and functions defined in packages `ggplot2`, `scales`, `ggrepel` and `cowplot`.

### What are `plot` specializations for?

The `plot` specializations produce fully annotated plots as `ggplot` objects, which can be further manipulated if so desired. They use the metadata stored in spectral objects of classes defined in package 'photobiology' to automatically generate suitable axis labels, scales and annotations. (Please, see vignette "Plot methods" for details.)

### What are `ggplot` specializations for?

The `ggplot` specializations set default `aes` according to the type of spectral object. They also add support for `unit.out` arguments allowing on-the-fly conversion of units of expression or spectral quantities. These are only defaults and can be overridden by explicit use of `aes()` to set the mapping of _aesthetics_.

### What are the different _stats_ useful for?

The _stats_ defined in this package help with with the generation of annotations and decorations of plots of spectral data. They are meant to be used only when the _x_ aesthetic is mapped to a variable containing wavelength values expressed in nanometres. They are designed to work with spectral objects of the classes defined in package 'photobiology'. Many of them also work well with any data frame as long as the _x_ aesthetic mapping fulfils the expectations. Package 'ggpmisc' contains some equivalent _stats_ which do not assume that _x_ is mapped to wavelength, accepting `numeric` and _datetime_ values.  

| _stat_     | default _geom_ (used for)  | other uses                                   |
|:---------------|:---------------------|:----------------------------------------------|
| `stat_peaks`        | point (highlight maxima)  | wavelength label, spectral quantity label |
| `stat_valleys`        | point (highlight minima)  | wavelength label, spectral quantity label |
| `stat_label_peaks`   |  text (wavelength label)  | spectral quantity label (support 'ggrepel') |
| `stat_label_valleys`   | text (wavelength label)  | spectral quantity label (support 'ggrepel') |
| `stat_color`         | color, fill |                                              |
| `stat_wb_label` | text (waveband name) | rect (showing range of waveband and its color) |
| `stat_wb_total` | text (y integral) | label(s) with waveband integral |
| `stat_wb_mean` | text (y mean) | label(s) with waveband mean |
| `stat_wl_summary` | text (y mean) | label with wavelength _range_ mean |
| `stat_wb_contribution` | text (contribution) | label(s) with waveband integral / whole spectrum integral |
| `stat_wb_relative` | text (relative) | label(s) with waveband integral / sum of integrals of all wavebands |
| `stat_wb_e_irrad` | text (energy irradiance) |  rect (showing range of waveband and its color) |
| `stat_wb_q_irrad` |  text (photon irradiance) | rect (showing range of waveband and its color) |
| `stat_wb_e_sirrad` | text (spectral energy irradiance) |  rect (showing range of waveband and its color) |
| `stat_wb_q_sirrad` |  text (spectral photon irradiance) | rect (showing range of waveband and its color) |
| `stat_wl_strip` |  rect (fill of wavelength or waveband) | text (label with waveband name) |
| `stat_wb_box` |  rect (fill of waveband) |   |
| `stat_wb_hbar` |  errorbarh (color of waveband) |  |
| `stat_wb_column` |  rect (fill of waveband) |  |

### What is `geom_spct` useful for?

The `geom_spct` _geometry_ is a special case of `geom_area`, but with the minimum of the _y_ range fixed to 0, but with stacking not enabled.

### What are the new _scales_ for?

The new scales are convenience wrapper functions built on top of the scales exported by package 'ggplot2', but with default arguments that are suitable for spectral data. 

Functions for automatic generation of secondary x-axes in the case when a variable containing wavelength data (nm) is mapped to the _x_ _aesthetic_ simplify the task of adding an axis with frequencies or wave numbers to the plot of a spectrum.

| _scale_     | unit.exponent | name | labels                       |  breaks  |
|:---------------|:---------------------|:---------------|:----------------|:---------------|
| scale_y_cps_continuous | 0 | cps_label() | SI_pl_format() | |
| scale_y_counts_continuous | 3 | counts_label() | SI_pl_format() | |
| scale_y_counts_tg_continuous | 3 | counts_label() | SI_tg_format() | |
| scale_y_A_internal_continuous | 0 | A_internal_label() | SI_pl_format() | |
| scale_y_A_total_continuous | 0 | A_total_label() | SI_pl_format() | |
| scale_y_Tfr_internal_continuous | 0 | Tfr_internal_label() | SI_pl_format() | |
| scale_y_Tfr_total_continuous | 0 | Tfr_total_label() | SI_pl_format() | |
| scale_y_Rfr_internal_continuous | 0 | Rfr_internal_label() | SI_pl_format() | |
| scale_y_Rfr_total_continuous | 0 | Rfr_total_label() | SI_pl_format() | |
| scale_y_s.e.irrad_continuous | 0 | s.e.irrad_label() | SI_pl_format() | |
| scale_y_s.q.irrad_continuous | -6 | s.q.irrad_label() | SI_pl_format() | |
| scale_y_s.e.response_continuous | 0 | s.e.response_label() | SI_pl_format() | |
| scale_y_s.q.response_continuous | 0 | s.q.response_label() | SI_pl_format() | |
| scale_x_wl_continuous | -9 | w_length_label() | SI_pl_format() | pretty_breaks(n=7) |
 

In addition secondary axis definitions, `sec_axis_w_number()` and `sec_axis_w_frequency()`, and SI system formatters `SI_pl_format`, and `SI_tg_format` are exported, together with auxiliary functions for finding the nearest SI multiplier based on an arbitrary exponent.


### What are functions `color_chart()` and `black_or_white()` for?

Function `color_chart()` makes a color chart of rectangular tiles from a vector R color definitions. The chart returned is a `ggplot` object. Function `black_or_white()` accepts a vector of color definitions and returns a vector with colors `"white"` or `"black"` depending on the approximate luminosity of the each color in the input. The main use is to automatically achieve suitable contrast between text plotted on top of a color background.

### What is function `ggtitle_spct()` for?

Function `ggtitle_spct()` adds a title and/or subtitle to a plot. The difference with `ggtitle()` from package 'ggplot2' is that this function can automatically retrieve metadata from the plotted object and display it in the title. It used internally by all `plot()` methods defined in package 'ggspectra' and its use is described in _User Guide 2: Plot Methods_ together with plot annotations.

## Set up 

```{r}
library(ggplot2)
library(scales)
library(photobiology)
library(photobiologyWavebands)
library(ggspectra)
library(ggrepel)
```

```{r setup, include = FALSE, eval = FALSE}
library(svglite)
knitr::opts_chunk$set(
  dev = "svglite",
  fig.ext = ".svg"
)
```

```{r, include=FALSE, echo=FALSE}
library(knitr)
opts_chunk$set(fig.path = 'figure/guide-pos-', fig.align = 'center', 
               fig.show = 'hold', fig.width = 7, fig.height = 4)
options(warnPartialMatchArgs = FALSE)
```

We bind two spectra, to later on demonstrate grouping.

```{r}
two_suns.spct <- rbindspct(list(sun1 = sun.spct, sun2 = sun.spct * 2))
```

We change the default theme.

```{r}
theme_set(theme_bw())
```

## ggplot() methods for spectra

The only difference between these specializations and the base `ggplot()` method is that the aesthetics for $x$ and $y$ have suitable defaults. These are just defaults, so if needed they can still be supplied with a `mapping` argument with an user-defined `aes()`.

```{r}
ggplot(sun.spct) + geom_line()
```

It is possible to add to the defaults by means of `+` and `aes()` as shown below.

```{r}
ggplot(two_suns.spct) + aes(color = spct.idx) + geom_line()
```

If a mapping is supplied directly through `ggplot`, $x$ and $y$ should be included.

```{r}
ggplot(two_suns.spct, aes(w.length, s.e.irrad, color = spct.idx)) + geom_line()
```

In the case of `ggplot.source_spct()` an additional parameter allows setting the type of units to use in the plot. This not only sets a suitable `aes()` for $y$ but also if needed converts the spectral data. The two possible values are `"energy"` and `"photon"` and the default, depends on option `photobiology.radiation.unit`. This parameter has a default value that can be modified through option `"photobiology.radiation.unit"`. Package 'photobiology' defines convenience functions for this.

```{r}
ggplot(sun.spct, unit.out = "photon") + geom_line()
```

After evaluation of `photon_as_default()`, a new default is in effect, but we can override it with an explicit argument if needed.

```{r}
photon_as_default()
ggplot(sun.spct) + geom_line()
ggplot(sun.spct, unit.out = "energy") + geom_line()
```

This new default will remain active for the rest of the R session, unless changed. We can easily either unset this default, or all photobiology-package related user set defaults.

```{r}
unset_user_defaults()
```

The next example is for spectral properties of filters.

```{r}
ggplot(yellow_gel.spct) + geom_line()
```

In the case of `ggplot.filter_spct()` the additional parameter is called `plot.qty` and allows choosing between `"transmittance"` and `"absorbance"`.

```{r}
ggplot(yellow_gel.spct, plot.qty = "absorbance") + geom_line()
```

In the case of `ggplot.object_spct()` three values (`"reflectance"`, `"transmittance"` and `"all"` are accepted. Passing `"all"` as argument results in the spectral data being molten into a long form, using `value` and `variable` as value and key columns, respectively. The column `variable` has three levels `Tfr`, `Rfr` and `Afr` indexing the `Tfr` and `Rfr` from the `object_spct` object plus newly calculated absorptance values. 

This parameter has a default value that can be modified through option `"photobiology.filter.qty"`. Package 'photobiology' defines convenience functions for this.

```{r}
Afr_as_default()
ggplot(yellow_gel.spct) + geom_line()
ggplot(polyester.spct) + geom_line()
unset_user_defaults()
```

The names of the additional parameters are consistent with those used in the `plot()` methods defined in this package.

## Scales

### Wavelength

Currently only an x-scale function suitable for wavelengths in nanometres is defined in package 'ggspectra'.

```{r}
ggplot(sun.spct) + 
  geom_line() +
  scale_x_wl_continuous()
```

Functions for automating the addition of secondary axes are also defined.

```{r}
ggplot(sun.spct) + 
  geom_line() +
  scale_x_wl_continuous(sec.axis = sec_axis_w_number())
```
```{r}
ggplot(sun.spct) + 
  geom_line() +
  scale_x_wl_continuous(sec.axis = sec_axis_w_frequency())
```
It is possible to set a different SI scaling factor for the units.
```{r}
ggplot(sun.spct) + 
  geom_line() +
  scale_x_wl_continuous(sec.axis = sec_axis_w_frequency(15))
```
It is possible to set a non-SI scaling factor for the units.
```{r}
ggplot(sun.spct) + 
  geom_line() +
  scale_x_wl_continuous(sec.axis = sec_axis_w_frequency(14))
```

It is possible find the largest valid SI-scaling factor that is smaller or equal to and arbitrary power of 10.

```{r}
nearest_SI_exponent(14)
```
### Raw counts

```{r}
ggplot(white_led.raw_spct) + 
  geom_line() +
  scale_x_wl_continuous() +
  scale_y_counts_continuous()
  
```

```{r}
ggplot(white_led.raw_spct) + 
  geom_line() +
  scale_x_wl_continuous() +
  scale_y_counts_tg_continuous()
  
```

### Counts per second

```{r}
ggplot(white_led.cps_spct) + 
  geom_line() +
  scale_x_wl_continuous() +
  scale_y_counts_continuous()
  
```


### Spectral irradiance

```{r}
ggplot(sun.spct) + 
  geom_line() +
  scale_x_wl_continuous() +
  scale_y_s.e.irrad_continuous()
```
```{r}
ggplot(sun.spct, unit.out = "photon") + 
  geom_line() +
  scale_x_wl_continuous() +
  scale_y_s.q.irrad_continuous()
```

We can change the SI unit multipliers on-the-fly. Beware that these are not data transformations, only the labelling of the axes changes! Consequently summary values will not be affected. We will express the spectral irradiance using milli watts instead of watts and wavelengths in micrometres instead of nanometres.

```{r}
ggplot(sun.spct) + 
  geom_line() +
  scale_x_wl_continuous(-6) +
  scale_y_s.e.irrad_continuous(-3)
```

The scales are just wrappers on the _scales_ defined in packages '**ggplot2**' and '**scales**' with defaults suitable for spectral data. They pass additional arguments to the underlying scale functions allowing, for example, the control of the formatting of tick labels.

```{r}
ggplot(sun.spct, unit.out = "photon") + 
  geom_line() +
  scale_x_wl_continuous() +
  scale_y_s.q.irrad_continuous(unit.exponent = 0,
                               labels = scientific_format())
```

In addition to formatters defined in package '**scales**' as used above, additional formatters are defined in package '**ggspectra**', like those used in the next example.

```{r}
library(scales)
ggplot(sun.spct, unit.out = "photon") + 
  geom_line() +
  scale_x_wl_continuous() +
  scale_y_s.q.irrad_continuous(unit.exponent = 0,
                               labels = SI_tg_format(exponent = -6))
```

Transformation objects for '**scales**', or user defined, can be also passed as arguments. We replace zeros to avoid a warnings from the `log10()` call, and as the scale `limits`
dicards some observations, we use `na.rm = TRUE` to silence this additional warning.

```{r}
temp.spct <- clean(sun.spct, range.s.data = c(1e-20, Inf), fill = 1e-20)
ggplot(temp.spct, unit.out = "photon") + 
  geom_line(na.rm = TRUE) +
  scale_x_wl_continuous() +
  scale_y_s.q.irrad_continuous(unit.exponent = 0,
                               trans = "log10",
                               labels = trans_format("log10", math_format()),
                               limits = c(1e-12, NA))
```

### Response

```{r}
ggplot(ccd.spct, unit.out = "photon") + 
  geom_line() +
  scale_x_wl_continuous() +
  scale_y_s.q.response_continuous()
```

```{r}
ggplot(ccd.spct, unit.out = "photon") + 
  geom_line() +
  scale_x_wl_continuous() +
  scale_y_s.q.response_continuous(trans = "log10",
                                  labels = trans_format("log10", math_format()))
```

### Transmittance

```{r}
ggplot(yellow_gel.spct) + 
  geom_line() +
  scale_x_wl_continuous() +
  scale_y_Tfr_total_continuous()
  
```

```{r}
ggplot(yellow_gel.spct) + 
  geom_line() +
  scale_x_wl_continuous() +
  scale_y_Tfr_total_continuous(labels = percent)
  
```
### Absorbance

```{r}
ggplot(yellow_gel.spct, plot.qty = "absorbance") + 
  geom_line() +
  scale_x_wl_continuous() +
  scale_y_A_total_continuous()
```

### Reflectance

```{r}
ggplot(green_leaf.spct) + 
  geom_line() +
  scale_x_wl_continuous() +
  scale_y_Rfr_total_continuous()
```

## Stats

Several `ggplot` stats are defined by this package. All of them target light spectra, as they expect $x$ to represent wavelengths expressed in nanometres. However, they should behave correctly as long as this is true, with any `ggplot` object, based on any data format acceptable to `ggplot`. The name of the original variable is irrelevant, and it is the user responsibility to supply the correct variables through `aes()`. Of course, when using the spectral classes defined in package `photobiology` the defaults easy this task.

### Peaks and valleys

Four stats are available, they all have the same formal parameters. These stats do not fit peaks, simply search for local maxima and local minima in the data as supplied. Stats `stat_peaks()` and `stat_valleys()` subset the original data while `stat_label_peaks()` and `stat_label_valleys()` only set a boolean flag to mark the local extremes. All these stats set several aesthetics based on calculated values. Not all of these aesthetics are used by the default geom, but they make using other geoms easy. Furthermore text labels are formatted with `sptintf()` and these four stats accept format definitions through parameters `label.fmt`, `x.label.fmt`, and `y.label.fmt`. Both the $x$ and $y$ values at the maxima or minima are returned or flagged. The stats use internally function `photobiology::find_peaks()` and arguments are passed down to it.

```{r}
ggplot(sun.spct) + geom_line() + stat_peaks(color = "red")
```

Because of the conversion, the location of maxima and minima when an spectrum is expressed in photon and energy based units may differ. This is expected and not a bug.

```{r}
ggplot(sun.spct, unit.out = "photon") + geom_line() + stat_peaks(color = "red")
```

The complement to `stat_peaks()` is `stat_valleys`.

```{r}
ggplot(sun.spct) + geom_line() + stat_valleys(color = "blue")
```

One of the values calculated and mapped is colour as seen by humans corresponding to the wavelength at the location of peaks and valleys. The colour is mapped to the `fill` aesthetic, so using a 'filled' shape results in a colourful plot. The _identity_ scale is needed so that the correct colours are displayed using the colour definitions in the calculated data instead of a palette.

```{r}
ggplot(sun.spct) + geom_line() + 
  stat_peaks(shape = 21, color = "black") + scale_fill_identity()
```

We can use any of the aesthetics affecting the default _geom_, `"point"`, and also with other _geom_s.

```{r}
ggplot(sun.spct) + geom_line() + 
  stat_peaks(span = 21, shape = 4, color = "red", size = 2) +
  stat_peaks(span = 21, color = "red", geom = "rug", sides = "b")
```

We can use several other _geoms_ as needed, demonstrated here with _geom_ `"text"`.

```{r}
ggplot(sun.spct) + geom_line() + 
  stat_peaks(span = 21, geom = "text", color = "red", vjust = "bottom") 
```

The same stat can be included more than once in the same plot, using different _geoms_. We here in addition demonstrate the use of several different parameters. The `span` argument determines the number of consecutive observations tested when searching for a local extreme, and it should be an odd integer number. In addition we here demonstrate the use of a _geom_ new to `ggplot2` 2.0.0 called `"label"` which again results in colourful labels by default.

```{r}
ggplot(sun.spct) + geom_line() + 
  stat_peaks(shape = 21, span = 25, size = 2) + 
  scale_fill_identity() +
  stat_peaks(aes(color = ..BW.color..), 
             geom = "label", span = 25, vjust = "bottom", size = 3) + 
  scale_color_identity()
```

To avoid overlap between labels we can use the repulsive geoms from package `ggrepel`. In this case we need to use `stat_label_peaks()`. Repulsion allows the use of larger labels. We also need to expand the $y$ limits to make space for the labels.

```{r}
ggplot(sun.spct) + geom_line() + 
  stat_peaks(shape = 21, span = 25, size = 2) + 
  stat_label_peaks(geom = "label_repel", span = 41, 
                   size = 3.5, nudge_y = 0.075, segment.colour = "black") +
  stat_valleys(shape = 21, span = 25, size = 2) + 
  stat_label_valleys(geom = "label_repel", span = 51, 
                     size = 3.5, nudge_y = -0.075, segment.colour = "black") +
  scale_fill_identity() + scale_color_identity() +
  expand_limits(y = c(-0.08, 0.9))
```

If we do not use a repulsive geom that skips labels set to `""`, the plot produced by `stat_label_peaks` is of little use unless we explicitly skip the unlabelled observations as shown below.

```{r}
ggplot(sun.spct) + geom_line() + 
  stat_peaks(shape = 21, span = 25, size = 2) + scale_fill_identity() +
  stat_label_peaks(geom = "label", span = 25, vjust = "bottom", size = 3, 
                   aes(label = ifelse(..is_peak.., ..x.label.., NA)), na.rm = TRUE) +
  scale_color_identity() +
  expand_limits(y = c(NA, 0.9))
```

Setting `span` to `NULL` results in the span set to the range of the data, and so in this case the stat returns the global extreme, instead of a local one. In this case we use geoms `"vline"` and `"hline"` taking advantage that suitable aesthetics are set by the stats.

```{r}
ggplot(sun.spct) + geom_line() + 
  stat_peaks(span = NULL, geom = "vline", linetype = "dotted", color = "red") +
  stat_peaks(span = NULL, geom = "hline", linetype = "dotted", color = "red")
```

By default the `label` aesthetic is mapped to a calculated label `..x.label..` giving the wavelength in nanometres. This mapping can be changed to give to a label giving the _y_-value at the peak.

```{r}
ggplot(sun.spct) + geom_line() + 
  stat_label_peaks(span = 31, geom = "label_repel", aes(label = ..y.label..), 
             label.fmt = "y = %1.2f", segment.colour = "red",
             min.segment.length = unit(0.05, "lines")) +
  expand_limits(y = 1) +
  scale_fill_identity() + scale_color_identity()
```

As _aesthetics_ can use values computed on-the-fly we can even use `paste()` to map a label that combines both values and adds additional text.

```{r}
ggplot(sun.spct) + geom_line() + 
  stat_peaks(span = NULL, color = "red") +
  stat_peaks(span = NULL, geom = "text", vjust = -0.5, color = "red", 
             aes(label = paste(..y.label.., "at", ..x.label.. , "nm"))) +
  expand_limits(y = c(NA, 0.9))
```

Finally we demonstrate that both stats can be simultaneously used. One can also choose to use different spans as demonstrated here, resulting in more maxima being marked by points than labelled with text.
```{r}
ggplot(sun.spct) + geom_line() + 
  stat_peaks(span = 21, geom = "point", colour = "red") +
  stat_valleys(span = 21, geom = "point", colour = "blue") +
  stat_peaks(span = 51, geom = "text", colour = "red", 
             vjust = -0.3, label.fmt = "%3.0f nm") +
  stat_valleys(span = 51, geom = "text", colour = "blue", 
               vjust = 1.2, label.fmt = "%3.0f nm")
```

This final example shows a few additional tricks used in this case to mark and label the maximum of the spectrum. This example also demonstrates why it is important that these are stats. The peaks are searched and labels generated once for each group, in this case each _facet_.

```{r}
ggplot(two_suns.spct) + aes(color = spct.idx) +
  geom_line() + ylim(NA, 1.8) +
  stat_peaks(span = NULL, color = "black") +
  stat_peaks(span = NULL, geom = "text", vjust = -0.5, size = 3, 
             color = "black", 
             aes(label = paste(..y.label.., "at", ..x.label.. , "nm"))) +
  facet_grid(spct.idx~.)
```

## Color from wavelength

This stat calculates the colour corresponding to each $x$-value (assumed expressed in nanometres) and adds it to the data. It does not summarize the data like `stat_summary()` nor does it subset the data like `stat_peaks`, consequently the plot does not require any additional _geom_ to have all observations plotted. It sets both _color_ and _fill_ aesthetics to a suitable default.

```{r}
ggplot(sun.spct) + 
  stat_color() + scale_color_identity()
```

By use of a filled _shape_ and adding a black border by overriding the default _color_ aesthetic and over-plotting these point on top of a line, we obtain a better separation from the background.

```{r}
ggplot(sun.spct) +
  geom_line() +
  stat_color(shape = 21, color = "black") + 
  scale_fill_identity()
```

With a _trick_ using many narrow _bars_ we can fill the area under the line with a the calculated colours. This works satisfactorily as the data set has a small wavelength step, as in this case we are using a bar of uniform colour for each wavelength value in the data set.

```{r}
ggplot(sun.spct) + 
  stat_color(geom = "bar") + 
  geom_point(shape = 21, color = "black", stroke = 1.2, fill = "white") +
  scale_fill_identity() + 
  scale_color_identity() + 
  theme_bw()
```

As final example we demonstrate a plot with _facets_ and _shape_ based groups.

```{r}
ggplot(two_suns.spct) + aes(shape = spct.idx) +
  stat_color() + scale_color_identity() +
  geom_line() + 
  facet_grid(spct.idx~., scales = "free_y")
```

## Averages and similar summaries

Our summary _statistics_ are quite different to `ggplot2`s `stat_summary()`. One could criticize that they calculates summaries using a grouping that is not based on a _ggplot_ _aesthetic_. This is a deviation from the grammar of graphics but allows the calculation of summaries for an arbitrary region of the range of $x$-values in the spectral data.

### Summaries producing graphical elements

Three _statistics_ generate only graphic output. First we demonstrate `stat_wb_box()` that produces a filled box for each waveband, filled with the color corresponding to the waveband.

```{r}
ggplot(sun.spct) + geom_line() + 
  stat_wb_box(w.band = VIS_bands(), color = "white") +
  scale_fill_identity()
```

The _statistics_ `stat_wb_column` outputs a column for each waveband, with an area equal to the integral for the corresponding region of the spectrum.

```{r}
ggplot(sun.spct) + stat_wb_column(w.band = VIS_bands()) + geom_line() +
  scale_fill_identity()
```
The _statistic_ `stat_wd_hbar` outputs a horizontal bar showing the mean spectral _y_-value for each waveband.

```{r}
ggplot(sun.spct) + geom_line() + 
  stat_wb_hbar(w.band = VIS_bands(), size = 1.2) +
  scale_color_identity()
```

These graphical summaries are frequently used together with text and label elements with names or numerical summaries.

### Name labels
```{r}
ggplot(sun.spct) + geom_line() + 
  stat_wb_box(w.band = PAR(), color = "white", ypos.fixed = 0.85) +
  stat_wb_label(w.band = PAR(), ypos.fixed = 0.85) +
  scale_fill_identity() + scale_color_identity()
```

### Summaries by wavelength range

The summary is calculated for a range of wavelengths, and the `range` argument defaults to the range of wavelengths in each group defined by other aesthetics. The default _geom_ is `"text"`.

```{r}
ggplot(sun.spct) + geom_line() + stat_wl_summary()
```

We can optionally supply an argument for `range` to limit the summary to a certain part of the spectrum, in which case the use of the default `"text"` _geom_ is misleading. We add the line last so that it is drawn on top of the rectangle.

```{r}
ggplot(sun.spct) + 
  stat_wl_summary(range = c(300,350), geom = "rect") +
  geom_line()
```

Here we show how to add horizontal line and label for the overall mean, by adding the same stat twice, using different values for `geom`.

```{r}
ggplot(sun.spct) +
  geom_line() + 
  stat_wl_summary(geom = "hline", color = "red") +
  stat_wl_summary(label.fmt = "Mean = %.3g", color = "red", vjust = -0.3)
```

Or we can add the _aesthetic_ twice with two different geoms to get the value plotted as a rectangular area and the value as formatted text. We use `vjust` to move the text above the end of the bar, instead of it being centred on the value itself.

```{r}
ggplot(sun.spct) +
  stat_wl_summary(range = c(400,500), geom = "rect", alpha = 0.2, fill = color_of(450)) +
  stat_wl_summary(range = c(400,500), label.fmt = "Mean = %.3g", vjust = -0.3, geom = "text") + 
  geom_line()
```

An example using the `color` _aesthetic_ for grouping and moving the text label down. Setting 

```{r}
ggplot(two_suns.spct) + aes(color = spct.idx) +
  geom_line() + 
  stat_wl_summary(geom = "hline") +
  stat_wl_summary(label.fmt = "Mean = %.3g", vjust = 1.2, show.legend = FALSE) +
  facet_grid(spct.idx~.)
```

Same example as above but using a free scale for $y$, still working as expected.

```{r}
ggplot(two_suns.spct) + aes(color = spct.idx) +
  geom_line() + 
  stat_wl_summary(geom = "hline") +
  stat_wl_summary(label.fmt = "Mean = %.3g", vjust = 1.2, show.legend = FALSE) +
  facet_grid(spct.idx~., scales = "free_y")
```

### Means by waveband

Our `stat_wb_mean()` is quite different to `ggplot2`s `stat_summary()`. One could criticize that it calculates summaries using a grouping that is not based on a _ggplot_ _aesthetic_. This is a deviation from the grammar of graphics but allows the calculation of summaries for an arbitrary waveband of the spectrum based on `photobiology::waveband` objects, or lists of such objects. In contrast to `stat_wl_summary()` this allows the use of several ranges, and also of different weighting functions. This function returns both mean and total values for each waveband. It differs from `stat_wb_total()` only in the default _aesthetics_ set.

The first example uses a `waveband` object created on-the-fly and defining a range of wavelengths.

```{r}
ggplot(sun.spct) +
  geom_line() + 
  stat_wb_hbar(w.band = PAR(), size = 1.3) +
  stat_wb_mean(aes(color = ..wb.color..), w.band = PAR(), ypos.mult = 0.95) +
  scale_color_identity() + 
  scale_fill_identity() +  
  theme_bw()
```

If a numeric vector or a spectrum is supplied as argument to `waveband`, its range is calculated and used to construct a temporary `waveband` object.

```{r}
ggplot(sun.spct) +
  stat_wb_hbar(w.band = c(400,500), size = 1.2) +
  stat_wb_mean(aes(color = ..wb.color..),
               w.band = c(400,500), ypos.mult = 0.95) +
  geom_line() + 
  scale_color_identity() + 
  scale_fill_identity() +
  theme_bw()
```
Lists of wavebands, either user-defined or as in this case using a list constructor can be also used.

```{r}
ggplot(sun.spct) +
  geom_line() + 
  stat_wb_hbar(w.band = list(Blue(), Red()), size = 1.2) +
  stat_wb_mean(aes(color = ..wb.color..),
               w.band = list(Blue(), Red()), ypos.mult = 0.95, 
               hjust = 1, angle = 90) +
  scale_color_identity() + 
  scale_fill_identity() +
  theme_bw()
```

### Totals by waveband

Our `stat_wb_total()` is quite different to `ggplot2`s `stat_summary()`. One could criticize that it calculates summaries using a grouping that is not based on a _ggplot_ _aesthetic_. This is a deviation from the grammar of graphics but allows the calculation of summaries for an arbitrary waveband of the spectrum based on `photobiology::waveband` objects, or lists of such objects. In contrast to `stat_wl_summary()` this allows the use of several ranges, and also of different weighting functions. This function returns both mean and total values for each waveband. It differs from `stat_wb_mean()` only in the default _aesthetics_ set.

The first example uses a `waveband` object created on-the-fly and defining a range of wavelengths.

```{r}
ggplot(sun.spct) +
  stat_wb_box(w.band = PAR()) +
  stat_wb_total(w.band = PAR()) +
  geom_line() + 
  scale_color_identity() + 
  scale_fill_identity() +  
  theme_bw()
```

If a numeric vector or a spectrum is supplied as argument to `waveband`, its range is calculated and used to construct a temporary `waveband` object.

```{r}
ggplot(sun.spct) +
  stat_wb_box(w.band = c(400,500)) +
  stat_wb_total(w.band = c(400,500)) +
  geom_line() + 
  scale_color_identity() + 
  scale_fill_identity() +
  theme_bw()
```

Lists of wavebands, either user-defined or as in this case using constructor defined in package `photobiologyWavebands` can be also used. In the case of totals, areas represent them graphically in a very useful way.

```{r}
ggplot(sun.spct * yellow_gel.spct) +
  stat_wb_box(w.band = Plant_bands(), color = "white", ypos.fixed = 0.7) +
  stat_wb_column(w.band = Plant_bands(), color = "white", alpha = 0.5) +
  stat_wb_mean(w.band = Plant_bands(), label.fmt = "%1.2f",
               ypos.fixed = 0.7, size = 2) +
  geom_line() + 
  scale_fill_identity() + scale_color_identity() +
  theme_bw()
```

### Irradiances by waveband

The _stat_s in previous sections can be used for non-weighed irradiances, but not for BSWFs. These `irrad` _stat_s have additional formal parameters for passing metadata, and use method `photobiology::irrad()` internally on a `photobiology::source_spct` object constructed from the
data for $x$ and $y$ _aesthetics_. Function `stat_wb_sirrad()` is equivalent to `stat_wb_mean()` and function `stat_wb_irrad()` is equivalent to `stat_wb_total()` following the same naming convention as in package `photobiology`. 

```{r}
ggplot(sun.spct) +
  stat_wb_box(w.band = PAR()) +
  stat_wb_irrad(w.band = PAR(), unit.in = "energy", time.unit = "second") +
  geom_line() + 
  scale_color_identity() + 
  scale_fill_identity() +  
  theme_bw()
```

```{r}
ggplot(sun.spct, unit.out = "photon") +
  stat_wb_box(w.band = PAR()) +
  stat_wb_irrad(w.band = PAR(),
                unit.in = "photon", time.unit = "second", 
                aes(label = sprintf("%s = %.3g", ..wb.name.., ..yint.. * 1e6))) +
  geom_line() + 
  scale_color_identity() + 
  scale_fill_identity() +  
  theme_bw()
```

Also following the same naming convention as in package `photobiology`, `e` and `q` versions of these functions default to energy and photon based quantities to `"seconds"` for time unit.

```{r}
ggplot(sun.spct) +
  stat_wb_box(w.band = PAR()) +
  stat_wb_e_irrad(w.band = PAR()) +
  geom_line() + 
  scale_color_identity() + 
  scale_fill_identity() +  
  theme_bw()
```

We can also use `waveband` objects describing _biological spectral weighting functions_ (BSWFs), such as CIE's erythema function.

```{r}
ggplot(sun.spct) +
  stat_wb_box(w.band = CIE()) +
  stat_wb_e_irrad(w.band = CIE()) +
  geom_line() + 
  scale_color_identity() + 
  scale_fill_identity() +  
  theme_bw()
```

For daily data we need to override the default time unit.

```{r}
ggplot(sun.daily.spct) +
  stat_wb_box(w.band = CIE()) +
  stat_wb_e_irrad(w.band = CIE(), time.unit = "day", label.mult = 1e-3) +
  geom_line() + 
  scale_color_identity() + 
  scale_fill_identity() +  
  theme_bw()
```

Here we pass a list of `waveband` objects. And add areas to facilitate comparisons as irradiances are integral over wavelengths.

```{r}
ggplot(sun.spct, unit.out = "photon") +
  stat_wb_box(w.band = VIS_bands(), color = "black") +
  stat_wb_column(w.band = VIS_bands(), color = NA, alpha = 0.5) +
  stat_wb_q_irrad(w.band = VIS_bands(), label.mult = 1e6, size = 2) +
  geom_line() + 
  scale_color_identity() + 
  scale_fill_identity() +  
  theme_bw()
```

### Spectral irradiances by waveband

Spectral irradiances are equivalent to means, and can be best represented graphically as horizontal bars.

```{r}
ggplot(sun.spct) +
  geom_line() + 
  stat_wb_hbar(w.band = PAR(), size = 1.4) +
  stat_wb_e_sirrad(aes(color = ..wb.color..), 
                   w.band = PAR(), ypos.mult = 0.95) +
  scale_color_identity() + 
  scale_fill_identity() +  
  theme_bw()
```

```{r}
ggplot(sun.spct, unit.out = "photon") +
  stat_wb_column(w.band = PAR(), alpha = 0.8) +
  stat_wb_q_sirrad(w.band = PAR(), 
                   mapping =
                     aes(label = sprintf("Total %s = %.3g", 
                                         ..wb.name.., ..yint.. * 1e6)), 
                   ypos.mult = 0.55) +
  stat_wb_q_sirrad(w.band = PAR(),
                   mapping = 
                     aes(label = sprintf("Mean %s = %.3g", 
                                         ..wb.name.., ..ymean.. * 1e6)), 
                   ypos.mult = 0.45) +
  geom_line() + 
  scale_color_identity() + 
  scale_fill_identity() +  
  theme_bw()
```

```{r}
ggplot(sun.spct) +
  stat_wb_box(w.band = waveband(CIE()), ypos.fixed = 0.85) +
  stat_wb_e_sirrad(w.band = CIE(), ypos.fixed = 0.85) +
  geom_line() + 
  scale_color_identity() + 
  scale_fill_identity() +  
  theme_bw()
```

```{r}
ggplot(sun.daily.spct) +
  stat_wb_box(w.band = waveband(CIE()), ypos.fixed = 34e3) +
  stat_wb_e_sirrad(w.band = CIE(),
                   label.fmt = "%.2g kj / day",
                   time.unit = "day",
                   ypos.fixed = 34e3) +
  geom_line() + 
  scale_color_identity() + 
  scale_fill_identity() +  
  theme_bw()
```

```{r}
my.bands <- split_bands(c(300,800), length.out = 10)
ggplot(sun.spct, unit.out = "photon") +
  stat_wb_hbar(w.band = my.bands, size = 1.4) +
  stat_wb_q_sirrad(geom = "label", w.band = my.bands, 
                   size = 2.5, ypos.fixed = 3.5e-6) +
  geom_line() + 
  scale_color_identity() + 
  scale_fill_identity() +  
  theme_bw()
```

### Irradiances by waveband

```{r}
ggplot(sun.spct) +
  stat_wb_column(w.band = VIS_bands(), alpha = 0.5) +
  stat_wb_e_irrad(w.band = VIS_bands(), angle = 90,
                   ypos.fixed = 0.05, hjust = 0,
                   aes(label = paste(..wb.name.., ..y.label.., sep = " = "))) +
  geom_line() + 
  scale_color_identity() + 
  scale_fill_identity() +  
  theme_bw()
```

```{r}
ggplot(sun.spct, unit.out = "photon") +
  stat_wb_column(w.band = VIS_bands(), alpha = 0.5) +
  stat_wb_q_irrad(w.band = VIS_bands(), angle = 90, 
                  label.mult = 1e6, ypos.fixed = 1e-7, hjust = 0,
                  aes(label = paste(..wb.name.., ..y.label.., sep = " = "))) +
  geom_line() + 
  scale_color_identity() + 
  scale_fill_identity() +  
  theme_bw()
```


```{r}
my.bands <- split_bands(c(300,800), length.out = 10)
ggplot(sun.spct) +
  stat_wb_column(w.band = my.bands, alpha = 0.5) +
  stat_wb_e_irrad(w.band = my.bands, angle = 90,
                  ypos.fixed = 0.05, hjust = 0) +
  geom_line() + 
  scale_color_identity() + 
  scale_fill_identity() +  
  theme_bw()
```

## Labels from wavebands

Sometimes we may want to only annotate a plot with waveband names and regions without calculating any summary quantity. `stat_wb_label()` fills this role. Although the same result can be achieved with some of the summary statistics, if no summary is needed this statistic can avoid unnecessary computations, and more importantly used in plots where the $y$ is not mapped, as only the $x$ aesthetic is required.

```{r}
ggplot(data.frame(w.length = 300:800), aes(w.length)) +
  stat_wl_strip(w.band = VIS_bands(), ymax = Inf, ymin = -Inf) +
  stat_wb_label(w.band = VIS_bands(), angle = 90) +
  scale_fill_identity() + 
  scale_color_identity() + 
  scale_y_continuous(labels = NULL) +
  scale_x_continuous(breaks = seq(from = 300, to = 800, by = 25)) +
  labs(x = "Wavelength (nm)", title = "Colours according to ISO standard") +
  theme_minimal()

```

We can also in a similar way make a plot comparing different sets of wavebands, in the next example we compare the VIS and NIR bands of the different imagers used in Landsat missions 1 to 8.

```{r}
ggplot(data.frame(w.length = 300:1100), aes(w.length)) +
  stat_wl_strip(w.band = RBV_bands(), ymax = 1, ymin = 3) +
  stat_wb_label(w.band = RBV_bands(), ypos.fixed = 2, angle = 90, vjust = 0.3, size = 3) +
  stat_wl_strip(w.band = MSS_bands(), ymax = 4, ymin = 6, na.rm = TRUE) +
  stat_wb_label(w.band = MSS_bands(), ypos.fixed = 5, angle = 90, vjust = 0.3, size = 3) +
  stat_wl_strip(w.band = ETM_bands(), ymax = 7, ymin = 9, na.rm = TRUE) +
  stat_wb_label(w.band = ETM_bands(), ypos.fixed = 8, angle = 90, vjust = 0.3, size = 3) +
  stat_wl_strip(w.band = OLI_bands(), ymax = 10, ymin = 12, na.rm = TRUE) +
  stat_wb_label(w.band = OLI_bands(), ypos.fixed = 11, angle = 90, vjust = 0.3, size = 3) +
  scale_fill_identity() + 
  scale_color_identity() + 
  scale_y_continuous(labels = c("RBV", "MSS", "TM/ETM", "OLI"), 
                     breaks = c(2,5,8,11),
                     limits = c(0, 13),
                     name = "Imager",
                     sec.axis = dup_axis(labels = c("L1-L2", "L1-L5", "L4-L7", "L8"), name = "Landsat mission")) +
  scale_x_continuous(breaks = seq(from = 300, to = 1200, by = 100),
                     limits = c(400, 1100),
                     sec.axis = dup_axis()) +
  labs(x = "Wavelength (nm)", title = "Landsat imagers: VIS and NIR bands") +
  theme_classic()
```

The different definitions of the ultraviolet regions.

```{r}
ggplot(data.frame(w.length = 100:400), aes(w.length)) +
  stat_wl_strip(w.band = UV_bands("ISO"), ymax = 1, ymin = 3, color = "white") +
  stat_wb_label(w.band = UV_bands("ISO"), ypos.fixed = 2, size = 3) +
  stat_wl_strip(w.band = UV_bands("CIE"), ymax = 4, ymin = 6, color = "white") +
  stat_wb_label(w.band = UV_bands("CIE"), ypos.fixed = 5, size = 3) +
  stat_wl_strip(w.band = UV_bands("none"), ymax = 7, ymin = 9, color = "white") +
  stat_wb_label(w.band = UV_bands("none"), ypos.fixed = 8, size = 3) +  
  stat_wl_strip(w.band = UV_bands("medical"), ymax = 10, ymin = 12, color = "white") +
  stat_wb_label(w.band = UV_bands("medical"), ypos.fixed = 11, size = 3) +

  scale_fill_identity() + 
  scale_color_identity() + 
  scale_y_continuous(labels = c("ISO", "CIE", "none", "medical"), 
                     breaks = c(2,5,8,11),
                     limits = c(0, 13),
                     name = "Standard",
                     sec.axis = dup_axis(labels = 
                      c("use", "use", "avoid!", "avoid!"), name = "Recommendation")) +
  scale_x_continuous(breaks = c(seq(from = 100, to = 400, by = 50), 280, 315),
                     limits = c(100, 400),
                     sec.axis = 
                       dup_axis(breaks = 
                                c(100, 150, 200, 220, 250, 290, 320, 340, 400))) +
  labs(x = "Wavelength (nm)", title = "UV bands",
       subtitle = "According to ISO standard, CIE recommendations, and non-standard use") +
  theme_classic()
```
It should be noted that this approach is rather different from the way one would normally plot a horizontal bar plot with the grammar of graphics of 'ggplot2', but for plottings existing waveband definitions it is convenient and ensures that the waveband definitions agree with those used for computing summary quantities elsewhere.

## Wavelength colours at new _x_-values 

The `stat_wl_summary()` and `stat_wb_mean()` return a _reduced_ data set with fewer rows than the original data. `stat_wl_strip()` depending on the input, can also return a data set with more rows than the input data. This is the default behaviour, with `w.band` with argument `NULL`. This _stat_ operates only on the variable mapped to the _x_ _aesthetic_, a _y_-mapping is not required as input.

```{r}
my.data <- data.frame(x = 300:800)
ggplot(my.data, aes(x)) + stat_wl_strip(ymin = -1, ymax = 1, color = NA) +
    scale_fill_identity()
```

The default _geom_ is `"rect"` which with suitable mappings of `ymin` and `ymax` _aesthetics_ can be used to add a colour guide to the _x_-axis (if its scale maps wavelengths in nanometres). When `w.band` is `NULL` a long series of contiguous wavebands is generated to create the illusion of a continuous colour gradient.

```{r}
ggplot(sun.spct) +
  geom_line() +
  stat_wl_strip(ymin = -Inf, ymax = -0.025) + 
  scale_fill_identity() +
  theme_bw()
```

When a list of wavebands is supplied, it is used for the calculation of colours. These calculations do not use the spectral irradiance, they simply assume a flat spectrum, so the represent the colours of the wavelengths, rather than the colour of the light described by the spectral irradiance.

```{r}
ggplot(sun.spct) +
  geom_line() + 
  stat_wl_strip(w.band = VIS_bands(), ymin = -Inf, ymax = -0.025) + 
  scale_fill_identity() +
  theme_bw()
```

`stat_wl_strip()` can also used to produce a background layer with colours corresponding to _wavebands_. Here we use `alpha = 0.5` to add transparency.

```{r}
ggplot(sun.spct) +
  stat_wl_strip(w.band = VIS_bands(), ymin = -Inf, ymax = Inf, alpha = 0.4) + 
  scale_fill_identity() +
  geom_line() +
  theme_bw()
```

By default an almost continuous colour gradient can be generated for the background.

```{r}
ggplot(sun.spct) +
  stat_wl_strip(alpha = 0.4, ymin = -Inf, ymax = Inf) + 
  scale_fill_identity() +
  geom_line() +
  theme_bw()
```

## Multiple stats in the same plot

The _stats_ described above can be used together to produce more complex plots. This is just one possibility out of a vast range. Be aware that when adding many layers to the same plot, the order of the layers and adjusting their transparency using the `alpha` _aesthetic_ is very important, and best tuned by trial and error.

```{r}
ggplot(sun.spct, unit.out = "photon") +
  stat_wl_strip(alpha = 0.4, ymin = -Inf, ymax = Inf) + 
  stat_wb_box(w.band = PAR()) +
  stat_wb_total(w.band = PAR(), label.mult = 1e6,
                aes(label = paste(..wb.name.., " = ", ..y.label.., sep = ""))) +  
  geom_line() + 
  scale_fill_identity() + scale_color_identity() +
  theme_bw()
```

## Geometries

A simple _geom_ called `"spct"` is defined. It differs from _geom_ `"area"` only in the default `position` which is `"stacked"` for _geom_ `"area"` and `"identity"` for _geom_ `"spct"` which is usually better for spectra.

```{r}
ggplot(sun.spct) + geom_spct()
```

Using as fill the _color_ calculated from the spectral data is different to earlier examples in that the spectral irradiance is actually taken into account in the calculation of the colour, instead of just the wavelength range.

```{r}
ggplot(sun.spct) + 
  geom_spct(fill = color_of(sun.spct))
```

```{r}
ggplot(sun.spct * yellow_gel.spct) + 
  geom_spct(fill = color_of(sun.spct * yellow_gel.spct))
```

## Packaged stats, geoms plus scales

Some of the examples in previous sections can be simplified by use of `wl_guide()` and `wb_guide()` which add both the statistics and the scale, and provide a default _mapping_ for both `ymin` and `ymax`. This is handy for simple plots, but it can generate spurious warnings due to the replacement of existing scales with identical ones. In general only one of `wl_guide()` or `wb_guide()` should be used in a plot, and each one, only once. They just save some typing for the simplest uses, but are not suitable for complex _decorations_.

### wl_guide

The examples for `stat_wl_strip` can be simplified by use of `wl_guide()` which adds both the statistics and the scale, and provides default _mappings_ for both `ymin` (`-Inf`) and `ymax` (`Inf`). Another important difference is that the `"rect"` _geom_ used cannot be set to a different one by the user.

```{r}
ggplot(sun.spct) + 
  wl_guide(alpha = 0.4) +
  geom_line()
```

```{r}
ggplot(sun.spct) + 
  wl_guide(ymax = -0.025) +
  geom_line() 
```

This example produces a plot with a very different look than earlier ones, but can also be achieved with a very succinct statement.

```{r}
ggplot(sun.spct) + 
  wl_guide() +
  geom_spct(alpha = 0.75, colour = "white", size = 1) 
```

In the next example we demonstrate a trick achieved by over-plotting two lines of different width (`size`) to make the spectrum visible on a background of variable luminosity and colour.

```{r}
ggplot(sun.spct) + 
  wl_guide() +
  geom_line(size = 2, colour = "white") +
  geom_line(size = 1, colour = "black") +
  geom_hline(yintercept = 0, colour = "grey92") +
  theme_bw()
```

## Color charts

```{r}
color_chart(colors())
```
```{r}
color_chart(grep("blue", colors(), value = TRUE), ncol = 5, text.size = 4)
```

```{r}
 color_chart(w_length2rgb(570:689, color.name = as.character(570:689)), 
            use.names = TRUE, text.size = 4) +
  ggtitle("Reddish colors", subtitle = "Labels: wavelength (nm)")
```

