Calculate group averages

using UnfoldBIDS, PyMNE
using Unfold
using DataFrames
using Statistics
using CairoMakie, AlgebraOfGraphics
using LazyArtifacts
    CondaPkg Found dependencies: /home/runner/.julia/packages/CondaPkg/8GjrP/CondaPkg.toml
    CondaPkg Found dependencies: /home/runner/.julia/packages/PyMNE/cNGDN/CondaPkg.toml
    CondaPkg Found dependencies: /home/runner/.julia/packages/PythonCall/83z4q/CondaPkg.toml
    CondaPkg Initialising pixi
             /home/runner/.julia/artifacts/cefba4912c2b400756d043a2563ef77a0088866b/bin/pixi
             init
             --format pixi
             /home/runner/work/UnfoldBIDS.jl/UnfoldBIDS.jl/docs/.CondaPkg
✔ Created /home/runner/work/UnfoldBIDS.jl/UnfoldBIDS.jl/docs/.CondaPkg/pixi.toml
    CondaPkg Wrote /home/runner/work/UnfoldBIDS.jl/UnfoldBIDS.jl/docs/.CondaPkg/pixi.toml
             [dependencies]
             openssl = ">=3, <3.6"
             libstdcxx = ">=3.4,<15.0"
             uv = ">=0.4"
             libstdcxx-ng = ">=3.4,<15.0"
                              [dependencies.python]
                 channel = "conda-forge"
                 build = "*cp*"
                 version = ">=3.10,!=3.14.0,!=3.14.1,<4, >=3.4,<4"
                          [project]
             name = ".CondaPkg"
             platforms = ["linux-64"]
             channels = ["conda-forge", "anaconda"]
             channel-priority = "strict"
             description = "automatically generated by CondaPkg.jl"
                          [pypi-dependencies]
             mne = ">=1.4"
    CondaPkg Installing packages
             /home/runner/.julia/artifacts/cefba4912c2b400756d043a2563ef77a0088866b/bin/pixi
             install
             --manifest-path /home/runner/work/UnfoldBIDS.jl/UnfoldBIDS.jl/docs/.CondaPkg/pixi.toml
✔ The default environment has been installed.

Analysis

First let's redo the steps from the quickstart tutorial

sample_data_path = UnfoldBIDS.erp_core_example();
layout_df = bids_layout(sample_data_path, derivatives=false);
data_df = load_bids_eeg_data(layout_df);

33.3%┣██████████████▍                            ┫ 1/3 [00:00<Inf:Inf, InfGs/it]

66.7%┣████████████████████████████████                ┫ 2/3 [00:00<00:00, 2it/s]

100.0%┣███████████████████████████████████████████████┫ 3/3 [00:01<00:00, 4it/s]

Calculate results

basisfunction = firbasis(τ=(-0.2,.8),sfreq=1024)
f  = @formula 0~1
bfDict = ["stimulus"=>(f,basisfunction)]
UnfoldBIDS.rename_to_latency(data_df, :sample); # Unfold expects a :latency collumn in your events; if your event latency is named differently you can use this function as remedy

resultsAll = run_unfold(data_df, bfDict; eventcolumn="trial_type");

33.3%┣██████████████▍                            ┫ 1/3 [00:00<Inf:Inf, InfGs/it]

Progress:   6%|██▌                                      |  ETA: 0:00:06
Progress:  36%|██████████████▉                          |  ETA: 0:00:02
Progress:  85%|██████████████████████████████████▊      |  ETA: 0:00:00
Progress: 100%|█████████████████████████████████████████| Time: 0:00:01

66.7%┣████████████████████████████████                ┫ 2/3 [00:08<00:08, 8s/it]

Progress:  64%|██████████████████████████▏              |  ETA: 0:00:00
Progress: 100%|█████████████████████████████████████████| Time: 0:00:00

100.0%┣███████████████████████████████████████████████┫ 3/3 [00:09<00:00, 5s/it]

Progress:   6%|██▌                                      |  ETA: 0:00:09
Progress:  76%|███████████████████████████████          |  ETA: 0:00:00
Progress: 100%|█████████████████████████████████████████| Time: 0:00:00

Now, let's transform the data into a tidier format (Note: We use raw data without a high-pass filter here so estimates will be quite off)

tidy_df = unpack_results(bids_coeftable(resultsAll))
first(tidy_df, 5)
5×11 DataFrame
Rowsubjectsestaskrunchannelcoefnameestimateeventnamegroupstderrortime
SubStrin…MissingSubStrin…MissingInt64StringFloat64StringNothingNothingFloat64
1001missingP3missing1(Intercept)-17604.5stimulus-0.200195
2001missingP3missing2(Intercept)-3162.93stimulus-0.200195
3001missingP3missing3(Intercept)11587.9stimulus-0.200195
4001missingP3missing4(Intercept)-1056.33stimulus-0.200195
5001missingP3missing5(Intercept)-480.149stimulus-0.200195

Calculate average over subjects

mean_df = combine(groupby(tidy_df, [:time, :coefname]), :estimate => mean)
first(mean_df, 5)
5×3 DataFrame
Rowtimecoefnameestimate_mean
Float64StringFloat64
1-0.200195(Intercept)-5304.91
2-0.199219(Intercept)-5304.87
3-0.198242(Intercept)-5304.87
4-0.197266(Intercept)-5304.96
5-0.196289(Intercept)-5305.04

Importantly, the above can be extended to groupbyan arbitrary number of covariates!

Plot results using AOG

plt = data(mean_df) * mapping(:time, :estimate_mean, color = :coefname, group=:coefname => nonnumeric) * visual(Lines)
draw(plt, axis=(yticklabelsvisible=false,))
Example block output

This page was generated using Literate.jl.