Skip to content

Commit ea8aeae

Browse files
committed
fix conflict in topoplot
Merge branch 'master' of https://github.com/craddm/eegUtils # Conflicts: # R/topoplot.R # man/topoplot.Rd
2 parents 3c7e381 + 3c42aa5 commit ea8aeae

Some content is hidden

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

56 files changed

+1723
-1212
lines changed

.travis.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,5 +7,6 @@ addons:
77
apt:
88
packages:
99
- libfreetype6
10+
r_github_packages: lionel-/vdiffr
1011
after_success:
1112
- Rscript -e 'covr::codecov()'

NAMESPACE

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,9 @@ S3method(interp_elecs,eeg_data)
4646
S3method(list_epochs,eeg_ICA)
4747
S3method(list_epochs,eeg_epochs)
4848
S3method(plot_butterfly,default)
49+
S3method(plot_butterfly,eeg_data)
50+
S3method(plot_butterfly,eeg_epochs)
51+
S3method(plot_butterfly,eeg_evoked)
4952
S3method(plot_electrodes,default)
5053
S3method(plot_electrodes,eeg_data)
5154
S3method(plot_psd,data.frame)
@@ -66,6 +69,7 @@ S3method(reref_eeg,eeg_data)
6669
S3method(rm_baseline,data.frame)
6770
S3method(rm_baseline,eeg_data)
6871
S3method(rm_baseline,eeg_epochs)
72+
S3method(rm_baseline,eeg_evoked)
6973
S3method(rm_baseline,eeg_tfr)
7074
S3method(run_ICA,eeg_epochs)
7175
S3method(select_elecs,default)

NEWS.md

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,17 @@
33

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

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

3134
### Internal changes/ bug fixes
3235
- `reref_eeg()`
3336
- correctly excludes multiple named electrodes (i.e. passed as characters rather than numbers), where it previously silently failed.
3437
- no longer records the reference data in the `ref_data` field
3538
- `tf_morlet` recoded to be called internally
36-
- `compute_psd`
39+
- `compute_psd()`
3740
- recoded to call `welch_fft()` in order to support possibility of different FFT methods.
3841
- now drops the DC component (frequency 0)
3942
- `welch_fft()` internal function added

R/baseline_correction.R

Lines changed: 214 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,214 @@
1+
#' Baseline correction
2+
#'
3+
#' Used to remove the mean of a specified time period from the data. Currently
4+
#' only performs subtractive baseline. With a data frame, searches for
5+
#' "electrode" and "epoch" columns, and groups on these when found. An electrode
6+
#' column is always required; an epoch column is not.
7+
#'
8+
#' @author Matt Craddock \email{matt@@mattcraddock.com}
9+
#' @param data Data to be baseline corrected.
10+
#' @param ... other parameters to be passed to functions
11+
#' @export
12+
13+
rm_baseline <- function(data, ...) {
14+
UseMethod("rm_baseline", data)
15+
}
16+
17+
#' @param time_lim Numeric character vector (e.g. time_lim <- c(-.1, 0)). If
18+
#' none given, defaults to mean of the whole of each epoch if the data is epoched, or the
19+
#' channel mean if the data is continuous.
20+
#' @describeIn rm_baseline remove baseline from continuous \code{eeg_data}
21+
#' @export
22+
23+
rm_baseline.eeg_data <- function(data, time_lim = NULL, ...) {
24+
25+
if (is.null(time_lim)) {
26+
baseline_dat <- colMeans(data$signals)
27+
} else {
28+
base_times <- select_times(data,
29+
time_lim = time_lim)
30+
baseline_dat <- colMeans(base_times$signals)
31+
}
32+
data$signals <- sweep(data$signals,
33+
2,
34+
baseline_dat,
35+
'-')
36+
data
37+
}
38+
39+
#' @describeIn rm_baseline Remove baseline from eeg_epochs
40+
#' @export
41+
42+
rm_baseline.eeg_epochs <- function(data,
43+
time_lim = NULL,
44+
...) {
45+
46+
n_epochs <- length(unique(data$timings$epoch))
47+
n_times <- length(unique(data$timings$time))
48+
n_chans <- ncol(data$signals)
49+
elecs <- names(data$signals)
50+
51+
if (is.null(time_lim)) {
52+
# reshape to 3D matrix
53+
data$signals <- as.matrix(data$signals)
54+
dim(data$signals) <- c(n_times, n_epochs, n_chans)
55+
# colMeans gives an n_epochs * n_channels matrix - i.e. baseline value for
56+
# each epoch and channel
57+
baseline_dat <- colMeans(data$signals)
58+
# now we go through each timepoint subtracting the baseline values
59+
data$signals <- sweep(data$signals,
60+
c(2, 3),
61+
baseline_dat)
62+
} else {
63+
base_times <- select_times(data,
64+
time_lim = time_lim)
65+
base_times$signals <- as.matrix(base_times$signals)
66+
n_bl_times <- length(unique(base_times$timings$time))
67+
dim(base_times$signals) <- c(n_bl_times, n_epochs, n_chans)
68+
base_times <- colMeans(base_times$signals)
69+
70+
data$signals <- as.matrix(data$signals)
71+
dim(data$signals) <- c(n_times, n_epochs, n_chans)
72+
data$signals <- sweep(data$signals,
73+
c(2, 3),
74+
base_times,
75+
"-")
76+
}
77+
# Reshape and turn back into data frame
78+
data$signals <- array(data$signals,
79+
dim = c(n_epochs * n_times, n_chans))
80+
data$signals <- as.data.frame(data$signals)
81+
names(data$signals) <- elecs
82+
data
83+
}
84+
85+
#' @describeIn rm_baseline Legacy method for data.frames
86+
#' @export
87+
rm_baseline.data.frame <- function(data,
88+
time_lim = NULL,
89+
...) {
90+
91+
if (!("time" %in% colnames(data))) {
92+
stop("Time dimension is required.")
93+
}
94+
95+
if (length(time_lim) == 1) {
96+
stop("time_lim should specify the full time range.")
97+
}
98+
99+
# if the data is epoched, group by electrode and epoch; otherwise, just by
100+
# electrode.
101+
102+
if ("epoch" %in% colnames(data)) {
103+
data <- dplyr::group_by(data,
104+
electrode,
105+
epoch,
106+
add = TRUE)
107+
} else{
108+
data <- dplyr::group_by(data,
109+
electrode,
110+
add = TRUE)
111+
}
112+
113+
if (is.null(time_lim)) {
114+
# if no time_lim provided, just delete mean of all time points
115+
data <- dplyr::mutate(data,
116+
amplitude = amplitude - mean(amplitude))
117+
} else {
118+
119+
data_sel <- dplyr::filter(data,
120+
time >= time_lim[1],
121+
time <= time_lim[2])
122+
baseline <- dplyr::summarise(data_sel,
123+
bl = mean(amplitude))
124+
# This is relatively memory intensive - not so bad now but would prefer
125+
# another way. Could get extremely painful with time-frequency data.
126+
data <- dplyr::left_join(data,
127+
baseline)
128+
data <- dplyr::mutate(data,
129+
amplitude = amplitude - bl)
130+
data <- dplyr::select(data,
131+
-bl)
132+
}
133+
data <- ungroup(data)
134+
data
135+
}
136+
137+
#' @param type Type of baseline correction to apply. Options are ("divide",
138+
#' "ratio", "absolute", "db")
139+
#' @describeIn rm_baseline Method for \code{eeg_tfr} objects
140+
#' @export
141+
rm_baseline.eeg_tfr <- function(data,
142+
time_lim = NULL,
143+
type = "divide",
144+
...) {
145+
146+
valid_types <- c("absolute",
147+
"divide",
148+
"pc",
149+
"ratio",
150+
"db")
151+
152+
if (!(type %in% valid_types)) {
153+
stop("Unknown baseline type ", type)
154+
}
155+
156+
bline <- select_times(data, time_lim)
157+
bline <- colMeans(bline$signals, na.rm = TRUE)
158+
159+
# This function implements the various baseline correction types
160+
do_corrs <- function(data,
161+
type,
162+
bline) {
163+
switch(type,
164+
"divide" = ((data - bline) / bline) * 100,
165+
"pc" = ((data - bline) / bline) * 100 - 100,
166+
"absolute" = data - bline,
167+
"db" = 10 * log10(data / bline),
168+
"ratio" = data / bline
169+
)
170+
}
171+
172+
orig_dims <- dim(data$signals)
173+
174+
orig_dimnames <- dimnames(data$signals)
175+
176+
data$signals <- apply(data$signals,
177+
1,
178+
do_corrs,
179+
type = type,
180+
bline = bline)
181+
182+
dim(data$signals) <- c(orig_dims[2],
183+
orig_dims[3],
184+
orig_dims[1])
185+
186+
data$signals <- aperm(data$signals,
187+
c(3, 1, 2))
188+
189+
dimnames(data$signals) <- orig_dimnames
190+
data$freq_info$baseline <- type
191+
data$freq_info$baseline_time <- time_lim
192+
data
193+
}
194+
195+
#' @describeIn rm_baseline Method for \code{eeg_evoked} objects
196+
#' @export
197+
rm_baseline.eeg_evoked <- function(data,
198+
time_lim = NULL,
199+
...) {
200+
201+
if (is.null(time_lim)) {
202+
baseline_dat <- colMeans(data$signals)
203+
} else {
204+
base_times <- select_times(data,
205+
time_lim = time_lim)
206+
207+
baseline_dat <- colMeans(base_times$signals)
208+
}
209+
data$signals <- sweep(data$signals,
210+
2,
211+
baseline_dat,
212+
"-")
213+
data
214+
}

0 commit comments

Comments
 (0)