Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update ball berry vignette #33

Merged
merged 3 commits into from
Aug 17, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions NAMESPACE
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ export(process_tdl_cycle_erml)
export(read_gm_table)
export(read_licor_file)
export(read_tdl_file)
export(remove_points)
export(smooth_tdl_data)
export(specify_variables)

Expand Down
45 changes: 45 additions & 0 deletions R/remove_points.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
remove_points <- function(exdf_obj, ...) {
if (!is.exdf(exdf_obj)) {
stop("remove_points requires an exdf object")
}

# Create a list of the optional input arguments
arg_list <- list(...)

# Make sure the optional input arguments are all lists
list_check <- sapply(arg_list, function(x) {!is.list(x)})
if (any(list_check)) {
stop("optional arguments to remove_points must be lists")
}

# Make sure the optional input arguments have names
name_check <- sapply(arg_list, function(x) {is.null(names(x))})
if (any(name_check)) {
stop("optional arguments to remove_points must have names")
}

# Go through each set of conditions to remove the desired points
for (point_description in arg_list) {
# Make sure the exdf object contains the specified columns
required_columns <-
lapply(point_description, function(x) {return(NA)})

check_required_columns(exdf_obj, required_columns)

# Initialize the logical vector of points to keep
points_to_keep <- rep.int(FALSE, nrow(exdf_obj))

# Apply all the conditions, adding back any points that don't meet the
# criteria
for (i in seq_along(point_description)) {
name <- names(point_description)[i]
condition <- point_description[[i]]
points_to_keep <- points_to_keep | !(exdf_obj[ , name] %in% condition)
}

# Truncate the exdf to just the points that don't meet the condition
exdf_obj <- exdf_obj[points_to_keep, , TRUE]
}

return(exdf_obj)
}
58 changes: 58 additions & 0 deletions man/remove_points.Rd
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
\name{remove_points}

\alias{remove_points}

\title{Remove specific points from an exdf object}

\description{
Removes all points from an \code{exdf} object that satisfy a set of
conditions.
}

\usage{
remove_points(exdf_obj, \dots)
}

\arguments{
\item{exdf_obj}{An \code{exdf} object.}

\item{\dots}{
Each optional argument should be a list of named elements that specify
points to be removed from \code{exdf_obj}. For example,
\code{list(species = 'soybean', plot = c('1a', '1b'))} specifies the set of
points where (1) \code{species} is \code{'soybean'} and (2) \code{plot} is
\code{'1a'} or \code{'1b'}.
}
}

\value{
An \code{exdf} object formed from \code{exdf_obj} by removing all rows that
meet the conditions specified by the optional input arguments.
}

\seealso{\code{\link{exdf}}}

\examples{
# Create an exdf object by reading a Licor Excel file
licor_file <- read_licor_file(
system.file("extdata", "ball_berry_1.xlsx", package = "PhotoGEA"),
c(3, 5, 7, 9, 11, 13), 14, 15, 16, 17, 'time'
)

# Print the number of points in the data set
nrow(licor_file)

# Remove the following:
# - All points where `obs` is 28 (1 point)
# - All points where `species` is `soybean` and `plot` is `1a` or `1b` (14 points)
licor_file <- remove_points(
licor_file,
list(obs = 28),
list(species = 'soybean', plot = c('1a', '1b'))
)

# There should now be 15 fewer points remaining in the data set
nrow(licor_file)
}

\concept{exdf}
73 changes: 70 additions & 3 deletions vignettes/analyzing_ball_berry_data.Rmd
Original file line number Diff line number Diff line change
Expand Up @@ -310,6 +310,46 @@ so it is reasonable to expect that the measurements represent true steady-state
values. Considering this, all of these curves are acceptable based on the CO~2~
plots.

### Stability

```{r plot_stability}
xyplot(
`A:OK` + `gsw:OK` + Stable ~ Qin | curve_identifier,
data = licor_data$main_data,
type = 'b',
pch = 16,
auto = TRUE,
grid = TRUE,
xlim = c(0, 2200),
xlab = paste0('Incident PPFD (', licor_data$units$Qin, ')')
)
```

When measuring response curves with a Licor, it is possible to specify stability
criteria for each point in addition to minimum and maximum wait times. In other
words, once the set point for the driving variable is changed, the machine waits
until the stability criteria are met; there is a minimum waiting period, and
also a maximum to prevent the machine from waiting for too long. These stability
criteria are especially important for Ball-Berry curves, since the stomata may
take a long time to reach steady state.

When these curves were measured, stability criteria were supplied for the net
assimilation rate `A` and the stomatal conductance `gsw`. The stability status
for each was stored in the log file because the appropriate logging option for
stability was set. Now, for each point, it is possible to check whether
stability was achieved or whether the point was logged because the maximum
waiting period had been met. If the maximum waiting period is reached and the
plant has still not stabilized, the data point may be unreliable, so it is very
important to check this information.

In the plot, `A:OK` indicates whether `A` was stable (0 for no, 1 for yes),
`gsw:OK` indicates whether `gsw` was stable (0 for no, 1 for yes), and
`Stable` indicates the total number of stability conditions that were met. So,
we are looking for points where `Stable` is 2. Otherwise, we can check the other
traces to see whether `A` or `gsw` was unstable. Here it looks like many of the
high light points were not stable, and it may be a good idea to remove them
before proceeding with the Ball-Berry fitting.

### Light-Response Curves

```{r plot_assimilation}
Expand Down Expand Up @@ -340,10 +380,31 @@ likely a byproduct of the noise that was intentionally added to the true
measured data (see [The Data]). Nevertheless, it may be a good idea to remove
them before proceeding with the Ball-Berry fitting.

## Removing Bad Curves
## Cleaning the Licor Data

While checking over the plots in [Qualitative Checks], two issues were noticed:
(1) some points were logged before stability was achieved and (2) some of the
curves look abnormal. In this section, we will demonstrate how to remove the
unstable points and the weird curves.

The following command will keep only the points where `Stable` is exactly 2;
this condition means that all of the stability criteria were satisfied.
Sometimes, following this procedure, a curve will have very few stable points
remaining; it is usually a good idea to automatically exclude any curve with
fewer than three stable points.

```{r remove_unstable_points}
# Only keep points where stability was achieved
licor_data <- licor_data[licor_data[, 'Stable'] == 2, , TRUE]

# Remove any curves that have fewer than three remaining points
npts <- by(licor_data, licor_data[, 'curve_identifier'], nrow)
ids_to_keep <- names(npts[npts > 2])
licor_data <- licor_data[licor_data[, 'curve_identifier'] %in% ids_to_keep, , TRUE]
```

Since we have identified a few curves that may not be acceptable for Ball-Berry
fitting, we can remove them as follows:
fitting, we can remove them via the `remove_points` function from `PhotoGEA`:

```{r remove_curves}
# Define a list of curves to remove from the data set
Expand All @@ -355,9 +416,13 @@ curves_to_remove <- c(

# Remove them
licor_data <-
licor_data[!licor_data[, 'curve_identifier'] %in% curves_to_remove, , TRUE]
remove_points(licor_data, list(curve_identifier = curves_to_remove))
```

Note that `remove_points` can also be used to exclude individual points instead
of entire curves; see its help entry by typing `?remove_points` for more
information.

# Fitting Licor Data

Now that we have checked the data quality, we are ready to perform the fitting.
Expand Down Expand Up @@ -554,6 +619,8 @@ file to initialize your own script.

<<plot_assimilation>>

<<remove_unstable_points>>

<<remove_curves>>

<<calculate_bb_index>>
Expand Down
9 changes: 5 additions & 4 deletions vignettes/analyzing_tdl_data.Rmd
Original file line number Diff line number Diff line change
Expand Up @@ -349,9 +349,10 @@ system, and there is evidence that the calibration may be compromised during the
spike, it is probably a good idea to remove the TDL cycles where the ^12^C
signal from valve 26 suddenly becomes large.

Fortunately, this is simple to do in R. The following illustrates one way to
"clean" the data by removing the unreliable TDL cycles; here, we actually remove
two regions of the data that appear to be suspicious:
Fortunately, this is simple to do using the `remove_points` function from
`PhotoGEA`. The following illustrates how to "clean" the data by removing the
unreliable TDL cycles; here, we actually remove two regions of the data that
appear to be suspicious:

```{r removing_cycles}
# Define a vector of cycle numbers that should be removed
Expand All @@ -362,7 +363,7 @@ tdl_cycles_to_remove <- c(

# Remove them
tdl_files_clean <-
tdl_files[!tdl_files[, 'cycle_num'] %in% tdl_cycles_to_remove, , TRUE]
remove_points(tdl_files, list(cycle_num = tdl_cycles_to_remove))
```

## Smoothing the TDL Data
Expand Down