From cc42f28f71ae979e085f63990bdce27886852f0c Mon Sep 17 00:00:00 2001 From: Vladimir Mikheev <33777074+vladdez@users.noreply.github.com> Date: Fri, 10 Nov 2023 17:08:30 +0100 Subject: [PATCH] Erpgrid (#92) * Update plot_erp.jl * new tests, combined plot in docs * del * additional docs problems * little detail * dead links * docstring warnings * cross-refs again * test * pp_plot fixed * docs errors should be resolved * Update hide_deco.md * colorbar docs * liting * add Voltage label * linting + name consistency * formatter * no extra for circular * no extra toposeries * test for design matrix and no extra * test * no extra for erp * del extra in erpimage and parplot * g * citability * failed, but I will save it * fixed * fixed colorbar in toposeries * small test * review of current test * del chanNum argument --------- Co-authored-by: behinger (s-ccs 001) --- Project.toml | 2 +- docs/run_liveserver.jl | 2 +- src/UnfoldMakie.jl | 3 ++ src/eeg_series.jl | 8 ++-- src/plot_erp.jl | 8 +--- src/plot_erpgrid.jl | 87 ++++++++++++++++++++++++++++++++++++ src/plot_erpimage.jl | 11 +---- src/plot_topoplotseries.jl | 25 ++++------- test/runtests.jl | 2 +- test/setup.jl | 1 - test/test_butterfly.jl | 14 +++--- test/test_erp.jl | 4 +- test/test_erpgrid.jl | 17 +++++++ test/test_erpimage.jl | 11 +++-- test/test_pp.jl | 15 ++++++- test/test_topoplot.jl | 8 +++- test/test_toposeries.jl | 90 +++++++++++++++++++++++++------------- 17 files changed, 222 insertions(+), 86 deletions(-) create mode 100644 src/plot_erpgrid.jl create mode 100644 test/test_erpgrid.jl diff --git a/Project.toml b/Project.toml index 33d68f6d9..f8eec9edf 100644 --- a/Project.toml +++ b/Project.toml @@ -44,7 +44,7 @@ GeometryBasics = "0.4" GridLayoutBase = "0.9" ImageFiltering = "0.7" LinearAlgebra = "1" -Makie = "0.17,0.18,0.19" +Makie = "0.17, 0.18, 0.19" PyMNE = "0.2" SparseArrays = "1" StaticArrays = "1" diff --git a/docs/run_liveserver.jl b/docs/run_liveserver.jl index 409a5056b..352fd6a33 100644 --- a/docs/run_liveserver.jl +++ b/docs/run_liveserver.jl @@ -1,3 +1,3 @@ using LiveServer -servedocs(skip_dir=joinpath("src","generated"),literate_dir=joinpath("literate"),foldername=".") +servedocs(skip_dir=joinpath("src","generated"),literate_dir=joinpath("literate"),literate=joinpath("literate"),foldername=".") diff --git a/src/UnfoldMakie.jl b/src/UnfoldMakie.jl index 06440aeed..e742859f4 100644 --- a/src/UnfoldMakie.jl +++ b/src/UnfoldMakie.jl @@ -42,6 +42,7 @@ include("plot_topoplot.jl") include("plot_erpimage.jl") include("plot_parallelcoordinates.jl") include("plot_circulareegtopoplot.jl") +include("plot_erpgrid.jl") include("layout_helper.jl") include("eeg_positions.jl") @@ -68,6 +69,8 @@ export plot_circulareegtopoplot! export plot_topoplotseries export plot_topoplotseries! +export plot_erpgrid +export plot_erpgrid! export to_positions export nonnumeric # reexport from AoG diff --git a/src/eeg_series.jl b/src/eeg_series.jl index c02824f36..5df957b70 100644 --- a/src/eeg_series.jl +++ b/src/eeg_series.jl @@ -130,9 +130,10 @@ function eeg_topoplot_series!( select_col = isnothing(col) ? 1 : unique(data_mean[:, col]) select_row = isnothing(row) ? 1 : unique(data_mean[:, row]) + axlist = [] for r = 1:length(select_row) for c = 1:length(select_col) - ax = Axis(fig[r, c]; axisOptions...) + ax = Axis(fig[:, :][r, c]; axisOptions...) # select one topoplot sel = 1 .== ones(size(data_mean, 1)) # select all if !isnothing(col) @@ -159,14 +160,15 @@ function eeg_topoplot_series!( end if c == 1 && length(select_row) > 1 && row_labels #@show df_single - ax.ylabel = string(df_single.row[1]) + ax.ylabel = string(df_single[1, row]) ax.ylabelvisible = true end + push!(axlist, ax) end end colgap!(fig.layout, 0) - return fig + return fig, axlist end """ diff --git a/src/plot_erp.jl b/src/plot_erp.jl index 21e7de924..9d6d96389 100644 --- a/src/plot_erp.jl +++ b/src/plot_erp.jl @@ -149,10 +149,6 @@ function plot_erp!( mapp = mapp * mapping(; config.mapping.group) end - - - - # remove x / y mappingOthers = deleteKeys(config.mapping, [:x, :y]) @@ -169,7 +165,7 @@ function plot_erp!( # add the pvalues if !isempty(pvalue) - basic = basic + addPvalues(plotData, pvalue,config) + basic = basic + addPvalues(plotData, pvalue, config) end plotEquation = basic * mapp @@ -268,7 +264,7 @@ function topoplotLegend(axis, topomarkersize, topoPositionToColorFunction, allPo return topoplot end -function addPvalues(plotData, pvalue,config) +function addPvalues(plotData, pvalue, config) p = deepcopy(pvalue) # for now, add them to the fixed effect diff --git a/src/plot_erpgrid.jl b/src/plot_erpgrid.jl new file mode 100644 index 000000000..3e18e6458 --- /dev/null +++ b/src/plot_erpgrid.jl @@ -0,0 +1,87 @@ +""" + function plot_erpgrid!(f::Union{GridPosition, Figure}, data::Matrix{<:Real}, pos::Vector{Point{2,Float}}; kwargs...) + function plot_erpgrid(data::Matrix{<:Real}, pos::Vector{Point{2,Float}}; kwargs...) + +Plot an ERP image. +## Arguments: +- `f::Union{GridPosition, Figure}`: Figure or GridPosition that the plot should be drawn into; +- `plotData::Matrix{<:Real}`: Data for the plot visualization; +- `pos::Vector{Point{2,Float}}`: electrode positions. + +## Keyword Arguments +- `drawLabels` (bool, `false`) - Draw channels labels over each waveform. +- `times`: (Vector, `1:size(plotData, 2)`) - Vector of size() + +## Return Value: +The input `f` +""" + +# no figure? +plot_erpgrid(plotData::Matrix{<:Real}, pos; kwargs...) = + plot_erpgrid!(Figure(), plotData, pos; kwargs...) + +function plot_erpgrid!( + f::Union{GridPosition,Figure}, + plotData::Matrix{<:Real}, + pos; + drawLabels = false, + times = -1:size(plotData, 2)-2, #arbitrary strat just for fun + kwargs..., +) + chanNum = size(plotData, 1) + println(size(plotData, 1), " ", size(plotData, 2)) + plotData = plotData[1:chanNum, :] + pos = hcat([[p[1], p[2]] for p in pos]...) + + pos = pos[:, 1:chanNum] + minmaxrange = (maximum(pos, dims = 2) - minimum(pos, dims = 2)) + pos = (pos .- mean(pos, dims = 2)) ./ minmaxrange .+ 0.5 + + axlist = [] + #ax = Axis(f[1, 1],backgroundcolor=:green)# + + rel_zeropoint = argmin(abs.(times)) ./ length(times) + + for (ix, p) in enumerate(eachcol(pos)) + x = p[1] #- 0.1 + y = p[2] #- 0.1 + # todo: 0.1 should go into plot config + ax = Axis( + f[1, 1], + width = Relative(0.2), + height = Relative(0.2), + halign = x, + valign = y, + )# title = raw_ch_names[1:30]) + if drawLabels + text!( + ax, + rel_zeropoint + 0.1, + 1, + color = :gray, + fontsize = 12, + text = string.(ix), + align = (:left, :top), + space = :relative, + ) + end + # todo: add label if not nothing + + push!(axlist, ax) + end + # todo: make optional + be able to specify the linewidth + color + hlines!.(axlist, Ref([0.0]), color = :gray, linewidth = 0.5) + vlines!.(axlist, Ref([0.0]), color = :gray, linewidth = 0.5) + + times = isnothing(times) ? (1:size(plotData, 2)) : times + + # todo: add customizable kwargs + h = lines!.(axlist, Ref(times), eachrow(plotData)) + + linkaxes!(axlist...) + hidedecorations!.(axlist) + hidespines!.(axlist) + + f + +end diff --git a/src/plot_erpimage.jl b/src/plot_erpimage.jl index 3fd3fec20..2790cc222 100644 --- a/src/plot_erpimage.jl +++ b/src/plot_erpimage.jl @@ -35,15 +35,8 @@ plot_erpimage!(f::Union{GridPosition,Figure}, plotData::Matrix{<:Real}; kwargs.. # no figure? -plot_erpimage(times::AbstractVector, plotData::Matrix{<:Real}; kwargs...) = plot_erpimage!( - Figure(), - times, - plotData; - sortix = nothing, - meanPlot = false, - erpBlur = 10, - kwargs..., -) +plot_erpimage(times::AbstractVector, plotData::Matrix{<:Real}; kwargs...) = + plot_erpimage!(Figure(), times, plotData; kwargs...) function plot_erpimage!( f::Union{GridPosition,Figure}, diff --git a/src/plot_topoplotseries.jl b/src/plot_topoplotseries.jl index 9e13c1a28..93dcb108e 100644 --- a/src/plot_topoplotseries.jl +++ b/src/plot_topoplotseries.jl @@ -2,9 +2,10 @@ plot_topoplotseries!(f::Union{GridPosition, Figure}, plotData::DataFrame,Δbin::Real;kwargs...) plot_topoplotseries!(plotData::DataFrame, Δbin::Real;kwargs...) +Multiple miniature topoplots in regular distances -Plot a Topoplot Series. ## Arguments: + - `f::Union{GridPosition, Figure}`: Figure or GridPosition that the plot should be drawn into - `plotData::DataFrame`: DataFrame with data, needs a `time` column - `Δbin::Real`: A number for how large one bin should be. Δbin is in units of the `plotData.time` column @@ -23,7 +24,6 @@ The input `f` plot_topoplotseries(plotData::DataFrame, Δbin::Real; kwargs...) = plot_topoplotseries!(Figure(), plotData, Δbin; kwargs...) - function plot_topoplotseries!( f::Union{GridPosition,Figure}, plotData::DataFrame, @@ -36,6 +36,7 @@ function plot_topoplotseries!( rasterize_heatmaps = true, kwargs..., ) + config = PlotConfig(:topoplotseries) config_kwargs!(config; kwargs...) @@ -51,7 +52,7 @@ function plot_topoplotseries!( end - ftopo = eeg_topoplot_series!( + ftopo, axlist = eeg_topoplot_series!( f, plotData, Δbin; @@ -68,13 +69,8 @@ function plot_topoplotseries!( ) if config.layout.useColorbar - #println(fieldnames(typeof(ftopo.layout.content[5].content.content[2].content))) - #@show "colorbar" if typeof(ftopo) == Figure - d = ftopo.content[1].scene.plots[1] - #println(d.colorrange) - #println(d.colormap) Colorbar( f[1, end+1], colormap = d.colormap, @@ -83,20 +79,17 @@ function plot_topoplotseries!( flipaxis = false, label = "Voltage [µV]", ) - else # temporal - if length(ftopo.layout.content) > 2 - d = ftopo.layout.content[5].content.content[2].content.scene.plots[1].attributes - else - d = ftopo.layout.content[2].content.content[1].content.scene.plots[1].plots[1].attributes - end + else + # println(fieldnames(typeof((axlist[1])))) + d = axlist[1].scene.plots[1].attributes Colorbar( - f[1, ftopo.layout.size[2]+1], + f[:, :][1, length(axlist)+1], colormap = d.colormap, colorrange = d.colorrange, height = 100, flipaxis = false, label = "Voltage [µV]", - ) # why end is not working???? + ) end end return f diff --git a/test/runtests.jl b/test/runtests.jl index d7963c8f6..ffeec4f7e 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -1,4 +1,4 @@ - +using UnfoldMakie include("setup.jl") #include("../src/UnfoldMakie.jl") diff --git a/test/setup.jl b/test/setup.jl index 1fb043909..6a53f725a 100644 --- a/test/setup.jl +++ b/test/setup.jl @@ -1,4 +1,3 @@ -using UnfoldMakie using UnfoldSim using Test using CairoMakie diff --git a/test/test_butterfly.jl b/test/test_butterfly.jl index 1cfde5417..ec9f07701 100644 --- a/test/test_butterfly.jl +++ b/test/test_butterfly.jl @@ -1,19 +1,21 @@ +@testset "basic" begin + include("../docs/example_data.jl") + data, pos = example_data("TopoPlots.jl") + plot_butterfly(data; positions = pos) +end + @testset "markersize change" begin include("../docs/example_data.jl") data, pos = example_data("TopoPlots.jl") plot_butterfly( data; positions = pos, - markersize = 10, + topomarkersize = 10, topoheigth = 0.4, topowidth = 0.4, ) end -@testset "markersize change" begin - include("../docs/example_data.jl") - data, pos = example_data("TopoPlots.jl") - plot_butterfly(data; positions = pos) -end + diff --git a/test/test_erp.jl b/test/test_erp.jl index a4aa38c07..8a8e53351 100644 --- a/test/test_erp.jl +++ b/test/test_erp.jl @@ -1,4 +1,4 @@ -@testset "testing standart" begin +@testset "basic with results" begin data, evts = UnfoldSim.predef_eeg(; noiselevel = 12, return_epoched = true) data = reshape(data, (1, size(data)...)) f = @formula 0 ~ 1 + condition + continuous @@ -19,7 +19,7 @@ end -@testset "testing standart with more arguments" begin +@testset "basic with res_effects" begin data, evts = UnfoldSim.predef_eeg(; noiselevel = 12, return_epoched = true) data = reshape(data, (1, size(data)...)) f = @formula 0 ~ 1 + condition + continuous diff --git a/test/test_erpgrid.jl b/test/test_erpgrid.jl new file mode 100644 index 000000000..af8503978 --- /dev/null +++ b/test/test_erpgrid.jl @@ -0,0 +1,17 @@ +data, pos = TopoPlots.example_data() +data = data[:, :, 1] + +#times = -0.099609375:0.001953125:1.0 + +@testset "basic erpgrid: one plot is out of the border" begin + plot_erpgrid(data[1:3, 1:20], pos) +end + +@testset "basic erpgrid" begin + plot_erpgrid(data[1:6, 1:20], pos) +end + +@testset "erpgrid with GridPosition" begin + f = Figure() + plot_erpgrid!(f[1, 1], data, pos) +end diff --git a/test/test_erpimage.jl b/test/test_erpimage.jl index 1bd17b9b0..fda7b0e6b 100644 --- a/test/test_erpimage.jl +++ b/test/test_erpimage.jl @@ -1,21 +1,20 @@ #include("setup.jl") -@testset "testing no bottom erp plot" begin +@testset "basic" begin data, evts = UnfoldSim.predef_eeg(; noiselevel = 10, return_epoched = true) plot_erpimage(data;) end -@testset "testing with bottom erp plot" begin +@testset "with mean erp plot" begin data, evts = UnfoldSim.predef_eeg(; noiselevel = 10, return_epoched = true) plot_erpimage(data; meanPlot = true) end -@testset "testing no bottom erp plot in extra mode" begin +@testset "changing erpBlur to zero" begin data, evts = UnfoldSim.predef_eeg(; noiselevel = 10, return_epoched = true) - plot_erpimage(data; meanPlot = true) + plot_erpimage(data; meanPlot = true, erpBlur = 0) end - -@testset "testing no bottom erp plot in extra mode" begin +@testset "GridPosition" begin f = Figure() data, evts = UnfoldSim.predef_eeg(; noiselevel = 10, return_epoched = true) plot_erpimage!(f[1, 1], data; meanPlot = true) diff --git a/test/test_pp.jl b/test/test_pp.jl index 88bcb06ce..581e808e1 100644 --- a/test/test_pp.jl +++ b/test/test_pp.jl @@ -1,7 +1,18 @@ -@testset "markersize change" begin +@testset "Figure, 3 channels, 1 condition" begin include("../docs/example_data.jl") results_plot, positions = example_data(); - plot_parallelcoordinates(results_plot, [5,3,2]; # this selects channel 5,3 & 2 + plot_parallelcoordinates(results_plot, [5, 3, 2]; # this selects channel 5,3 & 2 mapping = (color = :coefname, y = :estimate)) end + + +@testset "GridPosition" begin + uf_5chan = example_data("UnfoldLinearModelMultiChannel") + d_singletrial, _ = UnfoldSim.predef_eeg(; return_epoched=true) + + f = Figure() + plot_parallelcoordinates!(f[1, 1], uf_5chan, [1, 2, 3, 4, 5]; + mapping=(; color=:coefname), layout=(; legendPosition=:bottom)) + f +end \ No newline at end of file diff --git a/test/test_topoplot.jl b/test/test_topoplot.jl index 4dfefb76b..5e642cff9 100644 --- a/test/test_topoplot.jl +++ b/test/test_topoplot.jl @@ -1,4 +1,10 @@ +data, positions = TopoPlots.example_data() + @testset "testing topoplot" begin - data, positions = TopoPlots.example_data() plot_topoplot(data[:, 150, 1]; positions=positions, t=150) end + +@testset "testing topoplot" begin + f = Figure() + plot_topoplot!(f[1, 1], data[:, 150, 1]; positions=positions, t=220) +end \ No newline at end of file diff --git a/test/test_toposeries.jl b/test/test_toposeries.jl index 367282b9e..161ebd305 100644 --- a/test/test_toposeries.jl +++ b/test/test_toposeries.jl @@ -1,48 +1,76 @@ +data, positions = TopoPlots.example_data() -@testset "testing standart" begin - data, positions = TopoPlots.example_data() - df = UnfoldMakie.eeg_matrix_to_dataframe(data[:, :, 1], string.(1:length(positions))); - Δbin=80 - UnfoldMakie.plot_topoplotseries(df, Δbin; positions=positions) - -end -@testset "testing with colorbar" begin - data, positions = TopoPlots.example_data() - df = UnfoldMakie.eeg_matrix_to_dataframe(data[:, :, 1], string.(1:length(positions))); - Δbin=80 - UnfoldMakie.plot_topoplotseries(df, Δbin; positions=positions, layout = (; useColorbar=true)) - +@testset "basic" begin + df = UnfoldMakie.eeg_matrix_to_dataframe(data[:, :, 1], string.(1:length(positions))) + Δbin = 80 + UnfoldMakie.plot_topoplotseries(df, Δbin; positions = positions) end - -@testset "testing with colorbar" begin - data, positions = TopoPlots.example_data() - df = UnfoldMakie.eeg_matrix_to_dataframe(data[:, :, 1], string.(1:length(positions))); - Δbin=80 - UnfoldMakie.plot_topoplotseries(df, Δbin; positions=positions, layout = (; useColorbar=true)) +@testset "basic without colorbar" begin + df = UnfoldMakie.eeg_matrix_to_dataframe(data[:, :, 1], string.(1:length(positions))) + Δbin = 80 + UnfoldMakie.plot_topoplotseries( + df, + Δbin; + positions = positions, + layout = (; useColorbar = false), + ) end -@testset "testing with colorbar and Figure" begin +@testset "GridPosition with a title" begin f = Figure() - ax = Axis(f[2, 1:5], aspect=DataAspect()) + ax = Axis(f[1:2, 1:5], aspect = DataAspect(), title = "Just a title") - data, positions = TopoPlots.example_data() df = UnfoldMakie.eeg_matrix_to_dataframe(data[:, :, 1], string.(1:length(positions))) Δbin = 80 - chaLeng = 5 - x = Array(55:120:600) - t = Array(-0.3:0.18:0.5) + a = plot_topoplotseries!( + f[1:2, 1:5], + df, + Δbin; + positions = positions, + layout = (; useColorbar = true), + ) + hidespines!(ax) + hidedecorations!(ax, label = false) - xlims!(low=0, high=600) - ylims!(low=0, high=110) + f - hidespines!(ax) - hidedecorations!(ax, label=false) - plot_topoplotseries!(f[1:2, 1:5], df, Δbin; positions=positions, visual=(label_scatter=false,), layout = (; useColorbar = true)) +end +@testset "14 topoplots and GridPosition" begin # horrific + f = Figure() + df = UnfoldMakie.eeg_matrix_to_dataframe(data[:, :, 1], string.(1:length(positions))) + Δbin = 30 + a = plot_topoplotseries!( + f[1, 1:5], + df, + Δbin; + positions = positions, + visual = (label_scatter = false,), + ) f +end + + +@testset "multi-row" begin + f = Figure() -end \ No newline at end of file + df = UnfoldMakie.eeg_matrix_to_dataframe(data[:, :, 1], string.(1:length(positions))) + df.condition = repeat(["A", "B"], size(df, 1) ÷ 2) + Δbin = 80 + + a = plot_topoplotseries!( + f[1:2, 1:2], + df, + Δbin; + col_labels = true, + mapping = (; row = :condition), + positions = positions, + visual = (label_scatter = false,), + ) + + f +end