{"id":16273301,"url":"https://github.com/mattansb/epp-tb","last_synced_at":"2025-07-02T14:34:41.088Z","repository":{"id":55582495,"uuid":"117083168","full_name":"mattansb/EPP-TB","owner":"mattansb","description":"EPP-TB: The ERP Post-Processing Tool Box","archived":false,"fork":false,"pushed_at":"2020-12-20T18:09:53.000Z","size":53873,"stargazers_count":8,"open_issues_count":3,"forks_count":1,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-02-28T21:56:44.974Z","etag":null,"topics":["eeg","eeglab","epp-tb","erp","ersp","itc","matlab","plotting","topo-plots","wavelet"],"latest_commit_sha":null,"homepage":"","language":"MATLAB","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/mattansb.png","metadata":{"files":{"readme":"README.Rmd","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2018-01-11T10:06:02.000Z","updated_at":"2025-02-04T18:05:38.000Z","dependencies_parsed_at":"2022-08-15T03:40:13.572Z","dependency_job_id":null,"html_url":"https://github.com/mattansb/EPP-TB","commit_stats":null,"previous_names":[],"tags_count":10,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mattansb%2FEPP-TB","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mattansb%2FEPP-TB/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mattansb%2FEPP-TB/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mattansb%2FEPP-TB/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/mattansb","download_url":"https://codeload.github.com/mattansb/EPP-TB/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":244031028,"owners_count":20386534,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["eeg","eeglab","epp-tb","erp","ersp","itc","matlab","plotting","topo-plots","wavelet"],"created_at":"2024-10-10T18:23:42.673Z","updated_at":"2025-03-19T23:31:35.223Z","avatar_url":"https://github.com/mattansb.png","language":"MATLAB","funding_links":[],"categories":[],"sub_categories":[],"readme":"---\noutput: github_document\n---\n\n\u003c!-- README.md is generated from README.Rmd. Please edit that file --\u003e\n\n# EPP-TB: The ERP Post-Processing Tool Box \u003cimg src=\"doc\\logo.png\" align=\"right\"/\u003e\n\n```{r setup, include=FALSE}\nknitr::opts_chunk$set(echo = FALSE, message = FALSE, warning = FALSE,fig.path = \"doc/\")\n\nlibrary(tidyverse)\nlibrary(magrittr)\nlibrary(scales)\nlibrary(patchwork)\n\n```\n\nOnce completing pre-processing in eeglab/erplab/Net Station, you're ready to get to the fun stuff: plotting and measuring with EPP-TB!\nThis package is aimed at simple (readable), concise (one function per action) and reproducible code writing.\nAdditionally, a major component is the ability to export data and plots to be used and further manipulated elsewhere (say, `ggplot2`?).\n\nAll user-end functions start with `epp_*`.\n\n## Getting Started\n\n### Prerequisites\n\nTo use EPP-TB you will need:\n\n* Matlab (2015a+).\n* [eeglab](https://sccn.ucsd.edu/eeglab/index.php) (14.X.X) for importing `.set` files, and plotting topos.\n* R (for plotting in R)  \n    + [`tidyverse`](https://github.com/tidyverse/tidyverse) + [`purrr`](https://github.com/tidyverse/purrr).\n    + [`scales`](https://github.com/hadley/scales) for plotting in R.\n    + [`mgcv`](https://cran.r-project.org/package=mgcv) for plotting topo plots.\n\n### Installing\n\nYou can install the package by [downloading](https://github.com/mattansb/EPP-TB/releases) and adding the EPP-TB folder (and sub-folders) to your Matlab paths.\n\n## Importing Data into an EPP structure\n\nThree import methods are currently supported:\n\n- `epp_loadeeglab` - Import multiple `.set` files from eeglab (supports wavelet analysis based on [Mike X. Cohen's great book and code](http://www.mikexcohen.com/)).\n- `epp_loaderplab` - Import from [erplab](http://www.erpinfo.org/erplab.html).\n- `epp_loadegimat` - Import multiple `.mat` files exported from Net Station (EGI).\n\nThe resulting structure array has `length(struct)` equal to the number of conditions, and contains the following fields, per condition:\n\n- **Condition**: the name of the conditions.\n- **timeLine**: a vector of time points.\n- **IDs**: a table with two variables - _**ID**_ and _**nTrials**_ (the number of trials a ERP has been averaged across).\n- **Data**: a `channels` *x* `time points` *x* `Subjects` matrix for ERP data.\n\nIf a wavelet analysis has been preformed, the Data field is replaced with:\n\n- **ersp** and **itc**: `channels` *x* `frequencies` *x* `time points` *x* `Subjects` matrices.\n\n- **Freqs**: a vector of frequencies used.\n\n\n### Data Reduction / Reshaping\n\nThese functions can be used to compute new conditions or manipulate existing data:\n\n- Merge 2 or more conditions with `epp_combineconds()`.\n- Compute differences between 2 conditions with `epp_diffwave()`.\n- Compute LRP with `epp_LRP()`\n- Compute global field potentials with `epp_GFP()`.\n- Collapse TF data to frequency waveforms with `epp_reshapeTF()`.\n- Make grand-average ERP/ERSP/ITC with `epp_makegrands()` (useful for plotting large data sets).\n\n\n### Working with ID data\n\n- Add data to `study.IDs` from a table with `epp_appendID()`.\n- Retain subjects that have data in all specified conditions with `epp_matchsubjects()`.\n- Select data from specific subjects by some variable in `study.IDs` with `epp_filter_by()`.\n- Pull data from `study.IDs` with `epp_extractIDs()`.\n\n## Plotting\n\n\u003e For all `epp_plot*` functions, which allow plotting data from `epp` structures, there is an accompanying general `p_*` function, that allows plotting from other data structures (with a little bit of wrangling).\n\n### ERP Plots\n\n#### Grand averages\nGrand averages can be plotted by specifying the conditions and channel indices (averaged across) to plot:\n\n```Matlab\nconds         = {'Crr','L5'};\nchannel_inds  = [5 6 11 12];\nepp_plotgrands(study,conds,channel_inds)\n```\n\n```{r grand_plot}\n\ngrand_data \u003c- read_csv(\"doc/grand_plot_data.csv\") %\u003e%    # load the data file\n  as.tbl() %\u003e% \n  mutate_at(.vars = c(\"Time\",\"mean\",\"sd\"), .funs = as.numeric) %\u003e% \n  mutate(Condition = as.factor(Condition),\n         N  = as.integer(N),\n         se = sd/sqrt(N)) %\u003e% \n  separate(Condition,c('Group','Level'))\n\ngrand_data %\u003e% \n  ggplot(aes(x = Time, y = mean,\n             color = Level, fill = Level,\n             group = Level)) +\n  geom_vline(xintercept = 0) +\n  geom_hline(yintercept = 0) +\n  geom_line(size = 1) + \n  scale_x_continuous(expand = c(0, 0)) +\n  scale_color_manual(values = c('blue','red')) +\n  labs(x = \"Time\", y = expression(paste(mu,\"V\"))) +\n  theme_minimal() + theme(legend.position=\"bottom\")\n\n```\n\n\nYou can also plot error envelopes:\n\n```Matlab\nepp_plotgrands(study,conds,channel_inds,'errorType','SE')\n% can also be set to 'SD' or 'CIXX' \n% (with XX replaced with any percent: 'CI95','CI80', etc...).\n```\n\n```{r grand_plot_se}\ngrand_data %\u003e% \n  ggplot(aes(x = Time, y = mean,\n             color = Level, fill = Level,\n             group = Level)) +\n  geom_vline(xintercept = 0) +\n  geom_hline(yintercept = 0) +\n  geom_ribbon(aes(ymin = mean-se, ymax = mean+se),\n              alpha = 0.25, color = NA) + \n  geom_line(size = 1) + \n  scale_x_continuous(expand = c(0, 0)) +\n  scale_color_manual(values = c('blue','red')) +\n  scale_fill_manual(values = c('blue','red')) +\n  labs(x = \"Time\", y = expression(paste(mu,\"V\"))) +\n  theme_minimal()+ theme(legend.position=\"bottom\")\n```\n\n\n#### Topo Plots\n\nTopo plotting is dependent on eeglab functions. Additionally, you will need to provide a eeglab-like chanlocs structure to these functions, with `length(chanlocs)==size(study.Data,1)`.\n\n```Matlab\ntimes = [185];\nepp_plottopo(study,chanlocs,conds,channel_inds,times)\n```\n```{r topo_plot}\n\nraw.data \u003c- read.csv(\"doc/topo_plot_data.csv\") %\u003e%\n  as.tbl() %\u003e% \n  mutate(Condition   = as.factor(Condition),\n         # convert Theta and Radius to (x,y)\n         radianTheta = pi/180*Theta,\n         x           = Radius*sin(radianTheta),\n         y           = Radius*cos(radianTheta),\n         r           = sqrt(x^2 + y^2))\n\nexpand.topo \u003c- function(data, gridRes = NULL) {\n  library(mgcv)\n  if (is.null(gridRes))\n    gridRes \u003c- data[[1]] %$% unique(Channel) %\u003e% {length(.)/2}\n  \n  res \u003c- list()\n  for (c in 1:length(data)) {\n    LL \u003c- data[[c]]\n    \n    minx \u003c- min(LL$x)*1.1\n    miny \u003c- min(LL$y)*1.1\n    maxx \u003c- max(LL$x)*1.1\n    maxy \u003c- max(LL$y)*1.1\n    \n    tmp.GAM \u003c- expand.grid(x = seq(minx*1.05,maxx*1.05,length = gridRes),\n                           y = seq(miny*1.05,maxy*1.05,length = gridRes)) %\u003e%\n      data.frame()\n    \n    tmp.GAM$Amp \u003c- LL %\u003e%\n      gam(Amp ~ s(x, y, bs = 'ts'), data = .) %\u003e% \n      predict(tmp.GAM, type = \"response\")\n    res[[c]] \u003c- tmp.GAM %\u003e% \n      filter(sqrt(x^2 + y^2) \u003c= max(diff(range(x)),diff(range(y)))/2)\n    rm(tmp.GAM)\n  }\n  return(res)\n}\n\ncircleFun \u003c- function(diameter = 1, center = c(0,0), npoints = 100) {\n  r  \u003c- diameter / 2\n  tt \u003c- seq(0,2*pi,length.out = npoints)\n  xx \u003c- center[1] + r * cos(tt)\n  yy \u003c- center[2] + r * sin(tt)\n  return(data.frame(x = xx, y = yy))\n}\n\n# Topo theme\ntheme_topo \u003c- function(base_size = 12) {\n  theme_bw(base_size = base_size) %+replace%\n    theme(rect       = element_blank(),\n          line       = element_blank(),\n          axis.text  = element_blank(),\n          axis.title = element_blank()\n    )\n}\n\nchanlocs \u003c- raw.data %\u003e% \n  select(Channel, x, y) %\u003e%\n  distinct()\n\ndiam      \u003c- chanlocs %$%\n  max(diff(range(x)),diff(range(y))) # can be adjusted\nhead \u003c- list()\nhead$shape \u003c- circleFun(diam*0.75)\nhead$mask  \u003c- circleFun(diam*1.15)\nhead$nose  \u003c- data.frame(x = c(-.075,0,.075),\n                         y = c(-.005,.075,-.005) + max(head$shape$y))\n\ntopo.data \u003c- raw.data %\u003e% \n  group_by(Condition,TimePnt) %\u003e% \n  select(Condition,TimePnt,Channel,x,y,Amp) %\u003e% \n  nest() %\u003e%\n  mutate(data = expand.topo(data)) %\u003e% \n  unnest() %\u003e% \n  separate(Condition,c('Group','Level'))\n\nggplot(topo.data,aes(x, y)) +\n  ## The Topos\n  geom_raster(aes(fill = Amp))+\n  facet_grid(~Level) +\n  ## The Head\n  geom_path(data = head$mask, color = \"white\",size = 4) +\n  geom_path(data = head$nose, size = 1.5) +\n  geom_path(data = head$shape, size = 1.5) +\n  ## The Channels\n  geom_point(data = chanlocs) +\n  ## Design\n  scale_fill_distiller(palette = \"RdYlBu\", direction = -1,\n                       limits = c(-2,2), oob = squish) +\n  labs(fill = \"Amplitude\") +\n  theme_topo() +\n  coord_equal()\n\n```\n\n#### Butterfly and Trace Plots\n\nButterfly plots can be used to plot the mean ERP for each subject individually.\n\n```Matlab\nepp_plotbutterfly(study,conds,channel_inds)\n```\n\n```{r butterfly_plot}\n\nbutterfly_data \u003c- read_csv(\"doc/butterfly_plot_data.csv\") %\u003e% # load the data file\n  group_by(Condition,Time) %\u003e% \n  mutate(meanAmp = mean(amp)) %\u003e% \n  ungroup() %\u003e% \n  separate(Condition,c('Group','Level'))\n\nbutterfly_data %\u003e% \n  ggplot(aes(x = Time, y = amp,\n             color = Level,\n             group = ID)) + \n  facet_wrap(~Level) +\n  geom_vline(xintercept = 0) + \n  geom_hline(yintercept = 0) + \n  geom_line(alpha = 0.8) + \n  geom_line(aes(y = meanAmp), color = \"black\", size = 1) +\n  scale_x_continuous(expand = c(0, 0)) +\n  scale_color_manual(values = c('blue','red')) +\n  labs(x = \"Time\", y = expression(paste(mu,\"V\"))) +\n  theme_minimal()+ theme(legend.position=\"none\")\n\n```\n\n\nTrace plots are similar to butterfly plots, but the mean activation (across subjects) is plotted for each channel separately.\n\n```Matlab\nchannel_inds = []; % if left blank, all channels are plotted.\nepp_plotbutterfly(study,conds,channel_inds,'trace',true)\n```\n```{r trace_plot}\n\ntrace_data \u003c- read_csv(\"doc/trace_plot_data.csv\") %\u003e% \n  separate(Condition,c('Group','Level'))\n\ntrace_data %\u003e% \n  ggplot(aes(x = Time, y = amp,\n             color = Level,\n             group = ID)) + \n  facet_wrap(~Level) +\n  geom_vline(xintercept = 0) + \n  geom_hline(yintercept = 0) + \n  geom_line(alpha = 0.8) + \n  scale_x_continuous(expand = c(0, 0)) + \n  scale_color_manual(values = c('blue','red')) +\n  labs(x = \"Time\", y = expression(paste(mu,\"V\"))) +\n  theme_minimal()+ theme(legend.position=\"none\")\n\n```\n\n#### Channel Plots\n\nSimilar to trace plots, channel plots give a picture of what is happening at each channel (like `eeglab`'s `plottopo`). These come in two flavors:  \n  \n  - Topo Plots - channel data is plotted in 2-d space, like a topo-plot.  \n  - Grid Plots - channel data is plotted on a simple grid.\n\nChannel topo plots are created with the following Matlab call:\n```Matlab\nchannel_inds = []; % if left blank, all channels are plotted.\nepp_plotchannels(study,conds,electrodes,'chanlocs',chanlocs)\n```\n\nGrid plots are called using the same call, without providing `chanlocs`.\n\n\n### TF Plots\n\n#### Time-Frequency Plot\n\nTime Frequency plots plot both ersp and itc:\n\n```Matlab\nepp_plotTF(study,conds,channel_inds)\n```\n\n```{r TFplot}\n\ndf \u003c- read_csv(\"doc/TFplot_data.csv\") %\u003e% \n  separate(Condition,'Level')\n\n# Plot --------------------------------------------------------------------\n\n# Use geom_raster to plot y-axis scale as is\nersp_plot \u003c- ggplot(df,aes(Time, Frequencies, fill = ersp)) + # or fill = itc\n  geom_raster(interpolate = T) +\n  facet_grid(.~Level) +\n  scale_y_log10(breaks = c(1,4,8,12,30), expand = c(0, 0)) + # if Frequencies are log-spaced\n  scale_x_continuous(breaks = seq(-200,700,by = 200), expand = c(0, 0)) +\n  scale_fill_gradientn(colors = c('black','red','yellow','white'),\n                       limits = c(0,2.5),oob=squish) +\n  theme_minimal() +\n  labs(fill = 'Power (dB)')\n\nitc_plot \u003c- ggplot(df,aes(Time, Frequencies, fill = itc)) + # or fill = itc\n  geom_raster(interpolate = T) +\n  facet_grid(.~Level) +\n  scale_y_log10(breaks = c(1,4,8,12,30), expand = c(0, 0)) + # if Frequencies are log-spaced\n  scale_x_continuous(breaks = seq(-200,700,by = 200), expand = c(0, 0)) +\n  scale_fill_gradientn(colors = c('black','red','yellow','white'),\n                       limits = c(0,0.4),oob=squish) +\n  theme_minimal() +\n  labs(fill = 'ITC')\n\nersp_plot/itc_plot\n\n```\n\n#### Other Plots\n\nAll the listed above plotting methods also support TF data. For example:\n\n```Matlab\ntimes = [160 410];\nbands = [4 8; 8 12];\n% a matrix of frequencies, with each row containing a range of frequencies\n% to plot (1st column is lower limit, 2nd column is upper limit of band).\nepp_plottopo(study,chanlocs,conds,channel_inds,times,...\n    'freqs',bands, 'type', 'ersp')\n```\n```{r TFtopo}\nraw.data \u003c- read.csv(\"doc/TFtopo_data.csv\") %\u003e%\n  as.tbl() %\u003e% \n  mutate(Condition   = as.factor(Condition),\n         # convert Theta and Radius to (x,y)\n         radianTheta = pi/180*Theta,\n         x           = Radius*sin(radianTheta),\n         y           = Radius*cos(radianTheta),\n         r           = sqrt(x^2 + y^2))\n\n\nexpand.topo \u003c- function(data, gridRes = NULL) {\n  if (is.null(gridRes))\n    gridRes \u003c- data %$% unique(Channel) %\u003e% {length(.)/2}\n  \n  range_x \u003c- range(data$x)*1.15\n  range_y \u003c- range(data$y)*1.15\n  \n  tmp.GAM \u003c- expand.grid(x = seq(range_x[1],range_x[2],length = gridRes),\n                         y = seq(range_y[1],range_y[2],length = gridRes)) %\u003e%\n    data.frame()\n  tmp.GAM$Amp \u003c- gam(Amp ~ s(x, y, bs = 'ts'), data = data) %\u003e% \n    predict(tmp.GAM, type = \"response\")\n  tmp.GAM %\u003e% \n    filter(sqrt(x^2 + y^2) \u003c= max(diff(range(x)),diff(range(y)))/2)\n}\n\ncircleFun \u003c- function(diameter = 1, center = c(0,0), npoints = 100) {\n  r  \u003c- diameter / 2\n  tt \u003c- seq(0,2*pi,length.out = npoints)\n  xx \u003c- center[1] + r * cos(tt)\n  yy \u003c- center[2] + r * sin(tt)\n  return(data.frame(x = xx, y = yy))\n}\n\n# Topo theme\ntheme_topo \u003c- function(base_size = 12) {\n  theme_bw(base_size = base_size) %+replace%\n    theme(rect       = element_blank(),\n          line       = element_blank(),\n          axis.text  = element_blank(),\n          axis.title = element_blank()\n    )\n}\n\n# Channel Data\nchanlocs \u003c- raw.data %\u003e% \n  select(Channel, x, y) %\u003e%\n  distinct()\n\n# Head Shapes\ndiam \u003c- chanlocs %\u003e%\n  select(x,y) %\u003e% \n  map_dbl(~diff(range(.))) %\u003e% max()\nhead \u003c- list(\n  shape = circleFun(diam*0.75),\n  mask  = circleFun(diam*1.15),\n  nose  = data.frame(x = c(-.075,0,.075),\n                     y = c(-.005,.075,-.005) + diam*0.375)\n  \n)\n\n# Topo Data\ntopo.data \u003c- raw.data %\u003e% \n  select(Condition,TimePnt,Channel,x,y,Amp) %\u003e% \n  separate(Condition,c('Level','Group','Band')) %\u003e% \n  mutate(Band = factor(Band, labels = c('Theta (4-8Hz)','Gamma (8-12Hz)'))) %\u003e% \n  group_by(Level,Band) %\u003e% \n  nest() %\u003e%\n  mutate(data = map(data,expand.topo)) %\u003e% \n  unnest()\n\n# Plot\nggplot(topo.data,aes(x, y)) +\n  geom_raster(aes(fill = Amp))+\n  facet_grid(Band~Level) +\n  geom_path(data = head$mask, color = \"white\",size = 4) +\n  geom_path(data = head$nose, size = 1.5) +\n  geom_path(data = head$shape, size = 1.5) +\n  scale_fill_gradientn(colors = c('white','cyan','blue','black','red','yellow','white'),\n                       limits = c(-2,2), oob = squish) +\n  labs(fill = \"Power (dB)\") +\n  theme_topo() +\n  coord_equal()\n\n```\n\n### Exporting to R\n\nAll plots can be exported to R and plotted with [`ggplot2`](https://github.com/tidyverse/ggplot2) by setting `'R',true` in any of the plotting function (this is how the plots in this README were made). This produces two time-stamped files: \n\n- A data file (`*_data.csv`)\n- A code file (`*_code.R`), to plot said data using `ggplot2`.\n\n\n## Measuring\n\nMeasuring can be done via the `epp_get*` functions. These are wrapper functions for the various `m_*` functions (with one functions per method), **which should not be called directly** (unless you know what you're doing).\n\nSaving results always produces a 2-sheet `.xlsx` file, with the second sheet containing the parameters used in measuring - this is to insure reproducibility of results. Thus, if you have the output `.xlsx` file, you'll never find yourself asking \"what was the time window we used last time?\".\n\n### ERP Amplitude\n\nThe function `epp_getAmp` implements the methods for measuring amplitudes described in chapter 9 of [Steven J. Luck's intro to ERP book](https://mitpress.mit.edu/books/introduction-event-related-potential-technique-0).\n\n - (Local) Peak amplitude\n - Point amplitude\n - Mean amplitude\n - Integral\n - Area\n\n### ERP Latency\n\nThe function `epp_getLat` implements the methods for measuring latencies described in chapter 9 of [Steven J. Luck's intro to ERP book](https://mitpress.mit.edu/books/introduction-event-related-potential-technique-0), as well as those described in [Kiesel et al.'s Jakknife paper](http://onlinelibrary.wiley.com/doi/10.1111/j.1469-8986.2007.00618.x/abstract).\n\n- (Local) Peak latency\n- Relative criterion\n- Fractional area\n- Baseline deviation\n- Absolute criterion\n\n### TF Power\n\nThe function `epp_getTF` measure the *mean* ersp / itc from selected channels, within a specified time-window,separately for specified frequency bands (as shown above, for `epp_plottopoTF`).\n\n## Authors\n\n- **Mattan S. Ben-Shachar** [aut, cre].\n- **Rachel Rac** [ctb].\n- **Michael Shmueli** [ctb].\n\n## Acknowledgments\n\n- **Mike X. Cohen** - who's [code](http://mikexcohen.com/lectures.html) was implemented in [`f_WaveletConv.m`](https://github.com/mattansb/EPP-TB/blob/master/supportfuncs/f_WaveletConv.m).\n- **Matt Craddock** - who's [code](https://craddm.github.io/blog/2017/02/25/EEG-topography) was implemented in [`epp_plottopo.R`](https://github.com/mattansb/EPP-TB/blob/master/plot/epp_plottopo.R).\n- **Winston Chang** - who's [code](http://www.cookbook-r.com/Graphs/Plotting_means_and_error_bars_(ggplot2)/) for computing within-subject (and mixed model) CI's was implemented in [`epp_plotgrands.m`](https://github.com/mattansb/EPP-TB/blob/master/plot/epp_plotgrands.m).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmattansb%2Fepp-tb","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmattansb%2Fepp-tb","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmattansb%2Fepp-tb/lists"}