From d8bd49ef9a7d5e4aaafba866d074273432cec79d Mon Sep 17 00:00:00 2001 From: Vladimir Mikheev Date: Thu, 16 Nov 2023 12:56:50 +0000 Subject: [PATCH] erp plot bug resolved --- src/plot_erp.jl | 57 +++++++------- test/runtests.jl | 17 +++-- test/test_complexplots.jl | 153 ++++++++++++++++++++++++++++++++++++++ test/test_erp.jl | 3 +- 4 files changed, 194 insertions(+), 36 deletions(-) create mode 100644 test/test_complexplots.jl diff --git a/src/plot_erp.jl b/src/plot_erp.jl index d6053a87c..317b9fb79 100644 --- a/src/plot_erp.jl +++ b/src/plot_erp.jl @@ -2,15 +2,15 @@ using DataFrames using TopoPlots using LinearAlgebra """ - plot_erp!(f::Union{GridPosition, GridLayout, Figure}, plotData::DataFrame; kwargs...) - plot_erp(plotData::DataFrame; kwargs...) + plot_erp!(f::Union{GridPosition, GridLayout, Figure}, plot_data::DataFrame; kwargs...) + plot_erp(plot_data::DataFrame; kwargs...) Plot an ERP plot. ## Arguments: - `f::Union{GridPosition, GridLayout, Figure}`: Figure, GridLayout or GridPosition that the plot should be drawn into. -- `plotData::DataFrame`: Data for the line plot visualization. +- `plot_data::DataFrame`: Data for the line plot visualization. - `kwargs...`: Additional styling behavior. Often used: `plot_erp(df; mapping=(; color=:coefname, col=:conditionA))`. ## kwargs (...; ...): @@ -30,7 +30,7 @@ $(_docstring(:erp)) - f - Figure() or the inputed `f` """ -plot_erp(plotData::DataFrame; kwargs...) = plot_erp!(Figure(), plotData, ; kwargs...) +plot_erp(plot_data::DataFrame; kwargs...) = plot_erp!(Figure(), plot_data, ; kwargs...) """ Plot a butterfly plot @@ -47,16 +47,16 @@ Plot a butterfly plot $(_docstring(:butterfly)) see also [`plot_erp`](@Ref) """ -plot_butterfly(plotData::DataFrame; kwargs...) = - plot_butterfly!(Figure(), plotData; kwargs...) +plot_butterfly(plot_data::DataFrame; kwargs...) = + plot_butterfly!(Figure(), plot_data; kwargs...) plot_butterfly!( f::Union{GridPosition,GridLayout,<:Figure}, - plotData::DataFrame; + plot_data::DataFrame; kwargs..., ) = plot_erp!( f, - plotData; + plot_data; butterfly = true, topolegend = true, topomarkersize = 10, @@ -70,7 +70,7 @@ plot_butterfly!( function plot_erp!( f::Union{GridPosition,GridLayout,Figure}, - plotData::DataFrame; + plot_data::DataFrame; positions = nothing, labels = nothing, categorical_color = true, @@ -92,10 +92,10 @@ function plot_erp!( config_kwargs!(config; kwargs...) end - plotData = deepcopy(plotData) # XXX why? + plot_data = deepcopy(plot_data) # XXX why? # resolve columns with data - config.mapping = resolveMappings(plotData, config.mapping) + config.mapping = resolveMappings(plot_data, config.mapping) #remove mapping values with `nothing` deleteKeys(nt::NamedTuple{names}, keys) where {names} = NamedTuple{filter(x -> x ∉ keys, names)}(nt) @@ -106,22 +106,22 @@ function plot_erp!( # turn "nothing" from group columns into :fixef - if "group" ∈ names(plotData) - plotData.group = plotData.group .|> a -> isnothing(a) ? :fixef : a + if "group" ∈ names(plot_data) + plot_data.group = plot_data.group .|> a -> isnothing(a) ? :fixef : a end # check if stderror values exist and create new collumsn with high and low band - if "stderror" ∈ names(plotData) && stderror - plotData.stderror = plotData.stderror .|> a -> isnothing(a) ? 0.0 : a - plotData[!, :se_low] = plotData[:, config.mapping.y] .- plotData.stderror - plotData[!, :se_high] = plotData[:, config.mapping.y] .+ plotData.stderror + if "stderror" ∈ names(plot_data) && stderror + plot_data.stderror = plot_data.stderror .|> a -> isnothing(a) ? 0.0 : a + plot_data[!, :se_low] = plot_data[:, config.mapping.y] .- plot_data.stderror + plot_data[!, :se_high] = plot_data[:, config.mapping.y] .+ plot_data.stderror end # Get topocolors for butterfly if (butterfly) if isnothing(positions) && isnothing(labels) topolegend = false - #colors = config.visual.colormap# get(colorschemes[config.visual.colormap],range(0,1,length=nrow(plotData))) + #colors = config.visual.colormap# get(colorschemes[config.visual.colormap],range(0,1,length=nrow(plot_data))) colors = nothing #config.mapping = merge(config.mapping,(;color=config.)) else @@ -166,11 +166,11 @@ function plot_erp!( basic = basic + visual(Band, alpha = 0.5) * m_se end - basic = basic * data(plotData) + basic = basic * data(plot_data) # add the pvalues if !isempty(pvalue) - basic = basic + addPvalues(plotData, pvalue, config) + basic = basic + addPvalues(plot_data, pvalue, config) end plotEquation = basic * mapp @@ -260,15 +260,15 @@ function topoplotLegend(axis, topomarkersize, topopositions_to_color, allPositio return topoplot end -function addPvalues(data, pvalue, config) +function addPvalues(plot_data, pvalue, config) p = deepcopy(pvalue) # for now, add them to the fixed effect if "group" ∉ names(p) # group not specified using first - if "group" ∈ names(data) - p[!, :group] .= data[1, :group] - if length(unique(data.group)) > 1 + if "group" ∈ names(plot_data) + p[!, :group] .= plot_data[1, :group] + if length(unique(plot_data.group)) > 1 @warn "multiple groups found, choosing first one" end else @@ -285,16 +285,17 @@ function addPvalues(data, pvalue, config) end # define an index to dodge the lines vertically - scaleY = [minimum(data.estimate), maximum(data.estimate)] + scaleY = [minimum(plot_data.estimate), maximum(plot_data.estimate)] stepY = scaleY[2] - scaleY[1] posY = stepY * -0.05 + scaleY[1] - Δt = diff(data.time[1:2])[1] + Δt = diff(plot_data.time[1:2])[1] Δy = 0.01 p[!, :segments] = [ Makie.Rect( Makie.Vec(x, posY + stepY * (Δy * (n - 1))), Makie.Vec(y - x + Δt, 0.5 * Δy * stepY), ) for (x, y, n) in zip(p.from, p.to, p.sigindex) - ] - return (data(p) * mapping(:segments) * visual(Poly)) + ] + res = data(p) * mapping(:segments) * visual(Poly) + return (res) end diff --git a/test/runtests.jl b/test/runtests.jl index 8ce7e7ba4..1b2d36f83 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -6,8 +6,13 @@ include("setup.jl") @testset "Test Config" begin include("test_config.jl") end -@testset "Circular EEG topoplot" begin - include("test_plot_circulareegtopoplot.jl") + +@testset "ERP plot" begin + include("test_erp.jl") +end + +@testset "Butterfly" begin + include("test_butterfly.jl") end @testset "Topoplot series" begin @@ -22,10 +27,10 @@ end include("test_topoplot.jl") end -@testset "Butterfly" begin - include("test_butterfly.jl") +@testset "Circular EEG topoplot" begin + include("test_plot_circulareegtopoplot.jl") end -@testset "Combined plots" begin - include("test_all.jl") +@testset "Complex plots" begin + include("test_complexplots.jl") end \ No newline at end of file diff --git a/test/test_complexplots.jl b/test/test_complexplots.jl new file mode 100644 index 000000000..d87c87623 --- /dev/null +++ b/test/test_complexplots.jl @@ -0,0 +1,153 @@ +@testset "8 plots" begin + f = Figure(resolution=(1200, 1400)) + ga = f[1, 1] = GridLayout() + gc = f[2, 1] = GridLayout() + ge = f[3, 1] = GridLayout() + gg = f[4, 1] = GridLayout() + geh = f[1:4, 2] = GridLayout() + gb = geh[1, 1] = GridLayout() + gd = geh[2, 1] = GridLayout() + gf = geh[3, 1] = GridLayout() + gh = geh[4, 1] = GridLayout() + + include("../docs/example_data.jl") + d_topo, pos = example_data("TopoPlots.jl") + uf_deconv = example_data("UnfoldLinearModelContinuousTime") + uf = example_data("UnfoldLinearModel") + results = coeftable(uf) + uf_5chan = example_data("UnfoldLinearModelMultiChannel") + d_singletrial, _ = UnfoldSim.predef_eeg(; return_epoched=true) + times = -0.099609375:0.001953125:1.0 + data, positions = TopoPlots.example_data() + df = UnfoldMakie.eeg_matrix_to_dataframe(data[:,:,1], string.(1:length(positions))); + + data_erp, evts = UnfoldSim.predef_eeg(; noiselevel = 12, return_epoched = true) + data_erp = reshape(data_erp, (1, size(data_erp)...)) + form = @formula 0 ~ 1 + condition + continuous + se_solver = (x, y) -> Unfold.solver_default(x, y, stderror = true); + m = fit( + UnfoldModel, + Dict(Any => (form, range(0, step = 1 / 100, length = size(data_erp, 2)))), + evts, + data_erp, + solver = se_solver, + ) + results = coeftable(m) + res_effects = effects(Dict(:continuous => -5:0.5:5), m); + + plot_erp!(ga, results; :stderror=>true, legend=(; framevisible = false)) + plot_butterfly!(gb, d_topo; positions=pos, topomarkersize = 10, topoheigth = 0.4, topowidth = 0.4,) + plot_topoplot!(gc, data[:,340,1]; positions = positions) + plot_topoplotseries!(gd, df, 80; positions=positions, visual=(label_scatter=false,), + layout = (; useColorbar=true)) + plot_erpgrid!(ge, data[:, :, 1], positions) + plot_erpimage!(gf, times, d_singletrial) + plot_parallelcoordinates!(gh, uf_5chan, [1, 2, 3, 4, 5]; + mapping=(; color=:coefname), layout=(; legendPosition=:bottom), legend=(; tellwidth =false)) + + for (label, layout) in zip(["A", "B", "C", "D", "E", "F", "G", "H"], [ga, gb, gc, gd, ge, gf, gg, gh]) + Label(layout[1, 1, TopLeft()], label, + fontsize=26, + font=:bold, + padding=(0, 5, 5, 0), + halign=:right) + end + f +end + + +@testset "8 plots with a Figure" begin + f = Figure(resolution=(1200, 1400)) + + include("../docs/example_data.jl") + d_topo, positions = example_data("TopoPlots.jl") + data, positions = TopoPlots.example_data() + uf = example_data("UnfoldLinearModel") + results = coeftable(uf) + uf_5chan = example_data("UnfoldLinearModelMultiChannel") + d_singletrial, _ = UnfoldSim.predef_eeg(; return_epoched=true) + + + pvals = DataFrame( + from=[0.1, 0.15], + to=[0.2, 0.5], + # if coefname not specified, line should be black + coefname=["(Intercept)", "category: face"] + ) + plot_erp!(f[1, 1], results, extra=(; + categoricalColor=false, + categoricalGroup=false, + pvalue=pvals, + stderror=true)) + + plot_butterfly!(f[1, 2], d_topo; positions=positions) + plot_topoplot!(f[2, 1], data[:, 150, 1]; positions=positions) + plot_topoplotseries!(f[2, 2], d_topo, 0.1; positions=positions, visual=(label_scatter=false,), layout = (; useColorbar=true)) + plot_erpgrid!(f[3, 1], data[:, :, 1], positions) + + times = -0.099609375:0.001953125:1.0 + plot_erpimage!(f[3, 2], times, d_singletrial) + + plot_parallelcoordinates!(f[4, 2], uf_5chan, [1, 2, 3, 4, 5]; mapping=(; color=:coefname), + layout=(; legendPosition=:bottom), legend=(; tellwidth =false)) + + for (label, layout) in zip(["A", "B", "C", "D", "E", "F", "G", "H"], + [f[1, 1], f[1, 2], f[2, 1], f[2, 2], f[3, 1], f[3, 2], f[4, 1], f[4, 2]]) + Label(layout[1, 1, TopLeft()], label, + fontsize=26, + font=:bold, + padding=(0, 5, 5, 0), + halign=:right) + end + f +end + + +@testset "testing combined figure (a Figure from mult_viz_in_fig from docs)" begin + include("../docs/example_data.jl") + d_topo, positions = example_data("TopoPlots.jl") + uf_deconv = example_data("UnfoldLinearModelContinuousTime") + uf = example_data("UnfoldLinearModel") + results = coeftable(uf) + uf_5chan = example_data("UnfoldLinearModelMultiChannel") + d_singletrial, _ = UnfoldSim.predef_eeg(; return_epoched=true) + data, positions = TopoPlots.example_data() + times = -0.099609375:0.001953125:1.0 + + f = Figure(resolution=(2000, 2000)) + + plot_butterfly!(f[1, 1:3], d_topo; positions=positions) + + pvals = DataFrame( + from=[0.1, 0.15], + 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, + pvalue=pvals, + stderror=true) + + plot_designmatrix!(f[2, 3], designmatrix(uf)) + + plot_topoplot!(f[3, 1], data[:, 150, 1]; positions=positions) + plot_topoplotseries!(f[4, 1:3], d_topo, 0.1; positions=positions, mapping=(; label=:channel)) + + 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), + legend=(; nbanks=2), + layout=(; showLegend=true, legendPosition=:right)) + + plot_parallelcoordinates!(f[3, 2:3], uf_5chan, [1, 2, 3, 4, 5]; mapping=(; color=:coefname), layout=(; legendPosition=:bottom)) + + plot_erpimage!(f[1, 4:5], times, d_singletrial) + plot_circulareegtopoplot!(f[3:4, 4:5], d_topo[in.(d_topo.time, Ref(-0.3:0.1:0.5)), :]; + positions=positions, predictor=:time, predictor_bounds=[-0.3, 0.5]) + + f + #save("test.png", f) +end \ No newline at end of file diff --git a/test/test_erp.jl b/test/test_erp.jl index fab357b52..78fd36833 100644 --- a/test/test_erp.jl +++ b/test/test_erp.jl @@ -40,8 +40,7 @@ end res_effects; mapping = (; y = :yhat, color = :continuous, group = :continuous), legend = (; nbanks = 2), - layout = (; legendPosition = :right), - showLegend = true, + layout = (; legendPosition = :right, showLegend = false), categorical_color = false, categorical_group = true, )