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

## Introduction

Package `ggspectra` extends `ggplot2` with stats, geoms and annotations suitable for light spectra. It also defines `ggplot()` and  `autoplot()` methods specialized for the classes defined in package `photobiology` for storing different types of spectral data. This vignette describes the use of these `autoplot()` methods.

The package uses 'ggplot2', 'photobiology' and 'photobiologyWavebands'. More importantly it defines specializations of methods defined in 'ggplot2' and
exports methods epecialized for classes defined in package 'photobiology',
consequently both 'ggplot2' and 'photobiology' are loaded automatically when
package 'ggspectra' is loaded. This is the behaviour from version 0.9.26 
onwards, when using earlier versions these packages needed to be loaded explicitly.

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

good_label_repel <- packageVersion('ggrepel') != "0.9.0" # >= 0.9.0 required
options(ggrepel.max.overlaps = Inf) # needed for 'ggrepel' (>= 0.9.0)
```


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

We bind two spectra into an object to be used later to demonstrate grouping.

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

We change the default theme.

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

## Plotting spectra

The most automatic way of plotting spectral data stored in one of the classes
defined in package `photobiology` is to use the `autoplot()` methods (for
compatibility with versions < 0.9.25 `plot()` remains as a deprecated name for
the same methods). As `autoplot()` methods defined by 'ggplot2' they take
advantage of all the data and metadata stored in objects of the special classes
used to store spectra. This allows the automatic construction of axis labels as
quantities and units are well defined.

### Single spectra

Here we use the same example `source_spct` object from package 'photobiology'
used in _User Guide 1_. In contrast to the examples in the User Guide 1, here
we obtain with a very simple statement an annotated plot of the solar spectrum
at ground level. The plotting of objects of all the classes defined in package
'photobiology' is similar except to those objects of the base class 
`generic_spct`. Function `spct_classes()` lists them.

```{r}
spct_classes()
```

The simplest call to `autoplot()`, using default arguments for all parameters is:

```{r}
autoplot(sun.spct)
```

We can change the basis of expression of spectral irradiance and irradiance from `"energy"` to `"photon"`. Be aware that by design, all values, summaries and spectral data will always use the same base of expression.


```{r}
autoplot(sun.spct, unit.out = "photon")
```

If a single object contains multiple spectra in long form, they are all plotted. In addition no summary values are displayed as they would overlap.

```{r}
autoplot(two_suns.spct)
```
Collections of spectra can be plotted also automatically. See next section for examples.

### Ploting collections of spectra

In addition to `autoplot()` methods for individual spectra, `autoplot()` methods
are available for collections of spectra. We use in the examples a simple
collection of two spectra. The output and acceptable arguments are the same as
those in the `autoplot()` methods for multiple spectra in long form described
above. The plotting of objects of all the classes for collections of spectra
defined in package 'photobiology' is similar except to those objects of the base
class `generic_mspct`. Function `mspct_classes()` lists them.

```{r}
mspct_classes()
``` 

```{r}
two_suns.mspct <- source_mspct(list(sun1 = sun.spct, sun2 = sun.spct / 2))
mixed.mspct <- generic_mspct(list(sun = sun.spct, filter = polyester.spct))
```

Plot accepting all defaults.

```{r}
autoplot(two_suns.mspct)
```

We can choose a different name for the factor identifying the spectra in the collection.

```{r}
autoplot(two_suns.mspct, idfactor = "Spectra")
```

Facets in one column. As there is only one spectrum per panel, the summaries per waveband are shown.

```{r}
autoplot(two_suns.mspct, facets = 1)
```
In two columns with `facets = 2`.

```{r}
autoplot(two_suns.mspct, facets = 2)
```

Plot as separate plots. This approach is specially useful with heterogeneous `generic_mspct` objects, although it works with any collection of spectra.

```{r, fig.width = 7, fig.height = 8}
multiplot(plotlist = mslply(mixed.mspct, autoplot))
```

All the examples above of plotting collections of spectra were done with the defaults `plot.data = "as.is"`. We can also plot a row-wise summary (wavelength by wavelength) of the spectra in the collection, here the `mean` of the spectra. Currently implemented only for spectra with identical wavelength vectors and of the same class.

```{r}
autoplot(two_suns.mspct, plot.data = "mean")
```

### Normalized and scaled spectra

In the case the spectra plotted have been previously normalized or scaled, the _y_-axis label will reflect this. In the case of normalized spectral data, and transmittance, reflectance and absorptance spectra expression as percent is supported. Finally, it is possible to normalize spectra on-the-fly by passing an argument to parameter `norm`. The default for `norm` varies with the type spectrum.

```{r}
autoplot(sun.spct, norm = "max")
```
```{r}
autoplot(sun.spct, norm = 400, pc.out = TRUE)
```
### Summary quantities in labels

Although the defaults provide a useful plot, the `autoplot()` methods accepts arguments for several parameters that allow to tweak the looks and contents of the plots without explicit manipulation of the spectral data. Numerical summaries can be added automatically to plots only when a single spectrum is plotted per plot panel.

In this first example we pass `"mean"` as argument to `label.qty`, to print means instead of integrals in the labels. Note that the units and quantity labels for the waveband summaries have also changed.

```{r}
autoplot(sun.spct, label.qty = "mean")
```

Two `label.qty` values need explanation. The first one, `"relative"` displays in labels the relative contribution of the integral of each waveband, to the sum of the integrals of all wavebands. The second one, `"contribution"` displays in labels the integral of each waveband divided by the integral of the whole spectrum. Consequently, this second option should be interpreted with caution, as the spectral data is unlikely in many cases to include the whole emission or absorption spectrum of a source. Using `"relative.pc"` or `"contribution.pc"` results in the corresponding values being expressed as percentages.

```{r}
autoplot(sun.spct, label.qty = "contribution")
```

```{r}
autoplot(sun.spct, label.qty = "relative")
```

### Automatic annotations

Which _annotations_ are included can be controlled through parameter `annotations` of the `autoplot()` methods, taking a vector of character strings as argument. Three values have special meaning if at the head of the vector (with index = 1): `"="` means override the current defaults with the annotations that follow in the vector, `"+"` means add to the current default the annotations that follow, and `"-"` means remove from the current default the annotations that follow. A `NULL` value means use package-defined defaults as is, `""` means no annotations, and `"reserve.space"` means no annotations, but expand axis limits and set identity scales ready for manually adding annotations. Used together with `"-"`, `"title*"`, `"peaks*"` and `"valleys*"` are _wildcards_ that remove all flavours of each of these annotations. In cases when the intention is to both add and remove annotations from the default, the argument to parameter `annotations` can be a list of character vectors, which are interpreted as above but operated upon sequentially.

Which annotations are included by default can be changed by setting R option `"photobiology.plot.annotations"` to a character vector with the names of the desired default annotations. Function `set_annotations_default()` allows to set this option using the same syntax as described for parameter `annotations`. 

| annotation | default for classes                       | overrides    |
|:-----------|:------------------------------------------|:-------------|
| "boxes"    | all                  | "segments"   |
| "segments" | none                 | "boxes"      |
| "color.guide" | all               |              |
| "peaks"    | all                  | "peak.labels"|
| "peak.labels" | none              | "peaks"      |
| "valleys"  | none                 | "valley.labels" |
| "valley.labels" | none            | "valleys"    |
| "wls"      | none                 | "wls.labels" |
| "wls.labels" | none               | "wls"    |
| "labels"   | all                  |              |
| "summaries" | `source_spct`, `response_spct`, `filter_spct`, `reflector_spct` |              |
| "boundaries"  | `raw_spct`       |               |
| "title"    | none                |               |
| "title:_type_" |   none | |
| "title:_type_:_type_" |   none | |
| "title:_type_:_type_:_type_" |   none | |

Titles come in different flavours. Package 'ggplot2' supports titles, subtitles and captions. The `"title"` as argument to parameter `annotation` of `autoplot()` methods and of function `autotitle()` takes up to three optional modifiers separated by colons that can be used to specify the contents of the _automatic_ title, subtitle and caption. Currently supported modifiers are shown in the table below. If the metadata item is not stored in the plotted spectral object, the title or subtitle will show `NA`. See the documentation of packages 'photobiology' and 'ooacquire' for information on how to set and unset attributes of spectral objects. To add an arbitrary title and/or subtitle to a plot, use either function `ggtitle()` or function `labs()` from package 'ggplot2'.

| Modifier | text source used |
| -------- | ------------- |
| `objt`   | name of the object plotted |
| `class`  | class of the plotted object |
| `what`   | what.measured attribute |
| `when`   | when.measured attribute |
| `where`  | where.measured attribute |
| `how`    | how.measured attribute |
| `inst.name` | spectrometer name |
| `inst.sn` | spectrometer serial number |
| `comment`| comment attribute |
| `none`   | _no title_, _no subtitle_ or _no caption_ |

For example `"title:objt"`, the default for `"title"`, adds a title with the name of the object being plotted. `what`, `when`, `where` and `how` use these attributes if available. For example `"title:what:when" will use the `what.measured` attribute for the title and the `when.measured` attribute for the subtitle. 

We can add an annotation to the defaults. 
```{r}
autoplot(sun.spct, 
     annotations = c("+", "title:objt:when:where"))
```

We use "none" as a _filler_ so that only subtitle and caption are added to the plot.

```{r}
autoplot(sun.spct, 
     annotations = c("+", "title:none:what:where"))
```

In this case `"boundaries"`, an annotation that adds a horizontal dashed line and does not override any other annotation.

```{r}
autoplot(sun.spct, 
     annotations = c("+", "boundaries"))
```

We can list all the annotations to be included in a plot, in which case `"="` is optional so as to maintain compatibility with earlier versions.

```{r}
autoplot(sun.spct, 
     annotations = c("=", "labels", "summaries", "color.guide", "peaks", "boundaries"))
```

As indicated in the table above, some annotations override other annotations which fulfil a similar role. Here `"segments"` overrides `"boxes"`, in the default.

```{r}
autoplot(sun.spct, 
     annotations = c("+", "segments"))
```

We can also _remove_ some of the default annotations on a case by case basis.

```{r}
autoplot(sun.spct, annotations = c("-", "summaries", "peaks"))
```

The behaviour of some annotations can be tweaked. Below we add `"valleys"` as annotations, and control with `span` how close to each other are the peaks and valleys found.

```{r}
autoplot(sun.spct, annotations = c("+", "valleys"), span = 41)
```

The annotations `"peak.labels"` and `"valley.labels"` override `"peaks"` and `"valleys"`. They use the _repulsive_ geometry `geom_label_repel` from package 'ggrepel'.

```{r, eval=good_label_repel}
autoplot(sun.spct, 
         annotations = list(c("+", "peak.labels"), 
                            c("-", "boxes", "summaries", "labels")), 
         span = 51)
```
```{r, eval=good_label_repel}
autoplot(sun.spct, 
         annotations = list(c("+", "valley.labels"), 
                            c("-", "peaks")), 
         span = 51)
```


```{r, eval=good_label_repel}
autoplot(sun.spct, annotations = c("+", "peak.labels", "valley.labels"), span = 51)
```

Passing `""` as argument to `annotations` results in a plot with no annotations, and no _scales_ set. 

```{r}
autoplot(sun.spct, annotations = "")
```

Passing `"reserve.space"` as argument to `annotations` results in a plot with no annotations, but _scales_ set and expanded so as to receive annotations.

```{r}
autoplot(sun.spct, annotations = "reserve.space")
```

The size of the font used for the annotations is controlled by argument `text.size`.

```{r}
autoplot(sun.spct, annotations = c("=", "segments", "labels", "color.guide"), 
     text.size = 3.5)
```

Argument `ylim` allows to mannually set the limits of the $y$ axis using the same syntax as in package 'ggplot2'. The annotations are still automatically possitioned, and the range extended to make space for them. In other words the values passed to `ylim` still give the "space" available for plotting data.

```{r}
autoplot(sun.spct, ylim = c(NA, 1))
```
Arguments `range` and `w.band` play very different roles. The first one determines the `range` of wavelengths to include in the data plotted, which is slightly different to the effect of `ggplot2::xlim()` as `range` is used to _trim_ the spectral data __before__ passing it to `ggplot`, using interpolation when needed (see `photobiology::trim_wl()`). The second one, `w.band` is only used for the _annotations_ and decorations. The default for `range` is always the range of the spectrum being plotted. 

Which wavebands are used by default can be changed by setting R option `"photobiology.plot.bands"` to a single waveband object or to a list waveband
objects. Function `set_w.band_default()` allows to set this option using the same syntax as described for parameter `w.band`.

```{r}
autoplot(sun.spct, range = VIS())
```

```{r}
autoplot(sun.spct, w.band = PAR())
```

```{r}
autoplot(sun.spct, w.band = CIE())
```

`NULL` as argument for `w.band` is replaced by a waveband covering the full range of the spectral data.

```{r}
autoplot(sun.spct, w.band = NULL)
```
The _whole range_ is the range plotted, which is controlled by the argument passed to `range`. 

```{r}
autoplot(sun.spct, w.band = NULL, range = c(400,700))
```
The argument passed to `range` can also be a `waveband` or and spectrum, in which case their wavelength range is used.

```{r}
autoplot(sun.spct, w.band = NULL, range = PAR())
```

```{r}
autoplot(sun.spct, w.band = PAR(), range = PAR())
```

```{r}
autoplot(sun.spct, w.band = VIS_bands(), range = VIS())
```

The time unit is also stored in the metadata, as demonstrated here. The units in axis labels have changed to the units used in the spectral data.

```{r}
getTimeUnit(sun.daily.spct)
autoplot(sun.daily.spct)
```

Even though the `autoplot()` methods can return a finished plot, the returned object is a `ggplot` object and can be built upon by adding additional elements like _facets_, _aesthetics_ and even additional _layers_. We pass `idfactor = NA` to suppress the mapping of the spectra to `linetype`.

```{r}
autoplot(two_suns.spct, idfactor = NA) + facet_wrap(~spct.idx)
```

It is possible to construct and bind the spectra on-the-fly, and to use arbitrary variable names for the index factor. This works automatically as long as row binding is done with function `rbindspct()` which saves the name of the factor.

```{r}
filter_no_yes.spct <- 
  rbindspct(list(sun = sun.spct, filtered = yellow_gel.spct * sun.spct), 
            idfactor = "Source")
autoplot(filter_no_yes.spct)
```

In the examples above the `source_spct` object `sun.spct` was used. The `autoplot()` methods for other spectral classes have slight differences. We show some examples for `filter_spct` objects. For a long-pass filter the wavelength at half maximum is more interesting than peaks or valleys.

```{r}
autoplot(yellow_gel.spct, 
         annotations = list(c("-", "peaks"), c("+", "wls")))
```

By default transmittance, reflectance and absorptance are expressed as fractions of one, as in the plot above, but optionally percents can be plotted.

```{r}
autoplot(yellow_gel.spct, pc.out = TRUE, 
         annotations = list(c("-", "peaks"), c("+", "wls")))
```

In many cases it is possible to convert on-the-fly the quantity plotted. In this case, given that the data are clipped as absorbance, a fixed target of A = 2 is appropriate.

```{r}
autoplot(yellow_gel.spct, plot.qty = "absorbance", wls.target = 2,
         annotations = list(c("-", "peaks"), c("+", "wls")))
```

<!-- We add a _guessed_ spectral reflectance to the data object to allow the estimation of internal absorptance. -->

```{r, eval=FALSE, echo=FALSE}
yellow_gel.spct$Rfr <- 1 - max(yellow_gel.spct$Tfr)
autoplot(yellow_gel.spct, plot.qty = "absorptance", annotations = c("-", "peaks"))
```

If one needs to, one can add a suitable _stat_ using 'local' data. A peak annotation could be added manually.

```{r}
autoplot(sun.spct) + geom_spct(fill = color_of(sun.spct)) + 
  geom_spct(data = yellow_gel.spct * sun.spct, color = "black", 
            fill = color_of(yellow_gel.spct * sun.spct))
```

The examples above use an emission spectrum. All the spectral classes defined in package 'photobiology' are supported, however.

In the case of quantities like transmittance which have a certain range of valid values, both upper and lower boundaries are highlighted, but in other cases only one, or even none depending on the possible valid ranges for the spectral quantities.

```{r}
autoplot(yellow_gel.spct, annotations = c("+", "boundaries"))
```

In the case of raw instrument counts data, if the spectral object contains an instrument descriptor as metadata, the upper boundary is set to the maximum counts of the detector.

```{r}
autoplot(white_led.raw_spct, annotations = c("+", "boundaries"))
```

**Changes in 'dplyr' have broken the next two examples.**
Both `raw_spct` and `cps_spct` objects contain multiple data columns when integration time bracketing has been used during data acquisition. In such cases, if one wants to plot only one of the raw spectra, method `select()` from package 'dplyr' should be used instead of subscripting (`[ ]`) so as to preserve the metadata. In addition renaming of the variable is needed as shown below when a single column is extracted.

```{r, eval=FALSE}
autoplot(dplyr::select(white_led.raw_spct, w.length, counts = counts_1),
     annotations = c("+", "boundaries"))
```

```{r, eval=FALSE}
autoplot(dplyr::select(white_led.raw_spct, w.length, counts_1, counts_3),
     annotations = c("+", "boundaries"))
```

### Handling of off-range data

If the supplied data include off-range values such as negative irradiance or fractional transmittance, reflectance, or absorptance outside the zero to one range the exceeded boundary is highlighted in red.

```{r, eval=FALSE}
# Not run so as to pass CRAN checks!!
autoplot(yellow_gel.spct - 0.01, annotations = c("+", "boundaries"))
```

## Editing plots and adding layers

Using colors is slightly more involved as the identity scale is in use for color in annotations. For this same reason no color key in generated automatically. (In the case of more than two spectra it is easier to use `plyr::mapvalues` instead of several nested `ifelse` calls.)

```{r}
autoplot(two_suns.mspct) + 
  aes(color = ifelse(spct.idx == "sun1", "darkgreen", "darkred"))
```

Plots created with `autoplot()` methods are `ggplot` objects and can be customized, bearing in mind that any added layers will be plotted on top or existing layers (that is unless we make use of methods from package 'gginnards' that allow insertion of layers at any position in a `ggplot` object).

Here we replace the default peaks annotations with a custom one, but still take advantage of other defaults like nice axis labels and other annotations.

```{r}
autoplot(two_suns.mspct, annotations = c("-", "peaks")) +
  stat_peaks(span = NULL, color = "red") +
  stat_peaks(span = NULL, geom = "text", 
             label.fmt = "max at %3.1f nm",
             vjust = -0.5, hjust = 0,
             color = "red", size = 3)
```

## Ploting wavebands

A `autoplot()` method for `waveband` objects is also provided.

```{r}
autoplot(VIS())
```

```{r}
autoplot(CIE(), range = CIE(), annotations = c("-", "color.guide"))
```

```{r}
autoplot(DNA_N(), range = c(270, 420), annotations = c("-", "color.guide"))
```
