-
Notifications
You must be signed in to change notification settings - Fork 7
OnsetFormulas, Sequences, and Component Functions - v0.4.0 -> actually v0.5.0 #104
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from 143 commits
8405a1a
afc69d7
49db0ba
41d7306
8e6de75
cd489c4
6c35f3c
809dc2e
31c69e6
54e9334
7114cd6
b4a8ac8
0c3a11d
de8c2a8
57a7f68
85f037b
2c65a7f
ee9e00a
ac0d3bd
373e535
b073526
89c09a1
1e2694f
9ab04aa
5671e2e
10c77a3
ea25ddc
e0c2310
34ce887
b5a60bf
b81b605
369faff
541cf67
f449083
fe00ec2
f93a3c1
aca3fd2
e868a14
43dd57c
68ce722
2dfd44b
2c34e5e
8848209
9749685
3a3bd3d
43e28e8
f5300c3
b8d85b9
b204234
04a1ed3
e05a9c6
8aa7591
395b5ee
da51a16
9603df9
612786a
272eb02
360b0eb
f082ce4
ba10e1d
f5facfe
7a0fffc
0e7df88
a10d5a9
5b53765
6685d8d
523f90b
5fb95bf
d3fa46e
5574425
1966fbe
fa6f78b
b9cde99
60b8941
01a1e44
33bc2b6
5d38311
25009e4
1a133ae
e14765b
7996783
d5c7b4d
c528f6a
73409f4
08b0738
ddbafdf
1de2186
36b1920
e610041
2cbad0b
f49004d
9be7376
d1defe0
c23c317
6ccd668
c28fbc1
89c3454
157932f
d7a87a2
cfb46b8
0bb23fc
82603d8
96c3fc5
ea7b288
ad13734
755daaa
8513184
ef9556d
c6b719f
adc225d
f0037f7
2b7930c
34be071
5908840
0e2a446
37539f2
2b8f600
c9afd8a
4adb5fd
a8d4d08
d6d64a6
5416d4d
3947c57
991ab38
02d38c7
7a0f81f
b345da4
a8c3801
b43a5a1
a6f4e3c
0c78de8
878c019
ca9af4c
6109b13
fb14397
89ee8e0
8f27939
c8fbae8
33ca351
4bf0034
f291a95
badd2db
d6101c3
885e0f2
3b65091
45ed602
0229392
b89fab7
86623ef
cedde16
05f699f
c697004
f5d21b7
34521a5
564be7b
5faf54b
b5d2d00
61b7d36
5b3cfc4
3227b90
0d8d5d1
683b273
a1ea003
ac7201b
d173c46
82a2e6a
72131a1
4381233
ea91727
48968af
75bed90
6f704f5
8249bce
27b5f15
62fcc24
dfc267d
75c9477
c66bdb5
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
| @@ -0,0 +1,69 @@ | ||||||
| # # Component Basisfunctions | ||||||
behinger marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||||||
| # HowTo use functions that depend on the `design` and return per-event basis-vectors, instead of the same basis vector for all events. | ||||||
behinger marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||||||
|
|
||||||
|
|
||||||
| # ### Setup | ||||||
| # ```@raw html | ||||||
| # <details> | ||||||
| # <summary>Click to expand</summary> | ||||||
| # ``` | ||||||
| ## Load required packages | ||||||
| using UnfoldSim | ||||||
| using Unfold | ||||||
| using Random | ||||||
| using DSP | ||||||
| using CairoMakie, UnfoldMakie | ||||||
| # ```@raw html | ||||||
| # </details > | ||||||
| # ``` | ||||||
|
|
||||||
|
|
||||||
| sfreq = 100; | ||||||
|
|
||||||
| # ## Design | ||||||
| # Let's generate a design with a categorical effect and a continuous duration effect | ||||||
| design = UnfoldSim.SingleSubjectDesign(; | ||||||
| conditions = Dict( | ||||||
| :category => ["dog", "cat"], | ||||||
| :duration => Int.(round.(20 .+ rand(100) .* sfreq)), | ||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. For this example, the magnitude does not really matter, but do I understand it correctly that the duration is ~20s? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. it's 20 to 120 samples => 0.2 to 1.2s |
||||||
| ), | ||||||
| ); | ||||||
|
|
||||||
|
|
||||||
| # Instead of defining a "boring" vector basis function e.g. `[0,0,1,2,3,3,2,1,0,0,0]`, let's use function - in our case a hanning window with the size depending on the experimental design's duration. | ||||||
behinger marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||||||
| # !!! important | ||||||
| # Two things have to be taken care of: | ||||||
| # 1. in case a rng is required to e.g. generate the design, or your basisfunction depends on it, you have to specify a two-argument basis-function: `(rng,design)->...` | ||||||
behinger marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||||||
| # 2. a `maxlength` has to be specified via a tuple `(function,maxlength)`` | ||||||
behinger marked this conversation as resolved.
Show resolved
Hide resolved
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
|
|
||||||
| mybasisfun = design -> hanning.(generate_events(design).duration) | ||||||
| signal = LinearModelComponent(; | ||||||
| basis = (mybasisfun, 100), | ||||||
| formula = @formula(0 ~ 1 + category), | ||||||
| β = [1, 0.5], | ||||||
| ); | ||||||
|
|
||||||
| erp = UnfoldSim.simulate_component(MersenneTwister(1), signal, design); | ||||||
|
|
||||||
| # After simulation, we are ready to plot it. We expect that the simulated responses are scaled by the design's duration. To show it more effectively, we sort by duration. | ||||||
behinger marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||||||
| ##--- | ||||||
| f = Figure() | ||||||
| df = UnfoldMakie.eeg_array_to_dataframe(erp') | ||||||
| df.duration = repeat(generate_events(design).duration, inner = size(erp, 1)) | ||||||
| df.category = repeat(generate_events(design).category, inner = size(erp, 1)) | ||||||
| plot_erp!( | ||||||
| f[1, 1], | ||||||
| df, | ||||||
| mapping = (; group = :group => nonnumeric, col = :category), # color = :duration, fails right nowUnfoldMakie#353 | ||||||
| layout = (; legend_position = :left), | ||||||
| colorbar = (; label = "Duration"), | ||||||
| ) | ||||||
| plot_erpimage!( | ||||||
| f[2, 1], | ||||||
| erp, | ||||||
| sortvalues = generate_events(design).duration, | ||||||
| layout = (; legend_position = :bottom), | ||||||
| ) | ||||||
| f | ||||||
|
Comment on lines
+49
to
+67
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I would suggest to hide the code for the figure or rather have it in an expandable/collapsible element, such that it can be opened if needed. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. And the legend of the figure needs fixing but we can postpone this and collect it in an issue: #99 (comment) (I added it already) |
||||||
|
|
||||||
| # The scaling by the two `condition` effect levels and the modified event duration by the `duration` are clearly visible | ||||||
behinger marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||||||
behinger marked this conversation as resolved.
Show resolved
Hide resolved
|
| Original file line number | Diff line number | Diff line change | ||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,116 @@ | ||||||||||||||||||
| # # Simulate ground truth marginalized Effects | ||||||||||||||||||
|
|
||||||||||||||||||
| # Often when testing some algorithm, we want to compare our results to a known ground truth. In the case of marginalized effects via the `Unfold.effects`/ `Effects.jl` interface, we can do this using an `EffectsDesign`. | ||||||||||||||||||
| # You can find more on what marginalized effects are here in the [Unfold.jl documentation](https://unfoldtoolbox.github.io/Unfold.jl/dev/generated/HowTo/effects/) | ||||||||||||||||||
|
||||||||||||||||||
| # # Simulate ground truth marginalized Effects | |
| # Often when testing some algorithm, we want to compare our results to a known ground truth. In the case of marginalized effects via the `Unfold.effects`/ `Effects.jl` interface, we can do this using an `EffectsDesign`. | |
| # You can find more on what marginalized effects are here in the [Unfold.jl documentation](https://unfoldtoolbox.github.io/Unfold.jl/dev/generated/HowTo/effects/) | |
| # # Simulate ground truth marginal effects | |
| # Often when testing some algorithm, we want to compare our results to a known ground truth. In the case of marginal effects via the `Unfold.effects`/ `Effects.jl` interface, we can do this using an `EffectsDesign`. | |
| # You can find more on what marginal effects are here in the [Unfold.jl documentation](https://unfoldtoolbox.github.io/Unfold.jl/dev/generated/HowTo/effects/) |
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| # ## Simulate marginalized effects directly | |
| # To marginalize effects we first have to specify an effects dictionary and subsequently hand this dict plus the original design to `EffectsDesign()` | |
| # ## Simulate marginal effects directly | |
| # To simulate marginal effects, we first have to specify an effects dictionary and subsequently hand this dict plus the original design to `EffectsDesign()` |
behinger marked this conversation as resolved.
Show resolved
Hide resolved
|
behinger marked this conversation as resolved.
Show resolved
Hide resolved
|
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,91 @@ | ||
| # # Sequence of events (e.g. SCR) | ||
|
|
||
| # In this HoWTo we learn to simulate a "SR"-Sequence, a stimulus response, followed by a button press response. | ||
| # ### Setup | ||
| # ```@raw html | ||
| # <details> | ||
| # <summary>Click to expand</summary> | ||
| # ``` | ||
| ## Load required packages | ||
| using UnfoldSim | ||
| using CairoMakie | ||
| using StableRNGs | ||
| # ```@raw html | ||
| # </details > | ||
| # ``` | ||
|
|
||
|
|
||
| # | ||
| # First we generate the minimal design of the experiment by specifying our conditions (a one-condition-two-levels design in our case) | ||
| design = SingleSubjectDesign(conditions = Dict(:condition => ["one", "two"])) | ||
| generate_events(design) | ||
| # Next we use the `SequenceDesign` and nest our initial design in it. "`SR_`" is code for an "`S`" (stimulus) event and an "`R`" (response) event - only single letter events are supported! The "`_`" is a signal for the onset generator to generate a bigger pause - no overlap between adjacent "`SR`" pairs. | ||
| design = SequenceDesign(design, "SR_") | ||
| generate_events(StableRNG(1), design) | ||
| # The main thing that happened is that the design was repeated for every event (each 'letter') of the sequence, and an `eventtype` column was added. | ||
| # !!! hint | ||
| # More advanced sequences are possible as well, like "SR{1,3}", or "A[BC]". Infinite sequences are **not** possible like "AB*". | ||
|
|
||
| # Finally, let's repeat the current design 4 times | ||
| design = RepeatDesign(design, 4) | ||
| generate_events(StableRNG(1), design) | ||
|
|
||
| # This results in 16 trials that nicely follow our sequence | ||
|
|
||
| # !!! hint | ||
| # There is a difference between `SequenceDesign(RepeatDesign)` and `RepeatDesign(SequenceDesign)` for variable sequences e.g. "A[BC]", where in the former case, one sequence is drawn e.g. "AC" and applied to all repeated rows, in the latter, one sequence for each repeat is drawn. | ||
|
|
||
|
|
||
| # Next we have to specify for both events `S` and `R` what the responses should look like. | ||
| p1 = LinearModelComponent(; | ||
| basis = p100(), | ||
| formula = @formula(0 ~ 1 + condition), | ||
| β = [1, 0.5], | ||
| ) | ||
|
|
||
| n1 = LinearModelComponent(; | ||
| basis = n170(), | ||
| formula = @formula(0 ~ 1 + condition), | ||
| β = [1, 0.5], | ||
| ) | ||
|
|
||
| p3 = LinearModelComponent(; | ||
| basis = UnfoldSim.hanning(Int(0.5 * 100)), # sfreq = 100 for the other bases | ||
| formula = @formula(0 ~ 1 + condition), | ||
| β = [1, 0], | ||
| ) | ||
|
|
||
| resp = LinearModelComponent(; | ||
| basis = UnfoldSim.hanning(Int(0.5 * 100)), # sfreq = 100 for the other bases | ||
| formula = @formula(0 ~ 1 + condition), | ||
| β = [1, 2], | ||
| offset = -10, | ||
| ) | ||
| nothing ## hide | ||
|
|
||
|
|
||
| # We combine them into a dictionary with a sequence-`Char` as key and simulate | ||
| components = Dict('S' => [p1, n1, p3], 'R' => [resp]) | ||
|
|
||
| data, evts = simulate( | ||
| StableRNG(1), | ||
| design, | ||
| components, | ||
| UniformOnset(offset = 40, width = 10), | ||
| NoNoise(), | ||
| ) | ||
| nothing ## hide | ||
|
|
||
| # Finally we can plot the results | ||
| f, ax, h = lines(data) | ||
| vlines!(ax, evts.latency[evts.event.=='S'], color = (:darkblue, 0.5)) | ||
| vlines!(ax, evts.latency[evts.event.=='R'], color = (:darkred, 0.5)) | ||
| ax.xlabel = "Time [samples]" | ||
| ax.ylabel = "EEG [a.u]" | ||
| xlims!(ax, 0, 500) | ||
| f | ||
|
|
||
| # As visible, the `R` response always follows the `S` response. Due to the "`_`" we have large breaks between the individual sequences. | ||
|
|
||
|
|
||
|
|
Uh oh!
There was an error while loading. Please reload this page.