Skip to content

Commit

Permalink
Merge pull request #237 from unfoldtoolbox/splines
Browse files Browse the repository at this point in the history
Splines and plot_erp

Fixed:
- #231 
- #235
- #225 - this parameter was deprecated at all
- #234 
- remove `legend.tellwidth = false` from the plotconfgs - better layout
- #55 and #238
- #216
- #56
- #232
- #172 
- #222
- #236 
- #205 
- partially #94 
- #106 
- #183 
- #141 
- #147 

Spline plot 
- #36 - here we added a new type of plot plot_splines
- knots with dashed line
- subplots for each spline term
- documentation page and config

Also
- system of supportive axis available for users to change
- opportunity to put them into docstrings via substitution
  • Loading branch information
vladdez authored Sep 24, 2024
2 parents 7677752 + 6d3dae6 commit b805907
Show file tree
Hide file tree
Showing 43 changed files with 829 additions and 480 deletions.
4 changes: 3 additions & 1 deletion Project.toml
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
name = "UnfoldMakie"
uuid = "69a5ce3b-64fb-4f22-ae69-36dd4416af2a"
authors = ["Vladimir Mikheev", "Daniel Baumgartner", "Sören Döring", "Niklas Gärtner", "Furkan Lokman", "Benedikt Ehinger"]
version = "0.5.7"
version = "0.5.8"

[deps]
AlgebraOfGraphics = "cbdf2221-f076-402e-a563-3d30da359d67"
BSplineKit = "093aae92-e908-43d7-9660-e50ee39d5a0a"
CategoricalArrays = "324d7699-5711-5eae-9e2f-1d82baa6b597"
ColorSchemes = "35d6a980-a343-548e-a6ea-1d62b119f2f4"
ColorTypes = "3da002f7-5984-5a60-b8a6-cbb66c0b333f"
Expand Down Expand Up @@ -34,6 +35,7 @@ UnfoldMakiePyMNEExt = "PyMNE"

[compat]
AlgebraOfGraphics = "0.7, 0.8"
BSplineKit = "0.16, 0.17"
CategoricalArrays = "0.10"
ColorSchemes = "3"
ColorTypes = "0.11"
Expand Down
16 changes: 12 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,15 @@
| <a href="https://github.com/unfoldtoolbox/Unfold.jl/tree/main"><img src="https://github-production-user-asset-6210df.s3.amazonaws.com/10183650/277623787-757575d0-aeb9-4d94-a5f8-832f13dcd2dd.png"></a> | <a href="https://github.com/unfoldtoolbox/UnfoldMakie.jl"><img src="https://github-production-user-asset-6210df.s3.amazonaws.com/10183650/277623793-37af35a0-c99c-4374-827b-40fc37de7c2b.png"></a>|<a href="https://github.com/unfoldtoolbox/UnfoldSim.jl"><img src="https://github-production-user-asset-6210df.s3.amazonaws.com/10183650/277623795-328a4ccd-8860-4b13-9fb6-64d3df9e2091.png"></a>|<a href="https://github.com/unfoldtoolbox/UnfoldBIDS.jl"><img src="https://github-production-user-asset-6210df.s3.amazonaws.com/10183650/277622460-2956ca20-9c48-4066-9e50-c5d25c50f0d1.png"></a>|<a href="https://github.com/unfoldtoolbox/UnfoldDecode.jl"><img src="https://github-production-user-asset-6210df.s3.amazonaws.com/10183650/277622487-802002c0-a1f2-4236-9123-562684d39dcf.png"></a>|<a href="https://github.com/unfoldtoolbox/UnfoldStats.jl"><img src="https://github-production-user-asset-6210df.s3.amazonaws.com/10183650/277623799-4c8f2b5a-ea84-4ee3-82f9-01ef05b4f4c6.png"></a>|

A toolbox for visualizations of EEG/ERP data and Unfold.jl models.
Based on the [Unfold](https://github.com/unfoldtoolbox/unfold.jl/) and [Makie](https://makie.juliaplots.org/stable/), it grants users high performance, and highly customizable plots.

We currently support:
Based on three libraries
- [Unfold](https://github.com/unfoldtoolbox/unfold.jl/) - for performing deconvolution regression;
- [Makie](https://makie.juliaplots.org/stable/) - very flexible visualisation library ([Maki-e](https://en.wikipedia.org/wiki/Maki-e) means "visualisation" on Japanese);
- [Algebra of Graphics](https://github.com/MakieOrg/AlgebraOfGraphics.jl) - Makie-based visualisation library, allowing flexible mapping.

This grants users high performance, and highly customizable plots.

We currently support 9 general ERP plots:
<img src="https://raw.githubusercontent.com/unfoldtoolbox/UnfoldMakie.jl/8plots3/docs/src/assets/complex_plot.png" width="300" align="right">
- ![icon_erpplot_20px](https://github.com/unfoldtoolbox/UnfoldMakie.jl/assets/10183650/22c8472d-df78-46d7-afe8-e1e4e7b04313)
ERP plots
Expand All @@ -37,9 +43,11 @@ ERP images
Channel images
- ![icon_parallel_20px](https://github.com/unfoldtoolbox/UnfoldMakie.jl/assets/10183650/dab097c3-bcd6-4405-a44b-71cbe3e5fac9)
Parallel coordinates
- Design matrices
- Circular topoplots

And 2 Unfold-specific plots:
- Design matrices
- Splines plot

## Install

Expand Down Expand Up @@ -113,8 +121,8 @@ If you use these visualizations, please cite:
<tbody>
<tr>
<td align="center" valign="top" width="14.28%"><a href="http://www.benediktehinger.de"><img src="https://avatars.githubusercontent.com/u/10183650?v=4?s=100" width="100px;" alt="Benedikt Ehinger"/><br /><sub><b>Benedikt Ehinger</b></sub></a><br /><a href="https://github.com/unfoldtoolbox/UnfoldMakie.jl/issues?q=author%3Abehinger" title="Bug reports">🐛</a> <a href="https://github.com/unfoldtoolbox/UnfoldMakie.jl/commits?author=behinger" title="Code">💻</a> <a href="https://github.com/unfoldtoolbox/UnfoldMakie.jl/commits?author=behinger" title="Documentation">📖</a> <a href="#ideas-behinger" title="Ideas, Planning, & Feedback">🤔</a> <a href="#infra-behinger" title="Infrastructure (Hosting, Build-Tools, etc)">🚇</a> <a href="#maintenance-behinger" title="Maintenance">🚧</a> <a href="#question-behinger" title="Answering Questions">💬</a> <a href="https://github.com/unfoldtoolbox/UnfoldMakie.jl/pulls?q=is%3Apr+reviewed-by%3Abehinger" title="Reviewed Pull Requests">👀</a> <a href="https://github.com/unfoldtoolbox/UnfoldMakie.jl/commits?author=behinger" title="Tests">⚠️</a> <a href="#tutorial-behinger" title="Tutorials">✅</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Link250"><img src="https://avatars.githubusercontent.com/u/4541950?v=4?s=100" width="100px;" alt="Quantum"/><br /><sub><b>Daniel Baumgartner</b></sub></a><br /><a href="https://github.com/unfoldtoolbox/UnfoldMakie.jl/commits?author=Link250" title="Code">💻</a> <a href="https://github.com/unfoldtoolbox/UnfoldMakie.jl/commits?author=Link250" title="Documentation">📖</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/vladdez"><img src="https://avatars.githubusercontent.com/u/33777074?v=4?s=100" width="100px;" alt="Vladimir Mikheev"/><br /><sub><b>Vladimir Mikheev</b></sub></a><br /><a href="https://github.com/unfoldtoolbox/UnfoldMakie.jl/issues?q=author%3Avladdez" title="Bug reports">🐛</a> <a href="https://github.com/unfoldtoolbox/UnfoldMakie.jl/commits?author=vladdez" title="Code">💻</a> <a href="https://github.com/unfoldtoolbox/UnfoldMakie.jl/commits?author=vladdez" title="Documentation">📖</a> <a href="#ideas-vladdez" title="Ideas, Planning, & Feedback">🤔</a> <a href="#maintenance-vladdez" title="Maintenance">🚧</a> <a href="https://github.com/unfoldtoolbox/UnfoldMakie.jl/pulls?q=is%3Apr+reviewed-by%3Avladdez" title="Reviewed Pull Requests">👀</a> <a href="https://github.com/unfoldtoolbox/UnfoldMakie.jl/commits?author=vladdez" title="Tests">⚠️</a> <a href="#tutorial-vladdez" title="Tutorials">✅</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Link250"><img src="https://avatars.githubusercontent.com/u/4541950?v=4?s=100" width="100px;" alt="Quantum"/><br /><sub><b>Daniel Baumgartner</b></sub></a><br /><a href="https://github.com/unfoldtoolbox/UnfoldMakie.jl/commits?author=Link250" title="Code">💻</a> <a href="https://github.com/unfoldtoolbox/UnfoldMakie.jl/commits?author=Link250" title="Documentation">📖</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/NiklasMGaertner"><img src="https://avatars.githubusercontent.com/u/54365174?v=4?s=100" width="100px;" alt="NiklasMGaertner"/><br /><sub><b>Niklas Gärtner</b></sub></a><br /><a href="https://github.com/unfoldtoolbox/UnfoldMakie.jl/commits?author=NiklasMGaertner" title="Code">💻</a> <a href="https://github.com/unfoldtoolbox/UnfoldMakie.jl/commits?author=NiklasMGaertner" title="Documentation">📖</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/SorenDoring"><img src="https://avatars.githubusercontent.com/u/54365184?v=4?s=100" width="100px;" alt="SorenDoring"/><br /><sub><b>Soren Doring</b></sub></a><br /><a href="https://github.com/unfoldtoolbox/UnfoldMakie.jl/commits?author=SorenDoring" title="Code">💻</a> <a href="https://github.com/unfoldtoolbox/UnfoldMakie.jl/commits?author=SorenDoring" title="Documentation">📖</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/lokmanfl"><img src="https://avatars.githubusercontent.com/u/44772645?v=4?s=100" width="100px;" alt="lokmanfl"/><br /><sub><b>Fadil Furkan Lokman</b></sub></a><br /><a href="https://github.com/unfoldtoolbox/UnfoldMakie.jl/commits?author=lokmanfl" title="Code">💻</a> <a href="https://github.com/unfoldtoolbox/UnfoldMakie.jl/commits?author=lokmanfl" title="Documentation">📖</a></td>
Expand Down
4 changes: 3 additions & 1 deletion docs/Project.toml
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
[deps]
AlgebraOfGraphics = "cbdf2221-f076-402e-a563-3d30da359d67"
BSplineKit = "093aae92-e908-43d7-9660-e50ee39d5a0a"
CSV = "336ed68f-0bac-5ca0-87d4-7b16caf5d00b"
CairoMakie = "13f3f980-e62b-5c42-98c6-ff1f3baf88f0"
ColorSchemes = "35d6a980-a343-548e-a6ea-1d62b119f2f4"
Expand All @@ -23,4 +24,5 @@ UnfoldSim = "ed8ae6d2-84d3-44c6-ab46-0baf21700804"
XML2_jll = "02c8fc9c-b97f-50b9-bbe4-9be30ff0a78a"

[compat]
AlgebraOfGraphics = "0.7, 0.8"
AlgebraOfGraphics = "0.7, 0.8"
BSplineKit = "0.16, 0.17"
63 changes: 52 additions & 11 deletions docs/example_data.jl
Original file line number Diff line number Diff line change
Expand Up @@ -6,24 +6,34 @@ using Random
"""
example_data(String)
Creates example data. Currently, 7 datasets are available.
- `TopoPlots.jl` (default) - tidy DataFrame from `TopoPlots.jl` with 2 conditions, 64 channels and 800 ms time range.
- `UnfoldLinearModel`
- `UnfoldLinearModelMultiChannel`
- `UnfoldLinearModelContinuousTime`
- `7channels`
- `UnfoldTimeExpanded`
- `sort_data` - includes DataFrame EEG recordings `dat` and `evts` with event variables occured during experiment. `evts` could be used for sorting EEG data in ERP image.
Creates example data or model. Currently, 3 datasets and 6 models are available.
Datasets:
- `TopoPlots.jl` (default) - 2 DataFrames from `TopoPlots.jl`:\\
- DataFrame with estimate, time, 64 channels, topopositions, sterror and pvalue and 800 ms time range.\\
- Posiions for 64 electrodes.
- `UnfoldLinearModelMultiChannel` - DataFrame with 5 channels, 3 coefnames, sterror, time and estimate.
- `sort_data` - 2 DataFrames:
- `dat` for EEG recordings and `evts` with event variables occured during experiment.\\
- `evts` could be used for sorting EEG data in ERP image.
Models:
- `UnfoldLinearModel` - Model with formula `1 + condition + continuous`.
- `UnfoldLinearModelContinuousTime` - Model with formula `timeexpand(1 + condition + continuous)` for times [0.0, 0.01 ... 0.5].
- `UnfoldLinearModelwith1Spline` - Model with formula `1 + condition + spl(continuous, 4)`.
- `UnfoldLinearModelwith2Splines` - Model with formula ` 1 + condition + spl(continuous, 4) + spl(continuous2, 6)`.
- `7channels` - Model with formula `timeexpand(1 + condA)` for times [-0.1, -0.09 ... 0.5].
- `UnfoldTimeExpanded` - Model with formula `timeexpand(1 + condition + continuous)` for times [-0.4, -0.39 ... 0.8].
**Return Value:** `DataFrame`.
"""
function example_data(example = "TopoPlots.jl")

if example == "UnfoldLinearModel"
# load and generate a simulated Unfold Design
data, evts = UnfoldSim.predef_eeg(; noiselevel = 12, return_epoched = true)
data = reshape(data, (1, size(data)...))
f = @formula 0 ~ 1 + condition + continuous
# generate ModelStruct
# generate ModelStruct
se_solver = (x, y) -> Unfold.solver_default(x, y, stderror = true)
return fit(
UnfoldModel,
Expand Down Expand Up @@ -72,6 +82,38 @@ function example_data(example = "TopoPlots.jl")
basis = firbasis([0, 0.5], 100)
# generate ModelStruct
return fit(UnfoldModel, [Any => (f, basis)], evts, data)
elseif example == "UnfoldLinearModelwith1Spline"
# load and generate a simulated Unfold Design
data, evts = UnfoldSim.predef_eeg(; noiselevel = 12, return_epoched = true)
data = reshape(data, (1, size(data)...))
evts.continuous2 .=
log10.(6 .+ rand(MersenneTwister(1), length(evts.continuous))) .^ 2
f = @formula 0 ~ 1 + condition + spl(continuous, 4)
# generate ModelStruct
se_solver = (x, y) -> Unfold.solver_default(x, y, stderror = true)
return fit(
UnfoldModel,
[Any => (f, range(0, length = size(data, 2), step = 1 / 100))],
evts,
data;
solver = se_solver,
)
elseif example == "UnfoldLinearModelwith2Splines"
# load and generate a simulated Unfold Design
data, evts = UnfoldSim.predef_eeg(; noiselevel = 12, return_epoched = true)
data = reshape(data, (1, size(data)...))
evts.continuous2 .=
log10.(6 .+ rand(MersenneTwister(1), length(evts.continuous))) .^ 2
f = @formula 0 ~ 1 + condition + spl(continuous, 4) + spl(continuous2, 6)
# generate ModelStruct
se_solver = (x, y) -> Unfold.solver_default(x, y, stderror = true)
return fit(
UnfoldModel,
[Any => (f, range(0, length = size(data, 2), step = 1 / 100))],
evts,
data;
solver = se_solver,
)
elseif example == "7channels"
design =
SingleSubjectDesign(conditions = Dict(:condA => ["levelA", "levelB"])) |>
Expand All @@ -89,7 +131,6 @@ function example_data(example = "TopoPlots.jl")
f = @formula 0 ~ 1 + condA
bf_dict = [Any => (f, basisfunction)]
return fit(UnfoldModel, bf_dict, evnts, df)

elseif example == "UnfoldTimeExpanded"
df, evts = UnfoldSim.predef_eeg()
f = @formula 0 ~ 1 + condition + continuous
Expand Down
2 changes: 1 addition & 1 deletion docs/literate/explanations/positions.jl
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
using UnfoldMakie
using CairoMakie
using TopoPlots
using PyMNE
using PyMNE;

# # Get positions from MNE

Expand Down
6 changes: 2 additions & 4 deletions docs/literate/how_to/hide_deco.jl
Original file line number Diff line number Diff line change
Expand Up @@ -32,17 +32,15 @@ plot_butterfly!(
data;
positions = pos,
topomarkersize = 10,
topoheight = 0.4,
topowidth = 0.4,
topo_axis = (; height = Relative(0.4), width = Relative(0.4)),
axis = (; title = "With decorations"),
)
plot_butterfly!(
f[2, 1],
data;
positions = pos,
topomarkersize = 10,
topoheight = 0.4,
topowidth = 0.4,
topo_axis = (; height = Relative(0.4), width = Relative(0.4)),
axis = (; title = "Without decorations"),
layout = (; hidedecorations = (:label => true, :ticks => true, :ticklabels => true)),
)
Expand Down
18 changes: 3 additions & 15 deletions docs/literate/how_to/mult_vis_in_fig.jl
Original file line number Diff line number Diff line change
Expand Up @@ -69,14 +69,7 @@ pvals = DataFrame(
to = [0.2, 0.5], # if coefname not specified, line should be black
coefname = ["(Intercept)", "category: face"],
)
plot_erp!(
f[2, 1:2],
results,
categorical_color = false,
categorical_group = false,
significance = pvals,
stderror = true,
)
plot_erp!(f[2, 1:2], results, significance = pvals, stderror = true)

plot_designmatrix!(f[2, 3], designmatrix(uf))

Expand All @@ -94,18 +87,14 @@ res_effects = effects(Dict(:continuous => -5:0.5:5), uf_deconv)
plot_erp!(
f[2, 4:5],
res_effects;
categorical_color = false,
categorical_group = true,
mapping = (; y = :yhat, color = :continuous, group = :continuous),
mapping = (; y = :yhat, color = :continuous, group = :continuous => nonnumeric),
legend = (; nbanks = 2),
layout = (; show_legend = true, legend_position = :right),
)

plot_parallelcoordinates(
f[3, 2:3],
uf_5chan;
mapping = (; color = :coefname),
layout = (; legend_position = :right),
)

plot_erpimage!(f[1, 4:5], times, d_singletrial)
Expand Down Expand Up @@ -157,8 +146,7 @@ plot_butterfly!(
d_topo;
positions = pos,
topomarkersize = 10,
topoheight = 0.4,
topowidth = 0.4,
topo_axis = (; height = Relative(0.4), width = Relative(0.4)),
)
hlines!(0, color = :gray, linewidth = 1)
vlines!(0, color = :gray, linewidth = 1)
Expand Down
17 changes: 9 additions & 8 deletions docs/literate/how_to/position2color.jl
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

# You want to change the colors of the lines and markers on the inserted topoplot.
# To do that you need to change the color scheme (aka color map) of the butterfly plot.
# You can find th elist of colormaps for Makie [here](https://docs.makie.org/v0.21/explanations/colors).

# # Setup

Expand All @@ -19,15 +20,15 @@ plot_butterfly(results; positions = positions)
# # Color schemes
# ## MNE style

#=
We can change the color scale by specifying a function that maps from an `(x, y)` tuple to a color. UnfoldMakie currently provides three different color scales:
- `pos2colorRGB` (same as MNE-Python),
- `pos2colorHSV` (HSV color space),
- `pos2colorRomaO`.
# We can change the color scale by specifying a function that maps from an `(x, y)` tuple to a color.
# `UnfoldMakie` currently provides three different color scales:
# - `pos2colorRGB` (same as MNE-Python),
# - `pos2colorHSV` (HSV color space),
# - `pos2colorRomaO`.

# While `RGB` & `HSV` have the advantage of being 2D color maps, `Roma0` has the advantage of being perceptually uniform.
# Also you can specify a uniform color.

While `RGB` & `HSV` have the advantage of being 2D color maps, `Roma0` has the advantage of being perceptually uniform.
Also you can specify a uniform color.
=#

plot_butterfly(
results;
Expand Down
12 changes: 6 additions & 6 deletions docs/literate/intro/code_principles.jl
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@

# Here we will write about principles which we developed through our publication.

#- Code should be clear and concise
#- Variables inside the code should have meaningful names
#- Every function exposed to the user should have documentation that specifies all parameters, types, input and output arguments.
#- Most people will not look at the defaults, so it is very important to nudge users to show important details with a picture or text.
#- Function naming should be based on some theory and naming conventions.
#- You should avoid functions longer 50 lines
# - Code should be clear and concise.
# - Variables inside the code should have meaningful names.
# - Every function exposed to the user should have documentation that specifies all parameters, types, input and output arguments.
# - Most people will not look at the defaults, so it is very important to nudge users to label important details of the plot.
# - Function naming should be based on some theory and naming conventions.
# - You should avoid functions longer 50 lines.
7 changes: 6 additions & 1 deletion docs/literate/tutorials/butterfly.jl
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,12 @@ plot_butterfly(df; positions = pos)

# You want to change size of topomarkers and size of topoplot:

plot_butterfly(df; positions = pos, topomarkersize = 10, topoheight = 0.4, topowidth = 0.4)
plot_butterfly(
df;
positions = pos,
topomarkersize = 10,
topo_axis = (; height = Relative(0.4), width = Relative(0.4)),
)

# You want to add vline and hline:

Expand Down
2 changes: 1 addition & 1 deletion docs/literate/tutorials/designmatrix.jl
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ using CairoMakie
# Data

include("../../../example_data.jl")
uf = example_data("UnfoldLinearModel")
uf = example_data("UnfoldLinearModel");

# # Plot Designmatrices

Expand Down
15 changes: 8 additions & 7 deletions docs/literate/tutorials/erp.jl
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ using CairoMakie
using DataFramesMeta
using UnfoldSim
using UnfoldMakie
include("../../../example_data.jl")
include("../../../example_data.jl");

# Data generation

Expand All @@ -36,6 +36,9 @@ res_effects = effects(Dict(:continuous => -5:0.5:5), m);
# ## Figure plotting
plot_erp(results)

# To change legend title use `mapping.color`:
plot_erp(results, mapping = (; color = :coefname => "Conditions"))

# # Additional features

# ## Effect plot
Expand All @@ -53,9 +56,7 @@ plot_erp(results)
plot_erp(
res_effects;
mapping = (; y = :yhat, color = :continuous, group = :continuous),
layout = (; show_legend = false),
categorical_color = false, # perceives color (here: continuous) as contionus
categorical_group = true, # separates lines, if `false` all lines will be connected
layout = (; use_colorbar = false),
)

# ## Significance lines
Expand All @@ -68,8 +69,8 @@ plot_erp(
m = example_data("UnfoldLinearModel")
results = coeftable(m)
significancevalues = DataFrame(
from = [0.1, 0.3],
to = [0.5, 0.7],
from = [0.01, 0.2],
to = [0.3, 0.4],
coefname = ["(Intercept)", "condition: face"], # if coefname not specified, line should be black
)
plot_erp(results; :significance => significancevalues)
Expand Down Expand Up @@ -110,7 +111,7 @@ text!(0.98, 0.2, text = "* Confidence\nintervals", align = (:right, :top))
f

# There are two ways to implement it.
# First is using `:stderror = true' after `;`.
# First is using `:stderror = true` after `;`.

results.se_low = results.estimate .- 0.5
results.se_high = results.estimate .+ 0.15
Expand Down
Loading

0 comments on commit b805907

Please sign in to comment.