Skip to content

Commit

Permalink
fix conflict in topoplot
Browse files Browse the repository at this point in the history
Merge branch 'master' of https://github.com/craddm/eegUtils

# Conflicts:
#	R/topoplot.R
#	man/topoplot.Rd
  • Loading branch information
craddm committed Nov 22, 2018
2 parents 3c7e381 + 3c42aa5 commit ea8aeae
Show file tree
Hide file tree
Showing 56 changed files with 1,723 additions and 1,212 deletions.
1 change: 1 addition & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,6 @@ addons:
apt:
packages:
- libfreetype6
r_github_packages: lionel-/vdiffr
after_success:
- Rscript -e 'covr::codecov()'
4 changes: 4 additions & 0 deletions NAMESPACE
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,9 @@ S3method(interp_elecs,eeg_data)
S3method(list_epochs,eeg_ICA)
S3method(list_epochs,eeg_epochs)
S3method(plot_butterfly,default)
S3method(plot_butterfly,eeg_data)
S3method(plot_butterfly,eeg_epochs)
S3method(plot_butterfly,eeg_evoked)
S3method(plot_electrodes,default)
S3method(plot_electrodes,eeg_data)
S3method(plot_psd,data.frame)
Expand All @@ -66,6 +69,7 @@ S3method(reref_eeg,eeg_data)
S3method(rm_baseline,data.frame)
S3method(rm_baseline,eeg_data)
S3method(rm_baseline,eeg_epochs)
S3method(rm_baseline,eeg_evoked)
S3method(rm_baseline,eeg_tfr)
S3method(run_ICA,eeg_epochs)
S3method(select_elecs,default)
Expand Down
17 changes: 10 additions & 7 deletions NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,17 @@

### Function changes
- `topoplot()` now has a scaling parameter to scale the size of any lines or markers drawn on the plot
- `plot_tfr` function now useable, with baseline correction added.
- `rm_baseline` now handles `eeg_tfr` objects.
- `as.data.frame` method added for `eeg_tfr` objects.
- `compute_tfr` function now available for use.
- Data selectors added for `eeg_tfr` objects (e.g. `select_elecs`)
- `plot_tfr()` function now useable, with baseline correction added.
- `rm_baseline()` now handles `eeg_tfr` objects.
- `as.data.frame()` method added for `eeg_tfr` objects.
- `compute_tfr()` function now available for use with Morlet wavelets.
- `plot_psd()` now allows changing of FFT parameters (e.g. number off FFT points, segment length)
- Data selectors added for `eeg_tfr` objects (e.g. `select_elecs()`)

### Internal changes/ bug fixes
- `plot_timecourse()` overhauled to be S3 method
- `plot_butterfly()` reworked internally to be more efficient
- `rm_baseline()` simplified internally, reworked to use matrices; split to separate file.
- `select_elecs()` now works for `eeg_evoked` objects
- `eeg_decomp` function in progress for performing SSD analyses
- Various methods added for TFR analyses
Expand All @@ -25,15 +28,15 @@
- `plot_tfr()` function added to handle `eeg_tfr` objects.
- `erp_image()` now works with `eeg_ICA` objects
- Generic print methods added for `eeg_epochs` and `eeg_data`
- `compute_tfr` function added to performed TFA on `eeg_epochs`
- `compute_tfr()` function added to performed TFA on `eeg_epochs`
- `epoch_data()` now warns if some events are not found rather than stops. Only stops if *no* events are found.

### Internal changes/ bug fixes
- `reref_eeg()`
- correctly excludes multiple named electrodes (i.e. passed as characters rather than numbers), where it previously silently failed.
- no longer records the reference data in the `ref_data` field
- `tf_morlet` recoded to be called internally
- `compute_psd`
- `compute_psd()`
- recoded to call `welch_fft()` in order to support possibility of different FFT methods.
- now drops the DC component (frequency 0)
- `welch_fft()` internal function added
Expand Down
214 changes: 214 additions & 0 deletions R/baseline_correction.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,214 @@
#' Baseline correction
#'
#' Used to remove the mean of a specified time period from the data. Currently
#' only performs subtractive baseline. With a data frame, searches for
#' "electrode" and "epoch" columns, and groups on these when found. An electrode
#' column is always required; an epoch column is not.
#'
#' @author Matt Craddock \email{matt@@mattcraddock.com}
#' @param data Data to be baseline corrected.
#' @param ... other parameters to be passed to functions
#' @export

rm_baseline <- function(data, ...) {
UseMethod("rm_baseline", data)
}

#' @param time_lim Numeric character vector (e.g. time_lim <- c(-.1, 0)). If
#' none given, defaults to mean of the whole of each epoch if the data is epoched, or the
#' channel mean if the data is continuous.
#' @describeIn rm_baseline remove baseline from continuous \code{eeg_data}
#' @export

rm_baseline.eeg_data <- function(data, time_lim = NULL, ...) {

if (is.null(time_lim)) {
baseline_dat <- colMeans(data$signals)
} else {
base_times <- select_times(data,
time_lim = time_lim)
baseline_dat <- colMeans(base_times$signals)
}
data$signals <- sweep(data$signals,
2,
baseline_dat,
'-')
data
}

#' @describeIn rm_baseline Remove baseline from eeg_epochs
#' @export

rm_baseline.eeg_epochs <- function(data,
time_lim = NULL,
...) {

n_epochs <- length(unique(data$timings$epoch))
n_times <- length(unique(data$timings$time))
n_chans <- ncol(data$signals)
elecs <- names(data$signals)

if (is.null(time_lim)) {
# reshape to 3D matrix
data$signals <- as.matrix(data$signals)
dim(data$signals) <- c(n_times, n_epochs, n_chans)
# colMeans gives an n_epochs * n_channels matrix - i.e. baseline value for
# each epoch and channel
baseline_dat <- colMeans(data$signals)
# now we go through each timepoint subtracting the baseline values
data$signals <- sweep(data$signals,
c(2, 3),
baseline_dat)
} else {
base_times <- select_times(data,
time_lim = time_lim)
base_times$signals <- as.matrix(base_times$signals)
n_bl_times <- length(unique(base_times$timings$time))
dim(base_times$signals) <- c(n_bl_times, n_epochs, n_chans)
base_times <- colMeans(base_times$signals)

data$signals <- as.matrix(data$signals)
dim(data$signals) <- c(n_times, n_epochs, n_chans)
data$signals <- sweep(data$signals,
c(2, 3),
base_times,
"-")
}
# Reshape and turn back into data frame
data$signals <- array(data$signals,
dim = c(n_epochs * n_times, n_chans))
data$signals <- as.data.frame(data$signals)
names(data$signals) <- elecs
data
}

#' @describeIn rm_baseline Legacy method for data.frames
#' @export
rm_baseline.data.frame <- function(data,
time_lim = NULL,
...) {

if (!("time" %in% colnames(data))) {
stop("Time dimension is required.")
}

if (length(time_lim) == 1) {
stop("time_lim should specify the full time range.")
}

# if the data is epoched, group by electrode and epoch; otherwise, just by
# electrode.

if ("epoch" %in% colnames(data)) {
data <- dplyr::group_by(data,
electrode,
epoch,
add = TRUE)
} else{
data <- dplyr::group_by(data,
electrode,
add = TRUE)
}

if (is.null(time_lim)) {
# if no time_lim provided, just delete mean of all time points
data <- dplyr::mutate(data,
amplitude = amplitude - mean(amplitude))
} else {

data_sel <- dplyr::filter(data,
time >= time_lim[1],
time <= time_lim[2])
baseline <- dplyr::summarise(data_sel,
bl = mean(amplitude))
# This is relatively memory intensive - not so bad now but would prefer
# another way. Could get extremely painful with time-frequency data.
data <- dplyr::left_join(data,
baseline)
data <- dplyr::mutate(data,
amplitude = amplitude - bl)
data <- dplyr::select(data,
-bl)
}
data <- ungroup(data)
data
}

#' @param type Type of baseline correction to apply. Options are ("divide",
#' "ratio", "absolute", "db")
#' @describeIn rm_baseline Method for \code{eeg_tfr} objects
#' @export
rm_baseline.eeg_tfr <- function(data,
time_lim = NULL,
type = "divide",
...) {

valid_types <- c("absolute",
"divide",
"pc",
"ratio",
"db")

if (!(type %in% valid_types)) {
stop("Unknown baseline type ", type)
}

bline <- select_times(data, time_lim)
bline <- colMeans(bline$signals, na.rm = TRUE)

# This function implements the various baseline correction types
do_corrs <- function(data,
type,
bline) {
switch(type,
"divide" = ((data - bline) / bline) * 100,
"pc" = ((data - bline) / bline) * 100 - 100,
"absolute" = data - bline,
"db" = 10 * log10(data / bline),
"ratio" = data / bline
)
}

orig_dims <- dim(data$signals)

orig_dimnames <- dimnames(data$signals)

data$signals <- apply(data$signals,
1,
do_corrs,
type = type,
bline = bline)

dim(data$signals) <- c(orig_dims[2],
orig_dims[3],
orig_dims[1])

data$signals <- aperm(data$signals,
c(3, 1, 2))

dimnames(data$signals) <- orig_dimnames
data$freq_info$baseline <- type
data$freq_info$baseline_time <- time_lim
data
}

#' @describeIn rm_baseline Method for \code{eeg_evoked} objects
#' @export
rm_baseline.eeg_evoked <- function(data,
time_lim = NULL,
...) {

if (is.null(time_lim)) {
baseline_dat <- colMeans(data$signals)
} else {
base_times <- select_times(data,
time_lim = time_lim)

baseline_dat <- colMeans(base_times$signals)
}
data$signals <- sweep(data$signals,
2,
baseline_dat,
"-")
data
}
Loading

0 comments on commit ea8aeae

Please sign in to comment.