Skip to content

Commit 151abbf

Browse files
authored
Merge pull request #87 from craddm/develop
Develop into master
2 parents f65305a + 49d8833 commit 151abbf

File tree

284 files changed

+2738
-1119
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

284 files changed

+2738
-1119
lines changed

.github/workflows/R-CMD-check.yaml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,10 +64,15 @@ jobs:
6464
eval sudo $cmd
6565
done < <(Rscript -e 'writeLines(remotes::system_requirements("ubuntu", "20.04"))')
6666
67+
- name: Install hdf5 on mac
68+
if: runner.os == 'macOS'
69+
run: brew install hdf5
70+
6771
- name: Install dependencies
6872
run: |
6973
remotes::install_deps(dependencies = TRUE)
7074
remotes::install_cran("rcmdcheck")
75+
remotes::install_cran("covr")
7176
shell: Rscript {0}
7277

7378
- name: Check
@@ -82,3 +87,8 @@ jobs:
8287
with:
8388
name: ${{ runner.os }}-r${{ matrix.config.r }}-results
8489
path: check
90+
91+
- name: Test coverage
92+
if: runner.os == 'macOS'
93+
run: covr::codecov(type = c("tests", "examples"), exclusions = "R/view_ica.R")
94+
shell: Rscript {0}

DESCRIPTION

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
Package: eegUtils
22
Type: Package
33
Title: Utilities for Electroencephalographic (EEG) Analysis
4-
Version: 0.6.1
5-
Date: 2021-02-21
4+
Version: 0.6.2
5+
Date: 2021-06-08
66
Authors@R: c(
77
person("Matt", "Craddock", role = c("aut", "cre", "cph"), email = "[email protected]"),
88
person("Matti", "Vuorre", role = "ctb", email = "[email protected]"),
@@ -20,7 +20,6 @@ Imports:
2020
ggplot2,
2121
dplyr (>= 1.0.0),
2222
scales,
23-
mgcv,
2423
purrr,
2524
shiny,
2625
tidyr (>= 1.0.0),
@@ -42,7 +41,8 @@ Imports:
4241
Depends:
4342
R (>= 3.3.0)
4443
RoxygenNote: 7.1.1
45-
Suggests: testthat,
44+
Suggests:
45+
testthat,
4646
vdiffr,
4747
covr,
4848
knitr,
@@ -54,7 +54,9 @@ Suggests: testthat,
5454
fICA,
5555
edfReader,
5656
ini,
57-
R.matlab
57+
R.matlab,
58+
hdf5r,
59+
mgcv
5860
URL: https://github.com/craddm/eegUtils, https://craddm.github.io/eegUtils
5961
BugReports: https://github.com/craddm/eegUtils/issues
6062
VignetteBuilder: knitr

NAMESPACE

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ S3method(compute_psd,eeg_evoked)
4444
S3method(compute_psd,eeg_group)
4545
S3method(compute_tfr,default)
4646
S3method(compute_tfr,eeg_epochs)
47+
S3method(compute_tfr,eeg_evoked)
4748
S3method(compute_tfr,eeg_group)
4849
S3method(eeg_average,default)
4950
S3method(eeg_average,eeg_epochs)
@@ -57,6 +58,7 @@ S3method(eeg_combine,eeg_evoked)
5758
S3method(eeg_combine,eeg_tfr)
5859
S3method(eeg_combine,list)
5960
S3method(eeg_combine,tfr_average)
61+
S3method(eeg_decompose,default)
6062
S3method(eeg_decompose,eeg_epochs)
6163
S3method(eeg_downsample,default)
6264
S3method(eeg_downsample,eeg_data)
@@ -71,13 +73,16 @@ S3method(eeg_reference,eeg_epochs)
7173
S3method(electrode_locations,data.frame)
7274
S3method(electrode_locations,eeg_data)
7375
S3method(electrode_locations,eeg_epochs)
76+
S3method(electrode_locations,eeg_tfr)
7477
S3method(epoch_data,default)
7578
S3method(epoch_data,eeg_data)
7679
S3method(epoch_data,eeg_epochs)
7780
S3method(epoch_stats,eeg_epochs)
7881
S3method(erp_image,data.frame)
82+
S3method(erp_image,default)
7983
S3method(erp_image,eeg_ICA)
8084
S3method(erp_image,eeg_epochs)
85+
S3method(erp_image,eeg_tfr)
8186
S3method(events,eeg_data)
8287
S3method(events,eeg_epochs)
8388
S3method(export_bva,default)
@@ -87,6 +92,7 @@ S3method(filter,eeg_data)
8792
S3method(filter,eeg_epochs)
8893
S3method(filter,eeg_evoked)
8994
S3method(filter,eeg_tfr)
95+
S3method(fit_glm,default)
9096
S3method(fit_glm,eeg_epochs)
9197
S3method(fortify,eeg_ICA)
9298
S3method(fortify,eeg_data)
@@ -294,8 +300,6 @@ importFrom(ggplot2,fortify)
294300
importFrom(graphics,abline)
295301
importFrom(graphics,par)
296302
importFrom(matrixStats,rowMedians)
297-
importFrom(matrixStats,rowSds)
298-
importFrom(mgcv,gam)
299303
importFrom(plotly,event_data)
300304
importFrom(plotly,plot_ly)
301305
importFrom(plotly,renderPlotly)

NEWS.md

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,22 @@
1-
# eegUtils 0.6.0.9999
1+
# eegUtils 0.6.2
2+
3+
### Function changes
4+
- added support for `EEGLAB` .set files saved in newer Matlab file formats.
5+
- changed first argument of `eeg_filter()` to `data` instead of `.data`
6+
- added some more informative user messages for importing data and adding electrode locations.
7+
- `erp_image()` now supports `eeg_tfr` objects.
8+
9+
### Internal changes / bug fixes
10+
11+
- When combining three or more continuous `eeg_data` objects, `eeg_combine()` would substantially undercorrect the timing of events in the third file - this is now fixed.
12+
- `groups` parameter for `topoplot()` now correctly passed for all types of object.
13+
- `stat_tests.R` file removed, will be reimplemented elsewhere
14+
- Long standing issues with import of channel locations from EEGLAB files hopefully fixed...
15+
- `rm_baseline()` for `eeg_evoked` no longer uses `data.table`
16+
- `as.data.frame.eeg_evoked()` handles grouped data better.
17+
- `import_set()` now handles all EEGLAB formats better.
18+
19+
# eegUtils 0.6.1
220

321
### Function changes
422

R/ar-faster.R

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -256,6 +256,7 @@ faster_cine <- function(data,
256256

257257
epochs <- split(data$signals,
258258
data$timings$epoch)
259+
n_epochs <- length(epochs)
259260

260261
# Work out which chans are bad in each epoch according to FASTER
261262
bad_chans <- lapply(epochs,
@@ -303,7 +304,17 @@ faster_cine <- function(data,
303304
new_epochs)
304305
epochs <- epochs[!names(epochs) %in% broken_epochs]
305306
epochs <- data.table::rbindlist(epochs)
306-
data$signals <- as.data.frame(epochs)
307+
data$signals <- tibble::as_tibble(epochs)
308+
data$reject$cine_list <- bad_chans
309+
data$reject$cine_total <- unlist(lapply(bad_chans,
310+
length))
311+
312+
if (length(bad_chans) > 0) {
313+
message(paste0(length(bad_chans), " of ", n_epochs, " epochs had at least one channel interpolated."))
314+
message(paste0("Max number of channels interpolated in one epoch: ", max(data$reject$cine_total)))
315+
} else {
316+
message("No channels were interpolated in single epochs.")
317+
}
307318
data
308319
}
309320

R/baseline_correction.R

Lines changed: 15 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -248,24 +248,23 @@ rm_baseline.eeg_evoked <- function(data,
248248
...) {
249249

250250
orig_cols <- channel_names(data)
251-
# Edit to handle cases where multiple epochs/participants, now that the internal structure differs
252-
if (is.null(time_lim)) {
253-
data$signals <- data.table::as.data.table(as.data.frame(data))
254-
data$signals <- data$signals[, c(orig_cols) := lapply(.SD,
255-
function(x) x - mean(x)),
256-
by = c("participant_id", "epoch"),
257-
.SDcols = orig_cols]
251+
n_times <- length(unique(data$timings$time))
252+
n_epochs <- nrow(data$epochs)
253+
n_chans <- length(orig_cols)
254+
base_times <- get_epoch_baselines(data,
255+
time_lim)
258256

259-
} else {
257+
data$signals <- as.matrix(data$signals)
258+
dim(data$signals) <- c(n_times,
259+
n_epochs,
260+
n_chans)
261+
data$signals <- baseline_epo(data$signals, base_times)
260262

261-
data$signals <- data.table::as.data.table(as.data.frame(data))
262-
data$signals <-
263-
data$signals[, c(orig_cols) := lapply(.SD,
264-
function(x) x - mean(x[time > time_lim[1] & time < time_lim[2]])),
265-
.SDcols = orig_cols,
266-
by = c("participant_id", "epoch")]
267-
}
268-
data$signals <- tibble::as_tibble(data$signals[, ..orig_cols])
263+
data$signals <- array(data$signals,
264+
dim = c(n_epochs * n_times, n_chans))
265+
colnames(data$signals) <- orig_cols
266+
data$signals <- tibble::as_tibble(data$signals)
267+
#names(data$signals) <- elecs
269268
data
270269
}
271270

R/channel_management.R

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -253,7 +253,6 @@ electrode_locations <- function(data, ...) {
253253
#' not available be removed? (Defaults to FALSE).
254254
#' @param montage Name of an existing montage set. Defaults to NULL.
255255
#' @importFrom dplyr inner_join pull left_join distinct
256-
#' @import ggplot2
257256
#' @importFrom tibble is_tibble
258257
#' @describeIn electrode_locations Adds standard locations to a data frame in
259258
#' long format
@@ -280,21 +279,21 @@ electrode_locations.data.frame <- function(data,
280279
dplyr::pull(electrodeLocs[, electrode])
281280

282281
if (!all(elecs)) {
283-
message(paste("Electrodes not found: ",
282+
message(paste("Electrode locations not found: ",
284283
paste(unique(data[, electrode])[!elecs, ],
285284
sep = ",")))
286285
} else if (!any(elecs)) {
287-
stop("No matching electrodes found.")
286+
stop("No matching electrode locations found.")
288287
}
289288
} else {
290289
elecs <-
291290
unique(data[, electrode]) %in% electrodeLocs[, electrode,
292291
drop = TRUE]
293292
if (!all(elecs)) {
294-
message("Electrodes not found: ",
293+
message("Electrodes locations not found: ",
295294
paste(unique(data[, electrode])[!elecs], collapse = " "))
296295
} else if (!any(elecs)) {
297-
stop("No matching electrodes found.")
296+
stop("No matching electrode locations found.")
298297
}
299298

300299
}
@@ -313,7 +312,6 @@ electrode_locations.data.frame <- function(data,
313312
}
314313

315314
#' @param overwrite Overwrite existing channel info. Defaults to FALSE.
316-
#' @import ggplot2
317315
#' @describeIn electrode_locations Adds standard locations to the chan_info field of an eeg_data object.
318316
#' @export
319317

@@ -329,8 +327,7 @@ electrode_locations.eeg_data <- function(data,
329327
overwrite = overwrite)
330328
}
331329

332-
#' @import ggplot2
333-
#' @describeIn electrode_locations Adds standard locations to the chan_info field of an eeg_data object.
330+
#' @describeIn electrode_locations Adds standard locations to the chan_info field of an `eeg_data` object.
334331
#' @export
335332

336333
electrode_locations.eeg_epochs <- function(data,
@@ -345,6 +342,8 @@ electrode_locations.eeg_epochs <- function(data,
345342
overwrite = overwrite)
346343
}
347344

345+
#' @describeIn electrode_locations Adds standard locations to the chan_info field of an `eeg_tfr` object.
346+
#' @export
348347
electrode_locations.eeg_tfr <- function(data,
349348
drop = FALSE,
350349
montage = NULL,

R/class_handling.R

Lines changed: 3 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -149,7 +149,7 @@ eeg_psd <- function(data,
149149
}
150150

151151

152-
#' Function to create an object of class `eeg_GA`
152+
#' Function to create an object of class `eeg_group`
153153
#'
154154
#' @noRd
155155

@@ -274,70 +274,6 @@ eeg_evoked <- function(data,
274274
value
275275
}
276276

277-
#' Function to create an S3 object of class "eeg_stats".
278-
#'
279-
#' @author Matt Craddock \email{matt@@mattcraddock.com}
280-
#' @param statistic Calculated statistic (e.g. t-statistic)
281-
#' @param pvals calculated p-values for that statistic
282-
#' @param chan_info String of character names for electrodes.
283-
#' @param timings Unique timepoints remaining in the data.
284-
#' @param method Type of statistical test
285-
#' @keywords internal
286-
287-
eeg_stats <- function(statistic,
288-
chan_info,
289-
pvals,
290-
timings,
291-
method) {
292-
293-
value <- list(statistic = statistic,
294-
pvals = tibble::as_tibble(pvals),
295-
chan_info = chan_info,
296-
timings = timings,
297-
method = method,
298-
version = utils::packageVersion("eegUtils"))
299-
class(value) <- "eeg_stats"
300-
value
301-
}
302-
303-
new_eeg_lm <- function(coefficients,
304-
std_err,
305-
t_stats,
306-
r_sq,
307-
chan_info,
308-
epochs,
309-
timings,
310-
formula) {
311-
312-
stopifnot(is.data.frame(coefficients))
313-
stopifnot(is.data.frame(std_err))
314-
stopifnot(is.data.frame(t_stats))
315-
stopifnot(is.data.frame(r_sq))
316-
#stopifnot(is.data.frame(chan_info))
317-
stopifnot(rlang::is_formula(formula))
318-
319-
new_eeg_stats(
320-
coefficients = coefficients,
321-
std_err = std_err,
322-
t_stats = t_stats,
323-
r_sq = r_sq,
324-
timings = timings,
325-
epochs = epochs,
326-
chan_info = chan_info,
327-
formula = formula,
328-
class = "eeg_lm"
329-
)
330-
}
331-
332-
new_eeg_stats <- function(...,
333-
class = character()) {
334-
335-
new_obj <- list(...)
336-
structure(
337-
new_obj,
338-
class = c(class, "eeg_stats")
339-
)
340-
}
341277

342278
#' Function to create an S3 object of class "eeg_ICA".
343279
#'
@@ -360,7 +296,8 @@ eeg_ICA <- function(mixing_matrix,
360296
chan_info,
361297
srate,
362298
epochs,
363-
algorithm) {
299+
algorithm,
300+
version = utils::packageVersion("eegUtils")) {
364301

365302
value <- list(mixing_matrix = mixing_matrix,
366303
unmixing_matrix = unmixing_matrix,

R/data_averaging.R

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ eeg_average.eeg_epochs <- function(data,
5959
}
6060
} else {
6161
col_names <- names(data$epochs)
62-
col_names <- col_names[!(col_names %in% c("epoch"))]
62+
col_names <- col_names[!(col_names %in% c("epoch", "recording", "event_type"))]
6363
}
6464

6565
data$signals <-
@@ -94,7 +94,7 @@ eeg_average.eeg_epochs <- function(data,
9494
data
9595
}
9696

97-
#' @describeIn eeg_average average an eeg_epochs object over epochs.
97+
#' @describeIn eeg_average average an `eeg_epochs` object over epochs.
9898
#' @export
9999
eeg_average.eeg_evoked <- function(data,
100100
cols = NULL,
@@ -200,7 +200,11 @@ average_tf <- function(data,
200200
} else {
201201
stop("Averaging of fourier coefficients not supported.")
202202
}
203-
data$timings <- tibble::tibble(time = as.numeric(dimnames(data$signals)[["time"]]))#dplyr::filter(data$timings, epoch == 1)
203+
data$timings <-
204+
tibble::tibble(
205+
time = rep(as.numeric(dimnames(data$signals)[["time"]]), new_epos),
206+
epoch = rep(1:new_epos, each = n_times)
207+
)#dplyr::filter(data$timings, epoch == 1)
204208
data
205209
}
206210

0 commit comments

Comments
 (0)