The User Guide is divided into two volumes: 1. Radiation and 2. Astronomy. The second volume also describes functions related to water vapour in the atmosphere.
I have developed package ‘photobiology’ over several years, and even though I have tried to remain consistent, some inconsistencies have crept in. I have attempted to correct inconsistencies without breaking old code by providing synonyms for some functions.
In general I have used names in snake case for methods and
functions, such as source_spct()
and dot case for
their arguments. There are two exceptions to this: the as.
and is.
methods which for consistency with base R, retain
the dot: as.source_spct()
and
ìs.source_spct()
. There are still some functions and
methods whose names are in camel case: these are mostly
accessors and setters of metadata attributes such as
setWhatMeasured()
and getWhatMeasured()
, in
which case synonyms what_measured<-()
and
what_measured()
are now provided with a syntax that
parallels that of R’s comment<-()
,
comment()
, and similar methods for other attributes. Names
of attributes themselves use dots, while classes use snake case as
functions do, allowing consistency between class names and their
constructor functions. There is an additional twist: functions named
like clip_wl()
are “verbs” that act on the wavelengths
(“wl”) modifying them, while those named like wl_range()
are “nouns” for the properties of the wavelengths.
In examples we use variable names ending in .spct
for
spectra, ending in .mspct
for collections of spectra and
ending in .tb
for tibbles. In most cases the root of the
variable names use “snake case” and may have a tag at the end separated
with a dot. In the case of variable names used in examples I have been
less strict about conventions than for the objects exported by the
package.
None of these naming conventions are enforced for user defined objects and classes; these conventions are simply those I have tried to follow while developing this package as well as other packages in the r4photobiology suite.
The package exports two sets of functions for many operations: low-level functions programmed following a functional paradigm, and higher-level functions using an object-oriented paradigm. The former functions take as arguments numeric vectors and are sometimes faster. The later ones take spectra objects as arguments, are easier to use, and at least at the moment, to some extent slower. For everyday use, methods for spectra objects are recommended, but when maximum performance or flexibility in scripts is desired, the use of the functions taking numeric vectors as arguments may allow optimizations that are not possible with the object-oriented functions. The differences in performance becomes relevant only in extreme cases such as processing in a single script tenths of thousands of spectra. In the vignettes we emphasize the use of the object-oriented classes and methods.
Data for several spectra are included for use in examples and vignettes, and in testing (Tables 1 and 2). Other packages in the ‘r4photobiology suite’ provide many additional data sets.
Table 1. Data sets included in the package: spectra. The CIE standard illuminant data in this package are normalized to one at \(\lambda = 560\,\)nm, while in the CIE standard they are normalized to 100 at the same wavelength. See documentation for each data object for details and data sources.
Object | class | units | data description |
---|---|---|---|
sun.spct |
source_spct |
\(W\,m^{-2}\,nm^{-1}\) | solar spectral irradiance |
sun.daily.spct |
source_spct |
\(J\,m^{-2}\,d^{-1}\,nm^{-1}\) | solar spectral exposure |
sun.data |
data.frame |
\(W\,m^{-2}\,nm^{-1}\) | solar spectral irradiance |
sun.daily.data |
data.frame |
\(J\,m^{-2}\,d^{-1}\,nm^{-1}\) | solar spectral exposure |
D65.illuminant.spct |
source_spct |
(norm. 560 nm) | CIE standard |
A.illuminant.spct |
source_spct |
(norm. 560 nm) | CIE standard |
clear.spct |
filter_spct |
fraction | ideal transparent filter |
opaque.spct |
filter_spct |
fraction | ideal opaque filter |
polyester.spct |
filter_spct |
fraction | plastic film |
yellow_gel.spct |
filter_spct |
fraction | theatrical gel filter |
green_leaf.spct |
reflector_spct |
fraction | a birch leaf |
clear_body.spct |
object_spct |
fraction | ideal transparent body |
black_body.spct |
object_spct |
fraction | ideal black body |
white_body.spct |
object_spct |
fraction | ideal white body |
Ler_leaf.spct |
object_spct |
fraction | Arabidopsis leaf |
Ler_leaf_trns.spct |
filter_spct |
fraction | Arabidopsis leaf (T total) |
Ler_leaf_trns_i.spct |
filter_spct |
fraction | Arabidopsis leaf (T internal) |
Ler_leaf_rflt.spct |
reflector_spct |
fraction | Arabidopsis leaf (R total) |
water.spct |
solute_spct |
\(m^{-1}\) | pure water molar att. coef. |
phenylalanine |
solute_spct |
\(m^{-1}\) | phenylalanine molar att. coef. |
photodiode.spct |
response_spct |
\(A / W\) | typical Si photodiode |
ccd.spct |
response_spct |
\(A / W\) | typical CCD array |
white_led.raw_spct |
raw_spct |
counts | example raw detector counts data |
white_led.cps_spct |
cps_spct |
counts / s | example detector counts data |
white_led.source_spct |
source_spct |
\(W\,m^{-2}\,nm^{-1}\) | spectral irradiance |
filter_cps.mspct |
cps_mspct |
\(\mathrm{counts} / s\) | example detector counts data |
Table 2. Data sets included in the package: chromaticity data. See documentation for each data object for details and data sources.
Object | class | data description |
---|---|---|
ciexyzCC2.spct |
chroma_spct |
human chromaticity coordinates \(2^\circ\) |
ciexyzCC10.spct |
chroma_spct |
human chromaticity coordinates \(10^\circ\) |
ciexyzCMF2.spct |
chroma_spct |
human colour matching function \(2^\circ\) |
ciexyzCMF10.spct |
chroma_spct |
human colour matching function \(10^\circ\) |
ciev2.spct |
chroma_spct |
human luminous efficiency \(2^\circ\) |
beesxyzCMF.spct |
chroma_spct |
bee colour matching function |
Package ‘photobiology’ defines a family of classes
based on the tibble
class, mostly compatible with R’s data
frames. The present package by imposing some restrictions on the naming
of the member vectors, allows methods to find the data when
passed one of these objects as argument. In addition, as the data are
checked when the object is built or modified, there is no need to test
for their validity each time a calculation is carried out. Another
advantage of using spectrum objects, is that specialized versions of
generic functions like print
and operators like
+
are defined for spectra. Objects of all the
..._spct
classes are also tibble
and
data.frame
objects, as a result of how classes have been
derived.
In this package we define a generic or base
spectrum class, derived from tibble
, which in turn has been
derived from data.frame
. Classes for specialized types of
spectra are derived from generic_spct
. This
parenthood hierarchy means that spectral objects can be used
almost anywhere where a data.frame
is expected (and also
converted into data frames with R’s function
as.data.frame()
). Specializations of many methods including
extraction (indexing) methods and partial assignment methods are defined
to ensure that the expectations on the variables contained in objects of
these classes remain valid in most situations. Other specializations of
methods and functions are related to achieving a convenient and concise
syntax tailored for spectral data as in the case of mathematical
operators and functions.
Another important aspect is that when spectral data are stored in objects of these classes, the physical quantities and units of expression are also stored as metadata. Furthermore, attributes are used to keep track of both metadata related to the origin of the data and of later transformations that affect their interpretation, such as normalization or re-scaling. Although sanity tests are applied at the time of object creation, to a large extent the responsibility of ensuring that the numbers provided as argument to object constructors comply with expectations remains with the users of the package.
In addition to the classes for storing individual spectra, classes
for storing collections of these spectral objects are defined. These
classes are derived from class list
and can contain member
spectra of different lengths and measured at different wavelength
values.
We give in this vignette brief descriptions and examples of the use of different classes, methods, functions and operators. We start with the simplest and most frequently used methods.
We load two packages in addition to ‘photobiology’, ‘lubridate’ and ‘dplyr’, as they will be used in the examples.
library(photobiology)
library(lubridate)
library(dplyr)
Package ‘photobiology’ defines several classes
intended to be used to store different types of spectral data. They are
all derived from generic_spct
, which in turn is derived
from tibble::tibble
. Table 1 lists these classes.
Attributes are used to store metadata such as information about
units of expression.
Table 1. Classes for spectral data. In addition to
the required variables listed in the table, additional arbitrary
variables are partly supported—some operations will not include them in
returned values to avoid ambiguity and other possible conflicts. In
addition to the attributes listed in the table, all spectral objects
support attributes multiple.wl
, idfactor
,
normalized
, scaled
,
when.measured
, where.measured
,
what.measured
, how.measured
plus the normal
attributes of tibble
(and data.frame
) objects
including comment
. All these attributes plus attributes
instrument.descriptor
and instrument.settings
are retained across operations on spectra as long as they remain
valid.
Class name | Required variables | Attributes |
---|---|---|
generic_spct |
w.length |
|
calib ration_spct |
w.length , irrad.mult |
instr.desc |
raw_spct |
w.length , counts |
instr.desc , instr.settings ,
linearized |
cps_spct |
w.length , cps |
instr.desc , instr.settings ,
linearized |
source_spct |
w.length , s.e.irrad |
instr.desc , instr.settings ,
time.unit , bswf |
w.length , s.q.irrad |
time.unit , bswf |
|
filter_spct |
w.length , Tfr |
Tfr.type ,
filter.properties |
w.length , A |
Tfr.type ,
filter.roperties |
|
ref lector_spct |
w.length , Rfr |
Rfr.type |
object_spct |
w.length , Tfr ,
Rfr |
Tfr.type , Rfr.type |
re sponse_spct |
w.length , s.e.response |
time.unit |
w.length , s.q.response |
time.unit |
|
chroma_spct |
w.length , x , y ,
z |
|
solute_spct |
w.length , K.mole |
K.type , solute,prperties |
w.length , K.mass |
K.type , solute,prperties |
The design imposes the restriction that data from different observations are never present as different data columns, if present, additional data columns represent different properties from the same observation event. In other words, the storage format is tidy as defined by Hadley Wickham. In most cases, one spectral object should correspond to one spectral observation, but some functions are compatible or can be used to create spectral objects where the spectral data from different observations are stored “longitudinally” and “tagged” with a factor with a level for each observation event. These observations must use consistent units of expression and attribute values. This long format is useful, for example, when producing plots with package ‘ggplot2’. If spectra are stored in long form, e.g. for plotting with ‘ggplot2’, attributes are stored as named lists or enforced to be the same across spectra. This allows to reconstruct a collection of spectra from a long-form spectral object and vice versa preserving most of the metadata.
Collections of spectra should be in general preferred to multiple spectra stored in a single spectral object. This is because collections are the “native” storage approach, supporting all operations efficiently. All operations that have as return value a spectrum are not implemented for spectral objects containing multiple spectra, while those summary methods that return a single numeric value for each spectrum are implemented by on-the-fly conversion of such spectra into collections.
A key assumption of the package is that wavelengths are always expressed in manometers (\(1~\mathrm{nm} = 1 \cdot 10^{-9}\,\mathrm{m}\)). If the data to be analysed use different units for wavelengths, e.g. Ångstrom (\(1~\textrm{Å} = 1 \cdot 10^{-10}\,\mathrm{m}\)), the values need to be re-expressed before creating objects of the spectral classes. The same applies to all spectral quantities, as there is an expectation in every case, of using base SI units for expression. Table 2 lists the units of expression for the different variables and the metadata attributes that may determine variations in the expression of the quantities.
Table 2. Variables used for spectral data and their units of
expression. A: as stored in objects of the
spectral classes, B: also recognized by the
set
family of functions for spectra and automatically
converted. time.unit
accepts in addition to the character
strings listed in the table, objects of classes
lubridate::duration
and period
, in addition
numeric
values are interpreted as seconds.
exposure.time
accepts these same values, but not the
character strings.
Variables | Unit of expression | Attribute value |
---|---|---|
A: stored | ||
w.length | nm | |
counts | \(n\) | |
cps | \(n\,s^{-1}\) | |
irrad.mult | \(J\,m^{-2}\,nm^{-1}\,n^{-1}\) | |
s.e.irrad | \(W\,m^{-2}\,nm^{-1}\) | time.unit = “second” |
s.e.irrad | \(J\,m^{-2}\,d^{-1}\,nm^{-1}\) | time.unit = “day” |
s.e.irrad | varies | time.unit = duration |
s.q.irrad | \(mol\,m^{-2}\,s^{-1}\,nm^{-1}\) | time.unit = “second” |
s.q.irrad | \(mol\,m^{-2}\,d^{-1}\,nm^{-1}\) | time.unit = “day” |
s.q.irrad | \(mol\,m^{-2}\,nm^{-1}\) | time.unit = “exposure” |
s.q.irrad | varies | time.unit = duration |
Tfr | [0,1] | Tfr.type = “total” |
Tfr | [0,1] | Tfr.type = “internal” |
A | a.u. | |
Afr | [0,1] | |
Rfr | [0,1] | Rfr.type = “total” |
Rfr | [0,1] | Rfr.type = “specular” |
s.e.response | \(\mathit{x}\,J^{-1}\,s^{-1}\,nm^{-1}\) | time.unit = “second” |
s.e.response | \(\mathit{x}\,mol^{-1}\,d^{-1}\,nm^{-1}\) | time.unit = “day” |
s.e.response | \(\mathit{x}\,J^{-1}\,nm^{-1}\) | time.unit = “exposure” |
s.e.response | varies | time.unit = duration |
s.q.response | \(\mathit{x}\,mol^{-1}\,s^{-1}\,nm^{-1}\) | time.unit = “second” |
s.q.response | \(\mathit{x}\,mol^{-1}\,d^{-1}\,nm^{-1}\) | time.unit = “day” |
s.q.response | \(\mathit{x}\,mol^{-1}\,nm^{-1}\) | time.unit = “exposure” |
s.q.response | varies | time.unit = duration |
x, y, z | [0,1] | |
K.mole | \(m^{-1}, \log_{10}\) based | K.type = “attenuation” |
K.mole | \(m^{-1}, \log_{10}\) based | K.type = “absorption” |
K.mole | \(m^{-1}, \log_{10}\) based | K.type = “scattering” |
B: converted | ||
wl \(\to\) w.length | nm | |
wavelength \(\to\) w.length | nm | |
Tpc \(\to\) Tfr | [0,100] | Tfr.type = “total” |
Tpc \(\to\) Tfr | [0,100] | Tfr.type = “internal” |
Rpc \(\to\) Rfr | [0,100] | Rfr.type = “total” |
Rpc \(\to\) Rfr | [0,100] | Rfr.type = “specular” |
counts.per.second \(\to\) cps | \(n\,s^{-1}\) | |
K.mole | \(m^{-1}, \log_{e}\) based | K.type = “attenuation” |
K.mole | \(m^{-1}, \log_{e}\) based | K.type = “absorption” |
K.mole | \(m^{-1}, \log_{e}\) based | K.type = “scattering” |
Energy irradiance is assumed to be expressed in \(W\,m^{-2}\) and photon irradiances in \(mol^{-1}\,m^{-2}\,s^{-1}\), that is to say using second as unit for time and no SI scale factors for the measured variables. With respect to time, second is the default, but it is possible to set the unit for time to an arbitrary time duration such as day. Obviously, this applies only to rate variables like irradiance and response rates, but not to time-invariant intensive properties like transmittance of filters.
The default time unit used is second, but minute,
hour, day and exposure can be used by
supplying as arguments "minute"
, "hour"
,
"day"
, or "exposure"
—The meaning of
"exposure"
is the total exposure time, in other words,
fluence instead of irradiance—to the constructor
source_spct()
. In addition to these character constants
objects of class lubridate:duration
are also accepted. In
other words irradiance is a flux rate while exposure is a flux, as both
are expressed per unit of illuminated area.
In the case of spectra of the molar attenuation coefficient we use \(\log_{10}\) as a base for the stored values but the constructor accepts data expressed in other log bases. The expected units are always in metres (\(m^{-1}\)) rather than the frequently used centimetres (\(cm^{-1}\)).
Transmittance, reflectance and absorptance are stored as fractions of one. The constructors also accept these quantities expressed as percentages, and convert them.
Most attributes are set when a spectral object is created, either
using default values or with values supplied as arguments to the
constructor. In many cases the default is NA
used to
indicate missing information.
Methods for querying and setting these attributes in already constructed objects are also available.
Not respecting the expectations about data inputs or setting erroneous values in the metadata attributes will yield completely wrong results if calculations are attempted! It is extremely important to make sure that the wavelengths are in nanometres as this is what all functions expect. If wavelength values are in the wrong units, the action-spectra weights and quantum to/from energy units conversions will be wrongly calculated, and the values returned by most functions wrong, without warning. Errors in some cases will be triggered at the time of object creation as the data input to constructors is tested to be within the expected range of values, which in the case of some quantities frequently allows detection of mistakes in the use unit scaling factors.
If spectral irradiance data is in \(W\,m^{-2}\,nm^{-1}\), and the wavelength in nm, as is the case for many Macam spectroradiometers, the data can be used directly and functions in the package will return irradiances in \(W\,m^{-2}\).
If, for example, the spectral irradiance data output by a spectroradiometer is expressed in \(mW\,m^{-2}\,nm^{-1}\), and the wavelengths are in Ångstrom then to obtain correct results when using any of the packages in the suite, we need to rescale the data when creating a new object.
# not run
<- source_spct(w.length = wavelength/10, s.e.irrad = irrad/1000) my.spct
In the example above, we take advantage of the behaviour of the R language: an operation between a scalar and a vector, is equivalent to applying this operation to each element of the vector. Consequently, in the code above, each value from the vector of wavelengths is divided by 10, and each value in the vector of spectral irradiances is divided by 1000.
Before giving examples of how to construct objects to store spectral
data we show how to query the class of an object, and how to query the
class of a spectrum. Consistently with R, the package provides
is functions for querying the type of spectra objects. The only
unusual function name, defined as a synonym for
is.generic_spct
: is.any_spct()
.
is.any_spct(sun.spct)
## [1] TRUE
is.generic_spct(sun.spct)
## [1] TRUE
is.source_spct(sun.spct)
## [1] TRUE
is.data.frame(sun.spct)
## [1] TRUE
In addition function class_spct()
returns directly the
spectrum-related class attributes—i.e. it filters out from the output of
class()
the underlying inherited classes.
class_spct(sun.spct)
## [1] "source_spct" "generic_spct"
class(sun.spct)
## [1] "source_spct" "generic_spct" "tbl_df" "tbl" "data.frame"
There are two different approaches to the creation of spectral
objects by users. The first group are constructors similar to the
data.frame()
constructor, which take vectors as arguments.
The second group are constructors that convert list
objects, and because of class derivation also data.frame
objects, into spectral objects. Constructors in this second group are
similar to as.data.frame
from base R. In contrast to the
data frame constructors, spectral object constructors require the
variables or the vector arguments to be suitably named so that they can
be recognized.
Here we briefly describe the as constructor functions for
spectra. In the first example we create an object to store spectral
irradiance data for a fictitious light source, by first
creating a data frame, and creating the spectral object as a copy of it.
In the example below we supply a single value, 1, for the spectral
irradiance. This value gets recycled as is normal in R, but of course in
real use it is more usual to supply a vector of the same length as the
w.length
vector.
<- data.frame(w.length = 400:410, s.e.irrad = 1)
my.df <- as.source_spct(my.df)
my.spct class(my.spct)
## [1] "source_spct" "generic_spct" "tbl_df" "tbl" "data.frame"
class(my.df)
## [1] "data.frame"
my.spct
## Object: source_spct [11 x 2]
## Wavelength range 400-410 nm, step 1 nm
## Time unit 1s
##
## # A tibble: 11 × 2
## w.length s.e.irrad
## <int> <dbl>
## 1 400 1
## 2 401 1
## 3 402 1
## 4 403 1
## # … with 7 more rows
## # ℹ Use `print(n = ...)` to see more rows
We can copy and convert any spectrum object into any of its base
clases, such as generic_spct
or data.frame
.
This can result in the immediate and surely in the delayed loss of
metadata when modified. In addition, objects downgraded to a
base class support fewer operations and those still available may behave
differently.
<- as.generic_spct(my.spct)
my.g.spct class(my.g.spct)
## [1] "generic_spct" "tbl_df" "tbl" "data.frame"
When constructing spectral objects from numeric vectors the names of the arguments are meaningful and convey information on the nature of the spectral data and basis of expression.
source_spct(w.length = 300:305, s.e.irrad = 1)
## Object: source_spct [6 x 2]
## Wavelength range 300-305 nm, step 1 nm
## Time unit 1s
##
## # A tibble: 6 × 2
## w.length s.e.irrad
## <int> <dbl>
## 1 300 1
## 2 301 1
## 3 302 1
## 4 303 1
## 5 304 1
## 6 305 1
<- 300:305
z <- 2
y source_spct(w.length = z, s.e.irrad = y)
## Object: source_spct [6 x 2]
## Wavelength range 300-305 nm, step 1 nm
## Time unit 1s
##
## # A tibble: 6 × 2
## w.length s.e.irrad
## <int> <dbl>
## 1 300 2
## 2 301 2
## 3 302 2
## 4 303 2
## 5 304 2
## 6 305 2
When argument names are not supplied explicitly as above, the names of the variables are used to identify the data vectors.
<- 300:305
w.length <- 1
s.e.irrad source_spct(w.length, s.e.irrad)
## Object: source_spct [6 x 2]
## Wavelength range 300-305 nm, step 1 nm
## Time unit 1s
##
## # A tibble: 6 × 2
## w.length s.e.irrad
## <int> <dbl>
## 1 300 1
## 2 301 1
## 3 302 1
## 4 303 1
## 5 304 1
## 6 305 1
The different constructors have additional arguments to be used in setting non-default values for the attributes. These arguments have the same name as the attributes. Here we used the data frame created in the first code chunk of this section.
<- as.source_spct(my.df, time.unit = "day") my.d.spct
Argument strict.range
can be used to override or make
more strict the validation of the data values.
source_spct(w.length = 300:305, s.e.irrad = -1)
## Warning in range_check(x, strict.range = strict.range): Negative spectral energy
## irradiance values; minimum s.e.irrad = -1.00
## Object: source_spct [6 x 2]
## Wavelength range 300-305 nm, step 1 nm
## Time unit 1s
##
## # A tibble: 6 × 2
## w.length s.e.irrad
## <int> <dbl>
## 1 300 -1
## 2 301 -1
## 3 302 -1
## 4 303 -1
## 5 304 -1
## 6 305 -1
source_spct(w.length = 300:305, s.e.irrad = -1, strict.range = NULL)
## Object: source_spct [6 x 2]
## Wavelength range 300-305 nm, step 1 nm
## Time unit 1s
##
## # A tibble: 6 × 2
## w.length s.e.irrad
## <int> <dbl>
## 1 300 -1
## 2 301 -1
## 3 302 -1
## 4 303 -1
## 5 304 -1
## 6 305 -1
Argument comment
can be used to add a comment to the
data at the time of construction.
<- source_spct(w.length = 300:305, s.e.irrad = 1,
my.cm.spct comment = "This is a comment")
comment(my.cm.spct)
## [1] "This is a comment"
The constructors treat unrecognized named arguments as data to create aditional columns in the spectral objects.
Metadata attributes are used in the spectral objects to store
metadata in a consistently. These metadata are in some cases required
for conversion among related physical quantities, while in other cases
allow printing of ancillary information needed for interpretation, like
units of expression. These metadata are also used in other packages in
the suite, for example in ‘ggspectra’ to automatically produce axis
labels, titles and annotations. A few attributes are simply a way or
organizing the storage of information which is not used in any
calculations, functioning as a kind of specialized comments. The
metadata described in this section are stored in spectral objects using
attributes, which are a normal feature of the R language. An example, is
attribute time.unit
used to indicate if spectral irradiance
is expressed per second or integrated over some other time duration.
Some attributes are meaningful for all the classes of spectra defined
in the package, while most others a specific to individual classes
(Table 1). Those that apply to all spectral objects and their summaries
are time of measurement using attribute
"when.measured"
, place of measurement using
attribute "where.measured"
, a user supplied label
using attribute "what.measured"
, a label describing origin
of the data using attribute "how.measured"
and free-text
comments. One can set and get comments stored in spectra by
means of base R’s comment()
and
comment() <-
functions and the other attributes listed
above with functions following the same syntax and named after the
attributes but replacing any .
by _
. Functions
in this package may set additional attributes to keep track of the
actions. For example when a spectrum is normalized or scaled a record of
these action is kept in attributes. When spectra are are operated upon
the metadata that is not invalidated will be merged when possible—e.g.,
comments of operands are concatenated comments and set as comment to the
returned object.
Functions when_measured()
and
when_measured<-()
are used for retrieving and setting
the "when.measured"
attribute to a date supplied as a
POSIXct
value. Note: we use POSIXct
objects
which describes instants in time in absolute terms as they include time
zone information. Package lubridate
makes entering and
operating on POSIXct
objects rather easy.
<- sun.spct
my.spct when_measured(my.spct) <- NULL
when_measured(my.spct)
## [1] NA
when_measured(my.spct) <- lubridate::ymd_hms("2015-10-31 22:55:00", tz = "EET")
when_measured(my.spct)
## [1] "2015-10-31 20:55:00 UTC"
Functions where_measured()
and
where_measured<-()
are used for retrieving and setting a
geocode stored in a data.frame
. This format is compatible
with function geocode()
from package ggmap
. We
pass latitude and longitude coordinates, as shown below. The returned
value is always a data frame with columns "lon"
,
"lat"
and "address"
.
where_measured(my.spct) <- NULL
where_measured(my.spct)
## # A tibble: 1 × 3
## lon lat address
## <dbl> <dbl> <chr>
## 1 NA NA <NA>
where_measured(my.spct) <- data.frame(lat = 60, lon = -10)
where_measured(my.spct)
## # A tibble: 1 × 3
## lat lon address
## <dbl> <dbl> <chr>
## 1 60 -10 <NA>
where_measured(my.spct) <- data.frame(lat = 60, lon = -10, address = "Somewhere")
where_measured(my.spct)
## # A tibble: 1 × 3
## lat lon address
## <dbl> <dbl> <chr>
## 1 60 -10 Somewhere
my.spct
## Object: source_spct [522 x 3]
## Wavelength range 280-800 nm, step 0.9230769-1 nm
## Label: sunlight, simulated
## Measured on 2015-10-31 20:55:00 UTC
## Measured at 60 N, -10 E; Somewhere
## Time unit 1s
##
## # A tibble: 522 × 3
## w.length s.e.irrad s.q.irrad
## <dbl> <dbl> <dbl>
## 1 280 0 0
## 2 281. 0 0
## 3 282. 0 0
## 4 283. 0 0
## # … with 518 more rows
## # ℹ Use `print(n = ...)` to see more rows
Functions what_measured()
and
where_measured<-()
, and how_measured()
and
how_measured<-()
are used for retrieving or setting a
text value containing information about what was measured to obtain the
data.
what_measured(my.spct) <- "something"
what_measured(my.spct)
## [1] "something"
my.spct
## Object: source_spct [522 x 3]
## Wavelength range 280-800 nm, step 0.9230769-1 nm
## Label: something
## Measured on 2015-10-31 20:55:00 UTC
## Measured at 60 N, -10 E; Somewhere
## Time unit 1s
##
## # A tibble: 522 × 3
## w.length s.e.irrad s.q.irrad
## <dbl> <dbl> <dbl>
## 1 280 0 0
## 2 281. 0 0
## 3 282. 0 0
## 4 283. 0 0
## # … with 518 more rows
## # ℹ Use `print(n = ...)` to see more rows
Functions using a different syntax are also available, for these and other attributes which are not likely to be set by users. Many of these additional attributes are meaningful only some types of spectra.
source_spct
objectsOne example is the time unit used to express spectral irradiance.
Functions are available for querying and setting the state if these
attributes. is_
functions return a logical value, and
get
functions return the values of the attributes
themselves. In addition set
functions can be used to set
the value stored in the attributes. Several of the set
functions are very rarely needed in user code, as these attributes are
set during construction or as a side effect of applying other functions
and/or operators to the objects. Function setBSWFUsed()
and
other set functions are mainly useful to programmers extending
the package, but only exceptionally to users. One exception is the case
when a wrong value has been assigned by mistake and needs to be
overwritten.
We can see in the printout that the time unit is reported in the header.
sun.spct
## Object: source_spct [522 x 3]
## Wavelength range 280-800 nm, step 0.9230769-1 nm
## Label: sunlight, simulated
## Measured on 2010-06-22 09:51:00 UTC
## Measured at 60.20911 N, 24.96474 E; Kumpula, Helsinki, FI
## Time unit 1s
##
## # A tibble: 522 × 3
## w.length s.e.irrad s.q.irrad
## <dbl> <dbl> <dbl>
## 1 280 0 0
## 2 281. 0 0
## 3 282. 0 0
## 4 283. 0 0
## # … with 518 more rows
## # ℹ Use `print(n = ...)` to see more rows
For example function is_effective()
returns
TRUE
if the spectral data has been weighted with a BSWF.
The corresponding getBSWFUsed()
function can be used, in
this case to retrieve the name of the BSWF that was used. Here we
demonstrate with one example, where we use a waveband
object—constructed on-the-fly with a constructor function—, defining a
range of wavelengths.
is_effective(sun.spct)
## [1] FALSE
is_effective(sun.spct * waveband(c(400, 700)))
## [1] FALSE
Sometimes it may be desired to change the time unit used for
expressing spectral irradiance or spectral response, and this can be
achieved with the conversion function
convertTimeUnit
. This function both converts spectral data
to the new unit of expression and sets the time.unit
attribute, preserving the validity of the data object.
<-
ten.minutes.spct convertTimeUnit(sun.spct, time.unit = duration(10, "minutes"))
ten.minutes.spct
## Object: source_spct [522 x 3]
## Wavelength range 280-800 nm, step 0.9230769-1 nm
## Label: sunlight, simulated
## Measured on 2010-06-22 09:51:00 UTC
## Measured at 60.20911 N, 24.96474 E; Kumpula, Helsinki, FI
## Time unit 600s (~10 minutes)
##
## # A tibble: 522 × 3
## w.length s.e.irrad s.q.irrad
## <dbl> <dbl> <dbl>
## 1 280 0 0
## 2 281. 0 0
## 3 282. 0 0
## 4 283. 0 0
## # … with 518 more rows
## # ℹ Use `print(n = ...)` to see more rows
getTimeUnit(ten.minutes.spct)
## [1] "600s (~10 minutes)"
filter_spct
objectsA crucial information is whether transmittance (Tfr
) is
expressed as internal or total, stored in attribute
Tfr.type
, as this affects how absorptances and absorbances
are computed. The key step is when a filter_spct
object is
created, when the user has to be careful to set this attribute
correctly.
The objects from which transmittance can differ in additional
properties that affect possible calculations. Attribute
filter.properties
is used to store these in an object with
fields Rfr.constant
, thickness
and
attenuation.mode
. When these metadata are available, in
many cases we can use function convertTfrType()
to convert
internal transmittance into total transmittance and vice versa
and function convertThickness()
to compute the spectral
transmittance of a filter of the same material but different
thickness.
These attributes are also allowed in the case of
object_spct
and reflector_spct
and retained
during class conversions between them and filter_spct
objects.
They are included in the printout of filter.spct
objects.
polyester.spct
## Object: filter_spct [561 x 2]
## Wavelength range 240-800 nm, step 1 nm
## Label: clear polyester film
## Transmittance of type 'total'
## Rfr (/1): 0.07, thickness (mm): 0.125, attenuation mode: absorption.
##
## # A tibble: 561 × 2
## w.length Tfr
## <int> <dbl>
## 1 240 0.00482
## 2 241 0.00464
## 3 242 0.00446
## 4 243 0.00429
## # … with 557 more rows
## # ℹ Use `print(n = ...)` to see more rows
We estimate the spectral transmittance of 2 mm-thick PET film.
convertThickness(polyester.spct, thickness = 2e-3)
## Object: filter_spct [561 x 2]
## Wavelength range 240-800 nm, step 1 nm
## Label: clear polyester film
## Transmittance of type 'total'
## Rfr (/1): 0.07, thickness (mm): 2, attenuation mode: absorption.
##
## # A tibble: 561 × 2
## w.length Tfr
## <int> <dbl>
## 1 240 2.53e-37
## 2 241 1.38e-37
## 3 242 7.39e-38
## 4 243 3.85e-38
## # … with 557 more rows
## # ℹ Use `print(n = ...)` to see more rows
Attributes instr_desc
and instr_settings
are used to store measurement-related metadata, describing the
instrument used and its settings. These attributes are lists, with a few
default fields and possibly unlimited special attributes. The
present package provides functions for operating on them and print-outs
include some of the default fields if the attribute is set. The
expectation is that these attributes are set by other packages such as
‘ooacquire’ used for direct data acquisition or raw instrument data
import.
These instrument-specific attributes can contain lots of information
and bloat the size of spectral objects. Two methods,
trimInstrDesc()
and trimInstrSettings()
can be
used to discard parts of these metadata, such as instrument calibration
information, once the raw data has been converted into physical
units.
Spectral objects created with earlier (pre-release) versions of this
package are missing some attributes. For this reason summary
and plot functions may not work as expected with them. These
very old objects can be updated by adding the missing
attributes using functions setTimeUnit
,
setBSWFUsed
, setTfrType
and
setRfrType
. However, in many cases function
update_spct
can be used to set the missing attributes to
default values, or the scripts re-run to rebuild the data objects from
raw data.
The package defines several classes intended to be used to store
collections of different types of spectral data. They are all
derived from generic_mspct
, which in turn is derived from
list
. Table 3 lists them.
Table 3. Classes for collections of spectral
objects. Objects of class generic_mspct
can have
member objects of any class derived from generic_spct
and
can be heterogeneous, while the other classes support homogeneous
collections of spectral objects. Attributes of these objects can be
queried and set with the normal R methods attr
and
attributes
as well as with functions defined in this
package. See table 1 for the attributes used in individual member
spectra of collections.
Class name | Class of member objects | Attributes |
---|---|---|
generic_mspct |
generic_spct |
names , dim , comment |
calibration_mspct |
calibration_spct |
names , dim , comment |
raw_mspct |
raw_spct |
names , dim , comment |
cps_mspct |
cps_spct |
names , dim , comment |
source_mspct |
source_spct |
names , dim , comment |
filter_mspct |
filter_spct |
names , dim , comment |
reflector_mspct |
reflector_spct |
names , dim , comment |
object_mspct |
object_spct |
names , dim , comment |
response_mspct |
response_spct |
names , dim , comment |
chroma_mspct |
chroma_spct |
names , dim , comment |
solute_mspct |
solute_spct |
names , dim , comment |
Objects of these classes, except for class
generic_mspct
, can only contain members belonging the
matching class of spectra. As all other spectral object classes are
derived from generic_spct
, generic_mspct
objects can contain heterogeneous collections of spectra. In all cases,
there are no restrictions on the lengths, wavelength range and/or
wavelength step size, or attributes other than class
of the
contained spectra. Mimicking R’s arrays and matrices, a dim
attribute is always present and dim
methods are provided.
This approach allows the storage of time series of spectral data, or
(hyper)spectral image data, or even higher dimensional spectral data.
The handling of 1D and 2D spectral collections is already implemented in
the summary methods. Handling of 3D and higher dimensional data can be
implemented in the future without changing the class definitions. By
having implemented dim
, also methods ncol
and
nrow
are available as they use dim
internally.
Array-like subscripting collections of spectra is not
implemented.
We can construct a collection using a list of spectral objects as a starting point, in this case the spectral irradiance for sunlight.
<- source_mspct(list(sun1 = sun.spct, sun2 = sun.spct))
two_suns.mspct two_suns.mspct
## Object: source_mspct [2 x 1]
## --- Member: sun1 ---
## Object: source_spct [522 x 3]
## Wavelength range 280-800 nm, step 0.9230769-1 nm
## Label: sunlight, simulated
## Measured on 2010-06-22 09:51:00 UTC
## Measured at 60.20911 N, 24.96474 E; Kumpula, Helsinki, FI
## Time unit 1s
##
## # A tibble: 522 × 3
## w.length s.e.irrad s.q.irrad
## <dbl> <dbl> <dbl>
## 1 280 0 0
## 2 281. 0 0
## 3 282. 0 0
## 4 283. 0 0
## # … with 518 more rows
## # ℹ Use `print(n = ...)` to see more rows
## --- Member: sun2 ---
## Object: source_spct [522 x 3]
## Wavelength range 280-800 nm, step 0.9230769-1 nm
## Label: sunlight, simulated
## Measured on 2010-06-22 09:51:00 UTC
## Measured at 60.20911 N, 24.96474 E; Kumpula, Helsinki, FI
## Time unit 1s
##
## # A tibble: 522 × 3
## w.length s.e.irrad s.q.irrad
## <dbl> <dbl> <dbl>
## 1 280 0 0
## 2 281. 0 0
## 3 282. 0 0
## 4 283. 0 0
## # … with 518 more rows
## # ℹ Use `print(n = ...)` to see more rows
##
## --- END ---
We can also create heterogeneous collections, but this drastically limits the methods that are applicable to the resulting collection.
<- generic_mspct(list(filter = polyester.spct, source = sun.spct))
mixed.mspct class(mixed.mspct)
## [1] "generic_mspct" "list"
lapply(mixed.mspct, class_spct)
## $filter
## [1] "filter_spct" "generic_spct"
##
## $source
## [1] "source_spct" "generic_spct"
The as.
coercion methods for collections of spectra, not
only change the class of the collection object, but can also optionally
apply the corresponding as.
functions to the member
objects. A copy of the original object is made and then class-converted
and returned.
<- as.generic_mspct(two_suns.mspct)
two_gen.mspct class(two_gen.mspct)
## [1] "generic_mspct" "list"
str(two_gen.mspct, max.level = 1, give.attr = FALSE)
## List of 2
## $ sun1: source_spct [522 × 3] (S3: source_spct/generic_spct/tbl_df/tbl/data.frame)
## $ sun2: source_spct [522 × 3] (S3: source_spct/generic_spct/tbl_df/tbl/data.frame)
In addition to coercion methods for lists of spectra objects, coercion methods are available for lists of data frames (or tibbles) and from matrix objects.
One additional feature is that if a single spectrum object or data frame are coerced into a collection of spectra, the behaviour is equivalent to having passed as argument a list containing such object as its only member.
<- as.source_mspct(sun.spct)
one_sun.mspct class(one_sun.mspct)
## [1] "source_mspct" "generic_mspct" "list"
str(one_sun.mspct, max.level = 1, give.attr = FALSE)
## List of 1
## $ spct_1: source_spct [522 × 3] (S3: source_spct/generic_spct/tbl_df/tbl/data.frame)
Sometimes spectral data stored in a matrix need to be coerced into a collection of spectra. Coercion methods are defined also for this cases. Several spectra may be stored in a matrix either by row or by column, but this can be deduced automatically in the case of rectangular matrices. Wavelengths values are not expected to be part of the matrix, and need to be supplied as a separate numeric vector sorted in ascending order. As in a spectrum wavelength values never repeat, the vector of wavelengths is never recycled and uniqueness of values is enforced.
We here use artificial data, in this first example with spectra saved by column. We assume that the values in the matrix are spectral transmittance stored as percentages (hence “Tpc”).
<- matrix(1:100, ncol = 2)
x <- 501:550 # wavelengths in nanometres
wl as.filter_mspct(x, wl, "Tpc")
## Object: filter_mspct [0 x 3]
## --- Member: spct_1 ---
## Object: filter_spct [50 x 2]
## Wavelength range 501-550 nm, step 1 nm
## Transmittance of type 'total'
## Rfr (/1): NA, thickness (mm): NA, attenuation mode: NA.
##
## # A tibble: 50 × 2
## w.length Tfr
## <int> <dbl>
## 1 501 0.01
## 2 502 0.02
## 3 503 0.03
## 4 504 0.04
## # … with 46 more rows
## # ℹ Use `print(n = ...)` to see more rows
## --- Member: spct_2 ---
## Object: filter_spct [50 x 2]
## Wavelength range 501-550 nm, step 1 nm
## Transmittance of type 'total'
## Rfr (/1): NA, thickness (mm): NA, attenuation mode: NA.
##
## # A tibble: 50 × 2
## w.length Tfr
## <int> <dbl>
## 1 501 0.51
## 2 502 0.52
## 3 503 0.53
## 4 504 0.54
## # … with 46 more rows
## # ℹ Use `print(n = ...)` to see more rows
##
## --- END ---
In a second example we supply explicit names for the spectra.
as.filter_mspct(x, wl, "Tpc", spct.names = c("A", "B"))
## Object: filter_mspct [0 x 3]
## --- Member: A ---
## Object: filter_spct [50 x 2]
## Wavelength range 501-550 nm, step 1 nm
## Transmittance of type 'total'
## Rfr (/1): NA, thickness (mm): NA, attenuation mode: NA.
##
## # A tibble: 50 × 2
## w.length Tfr
## <int> <dbl>
## 1 501 0.01
## 2 502 0.02
## 3 503 0.03
## 4 504 0.04
## # … with 46 more rows
## # ℹ Use `print(n = ...)` to see more rows
## --- Member: B ---
## Object: filter_spct [50 x 2]
## Wavelength range 501-550 nm, step 1 nm
## Transmittance of type 'total'
## Rfr (/1): NA, thickness (mm): NA, attenuation mode: NA.
##
## # A tibble: 50 × 2
## w.length Tfr
## <int> <dbl>
## 1 501 0.51
## 2 502 0.52
## 3 503 0.53
## 4 504 0.54
## # … with 46 more rows
## # ℹ Use `print(n = ...)` to see more rows
##
## --- END ---
There is no change in the call for data stored by row. We create a new matrix, with the same data as above, but stored by row, as some R packages do.
<- matrix(1:100, nrow = 2, byrow = TRUE)
xrow as.filter_mspct(xrow, wl, "Tpc")
## Object: filter_mspct [0 x 3]
## --- Member: spct_1 ---
## Object: filter_spct [50 x 2]
## Wavelength range 501-550 nm, step 1 nm
## Transmittance of type 'total'
## Rfr (/1): NA, thickness (mm): NA, attenuation mode: NA.
##
## # A tibble: 50 × 2
## w.length Tfr
## <int> <dbl>
## 1 501 0.01
## 2 502 0.02
## 3 503 0.03
## 4 504 0.04
## # … with 46 more rows
## # ℹ Use `print(n = ...)` to see more rows
## --- Member: spct_2 ---
## Object: filter_spct [50 x 2]
## Wavelength range 501-550 nm, step 1 nm
## Transmittance of type 'total'
## Rfr (/1): NA, thickness (mm): NA, attenuation mode: NA.
##
## # A tibble: 50 × 2
## w.length Tfr
## <int> <dbl>
## 1 501 0.51
## 2 502 0.52
## 3 503 0.53
## 4 504 0.54
## # … with 46 more rows
## # ℹ Use `print(n = ...)` to see more rows
##
## --- END ---
There is only one case when an explicit argument for
byrow
is needed: square matrices (same number of spectra as
of wavelength values in each spectrum).
When coercing collections of spectra into matrices, the metadata
contained in the individual spectral objects is discarded, and only the
"comment"
attribute of the collection of spectra copied to
the returned object. The wavelength values are preserved in an attribute
named “w.length”, but are not included as part of the matrix.
<- as.matrix(two_suns.mspct, "s.e.irrad")
two_suns.mat class(two_suns.mat)
## [1] "matrix" "array"
dim(two_suns.mat)
## [1] 522 2
head(dimnames(two_suns.mat)$spct)
## [1] "sun1" "sun2"
head(dimnames(two_suns.mat)$w.length)
## [1] "280" "280.923076923077" "281.846153846154" "282.769230769231"
## [5] "283.692307692308" "284.615384615385"
head(attr(two_suns.mat, "w.length"))
## [1] 280.0000 280.9231 281.8462 282.7692 283.6923 284.6154
The argument byrow
in the coercion into matrix methods
has the same meaning as in the matrix
constructor
function.
<- as.matrix(two_suns.mat, "s.e.irrad", byrow = TRUE)
two_suns.row_mat class(two_suns.row_mat)
## [1] "matrix" "array"
dim(two_suns.row_mat)
## [1] 522 2
head(dimnames(two_suns.row_mat)$spct)
## [1] "sun1" "sun2"
head(attr(two_suns.row_mat, "w.length"))
## [1] 280.0000 280.9231 281.8462 282.7692 283.6923 284.6154
Collections of spectra have a dim
attribute but it is
discarded as it describes dimensions that could require spectral data to
be stored in a three dimensional array and cannot be mapped to the two
dimensions of a matrix.
These functions are not fully automatic, the user needs to provide the name of the variable to extract from each spectrum. If the wavelength values are not consistent among spectra, only those with the same values as the first spectrum in the collection are retained and the remaining ones dropped with a warning.
Spectral objects containing multiple spectra identified by a factor
can be created by row-binding compatible spectral objects. For for
binding to succeed, the list of spectra passed as argument must be
homogeneous with respect to member class, as well as for certain
attributes such as time.unit
. Other metadata attributes are
retained as named lists or multi-row data frames.
<- rbindspct(list(a = sun.spct, b = sun.spct / 2))
two_suns.spct two_suns.spct
## Object: source_spct [1,044 x 4]
## containing 2 spectra in long form
## Wavelength range 280-800 nm, step 0.9230769-1 nm
## a label: sunlight, simulated
## b label: sunlight, simulated
## a measured on 2010-06-22 09:51:00 UTC
## b measured on 2010-06-22 09:51:00 UTC
## Measured at 60.20911 N, 24.96474 E; Kumpula, Helsinki, FI
## Measured at 60.20911 N, 24.96474 E; Kumpula, Helsinki, FI
## Time unit 1s
##
## # A tibble: 1,044 × 4
## w.length s.e.irrad spct.idx s.q.irrad
## <dbl> <dbl> <fct> <dbl>
## 1 280 0 a 0
## 2 281. 0 a 0
## 3 282. 0 a 0
## 4 283. 0 a 0
## # … with 1,040 more rows
## # ℹ Use `print(n = ...)` to see more rows
The reverse operation, separating the individual spectra from a
spectrum object containing multiple spectra in long form and
storing them as a collection, is implemented in method
subset2mspct
. In this case, metadata is set for the
individual spectra if it is available in the object being subset. What
metadata is automatically stored depends on the version of this package
used when creating the long form spectrum object by means of
rbindspct()
. Versions 0.9.14 and later preserve most of the
metadata.
subset2mspct(two_suns.spct)
## Object: source_mspct [2 x 1]
## --- Member: a ---
## Object: source_spct [522 x 3]
## Wavelength range 280-800 nm, step 0.9230769-1 nm
## Label: sunlight, simulated
## Measured on 2010-06-22 09:51:00 UTC
## Measured at 60.20911 N, 24.96474 E; Kumpula, Helsinki, FI
## Time unit 1s
##
## # A tibble: 522 × 3
## w.length s.e.irrad s.q.irrad
## <dbl> <dbl> <dbl>
## 1 280 0 0
## 2 281. 0 0
## 3 282. 0 0
## 4 283. 0 0
## # … with 518 more rows
## # ℹ Use `print(n = ...)` to see more rows
## --- Member: b ---
## Object: source_spct [522 x 3]
## Wavelength range 280-800 nm, step 0.9230769-1 nm
## Label: sunlight, simulated
## Measured on 2010-06-22 09:51:00 UTC
## Measured at 60.20911 N, 24.96474 E; Kumpula, Helsinki, FI
## Time unit 1s
##
## # A tibble: 522 × 3
## w.length s.e.irrad s.q.irrad
## <dbl> <dbl> <dbl>
## 1 280 0 0
## 2 281. 0 0
## 3 282. 0 0
## 4 283. 0 0
## # … with 518 more rows
## # ℹ Use `print(n = ...)` to see more rows
##
## --- END ---
If multiple spectra are stored in long form (as tidy data)
in an ordinary data.frame
or a tibble
object
with columns with suitable names, the same subset2mspct
method can be used. In these case, arguments indicating the target class
for conversion and supplying the name of the index variable encoding the
grouping into multiple spectra need to be supplied. A call as in the
example below, adds only default metadata to spectral objects.
<- data.frame(w.length = rep(200:210, 2),
test1.df s.e.irrad = rep(c(1, 2), c(11, 11)),
spectrum = factor(rep(c("A", "B"), c(11,11))))
subset2mspct(test1.df, member.class = "source_spct", idx.var = "spectrum")
## Object: source_mspct [2 x 1]
## --- Member: A ---
## Object: source_spct [11 x 2]
## Wavelength range 200-210 nm, step 1 nm
## Time unit 1s
##
## # A tibble: 11 × 2
## w.length s.e.irrad
## <int> <dbl>
## 1 200 1
## 2 201 1
## 3 202 1
## 4 203 1
## # … with 7 more rows
## # ℹ Use `print(n = ...)` to see more rows
## --- Member: B ---
## Object: source_spct [11 x 2]
## Wavelength range 200-210 nm, step 1 nm
## Time unit 1s
##
## # A tibble: 11 × 2
## w.length s.e.irrad
## <int> <dbl>
## 1 200 2
## 2 201 2
## 3 202 2
## 4 203 2
## # … with 7 more rows
## # ℹ Use `print(n = ...)` to see more rows
##
## --- END ---
If all member spectra share the same metadata, and the constructor has a parameter allowing it to be set, it can be passed as a named argument.
subset2mspct(test1.df, member.class = "source_spct", idx.var = "spectrum",
time.unit = "day")
## Object: source_mspct [2 x 1]
## --- Member: A ---
## Object: source_spct [11 x 2]
## Wavelength range 200-210 nm, step 1 nm
## Time unit 86400s (~1 days)
##
## # A tibble: 11 × 2
## w.length s.e.irrad
## <int> <dbl>
## 1 200 1
## 2 201 1
## 3 202 1
## 4 203 1
## # … with 7 more rows
## # ℹ Use `print(n = ...)` to see more rows
## --- Member: B ---
## Object: source_spct [11 x 2]
## Wavelength range 200-210 nm, step 1 nm
## Time unit 86400s (~1 days)
##
## # A tibble: 11 × 2
## w.length s.e.irrad
## <int> <dbl>
## 1 200 2
## 2 201 2
## 3 202 2
## 4 203 2
## # … with 7 more rows
## # ℹ Use `print(n = ...)` to see more rows
##
## --- END ---
To directly convert a tidy data frame into a long form
spectral object we need to pass the number of spectra through parameter
multiple.wl
to override the usual check for unique
wavelength values (default is multiple.wl = 1L
).
<- test1.df
test2.df setSourceSpct(test2.df, multiple.wl = 2L)
getMultipleWl(test2.df)
## [1] 2
If multiple.wl = NULL
a suitable value is guessed from
the data frame passed as first argument. This should work in most cases,
but is more time consuming. Using this approach in addition disables the
check for a fixed number of spectra.
<- test1.df
test3.df setSourceSpct(test3.df, multiple.wl = NULL)
getMultipleWl(test3.df)
## [1] 2
In a broad form (or untidy) data.frame the spectral
values for different spectra are stored side-by-side as columns, and a
single additional column used to store the shared wavelength values. To
create a collection of spectral objects, with each member containing a
single spectrum, we use function split2source_mspct
and its
equivalents for the remaining classes of spectral objects (class is
determined by the function used, and columns which are not
numeric
are skipped). The column containing wavelength
values in nanometres is recognized by means of its name. The names used
for the spectra in the collection are derived from the names of the
columns containing spectral values.
<- data.frame(w.length = 200:210, A = 1, B = 2, z = "A")
test2.df split2source_mspct(test2.df)
## Warning in split2mspct(x = x, member.class = "source_spct", spct.data.var =
## spct.data.var, : Skipping non-numeric column in x: z
## Object: source_mspct [2 x 1]
## --- Member: A ---
## Object: source_spct [11 x 2]
## Wavelength range 200-210 nm, step 1 nm
## Time unit 1s
##
## # A tibble: 11 × 2
## w.length s.e.irrad
## <int> <dbl>
## 1 200 1
## 2 201 1
## 3 202 1
## 4 203 1
## # … with 7 more rows
## # ℹ Use `print(n = ...)` to see more rows
## --- Member: B ---
## Object: source_spct [11 x 2]
## Wavelength range 200-210 nm, step 1 nm
## Time unit 1s
##
## # A tibble: 11 × 2
## w.length s.e.irrad
## <int> <dbl>
## 1 200 2
## 2 201 2
## 3 202 2
## 4 203 2
## # … with 7 more rows
## # ℹ Use `print(n = ...)` to see more rows
##
## --- END ---
split2source_mspct(test2.df, spct.data.var = "s.q.irrad")
## Warning in split2mspct(x = x, member.class = "source_spct", spct.data.var =
## spct.data.var, : Skipping non-numeric column in x: z
## Object: source_mspct [2 x 1]
## --- Member: A ---
## Object: source_spct [11 x 2]
## Wavelength range 200-210 nm, step 1 nm
## Time unit 1s
##
## # A tibble: 11 × 2
## w.length s.q.irrad
## <int> <dbl>
## 1 200 1
## 2 201 1
## 3 202 1
## 4 203 1
## # … with 7 more rows
## # ℹ Use `print(n = ...)` to see more rows
## --- Member: B ---
## Object: source_spct [11 x 2]
## Wavelength range 200-210 nm, step 1 nm
## Time unit 1s
##
## # A tibble: 11 × 2
## w.length s.q.irrad
## <int> <dbl>
## 1 200 2
## 2 201 2
## 3 202 2
## 4 203 2
## # … with 7 more rows
## # ℹ Use `print(n = ...)` to see more rows
##
## --- END ---
Also in this case, it is possible to pass additional named arguments to the constructor of spectral objects.
split2source_mspct(test2.df, spct.data.var = "s.q.irrad", time.unit = "day")
## Warning in split2mspct(x = x, member.class = "source_spct", spct.data.var =
## spct.data.var, : Skipping non-numeric column in x: z
## Object: source_mspct [2 x 1]
## --- Member: A ---
## Object: source_spct [11 x 2]
## Wavelength range 200-210 nm, step 1 nm
## Time unit 86400s (~1 days)
##
## # A tibble: 11 × 2
## w.length s.q.irrad
## <int> <dbl>
## 1 200 1
## 2 201 1
## 3 202 1
## 4 203 1
## # … with 7 more rows
## # ℹ Use `print(n = ...)` to see more rows
## --- Member: B ---
## Object: source_spct [11 x 2]
## Wavelength range 200-210 nm, step 1 nm
## Time unit 86400s (~1 days)
##
## # A tibble: 11 × 2
## w.length s.q.irrad
## <int> <dbl>
## 1 200 2
## 2 201 2
## 3 202 2
## 4 203 2
## # … with 7 more rows
## # ℹ Use `print(n = ...)` to see more rows
##
## --- END ---
Sometimes, when exporting spectral data we may need to convert a
collection of spectra into an untidy or wide form data
frame. In the example below we use a collection with only two member
spectra, but join_mspct()
can handle collections of any
length.
<- source_mspct(list(sun1 = sun.spct, sun2 = sun.spct * 2))
my.mspct <- join_mspct(my.mspct)
my.df head(my.df)
## w.length sun1 sun2
## 1 280.0000 0 0
## 2 280.9231 0 0
## 3 281.8462 0 0
## 4 282.7692 0 0
## 5 283.6923 0 0
## 6 284.6154 0 0
is.
functions are defined for all the new classes. R’s
class
method can also be used.
is.source_mspct(two_suns.mspct)
## [1] TRUE
class(two_suns.mspct)
## [1] "source_mspct" "generic_mspct" "list"
In addition to using class
to query the class of the
collection, we can use base R’s lapply
together with
class
or class_spct
to query the class of each
of the members of the collection.
is.filter_mspct(mixed.mspct)
## [1] FALSE
is.any_mspct(mixed.mspct)
## [1] TRUE
class(mixed.mspct)
## [1] "generic_mspct" "list"
lapply(mixed.mspct, class_spct)
## $filter
## [1] "filter_spct" "generic_spct"
##
## $source
## [1] "source_spct" "generic_spct"
lapply(mixed.mspct, class)
## $filter
## [1] "filter_spct" "generic_spct" "tbl_df" "tbl" "data.frame"
##
## $source
## [1] "source_spct" "generic_spct" "tbl_df" "tbl" "data.frame"
R’s extraction and replacement methods have specializations for collections of spectra and can be used with the same syntax and functionality as for R lists. However they test the class and validity of the returned objects and replacement members.
Methods [
, and [<-
, extract and replace
parts of the collection, respectively. Even when only one
member is extracted, the returned value is a collection of spectra. The
expected replacement value is also, always a collection of spectra.
# not run as this triggers an error when building the vignette with 'devtools'
1]
two_suns.mspct[1:2] two_suns.mspct[
Avoid code like that in the chunk bellow. Collections of spectra are named lists, consequently assigning by position as shown here swaps the values without swapping the names of the slots!
# not run as this triggers an error when building the vignette with 'devtools'
1:2] <- two_suns.mspct[2:1] two_suns.mspct[
Methods [[
, $
and [[<-
,
extract and replace individual members of the collection, respectively.
They always return or expect objects of one of the spectral classes.
1]] two_suns.mspct[[
## Object: source_spct [522 x 3]
## Wavelength range 280-800 nm, step 0.9230769-1 nm
## Label: sunlight, simulated
## Measured on 2010-06-22 09:51:00 UTC
## Measured at 60.20911 N, 24.96474 E; Kumpula, Helsinki, FI
## Time unit 1s
##
## # A tibble: 522 × 3
## w.length s.e.irrad s.q.irrad
## <dbl> <dbl> <dbl>
## 1 280 0 0
## 2 281. 0 0
## 3 282. 0 0
## 4 283. 0 0
## # … with 518 more rows
## # ℹ Use `print(n = ...)` to see more rows
$sun1 two_suns.mspct
## Object: source_spct [522 x 3]
## Wavelength range 280-800 nm, step 0.9230769-1 nm
## Label: sunlight, simulated
## Measured on 2010-06-22 09:51:00 UTC
## Measured at 60.20911 N, 24.96474 E; Kumpula, Helsinki, FI
## Time unit 1s
##
## # A tibble: 522 × 3
## w.length s.e.irrad s.q.irrad
## <dbl> <dbl> <dbl>
## 1 280 0 0
## 2 281. 0 0
## 3 282. 0 0
## 4 283. 0 0
## # … with 518 more rows
## # ℹ Use `print(n = ...)` to see more rows
"sun1"]] two_suns.mspct[[
## Object: source_spct [522 x 3]
## Wavelength range 280-800 nm, step 0.9230769-1 nm
## Label: sunlight, simulated
## Measured on 2010-06-22 09:51:00 UTC
## Measured at 60.20911 N, 24.96474 E; Kumpula, Helsinki, FI
## Time unit 1s
##
## # A tibble: 522 × 3
## w.length s.e.irrad s.q.irrad
## <dbl> <dbl> <dbl>
## 1 280 0 0
## 2 281. 0 0
## 3 282. 0 0
## 4 283. 0 0
## # … with 518 more rows
## # ℹ Use `print(n = ...)` to see more rows
"sun1"]] <- sun.spct * 2
two_suns.mspct[["sun2"]] <- NULL
two_suns.mspct[[ two_suns.mspct
## Object: source_mspct [1 x 1]
## --- Member: sun1 ---
## Object: source_spct [522 x 2]
## Wavelength range 280-800 nm, step 0.9230769-1 nm
## Label: sunlight, simulated
## Measured on 2010-06-22 09:51:00 UTC
## Measured at 60.20911 N, 24.96474 E; Kumpula, Helsinki, FI
## Time unit 1s
##
## # A tibble: 522 × 2
## w.length s.e.irrad
## <dbl> <dbl>
## 1 280 0
## 2 281. 0
## 3 282. 0
## 4 283. 0
## # … with 518 more rows
## # ℹ Use `print(n = ...)` to see more rows
##
## --- END ---
As with R’s list
objects, can combine collections of
spectra with method c()
but we can not create new
collections from individual spectra using this method.
c(two_suns.mspct, mixed.mspct)
## Object: generic_mspct [3 x 1]
## --- Member: sun1 ---
## Object: source_spct [522 x 2]
## Wavelength range 280-800 nm, step 0.9230769-1 nm
## Label: sunlight, simulated
## Measured on 2010-06-22 09:51:00 UTC
## Measured at 60.20911 N, 24.96474 E; Kumpula, Helsinki, FI
## Time unit 1s
##
## # A tibble: 522 × 2
## w.length s.e.irrad
## <dbl> <dbl>
## 1 280 0
## 2 281. 0
## 3 282. 0
## 4 283. 0
## # … with 518 more rows
## # ℹ Use `print(n = ...)` to see more rows
## --- Member: filter ---
## Object: filter_spct [561 x 2]
## Wavelength range 240-800 nm, step 1 nm
## Label: clear polyester film
## Transmittance of type 'total'
## Rfr (/1): 0.07, thickness (mm): 0.125, attenuation mode: absorption.
##
## # A tibble: 561 × 2
## w.length Tfr
## <int> <dbl>
## 1 240 0.00482
## 2 241 0.00464
## 3 242 0.00446
## 4 243 0.00429
## # … with 557 more rows
## # ℹ Use `print(n = ...)` to see more rows
## --- Member: source ---
## Object: source_spct [522 x 3]
## Wavelength range 280-800 nm, step 0.9230769-1 nm
## Label: sunlight, simulated
## Measured on 2010-06-22 09:51:00 UTC
## Measured at 60.20911 N, 24.96474 E; Kumpula, Helsinki, FI
## Time unit 1s
##
## # A tibble: 522 × 3
## w.length s.e.irrad s.q.irrad
## <dbl> <dbl> <dbl>
## 1 280 0 0
## 2 281. 0 0
## 3 282. 0 0
## 4 283. 0 0
## # … with 518 more rows
## # ℹ Use `print(n = ...)` to see more rows
##
## --- END ---
For our apply functions we follow the naming convention used
in package plyr
, but using ms
as prefix for
_mspct
objects. The apply functions implemented in
the ‘photobiology’ package are msmsply
,
msdply
, mslply
and msaply
which
both accept a collection of spectra as first argument and return a
collection of spectra, a data frame, a list, or an array respectively
(see Table 4).
Table 4. Apply functions for collections of spectra.
Key: v., value returned by apply function; f.v., value returned
by the applied function (argument .fun
). In the table
generic_mspct
and generic_spct
indicate
objects of these classes or any class derived from them. The exact class
of the collection of spectra object returned will be determined by the
class(es) of the values returned by the applied function.
apply function | first arg. class | v. class | f.v. class | f.v. length | f.v. dims |
---|---|---|---|---|---|
msmsply |
generic_mspct |
generic_mspct |
generic_spct |
1 | any |
msdply |
generic_mspct |
data.frame |
numeric |
\(1\ldots n\) | 1 |
mslply |
generic_mspct |
list |
any | any | any |
msaply |
generic_mspct |
vector |
any simple | 1 | 0 |
msaply |
generic_mspct |
matrix |
any simple | \(2\ldots n\) | \(2\ldots n\) |
concolve_each |
generic_mspct |
generic_mspct |
generic_spct |
1 | any |
Functions msmsply()
, msdply
and
mslply
can be used to apply a function to each member
spectrum in a collection. The apply function to use depends on
the return value of the applied function.
In the case of msmsply()
the applied function is
expected to return a transformed spectrum as another object of
class generic_spct
or a class derived from it. The value
returned by msmsply
is a collection of spectra, of a type
determined by the class(es) of the member spectra in the new
collection.
We start with a simple example in which we add a constant to each spectrum in the collection
<- source_mspct(list(A = sun.spct * 1, B = sun.spct * 2))
two.mspct msmsply(two.mspct, `+`, 0.1)
## Object: source_mspct [2 x 1]
## --- Member: A ---
## Object: source_spct [522 x 2]
## Wavelength range 280-800 nm, step 0.9230769-1 nm
## Label: sunlight, simulated
## Measured on 2010-06-22 09:51:00 UTC
## Measured at 60.20911 N, 24.96474 E; Kumpula, Helsinki, FI
## Time unit 1s
##
## # A tibble: 522 × 2
## w.length s.e.irrad
## <dbl> <dbl>
## 1 280 0.1
## 2 281. 0.1
## 3 282. 0.1
## 4 283. 0.1
## # … with 518 more rows
## # ℹ Use `print(n = ...)` to see more rows
## --- Member: B ---
## Object: source_spct [522 x 2]
## Wavelength range 280-800 nm, step 0.9230769-1 nm
## Label: sunlight, simulated
## Measured on 2010-06-22 09:51:00 UTC
## Measured at 60.20911 N, 24.96474 E; Kumpula, Helsinki, FI
## Time unit 1s
##
## # A tibble: 522 × 2
## w.length s.e.irrad
## <dbl> <dbl>
## 1 280 0.1
## 2 281. 0.1
## 3 282. 0.1
## 4 283. 0.1
## # … with 518 more rows
## # ℹ Use `print(n = ...)` to see more rows
##
## --- END ---
and continue with a more complex example in which we trim each spectrum
msmsply(two.mspct, trim_wl, range = c(281, 500), fill = NA)
## Object: source_mspct [2 x 1]
## --- Member: A ---
## Object: source_spct [525 x 2]
## Wavelength range 280-800 nm, step 1.023182e-12-1 nm
## Label: sunlight, simulated
## Measured on 2010-06-22 09:51:00 UTC
## Measured at 60.20911 N, 24.96474 E; Kumpula, Helsinki, FI
## Time unit 1s
##
## # A tibble: 525 × 2
## w.length s.e.irrad
## <dbl> <dbl>
## 1 280 NA
## 2 281. NA
## 3 281. NA
## 4 281 0
## # … with 521 more rows
## # ℹ Use `print(n = ...)` to see more rows
## --- Member: B ---
## Object: source_spct [525 x 2]
## Wavelength range 280-800 nm, step 1.023182e-12-1 nm
## Label: sunlight, simulated
## Measured on 2010-06-22 09:51:00 UTC
## Measured at 60.20911 N, 24.96474 E; Kumpula, Helsinki, FI
## Time unit 1s
##
## # A tibble: 525 × 2
## w.length s.e.irrad
## <dbl> <dbl>
## 1 280 NA
## 2 281. NA
## 3 281. NA
## 4 281 0
## # … with 521 more rows
## # ℹ Use `print(n = ...)` to see more rows
##
## --- END ---
In the second example we pass two arguments by name to the applied function. The number of arguments is not fixed, but the spectrum will be always passed as the first argument to the function.
In the case of msdply()
the applied function is expected
to return an R object of the same length for each of the member
spectra.
msdply(two.mspct, max)
## # A tibble: 2 × 2
## spct.idx max.wl
## <fct> <dbl>
## 1 A 800
## 2 B 800
<- msdply(two.mspct, range)
ranges.df ranges.df
## # A tibble: 2 × 3
## spct.idx min.wl max.wl
## <fct> <dbl> <dbl>
## 1 A 280 800
## 2 B 280 800
cat(comment(ranges.df))
## Applied function: 'range'.
msdply(two.mspct, range, na.rm = TRUE)
## # A tibble: 2 × 3
## spct.idx min.wl max.wl
## <fct> <dbl> <dbl>
## 1 A 280 800
## 2 B 280 800
In the case of mslply()
the applied function is expected
to return an R object of any length, possibly variable among
members.
str(mslply(two.mspct, names))
## List of 2
## $ A: chr [1:2] "w.length" "s.e.irrad"
## $ B: chr [1:2] "w.length" "s.e.irrad"
## - attr(*, "comment")= chr "Applied function: 'names'.\n"
In the case of msaply()
the applied function is expected
to return an R object of length 1, although a list with dimensions will
be returned for longer return values.
str(msaply(two.mspct, max))
## num [1:2] 800 800
## - attr(*, "comment")= chr "Applied function: 'max'.\n"
str(msaply(two.mspct, range))
## num [1:2, 1:2] 280 280 800 800
## - attr(*, "dimnames")=List of 2
## ..$ : NULL
## ..$ : chr [1:2] "1" "2"
## - attr(*, "comment")= chr "Applied function: 'range'.\n"
For the most common cases for which one would use the apply functions described in the previous section methods and functions for operations on collections of spectra are defined in the package. These methods are described in a later section and listed in Table 9.
Starting from a collection of spectra we may want to obtain a single spectrum containing a summary of them. The current implementation of the methods described in this section expects that all spectra in a collection are of the same class, and data is available for each of them at exactly the same set of wavelengths.
functions | class of argument | class of returned spectrum | variables in spectrum |
---|---|---|---|
s_sum |
source_mspct |
source_spct |
same as input |
s_sum |
response_mspct |
response_spct |
same as input |
s_sum |
filter_mspct |
generic_spct |
input tagged .sum |
s_sum |
reflector_mspct |
generic_spct |
input tagged .sum |
s_sum |
calibration_mspct |
generic_spct |
input tagged .sum |
s_prod |
source_mspct |
source_spct |
input tagged .prod |
s_prod |
response_mspct |
response_spct |
input tagged .prod |
s_prod |
filter_mspct |
filter_spct |
same as input |
s_prod |
reflector_mspct |
reflector_spct |
same as input |
s_prod |
calibration_mspct |
generic_spct |
input tagged .prod |
s_mean or s_median |
source_mspct |
source_spct |
same as input |
s_mean or s_median |
response_mspct |
response_spct |
same as input |
s_mean or s_median |
filter_mspct |
filter_spct |
same as input |
s_mean or s_median |
reflector_mspct |
reflector_spct |
same as input |
s_mean or s_median |
calibration_mspct |
calibration_spct |
same as input |
s_var , s_se or
s_sd |
source_mspct |
generic_spct |
input tagged .var , .se or
.sd |
s_var , s_se or
s_sd |
response_mspct |
generic_spct |
input tagged .var , .se or
.sd |
s_var , s_se or
s_sd |
filter_mspct |
generic_spct |
input tagged .var , .se or
.sd |
s_var , s_se or
s_sd |
reflector_mspct |
generic_spct |
input tagged .var , .se or
.sd |
s_var , s_se or
s_sd |
calibration_mspct |
generic_spct |
input tagged .var , .se or
.sd |
s_mean_se |
source_mspct |
source_spct |
same as input plus col. tagged .se |
s_mean_se |
response_mspct |
response_spct |
same as input plus col. tagged .se |
s_mean_se |
filter_mspct |
filter_spct |
same as input plus col. tagged .se |
s_mean_se |
reflector_mspct |
reflector_spct |
same as input plus col. tagged .se |
s_mean_se |
calibration_mspct |
calibration_spct |
same as input plus col. tagged .se |
s_range |
source_mspct |
generic_spct |
input tagged .min and
.max |
s_range |
response_mspct |
generic_spct |
input tagged .min and
.max |
s_range |
filter_mspct |
generic_spct |
input tagged .min and
.max |
s_range |
reflector_mspct |
generic_spct |
input tagged .min and
.max |
s_range |
calibration_mspct |
generic_spct |
input tagged .min and
.max |
The calculations are done wavelength by wavelength yielding a
spectrum at the same wavelengths than those in the input. Removal of
NA
values is done wavelength by wavelength. As shown in the
table above, depending on the operation the returned quantity may be
equivalent or not to the quantity in the input. When the quantity
changes, even if units of expression remain the same, the name of the
variable and class of the returned spectrum are different to those in
the input.
Methods in this “family” are fast and are specially useful for large
collections of spectra containing even thousands of individual spectra.
Nonetheless, for the example below we use a collection of two spectra.
As computing the mean returns values of the same quantity as in the
input the returned value is a source_spct
object, in other
words of the same class as the members of two.mspct
.
s_mean(two.mspct)
## Object: source_spct [522 x 2]
## Wavelength range 280-800 nm, step 0.9230769-1 nm
## Label: Mean of 2 source_spct objects.
## Time unit 1s
##
## # A tibble: 522 × 2
## w.length s.e.irrad
## <dbl> <dbl>
## 1 280 0
## 2 281. 0
## 3 282. 0
## 4 283. 0
## # … with 518 more rows
## # ℹ Use `print(n = ...)` to see more rows
When we compute the standard error, the quantity returned is not the
same. Consequently, the object returned is in this case a
generic_spct
instead of source_spc
as it does
not contain spectral irradiance data as the input did. The variable name
is in addition tagged with .se
to advertise the
change in the quantity.
s_se(two.mspct)
## Object: generic_spct [522 x 2]
## Wavelength range 280-800 nm, step 0.9230769-1 nm
## Label: Standard error for 2 source_spct objects.
##
## # A tibble: 522 × 2
## w.length s.e.irrad.se
## <dbl> <dbl>
## 1 280 0
## 2 281. 0
## 3 282. 0
## 4 283. 0
## # … with 518 more rows
## # ℹ Use `print(n = ...)` to see more rows
We can also compute both the mean and standard error simultaneously.
s_mean_se(two.mspct)
## Object: source_spct [522 x 3]
## Wavelength range 280-800 nm, step 0.9230769-1 nm
## Label: Mean and SEM of 2 source_spct objects.
## Time unit 1s
##
## # A tibble: 522 × 3
## w.length s.e.irrad s.e.irrad.se
## <dbl> <dbl> <dbl>
## 1 280 0 0
## 2 281. 0 0
## 3 282. 0 0
## 4 283. 0 0
## # … with 518 more rows
## # ℹ Use `print(n = ...)` to see more rows
The other functions in this family work in a similar way to those described here.
By convolution we normally mean the multiplication value by value at matching wavelengths of two spectra. The function described in this section facilitates this and similar operations among collections of spectra. An example use case could be the convolution of spectral irradiance by spectral transmittance for all combinations of light sources and filters in a collection of source spectra and a collection of filter spectra.
Default operator (or function) is that for multiplication, either one or both of the two first arguments must be a collection of spectra. When only one argument is a collection of spectra, the other one can be a spectrum, or even a numeric vector. For multiplication the order of the operands does not affect the returned value. With operators or functions for non-transitive operations the order does matter.
convolve_each(two.mspct, sun.spct)
## Object: source_mspct [2 x 1]
## --- Member: A ---
## Object: source_spct [522 x 2]
## Wavelength range 280-800 nm, step 0.9230769-1 nm
## Label: sunlight, simulated
## Measured on 2010-06-22 09:51:00 UTC
## Measured at 60.20911 N, 24.96474 E; Kumpula, Helsinki, FI
## Time unit 1s
##
## # A tibble: 522 × 2
## w.length s.e.irrad
## <dbl> <dbl>
## 1 280 0
## 2 281. 0
## 3 282. 0
## 4 283. 0
## # … with 518 more rows
## # ℹ Use `print(n = ...)` to see more rows
## --- Member: B ---
## Object: source_spct [522 x 2]
## Wavelength range 280-800 nm, step 0.9230769-1 nm
## Label: sunlight, simulated
## Measured on 2010-06-22 09:51:00 UTC
## Measured at 60.20911 N, 24.96474 E; Kumpula, Helsinki, FI
## Time unit 1s
##
## # A tibble: 522 × 2
## w.length s.e.irrad
## <dbl> <dbl>
## 1 280 0
## 2 281. 0
## 3 282. 0
## 4 283. 0
## # … with 518 more rows
## # ℹ Use `print(n = ...)` to see more rows
##
## --- END ---
convolve_each(sun.spct, two.mspct)
## Object: source_mspct [2 x 1]
## --- Member: A ---
## Object: source_spct [522 x 2]
## Wavelength range 280-800 nm, step 0.9230769-1 nm
## Label: sunlight, simulated
## Measured on 2010-06-22 09:51:00 UTC
## Measured at 60.20911 N, 24.96474 E; Kumpula, Helsinki, FI
## Time unit 1s
##
## # A tibble: 522 × 2
## w.length s.e.irrad
## <dbl> <dbl>
## 1 280 0
## 2 281. 0
## 3 282. 0
## 4 283. 0
## # … with 518 more rows
## # ℹ Use `print(n = ...)` to see more rows
## --- Member: B ---
## Object: source_spct [522 x 2]
## Wavelength range 280-800 nm, step 0.9230769-1 nm
## Label: sunlight, simulated
## Measured on 2010-06-22 09:51:00 UTC
## Measured at 60.20911 N, 24.96474 E; Kumpula, Helsinki, FI
## Time unit 1s
##
## # A tibble: 522 × 2
## w.length s.e.irrad
## <dbl> <dbl>
## 1 280 0
## 2 281. 0
## 3 282. 0
## 4 283. 0
## # … with 518 more rows
## # ℹ Use `print(n = ...)` to see more rows
##
## --- END ---
<- two.mspct
another_two.mspct names(another_two.mspct) <- c("a", "b")
convolve_each(another_two.mspct, two.mspct)
## Object: source_mspct [2 x 2]
## --- Member: a_A ---
## Object: source_spct [522 x 2]
## Wavelength range 280-800 nm, step 0.9230769-1 nm
## Label: sunlight, simulated
## Measured on 2010-06-22 09:51:00 UTC
## Measured at 60.20911 N, 24.96474 E; Kumpula, Helsinki, FI
## Time unit 1s
##
## # A tibble: 522 × 2
## w.length s.e.irrad
## <dbl> <dbl>
## 1 280 0
## 2 281. 0
## 3 282. 0
## 4 283. 0
## # … with 518 more rows
## # ℹ Use `print(n = ...)` to see more rows
## --- Member: a_B ---
## Object: source_spct [522 x 2]
## Wavelength range 280-800 nm, step 0.9230769-1 nm
## Label: sunlight, simulated
## Measured on 2010-06-22 09:51:00 UTC
## Measured at 60.20911 N, 24.96474 E; Kumpula, Helsinki, FI
## Time unit 1s
##
## # A tibble: 522 × 2
## w.length s.e.irrad
## <dbl> <dbl>
## 1 280 0
## 2 281. 0
## 3 282. 0
## 4 283. 0
## # … with 518 more rows
## # ℹ Use `print(n = ...)` to see more rows
## --- Member: b_A ---
## Object: source_spct [522 x 2]
## Wavelength range 280-800 nm, step 0.9230769-1 nm
## Label: sunlight, simulated
## Measured on 2010-06-22 09:51:00 UTC
## Measured at 60.20911 N, 24.96474 E; Kumpula, Helsinki, FI
## Time unit 1s
##
## # A tibble: 522 × 2
## w.length s.e.irrad
## <dbl> <dbl>
## 1 280 0
## 2 281. 0
## 3 282. 0
## 4 283. 0
## # … with 518 more rows
## # ℹ Use `print(n = ...)` to see more rows
## --- Member: b_B ---
## Object: source_spct [522 x 2]
## Wavelength range 280-800 nm, step 0.9230769-1 nm
## Label: sunlight, simulated
## Measured on 2010-06-22 09:51:00 UTC
## Measured at 60.20911 N, 24.96474 E; Kumpula, Helsinki, FI
## Time unit 1s
##
## # A tibble: 522 × 2
## w.length s.e.irrad
## <dbl> <dbl>
## 1 280 0
## 2 281. 0
## 3 282. 0
## 4 283. 0
## # … with 518 more rows
## # ℹ Use `print(n = ...)` to see more rows
##
## --- END ---
The function convolve_each
will use other operators or
functions and even pass additional named arguments when these are
supplied as arguments.
convolve_each(two.mspct, sun.spct, oper = `+`)
## Object: source_mspct [2 x 1]
## --- Member: A ---
## Object: source_spct [522 x 2]
## Wavelength range 280-800 nm, step 0.9230769-1 nm
## Label: sunlight, simulated
## Measured on 2010-06-22 09:51:00 UTC
## Measured at 60.20911 N, 24.96474 E; Kumpula, Helsinki, FI
## Time unit 1s
##
## # A tibble: 522 × 2
## w.length s.e.irrad
## <dbl> <dbl>
## 1 280 0
## 2 281. 0
## 3 282. 0
## 4 283. 0
## # … with 518 more rows
## # ℹ Use `print(n = ...)` to see more rows
## --- Member: B ---
## Object: source_spct [522 x 2]
## Wavelength range 280-800 nm, step 0.9230769-1 nm
## Label: sunlight, simulated
## Measured on 2010-06-22 09:51:00 UTC
## Measured at 60.20911 N, 24.96474 E; Kumpula, Helsinki, FI
## Time unit 1s
##
## # A tibble: 522 × 2
## w.length s.e.irrad
## <dbl> <dbl>
## 1 280 0
## 2 281. 0
## 3 282. 0
## 4 283. 0
## # … with 518 more rows
## # ℹ Use `print(n = ...)` to see more rows
##
## --- END ---
There are cases where functions convolve_each()
and
msmsply()
can be both used, but there are also cases where
their differences matter. An example is convolving two collections of
spectra, a case where only convolve_each()
can be used. In
contrast, when one of the arguments is not a spectrum or a collection of
spectra, msmsply()
should be used instead.
Some of the set
and get
functions used with
attributes have method definitions for collections of spectra. Some
examples follow.
when_measured(two.mspct)
## # A tibble: 2 × 2
## spct.idx when.measured
## <fct> <dttm>
## 1 A 2010-06-22 09:51:00
## 2 B 2010-06-22 09:51:00
when_measured(two.mspct) <- ymd("2015-10-31", tz = "EET")
when_measured(two.mspct)
## # A tibble: 2 × 2
## spct.idx when.measured
## <fct> <dttm>
## 1 A 2015-10-30 22:00:00
## 2 B 2015-10-30 22:00:00
when_measured(two.mspct) <- list(ymd_hm("2015-10-31 10:00", tz = "EET"),
ymd_hm("2015-10-31 11:00", tz = "EET"))
when_measured(two.mspct)
## # A tibble: 2 × 2
## spct.idx when.measured
## <fct> <dttm>
## 1 A 2015-10-31 08:00:00
## 2 B 2015-10-31 09:00:00
two.mspct
## Object: source_mspct [2 x 1]
## --- Member: A ---
## Object: source_spct [522 x 2]
## Wavelength range 280-800 nm, step 0.9230769-1 nm
## Label: sunlight, simulated
## Measured on 2015-10-31 08:00:00 UTC
## Measured at 60.20911 N, 24.96474 E; Kumpula, Helsinki, FI
## Time unit 1s
##
## # A tibble: 522 × 2
## w.length s.e.irrad
## <dbl> <dbl>
## 1 280 0
## 2 281. 0
## 3 282. 0
## 4 283. 0
## # … with 518 more rows
## # ℹ Use `print(n = ...)` to see more rows
## --- Member: B ---
## Object: source_spct [522 x 2]
## Wavelength range 280-800 nm, step 0.9230769-1 nm
## Label: sunlight, simulated
## Measured on 2015-10-31 09:00:00 UTC
## Measured at 60.20911 N, 24.96474 E; Kumpula, Helsinki, FI
## Time unit 1s
##
## # A tibble: 522 × 2
## w.length s.e.irrad
## <dbl> <dbl>
## 1 280 0
## 2 281. 0
## 3 282. 0
## 4 283. 0
## # … with 518 more rows
## # ℹ Use `print(n = ...)` to see more rows
##
## --- END ---
Other methods available are getWhereMeasured
and
setWhereMeasured
, and getWhatMeasured
and
setWhatMeasured
.
Functions when.measured2tb()
, geocode2tb()
,
lon2tb()
, lat2tb()
and
what.measured2tb()
extract these same attributes from
collection members into a tibble or data frame. In contrast to the “get”
methods described above, if an existing data frame or tibble with a
matching number of rows is passed as second argument, the values for the
attribute are saved into a new column appended at the right edge of the
tibble or data frame.
when_measured2tb(two.mspct)
## # A tibble: 2 × 2
## spct.idx when.measured
## <fct> <dttm>
## 1 A 2015-10-31 08:00:00
## 2 B 2015-10-31 09:00:00
By default the new column is named after the name of the attribute, but this default can be overridden by the user.
when_measured2tb(two.mspct, col.names = c(when.measured = "time"))
## # A tibble: 2 × 2
## spct.idx time
## <fct> <dttm>
## 1 A 2015-10-31 08:00:00
## 2 B 2015-10-31 09:00:00
Function spct_metadata()
returns the metadata in a
tibble. Unless the user supplies a list of names of attributes, all
applicable metadata values are returned. A single spectrum or a
collection of spectra can be passed. By default columns containing only
missing data are dropped.
spct_metadata(two.mspct)
## # A tibble: 2 × 10
## spct.idx lat lon address when.measured what.…¹ norma…² multi…³
## <fct> <dbl> <dbl> <chr> <dttm> <chr> <dbl> <dbl>
## 1 A 60.2 25.0 Kumpula, Hel… 2015-10-31 08:00:00 sunlig… 0 1
## 2 B 60.2 25.0 Kumpula, Hel… 2015-10-31 09:00:00 sunlig… 0 1
## # … with 2 more variables: time.unit <dbl>, bswf.used <chr>, and abbreviated
## # variable names ¹what.measured, ²normalized, ³multiplier
## # ℹ Use `colnames()` to see all variable names
spct_metadata(two.mspct,
col.names = c("when.measured" = "time",
"where.measured" = "geocode"),
unnest = FALSE)
## # A tibble: 2 × 3
## spct.idx time geocode
## <fct> <dttm> <named list>
## 1 A 2015-10-31 08:00:00 <tibble [1 × 3]>
## 2 B 2015-10-31 09:00:00 <tibble [1 × 3]>
Function add_attr2tb()
adds one or more columns with
attributes to a tibble or data frame. We here also demonstrate that
because the data frame object is passed to the first positional
argument, we can use a pipe. This difference in interface is
the main difference between this function and
spct_metadata()
.
q_irrad(two.mspct) %>%
add_attr2tb(two.mspct,
col.names = c("lon", "lat", "when.measured"))
## # A tibble: 2 × 5
## spct.idx Q_Total lon lat when.measured
## <fct> <dbl> <dbl> <dbl> <dttm>
## 1 A 0.00126 25.0 60.2 2015-10-31 08:00:00
## 2 B 0.00251 25.0 60.2 2015-10-31 09:00:00
We can set the desired names for the columns if we wish them to be something else than the default.
q_irrad(two.mspct) %>%
add_attr2tb(two.mspct,
col.names = c(lon = "longitude",
lat = "latitude",
when.measured = "time"))
## # A tibble: 2 × 5
## spct.idx Q_Total longitude latitude time
## <fct> <dbl> <dbl> <dbl> <dttm>
## 1 A 0.00126 25.0 60.2 2015-10-31 08:00:00
## 2 B 0.00251 25.0 60.2 2015-10-31 09:00:00
When a range of wavelengths or a range of wavelengths plus a spectral
weighting function (SWF) is needed for radiation summaries or
transformations, methods, operators and functions defined in package
‘photobiology’ use waveband
objects to
store these data. A few other bits of information can be included to
fine-tune calculations. The waveband definitions do NOT describe whether
input spectral irradiances are photon or energy based, nor whether the
output irradiance will be based on photon or energy units. All waveband
objects belong to the S3 class waveband
.
A waveband stores the boundaries of a range of wavelengths, \(\lambda_1\) and \(\lambda_2\), so that wavelengths within \(\lambda_1 \ge \lambda > \lambda_2\) belong to the waveband. If the waveband describes a spectral weighting function, in addition to the range, two formulations of the function used to compute the weights as a function of wavelength are also stored, \(w_E(\lambda)\) and \(w_Q(\lambda)\) to be used with energy- or photon based irradiances.
Spectral weighting functions are normally used to compute effective irradiances. In the current implementation their use is limited to this case, while for other summaries only the wavelength range is made use of, even when weighting functions are available.
To create a waveband object we use constructor function
waveband
, and optionally giving a name to it. We
will use these objects in many of the examples below, so you will need
to run the code chunk bellow to be able to reproduce those
examples. It should be noted that waveband constructors for the
most frequently used wavelength-range definitions are provided by
package ‘photobiologyWavebands’.
<- waveband(c(400, 700), wb.name = "PAR")
PAR.wb <- waveband(c(315, 400), wb.name = "UVA")
UVA.wb <- waveband(c(280, 315), wb.name = "UVB")
UVB.wb <- waveband(c(100, 280), wb.name = "UVC")
UVC.wb <- waveband(c(100, 400), wb.name = "UV")
UV.wb <- list(UVC.wb, UVB.wb, UVA.wb) UV_bands.lst
When including a BSWF, we can supply, one or two versions of functions returning the weights as a function of wavelength. Several such functions are defined in package ‘photobiologyWavebands’ as well as waveband constructors using them. Here we show how a waveband can be defined based on a SWF, using the CIE definition for the erythemal spectral weighting function. Although the constructor is smart enough to derive the missing function when only one function is supplied, performance may suffer unless two performance-optimized function are provided, one for energy-based effect and a second one for photon-based effect.
<-
CIE_e_fun function(w.length){
<- numeric(length(w.length))
CIE.energy <= 298] <- 1
CIE.energy[w.length > 298) & (w.length <= 328)] <-
CIE.energy[(w.length 10^(0.094*(298-w.length[(w.length > 298) & (w.length <= 328)]))
> 328) & (w.length <= 400)] <-
CIE.energy[(w.length 10^(0.015*(139-w.length[(w.length > 328) & (w.length <= 400)]))
> 400] <- 0
CIE.energy[w.length return(CIE.energy)
}
<- waveband(c(250, 400), weight = "SWF",
CIE.wb SWF.e.fun = CIE_e_fun, SWF.norm = 298)
Another case where you might want to enter the same function twice, is if you are using an absorptance spectrum as SWF, as the percent of radiation absorbed will be independent of whether photon or energy units are used for the spectral irradiance.
The first argument to waveband()
does not need to be a
numeric vector of length two. Any R object of a class that supplies a
range()
method definition that can be interpreted as a
range of wavelengths in nanometres can be used. As a consequence, when
wanting to construct a waveband covering the whole range of a spectrum
one can simply supply the spectrum as argument, or to construct an
non-weighed waveband which covers exactly the same range of wavelengths
as an existing effective (weighted) waveband, one can supply a waveband
object as an argument.
waveband(sun.spct)
## Total
## low (nm) 280
## high (nm) 800
## weighted none
An “empty” waveband is returned by some functions as a “null” value.
waveband()
## range.NA.NA
## low (nm) NA
## high (nm) NA
## weighted none
The function is.waveband
can the used to query any R
object. This function returns a logical value.
is.waveband(PAR.wb)
## [1] TRUE
Above, we demonstrate that PAR.wb
is a waveband object,
the function photobiologyWavebands::PAR()
is a waveband
constructor returning a waveband object. See package
‘photobiologyWavebands’ for details on pre-defined
waveband constructors for frequently used wavelength ranges and
biological spectral weighting functions (BSWFs).
The function is_effective
can the used to query any R
object.
is_effective(waveband(c(400,500)))
## [1] FALSE
In the current implementation there is no special class used for
storing collections of waveband
objects. We simply use base
R’s list
class.
Just base R’s functions used to create a list object.
<- list(waveband(c(300,400)), waveband(c(400,500)))
wavebands wavebands
## [[1]]
## range.300.400
## low (nm) 300
## high (nm) 400
## weighted none
##
## [[2]]
## range.400.500
## low (nm) 400
## high (nm) 500
## weighted none
The function split_bands
can be used to generate lists
of non-weighed wavebands in two different ways: a) it can be used to
split a range of wavelengths given by an R object into a series of
adjacent wavebands, or b) with a list of objects returning ranges, it
can be used to create non-adjacent and even overlapping wavebands.
The code chunk bellow shows an example of two variations of case a).
With the default value for length.out
of NULL
each numerical value in the input is taken as a wavelength (nm) at the
boundary between adjacent wavebands. If a numerical value is supplied to
length.out
, then the whole wavelength range of the input is
split into this number of equally spaced adjacent wavebands.
split_bands(c(200, 225, 300))
## $wb1
## range.200.225
## low (nm) 200
## high (nm) 225
## weighted none
##
## $wb2
## range.225.300
## low (nm) 225
## high (nm) 300
## weighted none
split_bands(c(200, 225, 300), length.out = 2)
## $wb1
## range.200.250
## low (nm) 200
## high (nm) 250
## weighted none
##
## $wb2
## range.250.300
## low (nm) 250
## high (nm) 300
## weighted none
In both examples above, the output is a list of two wavebands, but the split boundaries are at a different wavelength. The chunk bellow gives a few more examples of the use of case a).
split_bands(sun.spct, length.out = 2)
## $wb1
## range.280.540
## low (nm) 280
## high (nm) 540
## weighted none
##
## $wb2
## range.540.800
## low (nm) 540
## high (nm) 800
## weighted none
split_bands(PAR.wb, length.out = 2)
## $wb1
## range.400.550
## low (nm) 400
## high (nm) 550
## weighted none
##
## $wb2
## range.550.700
## low (nm) 550
## high (nm) 700
## weighted none
split_bands(c(200, 800), length.out = 3)
## $wb1
## range.200.400
## low (nm) 200
## high (nm) 400
## weighted none
##
## $wb2
## range.400.600
## low (nm) 400
## high (nm) 600
## weighted none
##
## $wb3
## range.600.800
## low (nm) 600
## high (nm) 800
## weighted none
Now we demonstrate case b). This case is handled by recursion, so each list element can be anything that is a valid input to the function, including a nested list. However, the returned value is always a flat list of wavebands.
split_bands(list(A = c(200, 300), B = c(400, 500), C = c(250, 350)))
## $A
## range.200.300
## low (nm) 200
## high (nm) 300
## weighted none
##
## $B
## range.400.500
## low (nm) 400
## high (nm) 500
## weighted none
##
## $C
## range.250.350
## low (nm) 250
## high (nm) 350
## weighted none
split_bands(list(c(100, 150, 200), c(800, 825)))
## $wb.a
## range.100.150
## low (nm) 100
## high (nm) 150
## weighted none
##
## $<NA>
## range.150.200
## low (nm) 150
## high (nm) 200
## weighted none
##
## $wb.b
## range.800.825
## low (nm) 800
## high (nm) 825
## weighted none
In case b) if we supply a numeric value to length.out
,
this value is used recursively for each element of the list.
split_bands(UV_bands.lst, length.out = 2)
## $wb.a
## range.100.190
## low (nm) 100
## high (nm) 190
## weighted none
##
## $<NA>
## range.190.280
## low (nm) 190
## high (nm) 280
## weighted none
##
## $wb.b
## range.280.297.5
## low (nm) 280
## high (nm) 298
## weighted none
##
## $<NA>
## range.297.5.315
## low (nm) 298
## high (nm) 315
## weighted none
##
## $wb.c
## range.315.357.5
## low (nm) 315
## high (nm) 358
## weighted none
##
## $<NA>
## range.357.5.400
## low (nm) 358
## high (nm) 400
## weighted none
split_bands(list(c(100, 150, 200), c(800, 825)), length.out = 1)
## $wb.a
## range.100.200
## low (nm) 100
## high (nm) 200
## weighted none
##
## $wb.b
## range.800.825
## low (nm) 800
## high (nm) 825
## weighted none
The print()
method for spectra is based on the method
defined in package ‘tibble’, consequently, it is
possible to use the options from this package to control printing. In
the code chunk below, tibble.print_max
, the number of rows
in the spectral object above which only tibble.print_min
rows are printed, are both set to 5, instead of the default 20 and 10,
to avoid excessive clutter in our examples.
options(tibble.print_max = 4)
options(tibble.print_min = 4)
For explicit calls to print()
its argument
n
can be used to control the number of lines printed. If
n
is set to Inf
the whole spectrum is always
printed. The output differs from that of the print()
method
from package ‘dplyr’ in that additional metadata specific to spectra are
shown.
print(sun.spct, n = 3)
Specialized print()
methods for collections of spectra
and for waveband
objects are also defined.
The summary()
method for spectra is based on base R’s
summary()
method for data frames, and accepts the same
arguments. The main difference is that the attributes containing
metadata and dimensions of the original spectrum object are copied to
the summary object.
summary(sun.spct)
Specialized print()
methods for summaries of spectra are
defined. The output differs from that of the print()
method
from base R in that additional metadata specific to spectra are
shown.
NA
sFunctions na.omit()
and na.exclude
are
implemented for all spectral classes. These methods test for
NA
s only the spectral data, not wavelength. They set the
"na.action"
attribute in the same way as the corresponding
methods for data frames. In the case of na.fail()
,
na.pass()
and na.action()
, the methods from
base R, can be used with spectra.
na.omit(sun.spct)
## Object: source_spct [522 x 3]
## Wavelength range 280-800 nm, step 0.9230769-1 nm
## Label: sunlight, simulated
## Measured on 2010-06-22 09:51:00 UTC
## Measured at 60.20911 N, 24.96474 E; Kumpula, Helsinki, FI
## Time unit 1s
##
## # A tibble: 522 × 3
## w.length s.e.irrad s.q.irrad
## <dbl> <dbl> <dbl>
## 1 280 0 0
## 2 281. 0 0
## 3 282. 0 0
## 4 283. 0 0
## # … with 518 more rows
## # ℹ Use `print(n = ...)` to see more rows
na.exclude(sun.spct)
## Object: source_spct [522 x 3]
## Wavelength range 280-800 nm, step 0.9230769-1 nm
## Label: sunlight, simulated
## Measured on 2010-06-22 09:51:00 UTC
## Measured at 60.20911 N, 24.96474 E; Kumpula, Helsinki, FI
## Time unit 1s
##
## # A tibble: 522 × 3
## w.length s.e.irrad s.q.irrad
## <dbl> <dbl> <dbl>
## 1 280 0 0
## 2 281. 0 0
## 3 282. 0 0
## 4 283. 0 0
## # … with 518 more rows
## # ℹ Use `print(n = ...)` to see more rows
All of R’s built-in maths operators have definitions for spectra. It
is possible to sum, subtract, multiply and divide spectra. These
operators can be used even if the spectral data is on different
arbitrary sets of wavelengths. Operators by default return values
expressed in energy units. Only certain operations are meaningful for a
given combination of objects belonging to different classes, and
meaningless combinations return NA
also issuing a warning
(see Table 5). By default operations are carried out on spectral energy
irradiance for source_spct
objects and transmittance for
filter_spct
objects.
Table 5. Binary operators and their operands.
Validity and class of result. All operations marked
\Y' are allowed, those marked
’ are forbidden and return
NA
and issue a warning. Operators %/%
and
%%
follow /
.
e1 | + |
- |
* |
/ |
^ |
e2 | value |
---|---|---|---|---|---|---|---|
raw_spct |
Y | Y | Y | Y | Y | raw_spct |
raw_spct |
cps_spct |
Y | Y | Y | Y | Y | cps_spct |
cps_spct |
source_spct |
Y | Y | Y | Y | Y | source_spct |
source_spct |
filter_spct (T) |
N | N | Y | Y | N | filter_spct |
filter_spct |
filter_spct (A) |
Y | Y | N | N | N | filter_spct |
filter_spct |
reflector_spct |
N | N | Y | Y | N | reflector_spct |
reflector_spct |
object_spct |
N | N | N | N | N | object_spct |
– |
response_spct |
Y | Y | Y | Y | N | response_spct |
response_spct |
chroma_spct |
Y | Y | Y | Y | Y | chroma_spct |
chroma_spct |
raw_spct |
Y | Y | Y | Y | Y | numeric |
raw_spct |
cps_spct |
Y | Y | Y | Y | Y | numeric |
cps_spct |
calibration_spct |
Y | Y | Y | Y | Y | numeric |
calibration_spct |
source_spct |
Y | Y | Y | Y | Y | numeric |
source_spct |
filter_spct |
Y | Y | Y | Y | Y | numeric |
filter_spct |
reflector_spct |
Y | Y | Y | Y | Y | numeric |
reflector_spct |
object_spct |
N | N | N | N | N | numeric |
– |
response_spct |
Y | Y | Y | Y | Y | numeric |
response_spct |
chroma_spct |
Y | Y | Y | Y | Y | numeric |
chroma_spct |
cps_spct |
N | N | Y | N | N | calibration_spct |
source_spct |
source_spct |
N | N | Y | Y | N | response_spct |
response_spct |
source_spct |
N | N | Y | Y | N | filter_spct (T) |
source_spct |
source_spct |
N | N | Y | Y | N | filter_spct (A) |
source_spct |
source_spct |
N | N | Y | Y | N | reflector_spct |
source_spct |
source_spct |
N | N | N | N | N | object_spct |
– |
source_spct |
N | N | Y | N | N | waveband (no BSWF) |
source_spct |
source_spct |
N | N | Y | N | N | waveband (BSWF) |
source_spct (effective) |
* sun.spct sun.spct
## Object: source_spct [522 x 2]
## Wavelength range 280-800 nm, step 0.9230769-1 nm
## Label: sunlight, simulated
## Measured on 2010-06-22 09:51:00 UTC
## Measured at 60.20911 N, 24.96474 E; Kumpula, Helsinki, FI
## Time unit 1s
##
## # A tibble: 522 × 2
## w.length s.e.irrad
## <dbl> <dbl>
## 1 280 0
## 2 281. 0
## 3 282. 0
## 4 283. 0
## # … with 518 more rows
## # ℹ Use `print(n = ...)` to see more rows
When meaningful, operations between different spectra are also allowed. For example, it is possible to simulate the effect of a filter on a light source by multiplying (or convolving) the two spectra.
* polyester.spct sun.spct
## Object: source_spct [533 x 2]
## Wavelength range 280-800 nm, step 0.07692308-1 nm
## Label: sunlight, simulated
## Measured on 2010-06-22 09:51:00 UTC
## Measured at 60.20911 N, 24.96474 E; Kumpula, Helsinki, FI
## Time unit 1s
##
## # A tibble: 533 × 2
## w.length s.e.irrad
## <dbl> <dbl>
## 1 280 0
## 2 281. 0
## 3 281 0
## 4 282. 0
## # … with 529 more rows
## # ℹ Use `print(n = ...)` to see more rows
If we have two layers of the filter, this can be approximated using either of these two statements.
* polyester.spct * polyester.spct sun.spct
## Object: source_spct [533 x 2]
## Wavelength range 280-800 nm, step 0.07692308-1 nm
## Label: sunlight, simulated
## Measured on 2010-06-22 09:51:00 UTC
## Measured at 60.20911 N, 24.96474 E; Kumpula, Helsinki, FI
## Time unit 1s
##
## # A tibble: 533 × 2
## w.length s.e.irrad
## <dbl> <dbl>
## 1 280 0
## 2 281. 0
## 3 281 0
## 4 282. 0
## # … with 529 more rows
## # ℹ Use `print(n = ...)` to see more rows
* polyester.spct^2 sun.spct
## Object: source_spct [533 x 2]
## Wavelength range 280-800 nm, step 0.07692308-1 nm
## Label: sunlight, simulated
## Measured on 2010-06-22 09:51:00 UTC
## Measured at 60.20911 N, 24.96474 E; Kumpula, Helsinki, FI
## Time unit 1s
##
## # A tibble: 533 × 2
## w.length s.e.irrad
## <dbl> <dbl>
## 1 280 0
## 2 281. 0
## 3 281 0
## 4 282. 0
## # … with 529 more rows
## # ℹ Use `print(n = ...)` to see more rows
Operators are also defined for operations between a spectrum and a numeric vector (with normal recycling).
* 2 sun.spct
## Object: source_spct [522 x 2]
## Wavelength range 280-800 nm, step 0.9230769-1 nm
## Label: sunlight, simulated
## Measured on 2010-06-22 09:51:00 UTC
## Measured at 60.20911 N, 24.96474 E; Kumpula, Helsinki, FI
## Time unit 1s
##
## # A tibble: 522 × 2
## w.length s.e.irrad
## <dbl> <dbl>
## 1 280 0
## 2 281. 0
## 3 282. 0
## 4 283. 0
## # … with 518 more rows
## # ℹ Use `print(n = ...)` to see more rows
2 * sun.spct
## Object: source_spct [522 x 2]
## Wavelength range 280-800 nm, step 0.9230769-1 nm
## Label: sunlight, simulated
## Measured on 2010-06-22 09:51:00 UTC
## Measured at 60.20911 N, 24.96474 E; Kumpula, Helsinki, FI
## Time unit 1s
##
## # A tibble: 522 × 2
## w.length s.e.irrad
## <dbl> <dbl>
## 1 280 0
## 2 281. 0
## 3 282. 0
## 4 283. 0
## # … with 518 more rows
## # ℹ Use `print(n = ...)` to see more rows
* c(0,1) sun.spct
## Object: source_spct [522 x 2]
## Wavelength range 280-800 nm, step 0.9230769-1 nm
## Label: sunlight, simulated
## Measured on 2010-06-22 09:51:00 UTC
## Measured at 60.20911 N, 24.96474 E; Kumpula, Helsinki, FI
## Time unit 1s
##
## # A tibble: 522 × 2
## w.length s.e.irrad
## <dbl> <dbl>
## 1 280 0
## 2 281. 0
## 3 282. 0
## 4 283. 0
## # … with 518 more rows
## # ℹ Use `print(n = ...)` to see more rows
There is one special case, for chroma_spct
: if the
numeric operand has length three, containing three named values
x, y and z, the corresponding value is used
for each of the chromaticity columns in the
chroma_spct
. Un-named values or differently named values
are not treated specially.
Operators are also defined for operations between an spectrum and a
waveband
object. The next to code chunks demonstrate how
the class of the result depends on whether the waveband
object describes a range of wavelengths or a range of wavelengths plus a
BSWF.
* UVB.wb sun.spct
## Object: source_spct [37 x 2]
## Wavelength range 280-315 nm, step 0.9230769-1 nm
## Label: sunlight, simulated
## Measured on 2010-06-22 09:51:00 UTC
## Measured at 60.20911 N, 24.96474 E; Kumpula, Helsinki, FI
## Time unit 1s
##
## # A tibble: 37 × 2
## w.length s.e.irrad
## <dbl> <dbl>
## 1 280 0
## 2 281. 0
## 3 282. 0
## 4 283. 0
## # … with 33 more rows
## # ℹ Use `print(n = ...)` to see more rows
* CIE.wb sun.spct
And of course these operations can be combined into more complex statements, including parentheses, when needed. The example below estimates the difference in effective spectral irradiance according to the CIE98 definition, between sunlight and sunlight filtered with a polyester film. Of course, the result is valid only for the solar spectral data used, which corresponds to Southern Finland.
* CIE.wb - sun.spct * polyester.spct * CIE.wb sun.spct
## Object: source_spct [133 x 2]
## Wavelength range 280-400 nm, step 0.07692308-1 nm
## Label: sunlight, simulated
## Measured on 2010-06-22 09:51:00 UTC
## Measured at 60.20911 N, 24.96474 E; Kumpula, Helsinki, FI
## Time unit 1s
## Data weighted using 'range.250.400.wtd' BSWF
##
## # A tibble: 133 × 2
## w.length s.e.irrad
## <dbl> <dbl>
## 1 280 0
## 2 281. 0
## 3 281 0
## 4 282. 0
## # … with 129 more rows
## # ℹ Use `print(n = ...)` to see more rows
Many common maths functions, as well as unary minus and plus, are implemented for spectral objects (see Table 6).
Table 6. Unary operators and maths functions for
spectra. Classes for which they are implemented and class of
the result. All operations marked Y are allowed, those marked N are not
implemented and return NA
and issue a warning. Additional
supported functions:
log2, log10, sin, cos, tan, asin, acos, atan, sinpi, cospi, tanpi, signif, floor, ceiling, trunc, sign, abs
.
e1 | +, - |
log, exp |
trig. | round |
sqrt |
value |
---|---|---|---|---|---|---|
raw_spct |
Y | Y | Y | Y | Y | raw_spct |
cps_spct |
Y | Y | Y | Y | Y | cps_spct |
calibration_spct |
Y | Y | Y | Y | Y | calibration_spct |
source_spct |
Y | Y | Y | Y | Y | source_spct |
filter_spct |
Y | Y | Y | Y | Y | filter_spct |
reflector_spct |
Y | Y | Y | Y | Y | reflector_spct |
object_spct |
N | N | N | N | N | – |
response_spct |
Y | Y | Y | Y | Y | response_spct |
chroma_spct |
Y | Y | Y | Y | Y | chroma_spct |
-sun.spct
## Warning in range_check(x, strict.range = strict.range): Negative spectral energy
## irradiance values; minimum s.e.irrad = -0.82
## Object: source_spct [522 x 2]
## Wavelength range 280-800 nm, step 0.9230769-1 nm
## Label: sunlight, simulated
## Measured on 2010-06-22 09:51:00 UTC
## Measured at 60.20911 N, 24.96474 E; Kumpula, Helsinki, FI
## Time unit 1s
##
## # A tibble: 522 × 2
## w.length s.e.irrad
## <dbl> <dbl>
## 1 280 0
## 2 281. 0
## 3 282. 0
## 4 283. 0
## # … with 518 more rows
## # ℹ Use `print(n = ...)` to see more rows
sqrt(sun.spct)
## Object: source_spct [522 x 2]
## Wavelength range 280-800 nm, step 0.9230769-1 nm
## Label: sunlight, simulated
## Measured on 2010-06-22 09:51:00 UTC
## Measured at 60.20911 N, 24.96474 E; Kumpula, Helsinki, FI
## Time unit 1s
##
## # A tibble: 522 × 2
## w.length s.e.irrad
## <dbl> <dbl>
## 1 280 0
## 2 281. 0
## 3 282. 0
## 4 283. 0
## # … with 518 more rows
## # ℹ Use `print(n = ...)` to see more rows
Table 7 lists all the recognized options affecting maths operators
and functions, and their default values. Within the suite all functions
have a default value which is used when the options are undefined.
Options are set using base R’s function options
, and
queried with functions options
and
getOption
.
Table 7. Options used in the ‘r4photobiology suite’ and
recognized by methods, operators and functions in the ‘photobiology’
package. Option names, accepted and default values, and the
purpose of the options are given. Option
photobiology.verbose
is set to the value of R’s own
verbose
option at the time the ‘photobiology’ package is
attached to the session.
Option | values , default |
purpose, unit | convenience function |
---|---|---|---|
Base R | |||
digits |
7 | \(d - 3\) used by
summary |
|
tibble | |||
tibble.print_max | 20 | Maximum number of rows printed | |
tibble.print_min | 10 | Number of rows printed if row number threshold is exceeded | |
tibble.width | NULL | Output width | |
r4photobiology | |||
photobiology.radiation.unit | “energy” | \(W\,m^{-2}\,nm^{-1}\) | using_energy() , energy_as_default() |
"photon" |
\(\mu mol\,m^{-2}\,nm^{-1}\) | using_photon() , photon_as_default() |
|
photobiology.filter.qty | “transmittance” | \(/1\) | using_Tfr() , Tfr_as_default() |
"absorptance" |
\(/1\) | using_Afr() , Afr_as_default() |
|
"absorbance" |
a.u. \(\log_{10}\) base | using_A() , A_as_default() |
|
photobiology.strict.range | NA |
skip range test | strict_range_as_default(NA) |
TRUE |
trigger an error | strict_range_as_default(TRUE) |
|
FALSE | trigger a warning | strict_range_as_default(FALSE) |
|
photobiology.check.spct | TRUE | enable check_spct() |
enable_check_spct() |
FALSE |
disable check_spct() |
disable_check_spct() |
|
photobiology.waveband.trim | FALSE |
exclude | wb_trim_as_default(FALSE) |
TRUE | trim or exclude | wb_trim_as_default(TRUE) |
|
photobiology.use.cached.mult | FALSE | do not cache intermediate results | use_cached_mult_as_default(FALSE) |
TRUE |
cache intermediate results | use_cached_mult_as_default(TRUE) |
|
photobiology.verbose | FALSE |
minimal warnings and messages | verbose_as_default(FALSE) |
TRUE |
all warnings and messages | verbose_as_default(TRUE) |
The behaviour of the operators defined in this package depends on the
value of two global options. For example, if we would like the operators
to operate on spectral photon irradiance and return spectral photon
irradiance instead of spectral energy irradiance, this behaviour can be
set, and will remain active until unset or reset. It is possible to
change options using base R’s function options()
as shown
in the next code chunk. The other options listed in the Table above can
be set similarly, while to unset any option, they can be given a
NULL
value.
options(photobiology.radiation.unit = "photon")
* UVB.wb sun.spct
## Object: source_spct [37 x 2]
## Wavelength range 280-315 nm, step 0.9230769-1 nm
## Label: sunlight, simulated
## Measured on 2010-06-22 09:51:00 UTC
## Measured at 60.20911 N, 24.96474 E; Kumpula, Helsinki, FI
## Time unit 1s
##
## # A tibble: 37 × 2
## w.length s.q.irrad
## <dbl> <dbl>
## 1 280 0
## 2 281. 0
## 3 282. 0
## 4 283. 0
## # … with 33 more rows
## # ℹ Use `print(n = ...)` to see more rows
options(photobiology.radiation.unit = "energy")
* UVB.wb sun.spct
## Object: source_spct [37 x 2]
## Wavelength range 280-315 nm, step 0.9230769-1 nm
## Label: sunlight, simulated
## Measured on 2010-06-22 09:51:00 UTC
## Measured at 60.20911 N, 24.96474 E; Kumpula, Helsinki, FI
## Time unit 1s
##
## # A tibble: 37 × 2
## w.length s.e.irrad
## <dbl> <dbl>
## 1 280 0
## 2 281. 0
## 3 282. 0
## 4 283. 0
## # … with 33 more rows
## # ℹ Use `print(n = ...)` to see more rows
However using convenience functions is easier. The chunk above can be rewritten as below.
photon_as_default()
* UVB.wb sun.spct
## Object: source_spct [37 x 2]
## Wavelength range 280-315 nm, step 0.9230769-1 nm
## Label: sunlight, simulated
## Measured on 2010-06-22 09:51:00 UTC
## Measured at 60.20911 N, 24.96474 E; Kumpula, Helsinki, FI
## Time unit 1s
##
## # A tibble: 37 × 2
## w.length s.q.irrad
## <dbl> <dbl>
## 1 280 0
## 2 281. 0
## 3 282. 0
## 4 283. 0
## # … with 33 more rows
## # ℹ Use `print(n = ...)` to see more rows
energy_as_default()
* UVB.wb sun.spct
## Object: source_spct [37 x 2]
## Wavelength range 280-315 nm, step 0.9230769-1 nm
## Label: sunlight, simulated
## Measured on 2010-06-22 09:51:00 UTC
## Measured at 60.20911 N, 24.96474 E; Kumpula, Helsinki, FI
## Time unit 1s
##
## # A tibble: 37 × 2
## w.length s.e.irrad
## <dbl> <dbl>
## 1 280 0
## 2 281. 0
## 3 282. 0
## 4 283. 0
## # … with 33 more rows
## # ℹ Use `print(n = ...)` to see more rows
unset_radiation_unit_default()
Furthermore, it is possible to temporarily change the options for the
evaluation of a single, possibly compound, R expression using a
different syntax, reminiscent of that of R’s with()
.
using_photon(sun.spct * UVB.wb)
## Object: source_spct [37 x 2]
## Wavelength range 280-315 nm, step 0.9230769-1 nm
## Label: sunlight, simulated
## Measured on 2010-06-22 09:51:00 UTC
## Measured at 60.20911 N, 24.96474 E; Kumpula, Helsinki, FI
## Time unit 1s
##
## # A tibble: 37 × 2
## w.length s.q.irrad
## <dbl> <dbl>
## 1 280 0
## 2 281. 0
## 3 282. 0
## 4 283. 0
## # … with 33 more rows
## # ℹ Use `print(n = ...)` to see more rows
using_energy(sun.spct * UVB.wb)
## Object: source_spct [37 x 2]
## Wavelength range 280-315 nm, step 0.9230769-1 nm
## Label: sunlight, simulated
## Measured on 2010-06-22 09:51:00 UTC
## Measured at 60.20911 N, 24.96474 E; Kumpula, Helsinki, FI
## Time unit 1s
##
## # A tibble: 37 × 2
## w.length s.e.irrad
## <dbl> <dbl>
## 1 280 0
## 2 281. 0
## 3 282. 0
## 4 283. 0
## # … with 33 more rows
## # ℹ Use `print(n = ...)` to see more rows
In this section we describe methods and functions that take one or more spectral objects, and in some cases also waveband objects, as arguments and return another spectral object (see Tables 8 and 9) or that take a collection of spectral objects, and in some cases also waveband objects, as arguments and return a collection of spectral objects.
Table 8. Transformation methods for spectra. Key: + available, – not available.
methods | raw/cps | source | response | filter | reflector | object | chroma |
---|---|---|---|---|---|---|---|
merge | + | + | + | + | + | + | + |
rbindspct | + | + | + | + | + | + | + |
e2q, q2e | – | + | + | – | – | – | – |
A2T, T2A | – | – | – | + | – | – | – |
Afr2T, T2Afr | – | – | – | + | – | – | – |
any2T, any2A, any2Afr | – | – | – | + | – | – | – |
convertTfrType | – | – | – | + | – | – | – |
convertThickness | – | – | – | + | – | – | – |
subset | + | + | + | + | + | + | + |
clip_wl | + | + | + | + | + | + | + |
trim_wl | + | + | + | + | + | + | + |
(trim_spct) | + | + | + | + | + | + | + |
thin_wl | + | + | + | + | + | – | – |
interpolate_wl | – | + | + | + | + | + | + |
(interpolate_spct) | – | + | + | + | + | + | + |
fscale | + | + | + | + | + | – | – |
fshift | + | + | + | + | + | – | – |
normalize | + | + | + | + | + | – | – |
clean | – | + | + | + | + | – | – |
despike | – | + | + | + | + | – | – |
maths operators | + | + | + | + | + | + | + |
maths functions | + | + | + | + | + | + | + |
tag | – | + | + | + | + | + | + |
untag | – | + | + | + | + | + | + |
Table 9. Transformation methods for collections of
spectra. Key: + available, – not available, ms
use msmsply()
or convolve_each()
to apply
function or operator to collection members.
methods | raw/cps | source | response | filter | reflector | object | chroma |
---|---|---|---|---|---|---|---|
convolve_each | – | + | + | + | + | + | + |
msmsply | + | + | + | + | + | + | + |
msdply | + | + | + | + | + | + | + |
mslply | + | + | + | + | + | + | + |
msaply | + | + | + | + | + | + | + |
rbindspct | + | + | + | + | + | + | + |
c | + | + | + | + | + | + | + |
maths operators | ms | ms | ms | ms | ms | ms | ms |
maths functions | ms | ms | ms | ms | ms | ms | ms |
e2q, q2e | – | + | + | – | – | – | – |
A2T, T2A | – | – | – | + | – | – | – |
Afr2T, T2Afr | – | – | – | + | – | – | – |
any2T, any2A, any2Afr | – | – | – | + | – | – | – |
convertTfrType | – | – | – | + | – | – | – |
convertThickness | – | – | – | + | – | – | – |
clip_wl | + | + | + | + | + | + | + |
trim_wl | + | + | + | + | + | + | + |
trim2overlap | + | + | + | + | + | + | + |
extend2extremes | + | + | + | + | + | + | + |
(trim_mspct) | + | + | + | + | + | + | + |
thin_wl | + | + | + | + | + | – | – |
interpolate_wl | – | + | + | + | + | + | + |
(interpolate_mspct) | – | + | + | + | + | + | + |
fscale | + | + | + | + | + | – | – |
fshift | + | + | + | + | + | – | – |
normalize | + | + | + | + | + | – | – |
clean | – | + | + | + | + | – | – |
despike | – | + | + | + | + | – | – |
tag | – | + | + | + | + | + | + |
untag | – | + | + | + | + | + | + |
Sometimes, especially for plotting, we may want to row-bind spectra.
When the aim is that the returned object retains its class and other
attributes like the time unit. Package ‘photobiology’
provides function rbinspct
for row-binding spectra, with
the necessary checks for consistency of the bound spectra.
# STOPGAP
<- sun.spct shade.spct
By default an ID factor named spct.idx
is added allow to
identify the source of the observations after the binding. If the
supplied list has named members, then these names are used as factor
levels. If a character value is supplied to as idfactor
argument, this is used as name for the factor.
rbindspct(list(sun.spct, shade.spct))
## Object: source_spct [1,044 x 4]
## containing 2 spectra in long form
## Wavelength range 280-800 nm, step 0.9230769-1 nm
## spct_1 label: sunlight, simulated
## spct_2 label: sunlight, simulated
## spct_1 measured on 2010-06-22 09:51:00 UTC
## spct_2 measured on 2010-06-22 09:51:00 UTC
## Measured at 60.20911 N, 24.96474 E; Kumpula, Helsinki, FI
## Measured at 60.20911 N, 24.96474 E; Kumpula, Helsinki, FI
## Time unit 1s
##
## # A tibble: 1,044 × 4
## w.length s.e.irrad s.q.irrad spct.idx
## <dbl> <dbl> <dbl> <fct>
## 1 280 0 0 spct_1
## 2 281. 0 0 spct_1
## 3 282. 0 0 spct_1
## 4 283. 0 0 spct_1
## # … with 1,040 more rows
## # ℹ Use `print(n = ...)` to see more rows
rbindspct(list(A = sun.spct, B = shade.spct), idfactor = "site")
## Object: source_spct [1,044 x 4]
## containing 2 spectra in long form
## Wavelength range 280-800 nm, step 0.9230769-1 nm
## A label: sunlight, simulated
## B label: sunlight, simulated
## A measured on 2010-06-22 09:51:00 UTC
## B measured on 2010-06-22 09:51:00 UTC
## Measured at 60.20911 N, 24.96474 E; Kumpula, Helsinki, FI
## Measured at 60.20911 N, 24.96474 E; Kumpula, Helsinki, FI
## Time unit 1s
##
## # A tibble: 1,044 × 4
## w.length s.e.irrad s.q.irrad site
## <dbl> <dbl> <dbl> <fct>
## 1 280 0 0 A
## 2 281. 0 0 A
## 3 282. 0 0 A
## 4 283. 0 0 A
## # … with 1,040 more rows
## # ℹ Use `print(n = ...)` to see more rows
The name of the ID factor is stored as metadata in attribute
"idfactor"
of the spectral data object.
Special Extract methods for spectral objects have been implemented. These are used by default and preserve the attributes used by this package, except when the returned value is a single column from the spectral object.
1:10, ] sun.spct[
## Object: source_spct [10 x 3]
## Wavelength range 280-288.30769 nm, step 0.9230769 nm
## Label: sunlight, simulated
## Measured on 2010-06-22 09:51:00 UTC
## Measured at 60.20911 N, 24.96474 E; Kumpula, Helsinki, FI
## Time unit 1s
##
## # A tibble: 10 × 3
## w.length s.e.irrad s.q.irrad
## <dbl> <dbl> <dbl>
## 1 280 0 0
## 2 281. 0 0
## 3 282. 0 0
## 4 283. 0 0
## # … with 6 more rows
## # ℹ Use `print(n = ...)` to see more rows
1:10, 1] sun.spct[
## [1] 280.0000 280.9231 281.8462 282.7692 283.6923 284.6154 285.5385 286.4615
## [9] 287.3846 288.3077
1:10, 1, drop = TRUE] sun.spct[
## [1] 280.0000 280.9231 281.8462 282.7692 283.6923 284.6154 285.5385 286.4615
## [9] 287.3846 288.3077
1:10, "w.length", drop = TRUE] sun.spct[
## [1] 280.0000 280.9231 281.8462 282.7692 283.6923 284.6154 285.5385 286.4615
## [9] 287.3846 288.3077
In contrast to trim_spct
, subset
never
interpolates or inserts hinges. On the other hand, the
subset
argument accepts any logical expression and can be
consequently used to do subsetting, for example, based on factors. Both
subset()
and trim()
methods preserve
attributes.
subset(sun.spct, s.e.irrad > 0.2)
## Object: source_spct [475 x 3]
## Wavelength range 324-800 nm, step 1-3 nm
## Label: sunlight, simulated
## Measured on 2010-06-22 09:51:00 UTC
## Measured at 60.20911 N, 24.96474 E; Kumpula, Helsinki, FI
## Time unit 1s
##
## # A tibble: 475 × 3
## w.length s.e.irrad s.q.irrad
## <dbl> <dbl> <dbl>
## 1 324 0.208 0.000000562
## 2 325 0.217 0.000000589
## 3 326 0.277 0.000000756
## 4 327 0.285 0.000000779
## # … with 471 more rows
## # ℹ Use `print(n = ...)` to see more rows
subset(sun.spct, w.length > 600)
## Object: source_spct [200 x 3]
## Wavelength range 601-800 nm, step 1 nm
## Label: sunlight, simulated
## Measured on 2010-06-22 09:51:00 UTC
## Measured at 60.20911 N, 24.96474 E; Kumpula, Helsinki, FI
## Time unit 1s
##
## # A tibble: 200 × 3
## w.length s.e.irrad s.q.irrad
## <dbl> <dbl> <dbl>
## 1 601 0.630 0.00000316
## 2 602 0.631 0.00000317
## 3 603 0.636 0.00000321
## 4 604 0.658 0.00000332
## # … with 196 more rows
## # ℹ Use `print(n = ...)` to see more rows
subset(sun.spct, c(TRUE, rep(FALSE, 99)))
## Object: source_spct [6 x 3]
## Wavelength range 280-779 nm, step 99-100 nm
## Label: sunlight, simulated
## Measured on 2010-06-22 09:51:00 UTC
## Measured at 60.20911 N, 24.96474 E; Kumpula, Helsinki, FI
## Time unit 1s
##
## # A tibble: 6 × 3
## w.length s.e.irrad s.q.irrad
## <dbl> <dbl> <dbl>
## 1 280 0 0
## 2 379 0.413 0.00000131
## 3 479 0.754 0.00000302
## 4 579 0.647 0.00000313
## 5 679 0.580 0.00000329
## 6 779 0.471 0.00000307
R’s Extract methods $
and [[
can be used to
extract whole columns. Replace methods $<-
and
[<-
have definitions for spectral objects, which allow
their safe use. They work identically to those for data frames but check
the validity of the spectra after the replacement.
The functions e2q
and q2e
can be used on
source spectra to convert spectral energy irradiance into spectral
photon irradiance and vice versa. A second optional argument sets the
action with "add"
and "replace"
as possible
values. By default these functions use normal reference semantics.
e2q(sun.spct, "add")
## Object: source_spct [522 x 3]
## Wavelength range 280-800 nm, step 0.9230769-1 nm
## Label: sunlight, simulated
## Measured on 2010-06-22 09:51:00 UTC
## Measured at 60.20911 N, 24.96474 E; Kumpula, Helsinki, FI
## Time unit 1s
##
## # A tibble: 522 × 3
## w.length s.e.irrad s.q.irrad
## <dbl> <dbl> <dbl>
## 1 280 0 0
## 2 281. 0 0
## 3 282. 0 0
## 4 283. 0 0
## # … with 518 more rows
## # ℹ Use `print(n = ...)` to see more rows
e2q(sun.spct, "replace")
## Object: source_spct [522 x 2]
## Wavelength range 280-800 nm, step 0.9230769-1 nm
## Label: sunlight, simulated
## Measured on 2010-06-22 09:51:00 UTC
## Measured at 60.20911 N, 24.96474 E; Kumpula, Helsinki, FI
## Time unit 1s
##
## # A tibble: 522 × 2
## w.length s.q.irrad
## <dbl> <dbl>
## 1 280 0
## 2 281. 0
## 3 282. 0
## 4 283. 0
## # … with 518 more rows
## # ℹ Use `print(n = ...)` to see more rows
For filter_spct
objects functions any2T()
,
any2A()
, and any2Afr()
allow conversion among
spectral transmittance, spectral absorptance and spectral absorbance.
Although some conversions require a known reflectance, either as an
Rfr
column in the data or an Rfr.constant
in
the attribute filter.properties
.
polyester.spct
## Object: filter_spct [561 x 2]
## Wavelength range 240-800 nm, step 1 nm
## Label: clear polyester film
## Transmittance of type 'total'
## Rfr (/1): 0.07, thickness (mm): 0.125, attenuation mode: absorption.
##
## # A tibble: 561 × 2
## w.length Tfr
## <int> <dbl>
## 1 240 0.00482
## 2 241 0.00464
## 3 242 0.00446
## 4 243 0.00429
## # … with 557 more rows
## # ℹ Use `print(n = ...)` to see more rows
any2Afr(polyester.spct, "add")
## Object: filter_spct [561 x 3]
## Wavelength range 240-800 nm, step 1 nm
## Label: clear polyester film
## Transmittance of type 'total'
## Rfr (/1): 0.07, thickness (mm): 0.125, attenuation mode: absorption.
##
## # A tibble: 561 × 3
## w.length Tfr Afr
## <int> <dbl> <dbl>
## 1 240 0.00482 0.995
## 2 241 0.00464 0.995
## 3 242 0.00446 0.995
## 4 243 0.00429 0.995
## # … with 557 more rows
## # ℹ Use `print(n = ...)` to see more rows
any2Afr(polyester.spct, "replace")
## Object: filter_spct [561 x 2]
## Wavelength range 240-800 nm, step 1 nm
## Label: clear polyester film
## Rfr (/1): 0.07, thickness (mm): 0.125, attenuation mode: absorption.
##
## # A tibble: 561 × 2
## w.length Afr
## <int> <dbl>
## 1 240 0.995
## 2 241 0.995
## 3 242 0.995
## 4 243 0.995
## # … with 557 more rows
## # ℹ Use `print(n = ...)` to see more rows
Normalization is a way rescaling a spectrum so that the spectral quantity takes a fixed value, in most cases exactly 1, at a specific wavelength. Frequently this wavelength corresponds to the maximum value of the spectral quantity.
\[Q_\mathrm{norm}(\lambda) =
\frac{Q(\lambda)}{\max{Q(\lambda)}}\] When normalizing to a
specific wavelength, say 300 nm, the equation becomes \[Q_\mathrm{norm}(\lambda) =
\frac{Q(\lambda)}{{Q(\lambda = 300)}}\] Function
normalize
permits normalizing a spectrum to a value of one
at an arbitrary wavelength (nm) or to the wavelength of either the
maximum or the minimum spectral value. It supports all the different
spectral classes, In the example we use a source_spct
object. (Equivalent functions with names spelled with “s” instead of “z”
are available.)
normalize(sun.spct)
Which is equivalent to supplying "max"
as argument to
norm
, it is also possible to give a range within which the
maximum should be searched.
normalize(sun.spct, range = PAR.wb, norm = "max")
It is also possible to normalize to an arbitrary wavelength within the range of the data, even if it is not one of the wavelength values present in the spectral object, as interpolation is used when needed.
normalize(sun.spct, norm = 600.3)
The normalization status of a spectral object can be tested with
method is_normalized()
and the normalization used can be
recalled with method getNormalized()
.
<- normalize(sun.spct)
my.spct is_normalized(my.spct)
## [1] TRUE
getNormalized(my.spct)
## [1] 451
Once a spectrum is normalized, summary methods that return values in
absolute units such as irrad()
, will trigger an error if
applied. Ratios and similar summaries that are invariant with respect to
normalization can be calculated.
Applying method fscale()
removes the normalization and
clears the corresponding attribute where the normalization information
is stored. This attribute also can be cleared with method
setNormalized()
, but this is rarely valid or of any
use.
While normalization is done with respect to a single wavelength, rescaling as implemented in this package is more flexible. The scaling factor is computed as a summary over a range of wavelengths. This allows us, among other things to rescale spectral irradiance so that irradiance in a specific waveband is equal to one, or to some other user supplied target value.
\[Q^\prime(\lambda) = \frac{Q(\lambda)}{f(Q(\lambda))_{\ \mathrm{for}\ \ \lambda_1\geq\lambda>\lambda_2}}\times \alpha\] where \(\alpha\) is the target value for \(f(Q(\lambda))\).
In other words, function fscale()
rescales a spectrum by
dividing each spectral data value by a value calculated with a function
(f) selected by a character string (“total” or “mean”), or an actual R
function which can accept the spectrum object supplied as its first
argument. Additional named arguments can be also passed.
How metadata is set in the returned object is controlled by a logical
argument to parameter set.scaled
. If TRUE
, the
data are labelled as being expressed in relative units and if
FALSE
this attribute is not set. The default argument
depends on the value passed as argument to target
. If this
value is one, then the data are marked as no longer being expressed in
absolute units. If the target
is any other numeric value
then it is assumed that the intention is to re-scale the data and that
absolute physical units remain meaningful. It is important that the
metadata matches the actual use as printing of summaries and plot
labelling depends on them.
fscale(sun.spct)
## Object: source_spct [522 x 2]
## Wavelength range 280-800 nm, step 0.9230769-1 nm
## Label: sunlight, simulated
## Measured on 2010-06-22 09:51:00 UTC
## Measured at 60.20911 N, 24.96474 E; Kumpula, Helsinki, FI
## Time unit 1s
## Rescaled to 'mean of s.e.irrad' = 1 for wavelengths in 280-800 nm
##
## # A tibble: 522 × 2
## w.length s.e.irrad
## <dbl> <dbl>
## 1 280 0
## 2 281. 0
## 3 282. 0
## 4 283. 0
## # … with 518 more rows
## # ℹ Use `print(n = ...)` to see more rows
fscale(sun.spct, set.scaled = FALSE)
## Object: source_spct [522 x 2]
## Wavelength range 280-800 nm, step 0.9230769-1 nm
## Label: sunlight, simulated
## Measured on 2010-06-22 09:51:00 UTC
## Measured at 60.20911 N, 24.96474 E; Kumpula, Helsinki, FI
## Time unit 1s
##
## # A tibble: 522 × 2
## w.length s.e.irrad
## <dbl> <dbl>
## 1 280 0
## 2 281. 0
## 3 282. 0
## 4 283. 0
## # … with 518 more rows
## # ℹ Use `print(n = ...)` to see more rows
fscale(sun.spct, target = 100)
## Object: source_spct [522 x 2]
## Wavelength range 280-800 nm, step 0.9230769-1 nm
## Label: sunlight, simulated
## Measured on 2010-06-22 09:51:00 UTC
## Measured at 60.20911 N, 24.96474 E; Kumpula, Helsinki, FI
## Time unit 1s
##
## # A tibble: 522 × 2
## w.length s.e.irrad
## <dbl> <dbl>
## 1 280 0
## 2 281. 0
## 3 282. 0
## 4 283. 0
## # … with 518 more rows
## # ℹ Use `print(n = ...)` to see more rows
fscale(sun.spct, target = 100, set.scaled = TRUE)
## Object: source_spct [522 x 2]
## Wavelength range 280-800 nm, step 0.9230769-1 nm
## Label: sunlight, simulated
## Measured on 2010-06-22 09:51:00 UTC
## Measured at 60.20911 N, 24.96474 E; Kumpula, Helsinki, FI
## Time unit 1s
## Rescaled to 'mean of s.e.irrad' = 100 for wavelengths in 280-800 nm
##
## # A tibble: 522 × 2
## w.length s.e.irrad
## <dbl> <dbl>
## 1 280 0
## 2 281. 0
## 3 282. 0
## 4 283. 0
## # … with 518 more rows
## # ℹ Use `print(n = ...)` to see more rows
The default for f
can be overridden. R functions passed
as argument should be suitable for summarizing spectral objects as they
will receive as first argument a spectrum rather than a numeric vector.
Behind this requirement is the need to take into account wavelength
steps for integration to be meaningful. In the example below we compute
energy and photon irradiances. (The character arguments
"mean"
and "total"
call functions specific to
spectral data.)
fscale(sun.spct, f = "integral")
## Object: source_spct [522 x 2]
## Wavelength range 280-800 nm, step 0.9230769-1 nm
## Label: sunlight, simulated
## Measured on 2010-06-22 09:51:00 UTC
## Measured at 60.20911 N, 24.96474 E; Kumpula, Helsinki, FI
## Time unit 1s
## Rescaled to 'integral of s.e.irrad' = 1 for wavelengths in 280-800 nm
##
## # A tibble: 522 × 2
## w.length s.e.irrad
## <dbl> <dbl>
## 1 280 0
## 2 281. 0
## 3 282. 0
## 4 283. 0
## # … with 518 more rows
## # ℹ Use `print(n = ...)` to see more rows
fscale(sun.spct, range = PAR.wb, f = e_irrad)
## Object: source_spct [522 x 2]
## Wavelength range 280-800 nm, step 0.9230769-1 nm
## Label: sunlight, simulated
## Measured on 2010-06-22 09:51:00 UTC
## Measured at 60.20911 N, 24.96474 E; Kumpula, Helsinki, FI
## Time unit 1s
## Rescaled to 'a user supplied R function of s.e.irrad' = 1 for wavelengths in 400-700-none-NULL-NULL-NULL-NULL-c(399.999999999999, 400, 699.999999999999, 700)-PAR-PAR nm
##
## # A tibble: 522 × 2
## w.length s.e.irrad
## <dbl> <dbl>
## 1 280 0
## 2 281. 0
## 3 282. 0
## 4 283. 0
## # … with 518 more rows
## # ℹ Use `print(n = ...)` to see more rows
fscale(sun.spct, range = PAR.wb, f = q_irrad, target = 800e-6)
## Object: source_spct [522 x 2]
## Wavelength range 280-800 nm, step 0.9230769-1 nm
## Label: sunlight, simulated
## Measured on 2010-06-22 09:51:00 UTC
## Measured at 60.20911 N, 24.96474 E; Kumpula, Helsinki, FI
## Time unit 1s
##
## # A tibble: 522 × 2
## w.length s.e.irrad
## <dbl> <dbl>
## 1 280 0
## 2 281. 0
## 3 282. 0
## 4 283. 0
## # … with 518 more rows
## # ℹ Use `print(n = ...)` to see more rows
In the third example, the spectral data is rescaled so that the corresponding photosynthetically-active irradiance is equal to one.
The normalization status of a spectral object can be tested with
method is_normalized()
and the normalization used can be
recalled with method getNormalized()
.
<- fscale(sun.spct)
my.spct is_scaled(my.spct)
## [1] TRUE
getScaled(my.spct)
## $multiplier
## [1] 1.932188
##
## $f
## [1] "mean"
##
## $range
## [1] 280 800
##
## $target
## [1] 1
##
## $cols
## [1] "s.e.irrad"
Once a spectrum is scaled, summary methods that return values in
absolute units such as irrad()
, will trigger a warning if
applied. Ratios and similar summaries that are invariant with respect to
normalization do not trigger warnings.
Applying method normalize()
removes the scaling and
clears the corresponding attribute where the scaling information is
stored. This attribute also can be cleared with method
setScaled()
, and this can be useful is some cases such as
when irradiance has been measured separately from the emission
spectrum.
While re-scaling relies on a multiplicative factor shifting of the scale is done by addition (or subtraction) or constant. This allows us, among other things to remove a baseline computed from a region known to be equal to zero.
\[Q^\prime(\lambda) = Q(\lambda) -
f(Q(\lambda))_{\ \mathrm{for}\ \
\lambda_1\geq\lambda>\lambda_2}\] Function
fshift()
shifts the zero of the scale of a spectrum by
subtracting from each spectral data value a value calculated with a
function (f) selected by a character string (“mean”, “min” or “max”), or
an actual R function which can accept the spectrum object supplied as
its first argument. The range argument selects a region of the spectrum
to be used as reference in the calculation of the summary.
fshift(white_led.source_spct, range = UVB.wb, f = "mean")
## Object: source_spct [1,421 x 2]
## Wavelength range 251.16-898.81 nm, step 0.43-0.48 nm
## Label: led_desk201
## Measured on 2016-12-19 16:19:57 UTC
## Time unit 1s
##
## # A tibble: 1,421 × 2
## w.length s.e.irrad
## <dbl> <dbl>
## 1 251. 0
## 2 252. 0
## 3 252. 0
## 4 253. 0
## # … with 1,417 more rows
## # ℹ Use `print(n = ...)` to see more rows
fshift(sun.spct, range = c(280,290), f = "min")
## Object: source_spct [522 x 2]
## Wavelength range 280-800 nm, step 0.9230769-1 nm
## Label: sunlight, simulated
## Measured on 2010-06-22 09:51:00 UTC
## Measured at 60.20911 N, 24.96474 E; Kumpula, Helsinki, FI
## Time unit 1s
##
## # A tibble: 522 × 2
## w.length s.e.irrad
## <dbl> <dbl>
## 1 280 0
## 2 281. 0
## 3 282. 0
## 4 283. 0
## # … with 518 more rows
## # ℹ Use `print(n = ...)` to see more rows
In the first example, the spectral data shifted so that the mean spectral irradiance becomes zero for the UV-B region. In the second example the minimum value in the range of wavelengths between 280~nm and 290~nm is used as zero reference for the scale.
Method clean()
should be used with care as off-range
values stem almost always from calibration errors or measuring noise.
This function allows one to replace such values, but in many cases a
zero shift or rescaling could be a better option. Even when the
off-range values are the result of random noise, replacing them with the
boundary values can cause bias, by censoring the data. In such cases
smoothing may be applied first to reduce the possible bias caused by
clean()
. Here we create artificial off-range
values by subtracting a constant from each spectrum.
clean(polyester.spct - 0.053)
## Warning in range_check_Tfr(x, strict.range = strict.range): Off-range
## transmittance values [-0.050..0.872] instead of [0..1]
## Object: filter_spct [561 x 2]
## Wavelength range 240-800 nm, step 1 nm
## Label: clear polyester film
## Transmittance of type 'total'
## Rfr (/1): 0.07, thickness (mm): 0.125, attenuation mode: absorption.
##
## # A tibble: 561 × 2
## w.length Tfr
## <int> <dbl>
## 1 240 0
## 2 241 0
## 3 242 0
## 4 243 0
## # … with 557 more rows
## # ℹ Use `print(n = ...)` to see more rows
It is possible to restrict the cleaning to a range of wavelengths and to provide a value to be used as replacement for the off-range data.
clean(sun.spct - 0.01, range = c(280.5, 282), fill = NA)
## Object: source_spct [522 x 2]
## Wavelength range 280-800 nm, step 0.9230769-1 nm
## Label: sunlight, simulated
## Measured on 2010-06-22 09:51:00 UTC
## Measured at 60.20911 N, 24.96474 E; Kumpula, Helsinki, FI
## Time unit 1s
##
## # A tibble: 522 × 2
## w.length s.e.irrad
## <dbl> <dbl>
## 1 280 -0.01
## 2 281. NA
## 3 282. NA
## 4 283. -0.01
## # … with 518 more rows
## # ℹ Use `print(n = ...)` to see more rows
Method despike()
replaces spikes (very narrow peaks, or
valleys) by values estimated from neighbouring pixels. This method
should be also used carefully and the results inspected as it can remove
features of interest from the data. Usually one knows from theory or
experience if spikes can be real features or not.
spikes(sun.spct)
## Object: source_spct [2 x 2]
## Wavelength range 398-432 nm, step 34 nm
## Label: sunlight, simulated
## Measured on 2010-06-22 09:51:00 UTC
## Measured at 60.20911 N, 24.96474 E; Kumpula, Helsinki, FI
## Time unit 1s
##
## # A tibble: 2 × 2
## w.length s.e.irrad
## <dbl> <dbl>
## 1 398 0.504
## 2 432 0.646
<- despike(sun.spct)
my_sun.spct spikes(my_sun.spct)
## Object: source_spct [0 x 2]
## Label: sunlight, simulated
## Measured on 2010-06-22 09:51:00 UTC
## Measured at 60.20911 N, 24.96474 E; Kumpula, Helsinki, FI
## Time unit 1s
##
## # A tibble: 0 × 2
## # … with 2 variables: w.length <dbl>, s.e.irrad <dbl>
## # ℹ Use `colnames()` to see all variable names
We can use smoothing both to average out random variation among
nearby pixels caused by measuring noise, or to filter out the real fine
structure of a spectrum to better assess the larger features. The
methods described here work by averaging the spectral data from
neighbouring wavelengths. The simplest methods are running medians and
running means (or “boxcar smoothing” in the terminology used in some
software). There are several methods for smoothing available in R based
on different algorithms. Some of these methods also automatically set
the degree of smoothing based on the data being smoothed. Package
‘photobiology’ defines function smooth_spct
, which at the
moment supports three different methods. Two are wrappers on R’s own
methods and a third one, "custom"
, is designed to use
stronger smoothing for values close to zero, where noise in spectral
irradiance measurements is proportionally more. The strength of the
smoothing and the range of wavelengths operated upon can be adjusted
through arguments to parameters. The comment
attribute is
updated.
smooth_spct(sun.spct)
## Object: source_spct [522 x 3]
## Wavelength range 280-800 nm, step 0.9230769-1 nm
## Label: sunlight, simulated
## Measured on 2010-06-22 09:51:00 UTC
## Measured at 60.20911 N, 24.96474 E; Kumpula, Helsinki, FI
## Time unit 1s
##
## # A tibble: 522 × 3
## w.length s.e.irrad s.q.irrad
## <dbl> <dbl> <dbl>
## 1 280 0 0
## 2 281. 0 0
## 3 282. 0 0
## 4 283. 0 0
## # … with 518 more rows
## # ℹ Use `print(n = ...)` to see more rows
smooth_spct(polyester.spct, method = "supsmu", strength = 2)
## Object: filter_spct [561 x 2]
## Wavelength range 240-800 nm, step 1 nm
## Label: clear polyester film
## Transmittance of type 'total'
## Rfr (/1): 0.07, thickness (mm): 0.125, attenuation mode: absorption.
##
## # A tibble: 561 × 2
## w.length Tfr
## <int> <dbl>
## 1 240 0.00460
## 2 241 0.00453
## 3 242 0.00445
## 4 243 0.00438
## # … with 557 more rows
## # ℹ Use `print(n = ...)` to see more rows
Converting spectra available at a given set of wavelengths values to
a different one, is frequently needed when operating with several
spectra of different origin. One can increase the apparent
resolution by interpolation, and reduce it by local averaging or
smoothing and resampling. The same function works on all
spct
objects, interpolating every numeric column except
w.length
which is set to the new wavelength values supplied
as argument. The optional argument fill.value
controls what
value is assigned to the “interpolated” data columns at wavelengths in
the new data that are outside the range of wavelengths in the original
spectrum being interpolated.
interpolate_wl(sun.spct, seq(400, 500, by = 0.1))
## Object: source_spct [1,001 x 3]
## Wavelength range 400-500 nm, step 0.1 nm
## Label: sunlight, simulated
## Measured on 2010-06-22 09:51:00 UTC
## Measured at 60.20911 N, 24.96474 E; Kumpula, Helsinki, FI
## Time unit 1s
##
## # A tibble: 1,001 × 3
## w.length s.e.irrad s.q.irrad
## <dbl> <dbl> <dbl>
## 1 400 0.608 0.00000203
## 2 400. 0.610 0.00000204
## 3 400. 0.612 0.00000205
## 4 400. 0.614 0.00000205
## # … with 997 more rows
## # ℹ Use `print(n = ...)` to see more rows
clip_wl()
Sometimes it is desirable to change the range of wavelengths included
in a spectrum. If we are interested in a given part of the spectrum,
there is no need to do calculations or plotting the whole spectrum. To
select part of a spectrum based on a range of wavelengths we may use the
clip_wl()
method. Method clip_wl()
simply
selects a range from the existing spectrum, and unless the range exactly
matches the wavelength values present in the spectrum, the range of
wavelengths in the returned clipped spectrum will be slightly narrower
than the requested by range
.
The range of wavelengths expressed in nanometres can be given as numeric vector of length two.
clip_wl(sun.spct, range = c(400, 402))
## Object: source_spct [3 x 3]
## Wavelength range 400-402 nm, step 1 nm
## Label: sunlight, simulated
## Measured on 2010-06-22 09:51:00 UTC
## Measured at 60.20911 N, 24.96474 E; Kumpula, Helsinki, FI
## Time unit 1s
##
## # A tibble: 3 × 3
## w.length s.e.irrad s.q.irrad
## <dbl> <dbl> <dbl>
## 1 400 0.608 0.00000203
## 2 401 0.626 0.00000210
## 3 402 0.650 0.00000218
clip_wl(sun.spct, range = c(400, NA))
## Object: source_spct [401 x 3]
## Wavelength range 400-800 nm, step 1 nm
## Label: sunlight, simulated
## Measured on 2010-06-22 09:51:00 UTC
## Measured at 60.20911 N, 24.96474 E; Kumpula, Helsinki, FI
## Time unit 1s
##
## # A tibble: 401 × 3
## w.length s.e.irrad s.q.irrad
## <dbl> <dbl> <dbl>
## 1 400 0.608 0.00000203
## 2 401 0.626 0.00000210
## 3 402 0.650 0.00000218
## 4 403 0.621 0.00000209
## # … with 397 more rows
## # ℹ Use `print(n = ...)` to see more rows
As for other methods in the package, the range can be also supplied
as a waveband
object, or any other object for which
range()
returns a numeric range. Even a different spectrum
object is acceptable, and in many cases useful.
clip_wl(sun.spct, range = UVA.wb)
## Object: source_spct [86 x 3]
## Wavelength range 315-400 nm, step 1 nm
## Label: sunlight, simulated
## Measured on 2010-06-22 09:51:00 UTC
## Measured at 60.20911 N, 24.96474 E; Kumpula, Helsinki, FI
## Time unit 1s
##
## # A tibble: 86 × 3
## w.length s.e.irrad s.q.irrad
## <dbl> <dbl> <dbl>
## 1 315 0.113 0.000000297
## 2 316 0.102 0.000000270
## 3 317 0.149 0.000000394
## 4 318 0.141 0.000000376
## # … with 82 more rows
## # ℹ Use `print(n = ...)` to see more rows
The result can be a spectrum of length zero.
clip_wl(sun.spct, range = c(100, 200))
## Object: source_spct [0 x 3]
## Label: sunlight, simulated
## Measured on 2010-06-22 09:51:00 UTC
## Measured at 60.20911 N, 24.96474 E; Kumpula, Helsinki, FI
## Time unit 1s
##
## # A tibble: 0 × 3
## # … with 3 variables: w.length <dbl>, s.e.irrad <dbl>, s.q.irrad <dbl>
## # ℹ Use `colnames()` to see all variable names
trim_wl()
Sometimes, we need more flexibility. We may want to replace the observed values outside a certain range or expand the range of wavelengths, filling the expansion of all other variables with a certain value (i.e. a number, or NA.). In contrast to clipping (or functionally equivalent, indexing, or subsetting), trimming ensures that there will be spectral data returned at the boundaries of the trimmed region. These values are obtained by interpolation when they are not already present in the data.
More flexibility is available in method trim_wl()
, to
which we can supply arguments range
,
use.hinges
, and fill
. By default interpolation
is used at the boundaries of the range
, in which case the
range of wavelengths in the returned spectrum is that passed as argument
to range
.
trim_wl(sun.spct, c(282.5, NA))
## Object: source_spct [520 x 3]
## Wavelength range 282.5-800 nm, step 0.2692308-1 nm
## Label: sunlight, simulated
## Measured on 2010-06-22 09:51:00 UTC
## Measured at 60.20911 N, 24.96474 E; Kumpula, Helsinki, FI
## Time unit 1s
##
## # A tibble: 520 × 3
## w.length s.e.irrad s.q.irrad
## <dbl> <dbl> <dbl>
## 1 282. 0 0
## 2 283. 0 0
## 3 284. 0 0
## 4 285. 0 0
## # … with 516 more rows
## # ℹ Use `print(n = ...)` to see more rows
clip_wl(sun.spct, c(282.5, NA))
## Object: source_spct [519 x 3]
## Wavelength range 282.76923-800 nm, step 0.9230769-1 nm
## Label: sunlight, simulated
## Measured on 2010-06-22 09:51:00 UTC
## Measured at 60.20911 N, 24.96474 E; Kumpula, Helsinki, FI
## Time unit 1s
##
## # A tibble: 519 × 3
## w.length s.e.irrad s.q.irrad
## <dbl> <dbl> <dbl>
## 1 283. 0 0
## 2 284. 0 0
## 3 285. 0 0
## 4 286. 0 0
## # … with 515 more rows
## # ℹ Use `print(n = ...)` to see more rows
As for clip_wl()
the range can be also supplied as a
waveband
object, or any other object for which
range()
returns a numeric range. Even a different spectrum
object is acceptable.
trim_wl(sun.spct, PAR.wb)
## Object: source_spct [301 x 3]
## Wavelength range 400-700 nm, step 1 nm
## Label: sunlight, simulated
## Measured on 2010-06-22 09:51:00 UTC
## Measured at 60.20911 N, 24.96474 E; Kumpula, Helsinki, FI
## Time unit 1s
##
## # A tibble: 301 × 3
## w.length s.e.irrad s.q.irrad
## <dbl> <dbl> <dbl>
## 1 400 0.608 0.00000203
## 2 401 0.626 0.00000210
## 3 402 0.650 0.00000218
## 4 403 0.621 0.00000209
## # … with 297 more rows
## # ℹ Use `print(n = ...)` to see more rows
The default for fill
is NULL
which results
in deletion values outside the trimmed region. However, it is possible
to supply a different argument, to be used to replace the off-range data
values.
trim_wl(sun.spct, c(281.5, NA), fill = NA)
## Object: source_spct [524 x 3]
## Wavelength range 280-800 nm, step 1.023182e-12-1 nm
## Label: sunlight, simulated
## Measured on 2010-06-22 09:51:00 UTC
## Measured at 60.20911 N, 24.96474 E; Kumpula, Helsinki, FI
## Time unit 1s
##
## # A tibble: 524 × 3
## w.length s.e.irrad s.q.irrad
## <dbl> <dbl> <dbl>
## 1 280 NA NA
## 2 281. NA NA
## 3 281. NA NA
## 4 282. 0 0
## # … with 520 more rows
## # ℹ Use `print(n = ...)` to see more rows
Furthermore, when fill is not NULL
, expansion is
possible.
trim_wl(sun.spct, c(275, NA), fill = 0)
## Object: source_spct [529 x 3]
## Wavelength range 275-800 nm, step 1.023182e-12-1 nm
## Label: sunlight, simulated
## Measured on 2010-06-22 09:51:00 UTC
## Measured at 60.20911 N, 24.96474 E; Kumpula, Helsinki, FI
## Time unit 1s
##
## # A tibble: 529 × 3
## w.length s.e.irrad s.q.irrad
## <dbl> <dbl> <dbl>
## 1 275 0 0
## 2 276. 0 0
## 3 277. 0 0
## 4 277. 0 0
## # … with 525 more rows
## # ℹ Use `print(n = ...)` to see more rows
By default interpolation at the boundaries is used, but setting
use.hinges
to FALSE
results in clipping, a
behaviour similar to that of clip_wl
only if
fill == NULL
.
trim_wl(sun.spct, c(281.5, NA), fill = NA)
## Object: source_spct [524 x 3]
## Wavelength range 280-800 nm, step 1.023182e-12-1 nm
## Label: sunlight, simulated
## Measured on 2010-06-22 09:51:00 UTC
## Measured at 60.20911 N, 24.96474 E; Kumpula, Helsinki, FI
## Time unit 1s
##
## # A tibble: 524 × 3
## w.length s.e.irrad s.q.irrad
## <dbl> <dbl> <dbl>
## 1 280 NA NA
## 2 281. NA NA
## 3 281. NA NA
## 4 282. 0 0
## # … with 520 more rows
## # ℹ Use `print(n = ...)` to see more rows
trim_wl(sun.spct, c(281.5, NA), fill = NA, use.hinges = FALSE)
## Object: source_spct [522 x 3]
## Wavelength range 280-800 nm, step 0.9230769-1 nm
## Label: sunlight, simulated
## Measured on 2010-06-22 09:51:00 UTC
## Measured at 60.20911 N, 24.96474 E; Kumpula, Helsinki, FI
## Time unit 1s
##
## # A tibble: 522 × 3
## w.length s.e.irrad s.q.irrad
## <dbl> <dbl> <dbl>
## 1 280 NA NA
## 2 281. NA NA
## 3 282. 0 0
## 4 283. 0 0
## # … with 518 more rows
## # ℹ Use `print(n = ...)` to see more rows
When use.hinges == TRUE
and expansion or replacement is
done, two observations are inserted at each boundary, differing in
wavelength by \(1 \times 10^{-12}\),nm
to prevent rounding errors in later calculations.
trim2ovelap()
and
extend2extremes()
Functions trim2ovelap()
and
extend2extremes()
are defined only for collections of
spectra. They are convenience functions, as they handle special use
cases of trim_wl()
with a simplified syntax. They can be
used to make the wavelength range of the different members of a
collection of spectra consistent, either by trimming all spectra to the
range of overlapping wavelengths, or by extending the wavelength ranges
as needed and filling the added spectral values with a constant
value.
trim2overlap(two.mspct)
## Object: source_mspct [2 x 1]
## --- Member: A ---
## Object: source_spct [522 x 2]
## Wavelength range 280-800 nm, step 0.9230769-1 nm
## Label: sunlight, simulated
## Measured on 2015-10-31 08:00:00 UTC
## Measured at 60.20911 N, 24.96474 E; Kumpula, Helsinki, FI
## Time unit 1s
##
## # A tibble: 522 × 2
## w.length s.e.irrad
## <dbl> <dbl>
## 1 280 0
## 2 281. 0
## 3 282. 0
## 4 283. 0
## # … with 518 more rows
## # ℹ Use `print(n = ...)` to see more rows
## --- Member: B ---
## Object: source_spct [522 x 2]
## Wavelength range 280-800 nm, step 0.9230769-1 nm
## Label: sunlight, simulated
## Measured on 2015-10-31 09:00:00 UTC
## Measured at 60.20911 N, 24.96474 E; Kumpula, Helsinki, FI
## Time unit 1s
##
## # A tibble: 522 × 2
## w.length s.e.irrad
## <dbl> <dbl>
## 1 280 0
## 2 281. 0
## 3 282. 0
## 4 283. 0
## # … with 518 more rows
## # ℹ Use `print(n = ...)` to see more rows
##
## --- END ---
extend2extremes(two.mspct, fill = 0)
## Object: source_mspct [2 x 1]
## --- Member: A ---
## Object: source_spct [522 x 2]
## Wavelength range 280-800 nm, step 0.9230769-1 nm
## Label: sunlight, simulated
## Measured on 2015-10-31 08:00:00 UTC
## Measured at 60.20911 N, 24.96474 E; Kumpula, Helsinki, FI
## Time unit 1s
##
## # A tibble: 522 × 2
## w.length s.e.irrad
## <dbl> <dbl>
## 1 280 0
## 2 281. 0
## 3 282. 0
## 4 283. 0
## # … with 518 more rows
## # ℹ Use `print(n = ...)` to see more rows
## --- Member: B ---
## Object: source_spct [522 x 2]
## Wavelength range 280-800 nm, step 0.9230769-1 nm
## Label: sunlight, simulated
## Measured on 2015-10-31 09:00:00 UTC
## Measured at 60.20911 N, 24.96474 E; Kumpula, Helsinki, FI
## Time unit 1s
##
## # A tibble: 522 × 2
## w.length s.e.irrad
## <dbl> <dbl>
## 1 280 0
## 2 281. 0
## 3 282. 0
## 4 283. 0
## # … with 518 more rows
## # ℹ Use `print(n = ...)` to see more rows
##
## --- END ---
thin_wl()
One possible way of decreasing the storage space occupied by spectral
data is to vary the density of wavelength values stored based on the
local change in slope (second derivative) of the plot a spectrum. Method
thin_wl()
can be used to remove or “thin” down the
wavelength values stored in those regions of the spectrum where this
would result in minimal loss of information. The algorithm currently in
use is suboptimal in the removal of wavelength values but fast and easy
to implement. Which wavelength values are retained or not could
change with future implementations.
nrow(yellow_gel.spct)
## [1] 611
wl_stepsize(yellow_gel.spct)
## [1] 1 1
<- thin_wl(yellow_gel.spct)
thinned.spct nrow(thinned.spct)
## [1] 267
wl_stepsize(thinned.spct)
## [1] 1 8
The strength of the thinning can be adjusted by passing arguments to
parameters max.wl.step
and max.slope.delta
.
This method is implemented for objects of all spectral classes that a
single default data column in addition to wavelengths and also for
collections of those objects.
It is very instructive to look at weighted spectral data to understand how effective irradiances are calculated. Plotting effective spectral irradiance data can be very informative when analysing interactions among photoreceptors and ambient radiation. It can also illustrate the large effect that small measuring errors can have on the estimated effective irradiances or exposures when SWFs have a steep slope.
For biologically effective energy irradiance \(E_\mathrm{BE}\) the following equation describes the convolution, wavelength by wavelength, between spectral energy irradiance and a biological spectral weighting function
\[E_\mathrm{BE}(\lambda) = E(\lambda) \times w_E(\lambda)\] or for biologically effective photon irradiance \(Q_\mathrm{BE}\) \[Q_\mathrm{BE}(\lambda) = Q(\lambda) \times w_Q(\lambda)\] For the convolution to be possible, both spectral irradiance and spectral weights should be available for the same basis of expression and at the same discrete wavelength values.
The multiplication operator is defined for operations between a
source_spct
and a waveband
, so this is the
easiest way of doing the calculations.
* CIE.wb sun.spct
## Object: source_spct [122 x 2]
## Wavelength range 280-400 nm, step 0.9230769-1 nm
## Label: sunlight, simulated
## Measured on 2010-06-22 09:51:00 UTC
## Measured at 60.20911 N, 24.96474 E; Kumpula, Helsinki, FI
## Time unit 1s
## Data weighted using 'range.250.400.wtd' BSWF
##
## # A tibble: 122 × 2
## w.length s.e.irrad
## <dbl> <dbl>
## 1 280 0
## 2 281. 0
## 3 282. 0
## 4 283. 0
## # … with 118 more rows
## # ℹ Use `print(n = ...)` to see more rows
We call tagging, to the process of adding reference information to spectral data. For example we can add a factor indicating regions or bands in the spectrum. We can add also information on the colour, as seen by humans, for each observed value, or for individual regions or bands of the spectrum. In most cases this additional information is used for annotations when plotting the spectral data.
The function tag
can be used to tag different parts of a
spectrum according to wavebands.
tag(sun.spct, PAR.wb)
## Object: source_spct [524 x 6]
## Wavelength range 280-800 nm, step 1.023182e-12-1 nm
## Label: sunlight, simulated
## Measured on 2010-06-22 09:51:00 UTC
## Measured at 60.20911 N, 24.96474 E; Kumpula, Helsinki, FI
## Time unit 1s
##
## # A tibble: 524 × 6
## w.length s.e.irrad s.q.irrad wl.color wb.color wb.f
## <dbl> <dbl> <dbl> <chr> <chr> <fct>
## 1 280 0 0 #000000 <NA> <NA>
## 2 281. 0 0 #000000 <NA> <NA>
## 3 282. 0 0 #000000 <NA> <NA>
## 4 283. 0 0 #000000 <NA> <NA>
## # … with 520 more rows
## # ℹ Use `print(n = ...)` to see more rows
tag(sun.spct, UV_bands.lst)
## Object: source_spct [524 x 6]
## Wavelength range 280-800 nm, step 1.023182e-12-1 nm
## Label: sunlight, simulated
## Measured on 2010-06-22 09:51:00 UTC
## Measured at 60.20911 N, 24.96474 E; Kumpula, Helsinki, FI
## Time unit 1s
##
## # A tibble: 524 × 6
## w.length s.e.irrad s.q.irrad wl.color wb.color wb.f
## <dbl> <dbl> <dbl> <chr> <chr> <fct>
## 1 280 0 0 #000000 black UVB
## 2 281. 0 0 #000000 black UVB
## 3 282. 0 0 #000000 black UVB
## 4 283. 0 0 #000000 black UVB
## # … with 520 more rows
## # ℹ Use `print(n = ...)` to see more rows
The added factor and colour data can be used for further processing
or for plotting. Information about the tagging and wavebands is stored
in an attribute tag.attr
in every tagged spectrum, this
yields a more compact output and keeps a trace of the
tagging.
<- tag(sun.spct, PAR.wb)
tg.sun.spct attr(tg.sun.spct, "spct.tags")
## $valid
## [1] TRUE
##
## $time.unit
## [1] "second"
##
## $wb.key.name
## [1] "Bands"
##
## $wl.color
## [1] TRUE
##
## $wb.color
## [1] TRUE
##
## $wb.num
## [1] 1
##
## $wb.colors
## [1] "#735B57"
##
## $wb.names
## [1] "PAR"
##
## $wb.list
## $wb.list[[1]]
## PAR
## low (nm) 400
## high (nm) 700
## weighted none
Additional functions are available which return a tagged spectrum and take as input a list of wavebands, but no spectral data. They build a spectrum from the data in the wavebands, and are useful for plotting the boundaries of wavebands.
wb2tagged_spct(UV_bands.lst)
## Object: generic_spct [8 x 12]
## Wavelength range 100-400 nm, step 9.947598e-13-180 nm
##
## # A tibble: 8 × 12
## w.len…¹ counts cps s.e.i…² s.q.i…³ Tfr Rfl s.e.r…⁴ wl.co…⁵ wb.co…⁶ wb.f
## <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <chr> <chr> <fct>
## 1 100. 0 0 0 0 0 0 0 #000000 <NA> <NA>
## 2 100 0 0 0 0 0 0 0 #000000 black UVC
## 3 280. 0 0 0 0 0 0 0 #000000 black UVC
## 4 280 0 0 0 0 0 0 0 #000000 black UVB
## # … with 4 more rows, 1 more variable: y <dbl>, and abbreviated variable names
## # ¹w.length, ²s.e.irrad, ³s.q.irrad, ⁴s.e.response, ⁵wl.color, ⁶wb.color
## # ℹ Use `print(n = ...)` to see more rows, and `colnames()` to see all variable names
wb2rect_spct(UV_bands.lst)
## Object: generic_spct [3 x 15]
## Wavelength range 190-357.5 nm, step 60-107.5 nm
##
## # A tibble: 3 × 15
## w.length counts cps s.e.irrad s.q.irrad Tfr Rfl s.e.re…¹ wl.co…² wb.co…³
## <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <chr> <chr>
## 1 190 0 0 0 0 0 0 0 #000000 black
## 2 298. 0 0 0 0 0 0 0 #000000 black
## 3 358. 0 0 0 0 0 0 0 #000000 #02000F
## # … with 5 more variables: wb.name <chr>, wb.f <fct>, wl.high <dbl>,
## # wl.low <dbl>, y <dbl>, and abbreviated variable names ¹s.e.response,
## # ²wl.color, ³wb.color
## # ℹ Use `colnames()` to see all variable names
Function wb2tagged_spct
returns a tagged spectrum, with
two rows for each waveband, corresponding to the low and high wavelength
boundaries, while function wb2rect_spct
returns a spectrum
with only one row per waveband, with w.length
set to its
midpoint but with additional columns xmin
and
xmax
corresponding to the low and high wavelength
boundaries of the wavebands.
Function is_tagged
can be used to query if an spectrum
is tagged or not, and function untag
removes the tags.
tg.sun.spct
## Object: source_spct [524 x 6]
## Wavelength range 280-800 nm, step 1.023182e-12-1 nm
## Label: sunlight, simulated
## Measured on 2010-06-22 09:51:00 UTC
## Measured at 60.20911 N, 24.96474 E; Kumpula, Helsinki, FI
## Time unit 1s
##
## # A tibble: 524 × 6
## w.length s.e.irrad s.q.irrad wl.color wb.color wb.f
## <dbl> <dbl> <dbl> <chr> <chr> <fct>
## 1 280 0 0 #000000 <NA> <NA>
## 2 281. 0 0 #000000 <NA> <NA>
## 3 282. 0 0 #000000 <NA> <NA>
## 4 283. 0 0 #000000 <NA> <NA>
## # … with 520 more rows
## # ℹ Use `print(n = ...)` to see more rows
is_tagged(tg.sun.spct)
## [1] TRUE
<- untag(tg.sun.spct)
untg.sun.spct is_tagged(untg.sun.spct)
## [1] FALSE
In the chuck above, we can see how this works, using in this case the
default byref = FALSE
which adds the tags to a copy of the
spectrum object. In contrast, setting byref = TRUE
adds the
tags in place, or “by reference”“, to the spct object supplied as
argument. Passing arguments by reference is unusual for R and is best
avoided.
is_tagged(untg.sun.spct)
## [1] FALSE
untag(tg.sun.spct, byref = TRUE)
## Object: source_spct [524 x 3]
## Wavelength range 280-800 nm, step 1.023182e-12-1 nm
## Label: sunlight, simulated
## Measured on 2010-06-22 09:51:00 UTC
## Measured at 60.20911 N, 24.96474 E; Kumpula, Helsinki, FI
## Time unit 1s
##
## # A tibble: 524 × 3
## w.length s.e.irrad s.q.irrad
## <dbl> <dbl> <dbl>
## 1 280 0 0
## 2 281. 0 0
## 3 282. 0 0
## 4 283. 0 0
## # … with 520 more rows
## # ℹ Use `print(n = ...)` to see more rows
is_tagged(untg.sun.spct)
## [1] FALSE
Summaries can be calculated both from individual spectral objects (Table 10) and from collections of spectral objects (Table 11). They return a simpler object than the spectral data in their arguments. For example a vector of numeric values, possibly of length one, in the case of individual spectra, or a data frame containing one row of summary data for each spectrum in a collection of spectra.
Table 10. Summary methods for spectra. Key: + available, - not available, (+) object_spct objects can be converted into filter_spct or reflector_spct objects before applying these methods.
methods | raw/cps | source | response | filter | reflector | object | chroma |
---|---|---|---|---|---|---|---|
irrad | – | + | – | – | – | – | – |
e_irrad | – | + | – | – | – | – | – |
q_irrad | – | + | – | – | – | – | – |
fluence | – | + | – | – | – | – | – |
e_fluence | – | + | – | – | – | – | – |
q_fluence | – | + | – | – | – | – | – |
ratio | – | + | – | – | – | – | – |
e_ratio | – | + | – | – | – | – | – |
q_ratio | – | + | – | – | – | – | – |
qe_ratio | – | + | – | – | – | – | – |
eq_ratio | – | + | – | – | – | – | – |
response | – | – | + | – | – | – | – |
e_response | – | – | + | – | – | – | – |
q_response | – | – | + | – | – | – | – |
transmittance | – | – | – | + | – | + | – |
absorptance | – | – | – | + | – | + | – |
absorbance | – | – | – | + | – | + | – |
reflectance | – | – | – | – | + | + | – |
wl_range | + | + | + | + | + | + | + |
wl_min | + | + | + | + | + | + | + |
wl_max | + | + | + | + | + | + | + |
wl_stepsize | + | + | + | + | + | + | + |
wl_expanse | + | + | + | + | + | + | + |
wl_midpoint | + | + | + | + | + | + | + |
labels | + | + | + | + | + | + | + |
summary | + | + | + | + | + | + | + |
peaks | – | + | + | + | + | (+) | - |
spikes | – | + | + | + | + | (+) | - |
valleys | – | + | + | + | + | (+) | - |
wls_at_target | – | + | + | + | + | (+) | - |
integrate_spct | + | + | + | + | + | + | + |
average_spct | + | + | + | + | + | + | + |
color_of | – | + | – | – | – | – | – |
As mentioned above, summary methods for collections of spectra return
data frame objects. In many cases preserving the attributes from the
different members of the collection in the returned value is important,
and can be achieved easily by passing a suitable character vector as
argument to parameter attr2tb
, using the same syntax as
described for function add_attr2tb
.
Table 11. Summary methods for collections of
spectra. Key: + available, * attr2tb
supported, –
not available, ms use msmsply()
to apply
function to collection members, d use
msdply()
, l use mslply
to
apply function to collection members, a use
msaply
to apply function to collection members.
methods | raw/cps | source | response | filter | reflector | object | chroma |
---|---|---|---|---|---|---|---|
irrad | – | * | – | – | – | – | – |
e_irrad | – | * | – | – | – | – | – |
q_irrad | – | * | – | – | – | – | – |
fluence | – | * | – | – | – | – | – |
e_fluence | – | * | – | – | – | – | – |
q_fluence | – | * | – | – | – | – | – |
ratio | – | * | – | – | – | – | – |
e_ratio | – | * | – | – | – | – | – |
q_ratio | – | * | – | – | – | – | – |
qe_ratio | – | * | – | – | – | – | – |
eq_ratio | – | * | – | – | – | – | – |
response | – | – | * | – | – | – | – |
e_response | – | – | * | – | – | – | – |
q_response | – | – | * | – | – | – | – |
transmittance | – | – | – | * | – | * | – |
absorptance | – | – | – | * | – | * | – |
absorbance | – | – | – | * | – | * | – |
reflectance | – | – | – | – | * | * | – |
color_of | – | + | – | – | – | – | – |
wl_range | + | + | + | + | + | + | + |
wl_min | + | + | + | + | + | + | + |
wl_max | + | + | + | + | + | + | + |
wl_stepsize | + | + | + | + | + | + | + |
wl_spread | + | + | + | + | + | + | + |
wl_midpoint | + | + | + | + | + | + | + |
labels | l | l | l | l | l | l | l |
summary | l | l | l | l | l | l | l |
peaks | – | + | + | + | + | (+) | - |
valleys | – | + | + | + | + | (+) | - |
spikes | – | + | + | + | + | (+) | - |
wls_at_target | – | + | + | + | + | (+) | - |
integrate_spct | a, d, l | a, d, l | a, d, l | a, d, l | a, d, l | a, d, l | a, d, l |
average_spct | a, d, l | a, d, l | a, d, l | a, d, l | a, d, l | a, d, l | a, d, l |
Specialized definitions of summary
and the corresponding
print
methods are available for spectral objects.
Attributes "what.measured"
, "when.measured"
and "where.measured"
are included in the summary print out
only if set in the spectral object summarized.
summary(sun.spct)
## Summary of source_spct [522 x 3] object: sun.spct
## Wavelength range 280-800 nm, step 0.9230769-1 nm
## Label: sunlight, simulated
## Measured on 2010-06-22 09:51:00 UTC
## Measured at 60.20911 N, 24.96474 E; Kumpula, Helsinki, FI
## Time unit 1s
##
## w.length s.e.irrad s.q.irrad
## Min. :280.0 Min. :0.0000 Min. :0.000e+00
## 1st Qu.:409.2 1st Qu.:0.4115 1st Qu.:1.980e-06
## Median :539.5 Median :0.5799 Median :2.929e-06
## Mean :539.5 Mean :0.5160 Mean :2.407e-06
## 3rd Qu.:669.8 3rd Qu.:0.6664 3rd Qu.:3.154e-06
## Max. :800.0 Max. :0.8205 Max. :3.375e-06
summary(two_suns.spct)
## Summary of source_spct [1,044 x 4] object: two_suns.spct
## containing 2 spectra in long form
## Wavelength range 280-800 nm, step 0.9230769-1 nm
## a label: sunlight, simulated
## b label: sunlight, simulated
## a measured on 2010-06-22 09:51:00 UTC
## b measured on 2010-06-22 09:51:00 UTC
## Measured at 60.20911 N, 24.96474 E; Kumpula, Helsinki, FI
## Measured at 60.20911 N, 24.96474 E; Kumpula, Helsinki, FI
## Time unit 1s
##
## w.length s.e.irrad spct.idx s.q.irrad
## Min. :280.0 Min. :0.0000 a:522 Min. :0.000e+00
## 1st Qu.:409.0 1st Qu.:0.2471 b:522 1st Qu.:1.159e-06
## Median :539.5 Median :0.3494 Median :1.580e-06
## Mean :539.5 Mean :0.3870 Mean :1.806e-06
## 3rd Qu.:670.0 3rd Qu.:0.5799 3rd Qu.:2.928e-06
## Max. :800.0 Max. :0.8205 Max. :3.375e-06
The usual and three new summary methods are available for
spectra, but redefined to return wavelength-based summaries in
nanometres (nm). For clarity synonyms with clearer names are provided.
The three new generic methods midpoint()
,
expanse()
and stepsize()
are also defined for
numeric
.
wl_range(sun.spct)
## [1] 280 800
wl_min(sun.spct)
## [1] 280
wl_max(sun.spct)
## [1] 800
wl_midpoint(sun.spct)
## [1] 540
wl_expanse(sun.spct)
## [1] 520
wl_stepsize(sun.spct)
## [1] 0.9230769 1.0000000
Most frequently used summary methods are implemented for collections
of spectra. See the Table 11 for those methods that need to be applied
with functions msaply
, msdply
or
mslply
to members in a collection returning the results in
an array (vector, or matrix), a data frame or a list object. In many
cases depending of the class desired for the result, one can chose a
suitable apply function, and sometimes it is best to use such a
function, even when the corresponding method is implemented for
collections of spectra.
Collections of spectra can be useful not only for time-series of spectra or spectral images, but also when dealing with a small group of related spectra. In the example below we show how to use a collection of spectra for calculating summaries. The spectra in a collection do not need to have been measured at the same wavelength values, or have the same number of rows or even of columns. Consequently, in many cases applying the wavelength summary functions described above to collections of spectra can be useful. The value returned is a data frame, with a number of data columns equal to the length of the returned value by the corresponding method for individual spectra.
<- filter_mspct(list(none = clear.spct,
filters.mspct pet = polyester.spct,
yellow = yellow_gel.spct))
wl_range(filters.mspct)
## # A tibble: 3 × 3
## spct.idx min.wl max.wl
## <fct> <dbl> <dbl>
## 1 none 100 5000
## 2 pet 240 800
## 3 yellow 190 800
Peaks and valleys in spectra are usually features of interest, while in most cases spikes (very narrow peaks or valleys) are undesired “noise”. Of course, there are exceptions and for this reason methods used for extract any of these features have a similar interface.
Peaks and valleys can be identified simply as local maxima and minima, or their actual location better estimated by fitted a model to the local maximum or minimum and its neighbours.
Methods peaks
and valleys
take spectra as
first argument and return a subset of the spectral object data
corresponding to local maxima and local minima of the measured variable.
span
defines the width of the window used as a
number of observations.
peaks(sun.spct, span = 51)
## Object: source_spct [3 x 2]
## Wavelength range 451-747 nm, step 44-252 nm
## Label: sunlight, simulated
## Measured on 2010-06-22 09:51:00 UTC
## Measured at 60.20911 N, 24.96474 E; Kumpula, Helsinki, FI
## Time unit 1s
##
## # A tibble: 3 × 2
## w.length s.e.irrad
## <dbl> <dbl>
## 1 451 0.820
## 2 495 0.790
## 3 747 0.503
valleys(sun.spct, span = 51)
## Object: source_spct [9 x 2]
## Wavelength range 358-761 nm, step 30-72 nm
## Label: sunlight, simulated
## Measured on 2010-06-22 09:51:00 UTC
## Measured at 60.20911 N, 24.96474 E; Kumpula, Helsinki, FI
## Time unit 1s
##
## # A tibble: 9 × 2
## w.length s.e.irrad
## <dbl> <dbl>
## 1 358 0.254
## 2 393 0.242
## 3 431 0.414
## 4 487 0.651
## # … with 5 more rows
## # ℹ Use `print(n = ...)` to see more rows
In the case of source_spct
and
response_spct
methods unit.out
can be used to
force peaks to be searched using either energy or photon based spectral
irradiance. The default is energy, or the option
"photobiology.radiation.unit"
if set.
peaks(white_led.source_spct,
span = 101,
unit.out = "photon")$w.length
## [1] 455.48 608.62
By passing refine.wl = TRUE
we request that location of
the peaks is refined by fitting a model to describe the
peak.
peaks(white_led.source_spct,
span = 101,
unit.out = "photon",
refine.wl = TRUE)$w.length
## [1] 455.3068 608.8524
It is possible to approximately set the width in nanometres of the
moving window within which a maximum is searched by passing an odd
number as argument to span
. However, even numbers if passed
are increased with a warning.
peaks(sun.spct, span = 21)
## Object: source_spct [18 x 2]
## Wavelength range 354-774 nm, step 11-51 nm
## Label: sunlight, simulated
## Measured on 2010-06-22 09:51:00 UTC
## Measured at 60.20911 N, 24.96474 E; Kumpula, Helsinki, FI
## Time unit 1s
##
## # A tibble: 18 × 2
## w.length s.e.irrad
## <dbl> <dbl>
## 1 354 0.376
## 2 366 0.449
## 3 378 0.497
## 4 416 0.676
## # … with 14 more rows
## # ℹ Use `print(n = ...)` to see more rows
A value of NULL
as argument to span
searches for a single maximum for the whole spectrum.
peaks(sun.spct, span = NULL)
## Object: source_spct [1 x 2]
## Wavelength range 451-451 nm, step NA nm
## Label: sunlight, simulated
## Measured on 2010-06-22 09:51:00 UTC
## Measured at 60.20911 N, 24.96474 E; Kumpula, Helsinki, FI
## Time unit 1s
##
## # A tibble: 1 × 2
## w.length s.e.irrad
## <dbl> <dbl>
## 1 451 0.820
The position of peaks can be refined by spline interpolation. This is still an experimental feature, that may fail, especially in the estimate of the value of the spectral quantity at the peak.
peaks(sun.spct, span = NULL, refine.wl = TRUE)
## Object: source_spct [1 x 2]
## Wavelength range 451.02685-451.02685 nm, step NA nm
## Label: sunlight, simulated
## Measured on 2010-06-22 09:51:00 UTC
## Measured at 60.20911 N, 24.96474 E; Kumpula, Helsinki, FI
## Time unit 1s
##
## # A tibble: 1 × 2
## w.length s.e.irrad
## <dbl> <dbl>
## 1 451. 0.821
Method spikes
differs from peaks
in that it
uses a different algorithm that detects only very narrow peaks, usually
called by the name of spikes. The value returned is as in the case of
peaks
a subset of the original spectrum. The parameters
controlling the sensitivity also differ.
spikes(sun.spct)
## Object: source_spct [2 x 2]
## Wavelength range 398-432 nm, step 34 nm
## Label: sunlight, simulated
## Measured on 2010-06-22 09:51:00 UTC
## Measured at 60.20911 N, 24.96474 E; Kumpula, Helsinki, FI
## Time unit 1s
##
## # A tibble: 2 × 2
## w.length s.e.irrad
## <dbl> <dbl>
## 1 398 0.504
## 2 432 0.646
Low level functions find_peaks
, get_peaks
,
get_valleys
, fit_peaks
,
fit_valleys
, and find_spikes
take numeric
vectors as first argument.
The methods are also implemented for collections of spectra.
msmsply(filters.mspct, peaks, span = 21)
## Object: filter_mspct [3 x 1]
## --- Member: none ---
## Object: filter_spct [0 x 5]
## Label: theoretical fully transparent object
## Transmittance of type 'internal'
## Rfr (/1): NA, thickness (mm): NA, attenuation mode: NA.
##
## # A tibble: 0 × 5
## # … with 5 variables: w.length <dbl>, Tfr <dbl>, Rfr.constant <dbl>,
## # thickness <dbl>, attenuation.mode <chr>
## # ℹ Use `colnames()` to see all variable names
## --- Member: pet ---
## Object: filter_spct [3 x 2]
## Wavelength range 451-714 nm, step 102-161 nm
## Label: clear polyester film
## Transmittance of type 'total'
## Rfr (/1): 0.07, thickness (mm): 0.125, attenuation mode: absorption.
##
## # A tibble: 3 × 2
## w.length Tfr
## <int> <dbl>
## 1 451 0.925
## 2 612 0.918
## 3 714 0.913
## --- Member: yellow ---
## Object: filter_spct [5 x 2]
## Wavelength range 331-768 nm, step 23-293 nm
## Label: yellow theatrical 'gel', Rosco supergel no. 312, 'canary yellow'
## Transmittance of type 'total'
## Rfr (/1): 0.07, thickness (mm): 0.085, attenuation mode: absorption.
##
## # A tibble: 5 × 2
## w.length Tfr
## <int> <dbl>
## 1 331 0.00471
## 2 624 0.898
## 3 708 0.900
## 4 731 0.901
## 5 768 0.902
##
## --- END ---
Two of the filters in the collection do not have peaks, and a spectrum object of length zero is returned for them.
Method wls_at_target
takes a spectrum as first argument
and returns a subset of the spectral object data or a new object
corresponding to wavelengths at which the spectrum is at the target
value. Geometrically is equivalent to finding the wavelengths at which a
horizontal target line intercepts the curve depicting the
spectrum.
wls_at_target(Ler_leaf_trns.spct, target = "half.maximum")
## Object: filter_spct [1 x 2]
## Wavelength range 709.35352-709.35352 nm, step NA nm
## Label: Ler_06_black.spct
## Measured on 2017-07-03 13:18:18 UTC
## Transmittance of type 'total'
##
## # A tibble: 1 × 2
## w.length Tfr
## <dbl> <dbl>
## 1 709. 0.222
wls_at_target(Ler_leaf_trns.spct, target = "half.maximum", interpolate = TRUE)
## Object: filter_spct [1 x 2]
## Wavelength range 709.50991-709.50991 nm, step NA nm
## Label: Ler_06_black.spct
## Measured on 2017-07-03 13:18:18 UTC
## Transmittance of type 'total'
## Rfr (/1): NA, thickness (mm): NA, attenuation mode: NA.
##
## # A tibble: 1 × 2
## w.length Tfr
## <dbl> <dbl>
## 1 710. 0.224
This function can be used with all spectral classes defined in the
package. In the case of source_spct
and
response_spct
methods parameter unit.out
allows to switch between energy and photon units for the search and
returned value, while in the case of filter_spct
methods
filter.qty` allows to switch between transmittance, absorptance and
absorbance.
The method is also implemented for collections of spectra.
wls_at_target(filters.mspct, target = "half.maximum")
## Object: filter_mspct [3 x 1]
## --- Member: none ---
## Object: filter_spct [0 x 2]
## Transmittance of type 'total'
## Rfr (/1): NA, thickness (mm): NA, attenuation mode: NA.
##
## # A tibble: 0 × 2
## # … with 2 variables: w.length <dbl>, Tfr <dbl>
## # ℹ Use `colnames()` to see all variable names
## --- Member: pet ---
## Object: filter_spct [1 x 2]
## Wavelength range 322-322 nm, step NA nm
## Label: clear polyester film
## Transmittance of type 'total'
## Rfr (/1): 0.07, thickness (mm): 0.125, attenuation mode: absorption.
##
## # A tibble: 1 × 2
## w.length Tfr
## <int> <dbl>
## 1 322 0.462
## --- Member: yellow ---
## Object: filter_spct [1 x 2]
## Wavelength range 509-509 nm, step NA nm
## Label: yellow theatrical 'gel', Rosco supergel no. 312, 'canary yellow'
## Transmittance of type 'total'
## Rfr (/1): 0.07, thickness (mm): 0.085, attenuation mode: absorption.
##
## # A tibble: 1 × 2
## w.length Tfr
## <int> <dbl>
## 1 509 0.457
##
## --- END ---
Energy irradiance is the integral over wavelengths of spectral energy irradiance
\[E = \int_{\lambda = \lambda_1}^{\lambda = \lambda_2} E(\lambda)\ \mathrm{d}\lambda\] where \(\lambda_1 \geq \lambda > \lambda_2\) defines a waveband, or range of wavelengths.
Photon (=quantum) irradiance is the integral over wavelengths of spectral photon irradiance.
\[Q = \int_{\lambda = \lambda_1}^{\lambda = \lambda_2} Q(\lambda)\ \mathrm{d}\lambda\] Spectrally weighted (or biologically effective) energy irradiance is the integral of the result of the convolution of spectral energy irradiance by a spectral weighting function \(w(\lambda)\).
\[E_{BE} = \int_{\lambda = \lambda_1}^{\lambda = \lambda_2} E(\lambda) \cdot w_E(\lambda)\ \mathrm{d}\lambda\] Spectrally weighted (or effective) photon irradiance can be computed similarly with the corresponding weighting function \(w_Q(\lambda)\).
The code using spct
objects is simple; to integrate the
whole spectrum we can use irrad()
that returns by default
energy irradiance, unless an R option is set to make photon-based units
the default. When this flexibility is not needed, e_irrad()
and q_irrad()
should be preferred. For most examples we use
energy-based units and e_irrad()
, but they also apply
unchanged to q_irrad()
and photon-based units, and
vice-versa for those examples using q_irrad()
.
The abbreviations E and Q are used to denote these two quantities, usually with the waveband as a subscript. In what follows “Total” as subscript denotes the whole range of wavelengths in the spectrum. This is the default.
e_irrad(sun.spct)
## E_Total
## 269.1249
## attr(,"time.unit")
## [1] "second"
## attr(,"radiation.unit")
## [1] "total energy irradiance"
To integrate one restricted range of wavelengths from a spectrum, we
can provide a wavelength definition. In this example, waveband
PAR.wb
giving the definition of photosynthetically
active radiation. (PAR.wb
was defined above.)
e_irrad(sun.spct, PAR.wb)
## E_PAR
## 196.6343
## attr(,"time.unit")
## [1] "second"
## attr(,"radiation.unit")
## [1] "total energy irradiance"
It is also valid to pass as argument for w.band
a
numeric range representing wavelengths in manometers (nm), which is
converted into a waveband definition on-the-fly. Note, however, that the
automatically assigned name gives only the range.
e_irrad(sun.spct, c(400, 700))
## E_range.400.700
## 196.6343
## attr(,"time.unit")
## [1] "second"
## attr(,"radiation.unit")
## [1] "total energy irradiance"
The ‘photobiology’ package uses base SI units, so by default photon irradiance (= quantum irradiance) is expressed in \(mol\,s^{-1}\,m^{-2}\). We can pass a scaling factor as shown below if needed.
q_irrad(sun.spct, PAR.wb, scale.factor = 1e6) # umol s-1 m-2
## Q_PAR
## 894.1352
## attr(,"time.unit")
## [1] "second"
## attr(,"radiation.unit")
## [1] "total photon irradiance"
It is possible to supply a time unit to use, instead of the default of seconds, as basis of expression for the returned value. However, be aware that conversion into a different time unit than that used during measurement, is only valid for sources like lamps, which have an output the remains constant in time.
q_irrad(white_led.source_spct, PAR.wb, time.unit = "hour")
## Q_PAR
## 1.584957
## attr(,"time.unit")
## [1] "hour"
## attr(,"radiation.unit")
## [1] "total photon irradiance"
Using a shorter time unit than the original, yields an average value re-expressed on a new time unit base.
e_irrad(sun.daily.spct, PAR.wb, time.unit = "second")
## E_PAR
## 92.16251
## attr(,"time.unit")
## [1] "second"
## attr(,"radiation.unit")
## [1] "total energy irradiance"
Lists of wavebands are also accepted as argument for parameter
w.band
in which case a named numeric vector of summary
values is returned by default.
e_irrad(sun.spct, UV_bands.lst) # W m-2
## E_UVB E_UVA
## 0.6445105 27.9842061
## attr(,"time.unit")
## [1] "second"
## attr(,"radiation.unit")
## [1] "total energy irradiance"
q_irrad(sun.spct, UV_bands.lst) # mol s-1 m-2
## Q_UVB Q_UVA
## 1.675362e-06 8.481970e-05
## attr(,"time.unit")
## [1] "second"
## attr(,"radiation.unit")
## [1] "total photon irradiance"
q_irrad(sun.spct, UV_bands.lst, scale.factor = 1e6) # umol s-1 m-2
## Q_UVB Q_UVA
## 1.675362 84.819697
## attr(,"time.unit")
## [1] "second"
## attr(,"radiation.unit")
## [1] "total photon irradiance"
These functions have an additional argument quantity
,
with default "total"
, which can take values controlling the
output. The value “total” yields irradiance in \(W\,m^{-2}\), integrated over wavelengths
for each waveband, while “average” yields the mean spectral
irradiance within each waveband in \(W\,m^{-2}\,nm^{-1}\).
e_irrad(sun.spct, UV_bands.lst, quantity = "total") # watt m-2
## E_UVB E_UVA
## 0.6445105 27.9842061
## attr(,"time.unit")
## [1] "second"
## attr(,"radiation.unit")
## [1] "total energy irradiance"
e_irrad(sun.spct, UV_bands.lst, quantity = "average") # watt m-2 nm-1
## E(wl)_UVB E(wl)_UVA
## 0.01841458 0.32922595
## attr(,"time.unit")
## [1] "second"
## attr(,"radiation.unit")
## [1] "average energy irradiance"
When quantity = "contribution"
irradiances for
individual wavebands are expressed relative to the irradiance computed
for the whole spectrum, while for quantity = "relative"
they are expressed relative to the sum of the irradiances for all the
wavebands. In both cases values are expressed as fractions of one.
e_irrad(sun.spct, UV_bands.lst, quantity = "contribution")
## E/Etot_UVB E/Etot_UVA
## 0.002394838 0.103982226
## attr(,"time.unit")
## [1] "second"
## attr(,"radiation.unit")
## [1] "contribution energy irradiance"
e_irrad(sun.spct, UV_bands.lst, quantity = "relative")
## E/Esum_UVB E/Esum_UVA
## 0.02251273 0.97748727
## attr(,"time.unit")
## [1] "second"
## attr(,"radiation.unit")
## [1] "relative energy irradiance"
When setting "contribution.pc"
or
"relative.pc"
as quantity
the same values as
in the examples above, are expressed as percentages instead of
fractions.
e_irrad(sun.spct, UV_bands.lst, quantity = "contribution.pc")
## E/Etot_UVB E/Etot_UVA
## 0.2394838 10.3982226
## attr(,"time.unit")
## [1] "second"
## attr(,"radiation.unit")
## [1] "contribution.pc energy irradiance"
e_irrad(sun.spct, UV_bands.lst, quantity = "relative.pc")
## E/Esum_UVB E/Esum_UVA
## 2.251273 97.748727
## attr(,"time.unit")
## [1] "second"
## attr(,"radiation.unit")
## [1] "relative.pc energy irradiance"
The total radiation received on a surface during an exposure event
can be also calculated with methods irrad()
,
e_irrad()
and q_irrad()
, but the values
returned are irradiances expressed on a very unusual time basis. These
are no longer W m-2 (J s-1 m-2), but instead J per 8 hours per square
meter.
e_irrad(sun.spct, PAR.wb, time.unit = duration(8, "hours"))
## E_PAR
## 5663067
## attr(,"time.unit")
## [1] "28800s (~8 hours)"
## attr(,"radiation.unit")
## [1] "total energy irradiance"
When the intention is to calculate a total fluence or exposure for an
event, function fluence()
, e_fluence()
or
q_fluence()
should be used as this will add the correct
metadata attributes to the returned value: expressed as energy or
photons per unit area per event. See later sections for details.
e_fluence(sun.spct, PAR.wb, exposure.time = duration(8, "hours"))
## E_PAR
## 5663067
## attr(,"radiation.unit")
## [1] "energy fluence (J m-2)"
## attr(,"exposure.duration")
## [1] "28800s (~8 hours)"
In all earlier examples in this section, the default naming of
returned values was active. The default naming of the values is an
abbreviation of the physical quantity plus the name of the wavelength.
Alternatively "short"
naming uses only the name of the
wavebands as shown below, obtained from the label stored in the waveband
definitions.
q_irrad(sun.spct, UV_bands.lst, naming = "short")
## UVB UVA
## 1.675362e-06 8.481970e-05
## attr(,"time.unit")
## [1] "second"
## attr(,"radiation.unit")
## [1] "total photon irradiance"
Naming can also be completely suppressed.
q_irrad(sun.spct, UV_bands.lst, naming = "none")
## [1] 1.675362e-06 8.481970e-05
## attr(,"time.unit")
## [1] "second"
## attr(,"radiation.unit")
## [1] "total photon irradiance"
Names of members of a list of wavebands, override the labels in waveband definitions.
names(UV_bands.lst) <- c("UV-C", "UV-B", "UV-A")
q_irrad(sun.spct, UV_bands.lst, naming = "short", scale.factor = 1e6)
## UV-B UV-A
## 1.675362 84.819697
## attr(,"time.unit")
## [1] "second"
## attr(,"radiation.unit")
## [1] "total photon irradiance"
Collections of spectra can be useful not only for time-series of spectra or spectral images, but also when dealing with a small group of related spectra. In the example below we show how to use a collection of spectra to estimate irradiances under different filters set up in sunlight.
We create a collection of two spectra, for use in our examples.
<- source_mspct(list(sun1 = sun.spct, sun2 = sun.spct * 2)) two_suns.mspct
Methods irrad()
, e_irrad()
and
q_irrad()
can be used for collections of spectra exactly as
for a single spectrum (as described above). We here only show the
additional features that apply to collections. In this first example, we
can see that the returned object is a data frame instead of a named
numeric vector.
e_irrad(two_suns.mspct, w.band = PAR.wb)
## # A tibble: 2 × 2
## spct.idx E_PAR
## <fct> <dbl>
## 1 sun1 197.
## 2 sun2 393.
Spectral objects can contain metadata as attributes. When summarizing a collection of spectra it is frequently very useful to copy some of these metadata, extracted from each member of the collection, to columns in the returned data frame. This can be done as follows.
q_irrad(two_suns.mspct,
w.band = PAR.wb,
scale.factor = 1e6, # umol m-2 s-1
attr2tb = c(when.measured = "time", lon = "lon", lat = "lat"))
## # A tibble: 2 × 5
## spct.idx Q_PAR time lon lat
## <fct> <dbl> <dttm> <dbl> <dbl>
## 1 sun1 894. 2010-06-22 09:51:00 25.0 60.2
## 2 sun2 1788. 2010-06-22 09:51:00 25.0 60.2
For a more advanced example, we reuse the collection of filter
spectra filters.mspct
from an earlier section. We convolve
each filter’s spectral transmittance by the spectral irradiance of the
light source so as to predict the irradiances under the filters. We
specify the name of the column where the names of the spectra (their
index) is stored.
<- convolve_each(filters.mspct, sun.spct)
filtered_sun q_irrad(filtered_sun,
list(UVA.wb, PAR.wb),
scale.factor = 1e6,
idx = "Filter")
## # A tibble: 3 × 3
## Filter Q_UVA Q_PAR
## <fct> <dbl> <dbl>
## 1 none 84.8 894.
## 2 pet 70.2 823.
## 3 yellow 0.105 536.
The code above example can also be written as a single statement. Here we also tweak column names, delete one column, and swap the position of the remaining columns.
q_irrad(convolve_each(filters.mspct, sun.spct),
list("UV-A" = UVA.wb, PAR.wb),
scale.factor = 1e6, # umol m-2 s-1
naming = "short",
attr2tb = c(what.measured = "Filter type"))[ , c(4, 2, 3)]
## # A tibble: 3 × 3
## `Filter type` `UV-A` PAR
## <chr> <dbl> <dbl>
## 1 theoretical fully transparent object 84.8 894.
## 2 clear polyester film 70.2 823.
## 3 yellow theatrical 'gel', Rosco supergel no. 312, 'canary yellow' 0.105 536.
It is also possible to use an apply function. See sections
apply functions and convolve
for more details, as
in certain cases only one or the other can be used.
Energy fluence is energy irradiance integrated over a lapse of time or event, and is expressed as energy per area.
Energy fluence is the integral over wavelengths and time of spectral energy irradiance
\[F_E = \int_{\lambda = \lambda_1}^{\lambda = \lambda_2} \int_{t = t_1}^{t = t_2} E(\lambda)\ \mathrm{d}\lambda\,\mathrm{d}t\] where \(\lambda_1 \geq \lambda > \lambda_2\) defines a waveband, or range of wavelengths, and \(t_1 \geq t > t_2\).
However, if we assume that irradiance does not vary in time it simplifies to \[F_E = \Delta t\times\int_{\lambda = \lambda_1}^{\lambda = \lambda_2} E(\lambda)\ \mathrm{d}\lambda\] where \(\Delta t = t_2 - t_1\).
The equivalent equation for photon fluence is \[F_Q = \Delta t\times\int_{\lambda = \lambda_1}^{\lambda = \lambda_2} Q(\lambda)\ \mathrm{d}\lambda\]
Spectrally weighted (or effective) energy fluence is the integral over wavelengths and time of the result of the convolution of spectral energy irradiance by a spectral weight function \(w(\lambda)\). Assuming that spectral irradiance does not vary with time the corresponding equation is
\[F_{E_{BE}} = \Delta t\times\int_{\lambda = \lambda_1}^{\lambda = \lambda_2} E(\lambda) \times w_E(\lambda)\ \mathrm{d}\lambda\]
Spectrally weighted (or effective) photon fluence can be computed similarly with the corresponding weighting function \(w_Q(\lambda)\).
The calculation of fluence values (time-integrated irradiance) is
identical to that for irradiance, except that a
exposure.time
argument needs to be supplied. The exposure
time must be a lubridate::duration
, but any argument
accepted by as.duration
can also be used. Functions
fluence
, e_fluence
and q_fluence
correspond to irrad
, e_irrad
and
q_irrad
,
fluence(sun.spct, exposure.time = duration(1, "hours"))
## E_Total
## 968849.6
## attr(,"radiation.unit")
## [1] "energy fluence (J m-2)"
## attr(,"exposure.duration")
## [1] "3600s (~1 hours)"
or
fluence(sun.spct, exposure.time = 3600) # seconds
## converting 'time.unit' 3600 into a lubridate::duration
## E_Total
## 968849.6
## attr(,"radiation.unit")
## [1] "energy fluence (J m-2)"
## attr(,"exposure.duration")
## [1] 3600
and, to obtain the photon fluence for a range of wavelengths, in the
example, photosynthetically active radiation, we use the
PAR.wb
waveband object earlier defined, and integrate for
25 minutes of exposure.
q_fluence(sun.spct, PAR.wb, exposure.time = duration(25, "minutes"))
## Q_PAR
## 1.341203
## attr(,"radiation.unit")
## [1] "photon fluence (mol m-2)"
## attr(,"exposure.duration")
## [1] "1500s (~25 minutes)"
A way to summarize the “colour” of light is to compute a ratio between irradiances computed for two different wavebands of the same spectrum. They can be computed either on an energy or photon (quantum) basis, and although not a requirement, use of two wavelength bands with the same expanse is usually most informative. Photon ratios are usually preferred compared to energy ratios in work related to photobiology and photochemistry.
\[Q_1 : Q_2 = \frac{\int_{\lambda = \lambda_1}^{\lambda = \lambda_2} Q(\lambda)\ \mathrm{d}\lambda} {\int_{\lambda = \lambda_3}^{\lambda = \lambda_4} Q(\lambda)\ \mathrm{d}\lambda}\]
where \(\lambda_1 \geq \lambda > \lambda_2\) defines the waveband for the numerator and \(\lambda_3 \geq \lambda > \lambda_4\) defines the waveband for the denominator, i.e., two ranges of wavelengths.
Energy ratios are computed similarly
\[E_1 : E_2 = \frac{\int_{\lambda = \lambda_1}^{\lambda = \lambda_2} E(\lambda)\ \mathrm{d}\lambda} {\int_{\lambda = \lambda_3}^{\lambda = \lambda_4} E(\lambda)\ \mathrm{d}\lambda}\]
where \(\lambda_1 \geq \lambda > \lambda_2\) defines the waveband for the numerator and \(\lambda_3 \geq \lambda > \lambda_4\) defines the waveband for the denominator, i.e., two ranges of wavelengths.
An energy irradiance to photon irradiance ratio describes the average energy per mol of photon for a waveband or range of wavelengths.
\[E : Q = \frac{\int_{\lambda = \lambda_1}^{\lambda = \lambda_2} E(\lambda)\ \mathrm{d}\lambda} {\int_{\lambda = \lambda_1}^{\lambda = \lambda_2} Q(\lambda)\ \mathrm{d}\lambda}\]
where \(\lambda_1 \geq \lambda > \lambda_2\) defines a waveband, or range of wavelengths.
We can compute the photon to energy ratio (\(Q : E\)) similarly.
Although all these ratios are usually computed without use of spectral weighting functions, their computation can be easily done by including in the equations above a weighting functions (\(w(\lambda)\)) as described in the section on irradiance.
The functions described here, in there simplest use, calculate a
ratio between two wavebands. The function q_ratio
returning
photon ratios. However both waveband parameters can take lists of
wavebands as arguments, with normal recycling rules in effect. The
corresponding function e_ratio
returns energy ratios.
A single ratio.
q_ratio(sun.spct, UVB.wb, PAR.wb)
## UVB:PAR[q:q]
## 0.001873724
## attr(,"radiation.unit")
## [1] "q:q ratio"
If no waveband is passed as numerator, the whole spectrum is used. The waveband fully outside the wavelength range of the spectrum is dropped silently.
q_ratio(sun.spct, list(UVC.wb, UVB.wb, UVA.wb))
## UVB:Total[q:q] UVA:Total[q:q]
## 0.001334593 0.067567343
## attr(,"radiation.unit")
## [1] "q:q ratio"
Three denominators (one skipped) and a single denominator.
q_ratio(sun.spct, list(UVC.wb, UVB.wb, UVA.wb), PAR.wb)
## UVB:PAR[q:q] UVA:PAR[q:q]
## 0.001873724 0.094862270
## attr(,"radiation.unit")
## [1] "q:q ratio"
Function qe_ratio
, has only one waveband parameter, and
returns the photon to energy ratio, while its
complement eq_ratio
returns the energy to
photon ratio. Here we show how parameters
scale.factor
and name.tag
make scaling the
returned value easy.
qe_ratio(sun.spct,
list("UV-B" = UVB.wb, PAR.wb),
scale.factor = 1e6,
name.tag = " (umol/J)")
## UV-B (umol/J) PAR (umol/J)
## 2.599434 4.547199
## attr(,"radiation.unit")
## [1] "q:e ratio"
As other summary methods, q_ratio()
,
e_ratio()
, qe_ratio()
and
eq_ratio()
when applied to a collection of spectra, they
return a data frame.
q_ratio(filtered_sun,
list(UVB.wb, UVA.wb),
PAR.wb)
## # A tibble: 3 × 3
## spct.idx `UVB:PAR[q:q]` `UVA:PAR[q:q]`
## <fct> <dbl> <dbl>
## 1 none 0.00187 0.0949
## 2 pet 0.0000720 0.0853
## 3 yellow 0.00000387 0.000196
Additional parameters allow the scaling and customized column names possible.
q_ratio(filtered_sun,
list(UVB.wb, UVA.wb),
PAR.wb, scale.factor = 100,
name.tag = " (% photons)",
idx = "Filter")
## # A tibble: 3 × 3
## Filter `UVB:PAR (% photons)` `UVA:PAR (% photons)`
## <fct> <dbl> <dbl>
## 1 none 0.187 9.49
## 2 pet 0.00720 8.53
## 3 yellow 0.000387 0.0196
Given the laws of conservation of energy, transmittance, reflectance and absorptance, expressed as fractions, always add up to one.
\[1 = R_\mathrm{fr,total} + A_\mathrm{fr,total} + T_\mathrm{fr,total}\] Transmittance can be defined either as the fraction of the radiation “entering” an object that is transmitted, called internal transmittance (\(T_\mathrm{fr,internal}\)) or as the fraction of the ration incident on an object that is transmitted (\(T_\mathrm{fr,total}\)).
\[1 \times R_\mathrm{fr,total} = A_\mathrm{fr,internal} + T_\mathrm{fr,internal}\] giving
\[T_\mathrm{fr,internal} = T_\mathrm{fr,total} / R_\mathrm{fr,total}\] and \[A_\mathrm{fr,internal} = T_\mathrm{fr,total} / R_\mathrm{fr,total}\] In the case of reflectance, “total” has a different meaning, and refers to whether all reflected light or that an specific angle in considered.
In practice, both definitions of transmittance and absorptance are in use, while as it is easier to measure total- than internal transmittance, internal transmittance allows the computation of transmittance for different thickness of a material.
Consequently, absorptance can be computed as:
\[A_\mathrm{fr,internal} = 1 - T_\mathrm{fr,internal}\] or as
\[A_\mathrm{fr,total} = 1 - T_\mathrm{fr,total} - R_\mathrm{fr,total}\] Absorbance, is a log transformed quantity that tends to be used when the range of values spans several orders of magnitude. It is frequently based on internal absorptance, but can be also based on total absorptance.
\[A_\mathrm{internal} = -\log_{10}(1 -A_\mathrm{fr,internal}) = -\log_{10}(T_\mathrm{fr,internal}) \] and
\[A_\mathrm{total} = -\log_{10}(1 - A_\mathrm{fr,total}) = -\log_{10}(T_\mathrm{fr,total} + R_\mathrm{fr,total})\] When using a spectrophotometer, if our reference is a cuvette with pure solvent and the sample a solution of a compound in the same solvent we measure internal transmittance, absorptance or absorbance. If we instead measure the transmittance of a piece of glass or plastic with air as reference, we measure total transmittance, absorptance or absorbance. This is so because in the first case the reference is the light transmitted after the reflectance on the cuvette walls has taken place while in the second case the reflections at the glass-air interfaces are missing from the reference.
As a result of these different definitions, the implementation of the
class filter_spct()
and object_spct
and their
methods, need to keep track of whether quantities are expressed as
internal or total. As in many glasses reflectance varies very weakly
with wavelength, storing a constant value for \(R_\mathrm{fr,total}\) is also supported.
The refractive index of a material can also be used to estimate \(R_\mathrm{fr,total}\) for a polished
surface. Lack of a value for \(R_\mathrm{fr,total}\) can make some
conversions and computations impossible.
The functions transmittance
, absorptance
and absorbance
take filter_spct
as argument,
while function reflectance
takes
reflector_spct
objects as argument. Functions
transmittance
, reflectance
and
absorptance
are also implemented for
object_spct
. These functions return as default an average
value for these quantities assuming a light source with
a flat spectral energy output, but this can be changed as described
above for irrad()
.
transmittance(polyester.spct, list(UVB.wb, UVA.wb, PAR.wb))
## Tfr(wl)_UVB Tfr(wl)_UVA Tfr(wl)_PAR
## 0.009722449 0.781851261 0.920239286
## attr(,"Tfr.type")
## [1] "unknown"
## attr(,"radiation.unit")
## [1] "transmittance average"
We can obtain numerical values without names if needed,
transmittance(polyester.spct,
list(UVB.wb, UVA.wb, PAR.wb),
naming = "none")
## [1] 0.009722449 0.781851261 0.920239286
## attr(,"Tfr.type")
## [1] "unknown"
## attr(,"radiation.unit")
## [1] "transmittance average"
or named only according to the wavebands.
transmittance(polyester.spct,
list(UVB.wb, UVA.wb, PAR.wb),
naming = "short")
## UVB UVA PAR
## 0.009722449 0.781851261 0.920239286
## attr(,"Tfr.type")
## [1] "unknown"
## attr(,"radiation.unit")
## [1] "transmittance average"
The reflectance of a leaf.
reflectance(green_leaf.spct, waveband(c(600, 700)))
## Rfr(wl)_range.600.700
## 0.089647
## attr(,"Rfr.type")
## [1] "unknown"
## attr(,"radiation.unit")
## [1] "reflectance average"
Here we calculate the transmittance of a collection of spectra for
three filters in two wavebands, obtaining the results as a data frame,
with one row per filter, and one column per waveband. We reuse once more
filters.mspct
from an earlier section.
Column names formed from quantity abbreviation and label in waveband definitions.
transmittance(filters.mspct,
w.band = list(UVA.wb, PAR.wb))
## # A tibble: 3 × 3
## spct.idx `Tfr(wl)_UVA` `Tfr(wl)_PAR`
## <fct> <dbl> <dbl>
## 1 none 1.00 1.00
## 2 pet 0.782 0.920
## 3 yellow 0.00160 0.566
With naming = "short"
column names are the labels of
waveband definitions.
transmittance(filters.mspct,
w.band = list(UVA.wb, PAR.wb),
naming = "short")
## # A tibble: 3 × 3
## spct.idx UVA PAR
## <fct> <dbl> <dbl>
## 1 none 1.00 1.00
## 2 pet 0.782 0.920
## 3 yellow 0.00160 0.566
If list members are named, column names are formed from quantity abbreviation and name of list members, overriding the labels in the waveband definitions.
transmittance(filters.mspct,
w.band = list("UV-A" = UVA.wb, PAR = PAR.wb))
## # A tibble: 3 × 3
## spct.idx `Tfr(wl)_UV-A` `Tfr(wl)_PAR`
## <fct> <dbl> <dbl>
## 1 none 1.00 1.00
## 2 pet 0.782 0.920
## 3 yellow 0.00160 0.566
If list members are named, with naming = "short"
column
names are the names of list members.
transmittance(filters.mspct,
w.band = list(UVA = UVA.wb, PAR = PAR.wb),
naming = "short")
## # A tibble: 3 × 3
## spct.idx UVA PAR
## <fct> <dbl> <dbl>
## 1 none 1.00 1.00
## 2 pet 0.782 0.920
## 3 yellow 0.00160 0.566
We can add metadata attributes as columns, changing the name if desired.
transmittance(filters.mspct,
w.band = UVA.wb,
naming = "short",
attr2tb = c("what.measured" = "Filter type"))
## # A tibble: 3 × 3
## spct.idx UVA `Filter type`
## <fct> <dbl> <chr>
## 1 none 1.00 theoretical fully transparent object
## 2 pet 0.782 clear polyester film
## 3 yellow 0.00160 yellow theatrical 'gel', Rosco supergel no. 312, 'canary yel…
We can add metadata attributes as a column, and select and rearrange the columns.
transmittance(filters.mspct,
w.band = UVA.wb,
attr2tb = "what.measured")[ , c(3, 2)]
## # A tibble: 3 × 2
## what.measured `Tfr(wl)_UVA`
## <chr> <dbl>
## 1 theoretical fully transparent object 1.00
## 2 clear polyester film 0.782
## 3 yellow theatrical 'gel', Rosco supergel no. 312, 'canary yellow' 0.00160
Like the ratios discussed above normalized differences are a way of summarizing or describing the colour of light sources or objects independently of the overall irradiance. As their name tells, they are defined as differences relative to a sum.
Normalized difference indexes are used to summarize the spectral characteristics of light or objects. They are most frequently used in the analysis of spectral reflectance data in remote sensing.
\[NDI_{a, b} = \frac{R_a - R_b}{R_a + R_b}\]
where \(R_a\) and \(R_b\) are reflectances computed from the same spectrum using two different wavebands.
The most frequently used NDI is the NDVI or normalized difference vegetation index, which compares reflectance in the red and far-red regions as a way of assessing the presence of vegetation vs. bare land in remote sensing imagery.
However, they can be computed based on energy or photon irradiances for two wavebands as shown here, or for any other spectral quantity.
\[NDI_{a, b} = \frac{Q_a - Q_b}{Q_a + Q_b}\]
where \(Q_a\) and \(Q_b\) are irradiances computed from the same spectrum using two different wavebands.
Although we here describe how to compute normalized difference indexes from spectral data, they are most frequently generated from data from broad-band sensors in satellite, air-borne or terrestrial imagers. To reconstruct from spectral data indexes computed from these instruments we need to use waveband definitions that mimic the spectral response of the imager of interest. Package ‘photobiologyWavebands’ provides pre-defined wavebands for several different satellite imagers as well as for wavelength ranges in common use.
Here we give an example of a possible definition of NDVI using
function normalized_diff_ind()
can be used to calculate, or
any index with a similar formulation structure.
normalized_diff_ind(Ler_leaf_rflt.spct,
waveband(c(740, 840)), waveband(c(590, 690)),
reflectance)
## NDI reflectance [740.840] - [590.690]
## 0.7653852
Here we give an unusual example to demonstrate that function
normalized_diff_ind()
can be used to calculate any index
with a similar formulation structure and using other spectral quantities
and summary functions.
normalized_diff_ind(sun.spct,
waveband(c(600, 700)), waveband(c(400, 500)),
q_irrad)
## NDI q_irrad [600.700] - [400.500]
## 0.09188363
As with other spectral quantities, we can integrate over wavelengths spectral responsiveness. In response and action spectra the quantity is a response measured in some arbitrary unit expressed per unit wavelengths and per unit energy or quantum.
\[X_E = \int_{\lambda = \lambda_1}^{\lambda = \lambda_2} X_E(\lambda)\ \mathrm{d}\lambda\] where \(\lambda_1 \geq \lambda > \lambda_2\) defines a waveband, or range of wavelengths.
The conversion between energy and photon (= quantum) basis of expression is possible as it is for radiation spectra. Depending on the base of expression the returned integrated value is computed assuming either a light source with a flat spectral energy irradiance of 1 or spectral photon irradiance of 1, respectively.
The functions response
, e_response
and
q_response
take response_spct
objects as
arguments. If no waveband is supplied as argument, the whole spectrum is
integrated.
response(photodiode.spct)
## R[/e]_Total
## 24.40478
## attr(,"time.unit")
## [1] "second"
## attr(,"radiation.unit")
## [1] "total energy response"
When a waveband, or list of wavebands, is supplied the response is calculated for the wavebands.
e_response(photodiode.spct, list(UVB.wb, UVA.wb))
## R[/e]_]UVB R[/e]_UVA
## 0.346462 5.981818
## attr(,"time.unit")
## [1] "second"
## attr(,"radiation.unit")
## [1] "total energy response"
This function has an additional argument quantity
, with
default "total"
, as described for irrad()
.
<- response_mspct(list(GaAsP = photodiode.spct,
sensors CCD = ccd.spct))
response(sensors, list(UVB.wb, UVA.wb, PAR.wb), quantity = "contribution")
## # A tibble: 2 × 4
## spct.idx `R/Rtot[/e]_]UVB` `R/Rtot[/e]_UVA` `R/Rtot[/e]_PAR[`
## <fct> <dbl> <dbl> <dbl>
## 1 GaAsP 0.0142 0.245 0.741
## 2 CCD 0.0215 0.0634 0.411
When we need to integrate some numeric
variable stored
in a spectral object we can use functions integrate_spct
or
average_spct
.
We can integrate the values of arbitrary numeric
columns
other than w.length
in an spectral object. All spectral
classes are derived from generic_spct
, so the examples in
this section apply to objects of any of the derived spectral classes as
well.
integrate_spct(sun.spct)
## e.irrad q.irrad
## 2.691249e+02 1.255336e-03
The function average_spct
integrates every column
holding numeric values from a spectrum object, except for
w.length
, and divides the result by the spread or
width of the wavelength range integrated, returning a value expressed in
the same units as the spectral data.
average_spct(sun.spct)
## e.irrad q.irrad
## 5.175479e-01 2.414107e-06
Comparison of spectra for which data is expressed at different
discrete wavelength values can be easily affected by bias if
interpolation is used. Function compare_spct()
does a
coarse grained comparison by first summarizing each spectrum over
consecutive ranges of wavelengths, and then applying a comparison
function to these summary values.
The function can be used to compare pairs of spectra, stored as a
collection. In the next example we compare two source_spct
objects using defaults for most arguments.
compare_spct(source_mspct(list(sun1 = sun.spct, sun2 = sun.spct * 2)))
## Object: generic_spct [52 x 6]
## Wavelength range 285-795 nm, step 10 nm
##
## # A tibble: 52 × 6
## w.length wl.min wl.max sun1.irrad sun2.irrad comparison.result
## <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 285 280 290 0 0 NaN
## 2 295 290 300 0.00204 0.00407 2
## 3 305 300 310 0.203 0.406 2
## 4 315 310 320 1.13 2.26 2
## # … with 48 more rows
## # ℹ Use `print(n = ...)` to see more rows
The value returned by default is a generic_spct
object
containing the computed summaries for each waveband plus the result of
the comparison between the summaries. The first three columns contain
the wavelength at the midpoint of the wavelength range of waveband plus
its extremes.
In this example we compare two filter_spct
objects,
using summaries over 50-nm-wide bands, and using an operator returning a
logical value for the comparison instead of the default division
operator.
compare_spct(filter_mspct(list(pet = polyester.spct,
yllw = yellow_gel.spct)),
w.band = 50,
.comparison.fun = `<`)
## Object: generic_spct [11 x 6]
## Wavelength range 265-765 nm, step 50 nm
##
## # A tibble: 11 × 6
## w.length wl.min wl.max pet.transmittance yllw.transmittance comparison.result
## <dbl> <dbl> <dbl> <dbl> <dbl> <lgl>
## 1 265 240 290 0.00386 0.0000100 TRUE
## 2 315 290 340 0.292 0.00220 TRUE
## 3 365 340 390 0.861 0.000825 TRUE
## 4 415 390 440 0.918 0.0000100 TRUE
## # … with 7 more rows
## # ℹ Use `print(n = ...)` to see more rows
Different color_of()
methods allow calculation of RGB
colour values for light sources or objects. The returned values are R
colour definitions. Method color_of()
works rather
differently depending on the object. The method for numeric
vectors assumes the numbers are wavelengths in nanometres, and returns a
vector of colour definitions of the same length assuming monochromatic
light.
color_of(550) # green
## wl.550.nm.CMF
## "#00FF00"
color_of(630) # red
## wl.630.nm.CMF
## "#FF0000"
color_of(c(550, 630, 380, 750)) # vectorized
## wl.550.nm.CMF wl.630.nm.CMF wl.380.nm.CMF wl.750.nm.CMF
## "#00FF00" "#FF0000" "#000000" "#000000"
The method for source_spct
objects returns a single
colour definition corresponding to the whole spectrum of a light
sources.
color_of(sun.spct)
## source.CMF
## "#544F4B"
color_of(sun.spct * yellow_gel.spct)
## source.CMF
## "#946000"
There are no methods for filter_spct
and
reflector_spct
objects so as shown above we need to
convolve them with spectral irradiance from a source_spct
object.
The method for waveband
objects returns one colour
definition per waveband, corresponding to their central wavelength.
color_of(waveband(c(400, 500), wb.name = "my_BL"))
## my_BL.CMF
## "#000EFF"
By default CIE coordinates for typical human vision are
used, but the functions have a parameter that can be used for supplying
a different chromaticity definition as a chroma_spct
object.
color_of(sun.spct, chroma.type = "CC")
## source.CC
## "#B63C37"
color_of(sun.spct, chroma.type = "CMF")
## source.CMF
## "#544F4B"
color_of(sun.spct, chroma.type = beesxyzCMF.spct)
## source.chroma
## "#CD1F11"
In the case of bees, the RGB values represent a shift towards longer wavelengths compared to the true sensitivity. In other words, they are translated into colours that humans can see and monitors and printers can generate.