Nothing
#' @title Plot function for an RLum.Data.Spectrum S4 class object
#'
#' @description The function provides a standardised plot output for spectrum data of an
#' [RLum.Data.Spectrum-class] class object. The purpose of this function is to provide
#' easy and straight-forward spectra plotting, not provide a full customised access to
#' all plot parameters. If this is wanted, standard R plot functionality should be used
#' instead.
#'
#' **Matrix structure** \cr (cf. [RLum.Data.Spectrum-class])
#'
#' - `rows` (x-values): wavelengths/channels (`xlim`, `xlab`)
#' - `columns` (y-values): time/temperature (`ylim`, `ylab`)
#' - `cells` (z-values): count values (`zlim`, `zlab`)
#'
#' *Note: This nomenclature is valid for all plot types of this function!*
#'
#' **Nomenclature for value limiting**
#'
#' - `xlim`: Limits values along the wavelength axis
#' - `ylim`: Limits values along the time/temperature axis
#' - `zlim`: Limits values along the count value axis
#'
#' **Details on the plot functions**
#'
#' Spectrum is visualised as 3D or 2D plot. Both plot types are based on
#' internal R plot functions.
#'
#'**`plot.type = "persp"`**
#'
#' Arguments that will be passed to [graphics::persp]:
#'
#' - `shade`: default is `0.4`
#' - `phi`: default is `15`
#' - `theta`: default is `-30`
#' - `expand`: default is `1`
#' - `axes`: default is `TRUE`
#' - `box`: default is `TRUE`; accepts `"alternate"` for a custom plot design
#' - `ticktype`: default is `detailed`, `r`: default is `10`
#'
#' **Note:** Further parameters can be adjusted via `par`. For example
#' to set the background transparent and reduce the thickness of the lines use:
#' `par(bg = NA, lwd = 0.7)` previous the function call.
#'
#'**`plot.type = "single"`**
#'
#' Per frame a single curve is returned. Frames are time or temperature
#' steps.
#'
#' -`frames`: pick the frames to be plotted (depends on the binning!). Check without
#' this setting before plotting.
#'
#'**`plot.type = "multiple.lines"`**
#'
#' All frames plotted in one frame.
#'
#'-`frames`: pick the frames to be plotted (depends on the binning!). Check without
#' this setting before plotting.
#'
#' '**`plot.type = "image"` or `plot.type = "contour" **
#'
#' These plot types use the R functions [graphics::image] or [graphics::contour].
#' The advantage is that many plots can be arranged conveniently using standard
#' R plot functionality. If `plot.type = "image"` a contour is added by default,
#' which can be disabled using the argument `contour = FALSE` to add own contour
#' lines of choice.
#'
#'**`plot.type = "transect"`**
#'
#' Depending on the selected wavelength/channel range a transect over the
#' time/temperature (y-axis) will be plotted along the wavelength/channels
#' (x-axis). If the range contains more than one channel, values (z-values) are
#' summed up. To select a transect use the `xlim` argument, e.g.
#' `xlim = c(300,310)` plot along the summed up count values of channel
#' 300 to 310.
#'
#' **Further arguments that will be passed (depending on the plot type)**
#'
#' `xlab`, `ylab`, `zlab`, `xlim`, `ylim`, `box`,
#' `zlim`, `main`, `mtext`, `pch`, `type` (`"single"`, `"multiple.lines"`, `"interactive"`),
#' `col`, `border`, `lwd`, `bty`, `showscale` (`"interactive"`, `"image"`)
#' `contour`, `contour.col` (`"image"`)
#'
#' @param object [RLum.Data.Spectrum-class] or [matrix] (**required**):
#' S4 object of class `RLum.Data.Spectrum` or a `matrix` containing count
#' values of the spectrum.\cr
#' Please note that in case of a matrix row names and col names are set
#' automatically if not provided.
#'
#' @param par.local [logical] (*with default*):
#' use local graphical parameters for plotting, e.g. the plot is shown in one column and one row.
#' If `par.local = FALSE` global parameters are inherited.
#'
#' @param plot.type [character] (*with default*): plot type, for
#' 3D-plot use `persp`, or `interactive`, for a 2D-plot `image`, `contour`,
#' `single` or `multiple.lines` (along the time or temperature axis)
#' or `transect` (along the wavelength axis) \cr
#'
#' @param optical.wavelength.colours [logical] (*with default*):
#' use optical wavelength colour palette. Note: For this, the spectrum range is
#' limited: `c(350,750)`. Own colours can be set with the argument `col`. If you provide already
#' binned spectra, the colour assignment is likely to be wrong, since the colour gradients are calculated
#' using the bin number.
#'
#' @param bg.spectrum [RLum.Data.Spectrum-class] or [matrix] (*optional*): Spectrum
#' used for the background subtraction. By definition, the background spectrum should have been
#' measured with the same setting as the signal spectrum. If a spectrum is provided, the
#' argument `bg.channels` works only on the provided background spectrum.
#'
#' @param bg.channels [vector] (*optional*):
#' defines channel for background subtraction If a vector is provided the mean
#' of the channels is used for subtraction. If a spectrum is provided via `bg.spectrum`, this
#' argument only works on the `bg.spectrum`.
#'
#' **Note:** Background subtraction is applied prior to channel binning
#'
#' @param bin.rows [integer] (*with default*):
#' allow summing-up wavelength channels (horizontal binning),
#' e.g. `bin.rows = 2` two channels are summed up.
#' Binning is applied after the background subtraction.
#'
#' @param bin.cols [integer] (*with default*):
#' allow summing-up channel counts (vertical binning) for plotting,
#' e.g. `bin.cols = 2` two channels are summed up.
#' Binning is applied after the background subtraction.
#'
#' @param norm [character] (*optional*): Normalise data to the maximum (`norm = "max"`) or
#' minimum (`norm = "min"`) count values. The normalisation is applied after the binning.
#'
#' @param rug [logical] (*with default*):
#' enables or disables colour rug. Currently only implemented for plot
#' type `multiple.lines` and `single`
#'
#' @param limit_counts [numeric] (*optional*):
#' value to limit all count values to this value, i.e. all count values above
#' this threshold will be replaced by this threshold. This is helpful
#' especially in case of TL-spectra.
#'
#' @param xaxis.energy [logical] (*with default*): enables or disables energy instead of
#' wavelength axis. For the conversion the function [convert_Wavelength2Energy] is used.
#'
#' **Note:** This option means not only simply redrawing the axis,
#' instead the spectrum in terms of intensity is recalculated, s. details.
#'
#' @param legend.text [character] (*with default*):
#' possibility to provide own legend text. This argument is only considered for
#' plot types providing a legend, e.g. `plot.type="transect"`
#'
#' @param plot [logical] (*with default*): enables/disables plot output. If the plot
#' output is disabled, the [matrix] used for the plotting and the calculated colour values
#' (as attributes) are returned. This way, the (binned, transformed etc.) output can
#' be used in other functions and packages, such as plotting with the package `'plot3D'`
#'
#' @param ... further arguments and graphical parameters that will be passed
#' to the `plot` function.
#'
#' @return Returns a plot and the transformed `matrix` used for plotting with some useful
#' attributes such as the `colour` and `pmat` (the transpose matrix from [graphics::persp])
#'
#' @note Not all additional arguments (`...`) will be passed similarly!
#'
#' @section Function version: 0.6.8
#'
#' @author
#' Sebastian Kreutzer, Institute of Geography, Heidelberg University (Germany)
#'
#' @seealso [RLum.Data.Spectrum-class], [convert_Wavelength2Energy], [plot], [plot_RLum], [graphics::persp], [plotly::plot_ly], [graphics::contour], [graphics::image]
#'
#' @keywords aplot
#'
#' @examples
#'
#' ##load example data
#' data(ExampleData.XSYG, envir = environment())
#'
#' ##(1)plot simple spectrum (2D) - image
#' plot_RLum.Data.Spectrum(
#' TL.Spectrum,
#' plot.type="image",
#' xlim = c(310,750),
#' ylim = c(0,300),
#' bin.rows=10,
#' bin.cols = 1)
#'
#' ##(2) plot spectrum (3D)
#' plot_RLum.Data.Spectrum(
#' TL.Spectrum,
#' plot.type="persp",
#' xlim = c(310,750),
#' ylim = c(0,100),
#' bin.rows=10,
#' bin.cols = 1)
#'
#'##(3) plot spectrum on energy axis
#'##please note the background subtraction
#'plot_RLum.Data.Spectrum(TL.Spectrum,
#' plot.type="persp",
#' ylim = c(0,200),
#' bin.rows=10,
#' bg.channels = 10,
#' bin.cols = 1,
#' xaxis.energy = TRUE)
#'
#' ##(4) plot multiple lines (2D) - multiple.lines (with ylim)
#' plot_RLum.Data.Spectrum(
#' TL.Spectrum,
#' plot.type="multiple.lines",
#' xlim = c(310,750),
#' ylim = c(0,100),
#' bin.rows=10,
#' bin.cols = 1)
#'
#' \dontrun{
#' ##(4) interactive plot using the package plotly ("surface")
#' plot_RLum.Data.Spectrum(TL.Spectrum, plot.type="interactive",
#' xlim = c(310,750), ylim = c(0,300), bin.rows=10,
#' bin.cols = 1)
#'
#' ##(5) interactive plot using the package plotly ("contour")
#' plot_RLum.Data.Spectrum(TL.Spectrum, plot.type="interactive",
#' xlim = c(310,750), ylim = c(0,300), bin.rows=10,
#' bin.cols = 1,
#' type = "contour",
#' showscale = TRUE)
#'
#' ##(6) interactive plot using the package plotly ("heatmap")
#' plot_RLum.Data.Spectrum(TL.Spectrum, plot.type="interactive",
#' xlim = c(310,750), ylim = c(0,300), bin.rows=10,
#' bin.cols = 1,
#' type = "heatmap",
#' showscale = TRUE)
#'
#' }
#'
#' @md
#' @export
plot_RLum.Data.Spectrum <- function(
object,
par.local = TRUE,
plot.type = "contour",
optical.wavelength.colours = TRUE,
bg.spectrum = NULL,
bg.channels = NULL,
bin.rows = 1,
bin.cols = 1,
norm = NULL,
rug = TRUE,
limit_counts = NULL,
xaxis.energy = FALSE,
legend.text,
plot = TRUE,
...
){
# Integrity check -----------------------------------------------------------
##check if object is of class RLum.Data.Spectrum
if(!inherits(object, "RLum.Data.Spectrum")){
if(inherits(object, "matrix")){
if(is.null(colnames(object))){
colnames(object) <- 1:ncol(object)
}
if(is.null(rownames(object))){
rownames(object) <- 1:nrow(object)
}
object <- set_RLum(class = "RLum.Data.Spectrum",
data = object)
message("[plot_RLum.Data.Spectrum()] Input has been converted to a RLum.Data.Spectrum object using set_RLum()")
}else{
stop("[plot_RLum.Data.Spectrum()] Input object neither of class 'RLum.Data.Spectrum' nor 'matrix'.",
call. = FALSE)
}
}
##XSYG
##check for curveDescripter
if("curveDescripter" %in% names(object@info) == TRUE){
temp.lab <- strsplit(object@info$curveDescripter, split = ";")[[1]]
xlab <- if(xaxis.energy == FALSE){
temp.lab[2]}else{"Energy [eV]"}
ylab <- temp.lab[1]
zlab <- temp.lab[3]
}else{
xlab <- if(xaxis.energy == FALSE){
"Row values [a.u.]"}else{"Energy [eV]"}
ylab <- "Column values [a.u.]"
zlab <- "Cell values [a.u.]"
}
# Do energy axis conversion -------------------------------------------------------------------
if (xaxis.energy){
##conversion
object <- convert_Wavelength2Energy(object, digits = 5)
##modify row order (otherwise subsequent functions, like persp, have a problem)
object@data[] <- object@data[order(as.numeric(rownames(object@data))),]
rownames(object@data) <- sort(as.numeric(rownames(object@data)))
}
##deal with addition arguments
extraArgs <- list(...)
main <- if("main" %in% names(extraArgs)) {extraArgs$main} else
{"RLum.Data.Spectrum"}
zlab <- if("zlab" %in% names(extraArgs)) {extraArgs$zlab} else
{ifelse(plot.type == "multiple.lines", ylab, zlab)}
xlab <- if("xlab" %in% names(extraArgs)) {extraArgs$xlab} else
{xlab}
ylab <- if("ylab" %in% names(extraArgs)) {extraArgs$ylab} else
{ifelse(plot.type == "single" | plot.type == "multiple.lines",
"Luminescence [cts/channel]", ylab)}
xlim <- if("xlim" %in% names(extraArgs)) {extraArgs$xlim} else
{c(min(as.numeric(rownames(object@data))),
max(as.numeric(rownames(object@data))))}
ylim <- if("ylim" %in% names(extraArgs)) {extraArgs$ylim} else
{c(min(as.numeric(colnames(object@data))),
max(as.numeric(colnames(object@data))))}
#for zlim see below
mtext <- if("mtext" %in% names(extraArgs)) {extraArgs$mtext} else
{""}
cex <- if("cex" %in% names(extraArgs)) {extraArgs$cex} else
{1}
phi <- if("phi" %in% names(extraArgs)) {extraArgs$phi} else
{15}
theta <- if("theta" %in% names(extraArgs)) {extraArgs$theta} else
{-30}
r <- if("r" %in% names(extraArgs)) {extraArgs$r} else
{10}
shade <- if("shade" %in% names(extraArgs)) {extraArgs$shade} else
{0.4}
expand <- if("expand" %in% names(extraArgs)) {extraArgs$expand} else
{0.6}
border <- if("border" %in% names(extraArgs)) {extraArgs$border} else
{NULL}
box <- if("box" %in% names(extraArgs)) {extraArgs$box} else
{TRUE}
axes <- if("axes" %in% names(extraArgs)) {extraArgs$axes} else
{TRUE}
ticktype <- if("ticktype" %in% names(extraArgs)) {extraArgs$ticktype} else
{"detailed"}
log<- if("log" %in% names(extraArgs)) {extraArgs$log} else
{""}
type<- if("type" %in% names(extraArgs)) {extraArgs$type} else
{
if (plot.type == "interactive") {
"surface"
} else{
"l"
}
}
pch<- if("pch" %in% names(extraArgs)) {extraArgs$pch} else
{1}
lwd<- if("lwd" %in% names(extraArgs)) {extraArgs$lwd} else
{1}
bty <- if("bty" %in% names(extraArgs)) {extraArgs$bty} else
{NULL}
sub<- if("sub" %in% names(extraArgs)) {extraArgs$sub} else
{""}
#for plotly::plot_ly
showscale<- if("showscale" %in% names(extraArgs)) {extraArgs$showscale} else
{FALSE}
# prepare values for plot ---------------------------------------------------
##copy data
temp.xyz <- object@data
##check for NULL column names
if(is.null(colnames(temp.xyz))){
colnames(temp.xyz) <- 1:ncol(temp.xyz)
}
if(is.null(rownames(temp.xyz))){
rownames(temp.xyz) <- 1:nrow(temp.xyz)
}
##check for the case of a single column matrix
if(ncol(temp.xyz)>1){
##reduce for xlim
temp.xyz <- temp.xyz[as.numeric(rownames(temp.xyz)) >= xlim[1] &
as.numeric(rownames(temp.xyz)) <= xlim[2],]
##reduce for ylim
temp.xyz <- temp.xyz[, as.numeric(colnames(temp.xyz)) >= ylim[1] &
as.numeric(colnames(temp.xyz)) <= ylim[2]]
}
## wavelength
x <- as.numeric(rownames(temp.xyz))
## time/temp
y <- as.numeric(colnames(temp.xyz))
# Background spectrum -------------------------------------------------------------------------
if(!is.null(bg.spectrum)){
if(inherits(bg.spectrum, "RLum.Data.Spectrum") || inherits(bg.spectrum, "matrix")){
##case RLum
if(inherits(bg.spectrum, "RLum.Data.Spectrum")) bg.xyz <- bg.spectrum@data
##case matrix
if(inherits(bg.spectrum, "matrix")) bg.xyz <- bg.spectrum
##take care of channel settings, otherwise set bg.channels
if(is.null(bg.channels))
bg.channels <- c(1:ncol(bg.xyz))
##set rownames
if(is.null(rownames(bg.xyz)))
rownames(bg.xyz) <- 1:nrow(bg.xyz)
##convert to energy scale if needed
if(xaxis.energy){
#conversion
bg.xyz <- convert_Wavelength2Energy(cbind(as.numeric(rownames(bg.xyz)), bg.xyz), digits = 5)
rownames(bg.xyz) <- bg.xyz[,1]
bg.xyz <- bg.xyz[,-1, drop = FALSE]
##modify row order (otherwise subsequent functions, like persp, have a problem)
bg.xyz <- bg.xyz[order(as.numeric(rownames(bg.xyz))),,drop = FALSE]
rownames(bg.xyz) <- sort(as.numeric(rownames(bg.xyz)))
}
##reduce for xlim
bg.xyz <- bg.xyz[as.numeric(rownames(bg.xyz)) >= xlim[1] &
as.numeric(rownames(bg.xyz)) <= xlim[2],,drop = FALSE]
}else{
stop("[plot_RLum.Data.Spectrum()] Input for 'bg.spectrum' not supported, please check manual!", call. = FALSE)
}
}
# Background subtraction ---------------------------------------------------
if(!is.null(bg.channels)){
##set background object if not available
if(is.null(bg.spectrum)) bg.xyz <- temp.xyz
if(max(bg.channels) > ncol(bg.xyz) || any(bg.channels <= 0)){
##correct the mess
bg.channels <- sort(unique(bg.channels))
bg.channels[bg.channels <= 0] <- 1
bg.channels[bg.channels >= ncol(bg.xyz)] <- ncol(bg.xyz)
warning(
paste0(
"[plot_RLum.Data.Spectrum()] 'bg.channels' out of range, corrected to: ",
min(bg.channels),
":",
max(bg.channels)
), call. = FALSE)
}
if(length(bg.channels) > 1){
temp.bg.signal <- rowMeans(bg.xyz[,bg.channels])
temp.xyz <- temp.xyz - temp.bg.signal
}else{
temp.xyz <- temp.xyz - bg.xyz[,bg.channels]
}
##set values < 0 to 0
temp.xyz[temp.xyz < 0] <- 0
##check worst case
if(sum(temp.xyz) == 0){
message("[plot_RLum.Data.Spectrum()] After background subtraction all counts < 0. Nothing plotted, NULL returned!")
return(NULL)
}
}
# Channel binning ---------------------------------------------------------
##rewrite arguments; makes things easier
bin.cols <- bin.cols[1]
bin.rows <- bin.rows[1]
##fatal check (not needed anymore, but never change running code)
if(bin.cols < 1 | bin.rows < 1)
stop("[plot_RLum.Data.Spectrum()] 'bin.cols' and 'bin.rows' have to be > 1!", call. = FALSE)
if(bin.rows > 1){
temp.xyz <- .matrix_binning(temp.xyz, bin_size = bin.rows, bin_col = FALSE, names = "mean")
x <- as.numeric(rownames(temp.xyz))
##remove last channel (this is the channel that included less data)
if(length(x)%%bin.rows != 0){
##return warning
warning(
paste0("[plot_RLum.Data.Spectrum()] ",length(x)%%bin.rows,
" channel(s) removed due to row (wavelength) binning."),
call. = FALSE)
##do it
temp.xyz <- temp.xyz[-length(x),]
x <- x[-length(x)]
}
}
if(bin.cols > 1){
temp.xyz <- .matrix_binning(temp.xyz, bin_size = bin.cols, bin_col = TRUE, names = "groups")
y <- as.numeric(colnames(temp.xyz))
##remove last channel (this is the channel that included less data)
if(length(y)%%bin.cols != 0){
##return warning
warning(
paste0("[plot_RLum.Data.Spectrum()] ",length(y)%%bin.cols,
" channel(s) removed due to column (frame) binning."),
call. = FALSE)
##do it
temp.xyz <- temp.xyz[,-length(y)]
y <- y[-length(y)]
}
}
##limit z-values if requested, this idea was taken from the Diss. by Thomas Schilles, 2002
if(!is.null(limit_counts[1]))
temp.xyz[temp.xyz[] > max(min(temp.xyz), limit_counts[1])] <- limit_counts[1]
# Normalise if wanted -------------------------------------------------------------------------
if(!is.null(norm)){
if(norm == "min")
temp.xyz <- temp.xyz/min(temp.xyz)
if(norm == "max")
temp.xyz <- temp.xyz/max(temp.xyz)
}
##check for zlim
zlim <- if("zlim" %in% names(extraArgs)) {extraArgs$zlim} else
{range(temp.xyz)}
# set colour values --------------------------------------------------------
if("col" %in% names(extraArgs) == FALSE | plot.type == "single" | plot.type == "multiple.lines"){
if(optical.wavelength.colours == TRUE | (rug == TRUE & (plot.type != "persp" & plot.type != "interactive"))){
##make different colour palette for energy values
if (xaxis.energy) {
col.violet <- c(2.76, ifelse(max(xlim) <= 4.13, max(xlim), 4.13))
col.blue <- c(2.52, 2.76)
col.green <- c(2.18, 2.52)
col.yellow <- c(2.10, 2.18)
col.orange <- c(2.00, 2.10)
col.red <- c(1.57, 2.00)
col.infrared <-
c(1.55, ifelse(min(xlim) >= 1.55, min(xlim), 1.57))
#set colour palette
col <- unlist(sapply(1:length(x), function(i){
if(x[i] >= col.violet[1] & x[i] < col.violet[2]){"#EE82EE"}
else if(x[i] >= col.blue[1] & x[i] < col.blue[2]){"#0000FF"}
else if(x[i] >= col.green[1] & x[i] < col.green[2]){"#00FF00"}
else if(x[i] >= col.yellow[1] & x[i] < col.yellow[2]){"#FFFF00"}
else if(x[i] >= col.orange[1] & x[i] < col.orange[2]){"#FFA500"}
else if(x[i] >= col.red[1] & x[i] < col.red[2]){"#FF0000"}
else if(x[i] <= col.infrared[2]){"#BEBEBE"}
}))
}else{
##wavelength colours for wavelength axis
col.violet <- c(ifelse(min(xlim) <= 300, min(xlim), 300),450)
col.blue <- c(450,495)
col.green <- c(495,570)
col.yellow <- c(570,590)
col.orange <- c(590,620)
col.red <- c(620,790)
col.infrared <-
c(790, ifelse(max(xlim) >= 800, max(xlim), 800))
#set colour palette
col <- unlist(sapply(1:length(x), function(i){
if(x[i] >= col.violet[1] & x[i] < col.violet[2]){"#EE82EE"}
else if(x[i] >= col.blue[1] & x[i] < col.blue[2]){"#0000FF"}
else if(x[i] >= col.green[1] & x[i] < col.green[2]){"#00FF00"}
else if(x[i] >= col.yellow[1] & x[i] < col.yellow[2]){"#FFFF00"}
else if(x[i] >= col.orange[1] & x[i] < col.orange[2]){"#FFA500"}
else if(x[i] >= col.red[1] & x[i] < col.red[2]){"#FF0000"}
else if(x[i] >= col.infrared[1]){"#BEBEBE"}
}))
}
##find unique colours
col.unique <- unique(col)
##if only one colour value, then skip gradient calculation as it causes
##an error
if(length(col.unique) > 1){
##set colour function for replacement
colfunc <- colorRampPalette(col.unique)
##get index for colour values to be cut from the current palette
col.unique.index <-
vapply(col.unique, function(i) {
max(which(col == i))
}, numeric(1))
##remove last index (no colour gradient needed), for energy axis use the first value
col.unique.index <- col.unique.index[-length(col.unique.index)]
##set borders for colour gradient recalculation
col.unique.index.min <- col.unique.index - (50/bin.rows)
col.unique.index.max <- col.unique.index + (50/bin.rows)
##set negative values to the lowest index
col.unique.index.min[col.unique.index.min<=0] <- 1
##build up new index sequence (might be better)
col.gradient.index <- as.vector(unlist((
sapply(1:length(col.unique.index.min), function(j){
seq(col.unique.index.min[j],col.unique.index.max[j], by = 1)
}))))
##generate colour ramp and replace values
col.new <- colfunc(length(col.gradient.index))
col[col.gradient.index] <- col.new
##correct for overcharged colour values (causes zebra colour pattern)
if (diff(c(length(col), nrow(temp.xyz))) < 0) {
col <- col[1:c(length(col) - diff(c(length(col), nrow(temp.xyz))))]
}else if(diff(c(length(col), nrow(temp.xyz))) > 0){
col <- col[1:c(length(col) + diff(c(length(col), nrow(temp.xyz))))]
}
}
}else{
col <- "black"
}
}else{
col <- extraArgs$col
}
# Do log scaling if needed -------------------------------------------------
##x
if(grepl("x", log)==TRUE){x <- log10(x)}
##y
if(grepl("y", log)==TRUE){y <- log10(y)}
##z
if(grepl("z", log)==TRUE){temp.xyz <- log10(temp.xyz)}
# PLOT --------------------------------------------------------------------
## set variables we need later
pmat <- NA
if(plot){
##par setting for possible combination with plot method for RLum.Analysis objects
if(par.local) par(mfrow=c(1,1), cex = cex)
##rest plot type for 1 column matrix
if(ncol(temp.xyz) == 1 && plot.type != "single"){
plot.type <- "single"
warning("[plot_RLum.Data.Spectrum()] Single column matrix: plot.type has been automatically reset to 'single'", call. = FALSE)
}
##do not let old code break down ...
if(plot.type == "persp3d"){
plot.type <- "interactive"
warning("[plot_RLum.Data.Spectrum()] 'plot.type' has been automatically reset to interactive!", call. = FALSE)
}
if(plot.type == "persp" && ncol(temp.xyz) > 1){
## Plot: perspective plot ----
## ==========================================================================#
pmat <- persp(
x, y, temp.xyz,
shade = shade,
axes = if(box[1] == "alternate") FALSE else axes,
phi = phi,
theta = theta,
xlab = xlab,
ylab = ylab,
zlab = zlab,
zlim = zlim,
scale = TRUE,
col = col[1:(length(x)-1)], ##needed due to recycling of the colours
main = main,
expand = expand,
border = border,
box = if(box[1] == "alternate") FALSE else box,
r = r,
ticktype = ticktype)
## this is custom plot output that might come in handy from time to time
if(axes & box[1] == "alternate") {
## add axes manually
x_axis <- seq(min(x), max(x), length.out = 20)
y_axis <- seq(min(y), max(y), length.out = 20)
z_axis <- seq(min(temp.xyz), max(temp.xyz), length.out = 20)
lines(grDevices::trans3d(x_axis,min(y) - 5, min(temp.xyz),pmat))
lines(grDevices::trans3d(min(x) - 5,y_axis, min(temp.xyz),pmat))
lines(grDevices::trans3d(min(x) - 5,max(y), z_axis,pmat))
## x-axis
px_axis <- pretty(x_axis)
px_axis <- px_axis[(px_axis) > min(x_axis) & px_axis < max(x_axis)]
tick_start <- grDevices::trans3d(px_axis, min(y_axis), min(z_axis), pmat)
tick_end <- grDevices::trans3d(
px_axis, min(y_axis) - max(y_axis) * 0.05, min(z_axis), pmat)
## calculate slope angle for xlab and ticks
m <- (tick_start$y[2] - tick_start$y[1]) / (tick_start$x[2] - tick_start$x[1])
m <- atan(m) * 360 / (2 * pi)
segments(tick_start$x, tick_start$y, tick_end$x, tick_end$y)
text(
tick_end$x,
tick_end$y,
adj = c(0.5,1.2),
px_axis,
xpd = TRUE,
cex = 0.85,
srt = m)
## x-axis label
text(
mean(tick_end$x),
min(tick_end$y),
adj = c(0.5, 1),
xlab,
srt = m,
xpd = TRUE)
## y-axis
py_axis <- pretty(y_axis)
py_axis <- py_axis[(py_axis) > min(y_axis) & py_axis < max(y_axis)]
tick_start <- grDevices::trans3d(min(x_axis), py_axis, min(z_axis), pmat)
tick_end <- grDevices::trans3d(
min(x_axis) - max(x_axis) * 0.025, py_axis, min(z_axis), pmat)
segments(tick_start$x, tick_start$y, tick_end$x, tick_end$y)
## calculate slope angle for xlab and ticks
m <- (tick_start$y[2] - tick_start$y[1]) / (tick_start$x[2] - tick_start$x[1])
m <- atan(m) * 360 / (2 * pi)
text(
tick_end$x,
tick_end$y,
py_axis,
adj = c(0.6,1.2),
srt = m,
cex = 0.85,
xpd = TRUE)
## y-axis label
text(
min(tick_end$x),
mean(tick_end$y),
adj = c(0.5, 1),
ylab,
srt = m,
xpd = TRUE)
## z-axis
pz_axis <- pretty(z_axis)
pz_axis <- pz_axis[(pz_axis) > min(z_axis) & pz_axis < max(z_axis)]
tick_start <- grDevices::trans3d(min(x_axis), max(y_axis), pz_axis, pmat)
tick_end <- grDevices::trans3d(
min(x_axis) - max(x_axis) * 0.015, max(y_axis), pz_axis, pmat)
segments(tick_start$x, tick_start$y, tick_end$x, tick_end$y)
## calculate slope angle for xlab and ticks
m <- (tick_start$y[2] - tick_start$y[1]) / (tick_start$x[2] - tick_start$x[1])
m <- atan(m) * 360 / (2 * pi)
text(
tick_end$x,
tick_end$y,
format(pz_axis, scientific = TRUE, digits = 1),
adj = c(0.5,1.2),
srt = m,
xpd = TRUE,
cex = 0.85)
## z-axis label
text(
min(tick_end$x),
mean(tick_end$y),
adj = c(0.5, 2.5),
zlab,
srt = m,
xpd = TRUE)
}
##plot additional mtext
mtext(mtext, side = 3, cex = cex * 0.8)
}else if(plot.type == "interactive" && ncol(temp.xyz) > 1) {
## ==========================================================================#
##interactive plot and former persp3d
## ==========================================================================#
## Plot: interactive ----
##http://r-pkgs.had.co.nz/description.html
if (!requireNamespace("plotly", quietly = TRUE)) {
stop("[plot_RLum.Data.Spectrum()] Package 'plotly' needed for this plot type. Please install it.",
call. = FALSE)
}
##set up plot
p <- plotly::plot_ly(
z = temp.xyz,
x = as.numeric(colnames(temp.xyz)),
y = as.numeric(rownames(temp.xyz)),
type = type,
showscale = showscale
#colors = col[1:(length(col)-1)],
)
##change graphical parameters
p <- plotly::layout(
p = p,
scene = list(
xaxis = list(
title = ylab
),
yaxis = list(
title = xlab
),
zaxis = list(title = zlab)
),
title = main
)
print(p)
on.exit(return(p))
}else if(plot.type == "contour" && ncol(temp.xyz) > 1) {
## Plot: contour plot ----
## ==========================================================================#
contour(x,y,temp.xyz,
xlab = xlab,
ylab = ylab,
main = main,
labcex = 0.6 * cex,
col = "black"
)
##plot additional mtext
mtext(mtext, side = 3, cex = cex*0.8)
}else if(plot.type == "image" && ncol(temp.xyz) > 1) {
## Plot: image plot ----
## ==========================================================================#
graphics::image(x,y,temp.xyz,
xlab = xlab,
ylab = ylab,
main = main,
col = if(is.null(list(...)$col)) grDevices::hcl.colors(50, palette = "Inferno") else
list(...)$col
)
if(is.null(list(...)$contour) || list(...)$contour != FALSE) {
contour(x, y, temp.xyz,
col = if(is.null(list(...)$contour.col)) rgb(1,1,1,0.8) else list(...)$contour.col,
labcex = 0.6 * cex,
add = TRUE)
}
##plot additional mtext
mtext(mtext, side = 3, cex = cex*0.8)
} else if(plot.type == "single") {
## Plot: single plot ----
## ==========================================================================#
## set colour rug
col.rug <- col
col <- if("col" %in% names(extraArgs)) {extraArgs$col} else {"black"}
box <- if("box" %in% names(extraArgs)) extraArgs$box[1] else TRUE
frames <- if("frames" %in% names(extraArgs)) extraArgs$frames else 1:length(y)
for(i in frames) {
if("zlim" %in% names(extraArgs) == FALSE){zlim <- range(temp.xyz[,i])}
plot(x, temp.xyz[,i],
xlab = xlab,
ylab = ylab,
main = main,
xlim = xlim,
ylim = zlim,
frame = box,
xaxt = "n",
col = col,
sub = paste(
"(frame ",i, " | ",
ifelse(i==1,
paste("0.0 :", round(y[i], digits = 1)),
paste(round(y[i-1], digits = 1),":",
round(y[i], digits =1))),")",
sep = ""),
type = type,
pch = pch)
## add colour rug
if(rug){
##rug as continuous rectangle
i <- floor(seq(1,length(x), length.out = 300))
graphics::rect(
xleft = x[i[-length(i)]],
xright = x[i[-1]],
ytop = par("usr")[3] + diff(c(par("usr")[3], min(zlim))) * 0.9,
ybottom = par("usr")[3],
col = col.rug[i],
border = NA,
lwd = 1)
## add rectangle from zero to first value
graphics::rect(
xleft = par()$usr[1],
xright = x[i[1]],
ytop = par("usr")[3] + diff(c(par("usr")[3], min(zlim))) * 0.9,
ybottom = par("usr")[3],
col = col.rug[1],
density = 50,
border = NA,
lwd = 1)
## add rectangle from the last value to end of plot
graphics::rect(
xleft = x[i[length(i)]],
xright = par()$usr[2],
ytop = par("usr")[3] + diff(c(par("usr")[3], min(zlim))) * 0.9,
ybottom = par("usr")[3],
col = col.rug[length(col.rug)],
density = 50,
border = NA,
lwd = 1)
}
## add y axis to prevent overplotting
graphics::axis(side = 1)
## add box if needed
if(box) graphics::box()
}
##plot additional mtext
mtext(mtext, side = 3, cex = cex*0.8)
}else if(plot.type == "multiple.lines" && ncol(temp.xyz) > 1) {
## Plot: multiple.lines ----
## ========================================================================#
col.rug <- col
col<- if("col" %in% names(extraArgs)) {extraArgs$col} else {"black"}
box <- if("box" %in% names(extraArgs)) extraArgs$box else TRUE
frames <- if("frames" %in% names(extraArgs)) extraArgs$frames else 1:length(y)
##change graphic settings
par.default <- par()[c("mfrow", "mar", "xpd")]
par(mfrow = c(1,1), mar=c(5.1, 4.1, 4.1, 8.1), xpd = TRUE)
##grep zlim
if("zlim" %in% names(extraArgs) == FALSE){zlim <- range(temp.xyz)}
##open plot area
plot(NA, NA,
xlab = xlab,
ylab = ylab,
main = main,
xlim = xlim,
ylim = zlim,
frame = box,
xaxt = "n",
sub = sub,
bty = bty)
## add colour rug
if(rug){
##rug as continuous rectangle
i <- floor(seq(1,length(x), length.out = 300))
graphics::rect(
xleft = x[i[-length(i)]],
xright = x[i[-1]],
ytop = par("usr")[3] + diff(c(par("usr")[3], min(zlim))) * 0.9,
ybottom = par("usr")[3],
col = col.rug[i],
border = NA,
lwd = NA)
## add rectangle from zero to first value
graphics::rect(
xleft = par()$usr[1],
xright = x[i[1]],
ytop = par("usr")[3] + diff(c(par("usr")[3], min(zlim))) * 0.9,
ybottom = par("usr")[3],
col = col.rug[1],
density = 50,
border = NA,
lwd = 1)
## add rectangle from the last value to end of plot
graphics::rect(
xleft = x[i[length(i)]],
xright = par()$usr[2],
ytop = par("usr")[3] + diff(c(par("usr")[3], min(zlim))) * 0.9,
ybottom = par("usr")[3],
col = col.rug[length(col.rug)],
density = 50,
border = NA,
lwd = 1)
}
##add lines
for(i in frames){
lines(x,
temp.xyz[,i],
lty = i,
lwd = lwd,
type = type,
col = col)
}
## add y axis to prevent overplotting
graphics::axis(side = 1)
## add box if needed
if(box) graphics::box()
##for missing values - legend.text
if(missing(legend.text))
legend.text <- as.character(paste(round(y[frames],digits=1), zlab))
##legend
legend(x = par()$usr[2],
y = par()$usr[4],
legend = legend.text,
lwd= lwd,
lty = frames,
bty = "n",
cex = 0.6*cex)
##plot additional mtext
mtext(mtext, side = 3, cex = cex*0.8)
##reset graphic settings
par(par.default)
rm(par.default)
}else if(plot.type == "transect" && ncol(temp.xyz) > 1) {
## Plot: transect plot ----
## ========================================================================#
##sum up rows (column sum)
temp.xyz <- colSums(temp.xyz)
##consider differences within the arguments
#check for zlim
zlim <- if("zlim" %in% names(extraArgs)) {extraArgs$zlim} else
{c(0,max(temp.xyz))}
#check for zlim
zlab <- if("ylab" %in% names(extraArgs)) {extraArgs$ylab} else
{paste("Counts [1/summed channels]")}
plot(y, temp.xyz,
xlab = ylab,
ylab = zlab,
main = main,
xlim = ylim,
ylim = zlim,
col = col,
sub = paste("(channel range: ", min(xlim), " : ", max(xlim), ")", sep=""),
type = type,
pch = pch)
##plot additional mtext
mtext(mtext, side = 3, cex = cex*0.8)
}else{
stop("[plot_RLum.Data.Spectrum()] Unknown plot type.", call. = FALSE)
}
## option for plotting nothing
}
# Return ------------------------------------------------------------------
## add some attributes
attr(temp.xyz, "colour") <- col
attr(temp.xyz, "pmat") <- pmat
## return visible or not
if(plot) invisible(temp.xyz) else return(temp.xyz)
}
Any scripts or data that you put into this service are public.
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.