From d9e56b5c27700172a3a307fd4ff440bb113c9351 Mon Sep 17 00:00:00 2001 From: Vladimir Mikheev <33777074+vladdez@users.noreply.github.com> Date: Mon, 13 Nov 2023 17:58:30 +0100 Subject: [PATCH] 8plots (#97) * 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 * adding Gridlayout option * small fixes * add new argument to erp plot * colorbar section in configs for toposeries * whatever --------- Co-authored-by: behinger (s-ccs 001) --- docs/src/tutorials/topoplotseries.md | 4 +- src/eeg-series.jl | 176 -------------------------- src/eeg_series.jl | 4 +- src/plot_circulareegtopoplot.jl | 8 +- src/plot_designmatrix.jl | 6 +- src/plot_erp.jl | 61 ++++----- src/plot_erpgrid.jl | 7 +- src/plot_erpimage.jl | 8 +- src/plot_parallelcoordinates.jl | 25 ++-- src/plot_topoplot.jl | 8 +- src/plot_topoplotseries.jl | 6 +- src/plotconfig.jl | 11 +- test/test_all.jl | 106 ++++++++++++++++ test/test_butterfly.jl | 2 +- test/test_dm.jl | 15 ++- test/test_erp.jl | 90 +++++++++++++ test/test_erpgrid.jl | 7 + test/test_pcp.jl | 18 +++ test/test_plot_circulareegtopoplot.jl | 17 ++- 19 files changed, 322 insertions(+), 257 deletions(-) delete mode 100644 src/eeg-series.jl create mode 100644 test/test_pcp.jl diff --git a/docs/src/tutorials/topoplotseries.md b/docs/src/tutorials/topoplotseries.md index 10eacfddb..ff88fe472 100644 --- a/docs/src/tutorials/topoplotseries.md +++ b/docs/src/tutorials/topoplotseries.md @@ -27,10 +27,10 @@ nothing #hide plot_topoplotseries(df, Δbin; positions = positions) ``` -With colorbar: +Without colorbar: ```@example main -plot_topoplotseries(df, Δbin; positions=positions, layout = (; useColorbar=true)) +plot_topoplotseries(df, Δbin; positions=positions, layout = (; useColorbar=false)) ``` ### Positions diff --git a/src/eeg-series.jl b/src/eeg-series.jl deleted file mode 100644 index 1245ba57f..000000000 --- a/src/eeg-series.jl +++ /dev/null @@ -1,176 +0,0 @@ -# Note: This is copied from https://github.com/MakieOrg/TopoPlots.jl/pull/3 because they apparently cannot do a review in ~9month... - -""" -Helper function converting a matrix (channel x times) to a tidy dataframe - with columns :estimate, :time and :label -""" -function eeg_matrix_to_dataframe(data, label) - df = DataFrame(data', label) - df[!, :time] .= 1:nrow(df) - df = stack(df, Not([:time]); variable_name=:label, value_name="estimate") - return df -end - -""" -function eeg_topoplot_series(data::DataFrame, - Δbin; - y=:estimate, - label=:label, - col=:time, - row=nothing, - figure = NamedTuple(), - combinefun=mean, - row_labels = false, - col_labels = false, - topoplot_attributes... - ) -Plot a series of topoplots. The function automatically takes the `combinefun=mean` over the `:time`` column of `data` in `Δbin` steps. -Dataframe `data` needs columns `:time` and `y(=:erp)`, and `label(=:label)`. -If `data` is a `Matrix`, it is automatically cast to a dataframe, time-bins are then in samples, labels are `string.(1:size(data,1))` -` -Δbin in `:time`-units, specifise the time-steps. -All other keyword arguments are forwarded to the EEG_TopoPlot (eeg_toplot) recipe. In most cases user should provide the electrode positions via -`positions=pos`. -`col` and `row` specify the field to split by columns and rows. By default `col=:time`, to split by the time field and `row=nothing`. Useful -to split by a condition e.g. `...(...,col=:time, row=:condition)` would result in multiple (as many as different values in df.condition) rows of topoplot series -`figure` allows to include information for the figure generation. Alternatively you can provide a fig object `eeg_topoplot_series!(fig,data::DataFrame,Δbin; kwargs..)` - `row_labels` and `col_labels` indicate whether there should be labels in the the plots in the first column indicating the row-value and in the last row to indicate the time (typically timerange) - -# Examples -Desc -```julia-repl -julia> df = DataFrame(:erp=>repeat(1:63,100),:time=>repeat(1:20,5*63),:label=>repeat(1:63,100)) # fake data -julia> pos = [(1:63)./63 .* (sin.(range(-2*pi,2*pi,63))) (1:63)./63 .* cos.(range(-2*pi,2*pi,63))].*0.5 .+0.5 # fake electrode positions -julia> pos = [Point2.(pos[k,1],pos[k,2]) for k in 1:size(pos,1)] -julia> eeg_topoplot_series(df,5; positions=pos) -``` -""" -function eeg_topoplot_series(data::DataFrame, Δbin; figure=NamedTuple(), kwargs...) - return eeg_topoplot_series!(Figure(; figure...), data, Δbin; kwargs...) -end -function eeg_topoplot_series(data::AbstractMatrix, Δbin; figure=NamedTuple(), kwargs...) - return eeg_topoplot_series!(Figure(; figure...), data, Δbin; kwargs...) -end -# allow to specify Δbin as an keyword for nicer readability -eeg_topoplot_series(data::DataFrame; Δbin, kwargs...) = eeg_topoplot_series(data, Δbin; kwargs...) -AbstractMatrix -function eeg_topoplot_series!(fig, data::AbstractMatrix, Δbin; kwargs...) - return eeg_topoplot_series!(fig, data, string.(1:size(data, 1)), Δbin; kwargs...) -end - -# convert a 2D Matrix to the dataframe -function eeg_topoplot_series(data::AbstractMatrix, labels, Δbin; kwargs...) - return eeg_topoplot_series(eeg_matrix_to_dataframe(data, labels), Δbin; kwargs...) -end -function eeg_topoplot_series!(fig, data::AbstractMatrix, labels, Δbin; kwargs...) - return eeg_topoplot_series!(fig, eeg_matrix_to_dataframe(data, labels), Δbin; kwargs...) -end - -""" -eeg_topoplot_series!(fig,data::DataFrame,Δbin; kwargs..) -In place plotting of topoplot series -see eeg_topoplot_series(data,Δbin) for help -""" -function eeg_topoplot_series!(fig, data::DataFrame, - Δbin; - y=:erp, - label=:label, - col=:time, - row=nothing, - combinefun=mean, - col_labels = false, - row_labels = false, - rasterize_heatmap = true, - topoplot_attributes...) - - # cannot be made easier right now, but Simon promised a simpler solution "soonish" - axisOptions = (aspect=1, xgridvisible=false, xminorgridvisible=false, xminorticksvisible=false, - xticksvisible=false, xticklabelsvisible=false, xlabelvisible=false, ygridvisible=false, - yminorgridvisible=false, yminorticksvisible=false, yticksvisible=false, - yticklabelsvisible=false, ylabelvisible=false, - leftspinevisible=false, rightspinevisible=false, topspinevisible=false, - bottomspinevisible=false, limits=((-0.25, 1.25), (-0.25, 1.25))) - - # aggregate the data over time-bins - data_mean = df_timebin(data, Δbin; - col_y=y, - fun=combinefun, - grouping=[label, col, row]) - - # using same colormap + contour levels for all plots - (q_min, q_max) = Statistics.quantile(data_mean[:, y], [0.001, 0.999]) - # make them symmetrical - q_min = q_max = max(abs(q_min), abs(q_max)) - q_min = -q_min - - topoplot_attributes = merge((colorrange=(q_min, q_max), contours=(levels=range(q_min, q_max; length=7),)), - topoplot_attributes) - - # do the col/row plot - - select_col = isnothing(col) ? 1 : unique(data_mean[:, col]) - select_row = isnothing(row) ? 1 : unique(data_mean[:, row]) - - for r in 1:length(select_row) - for c in 1:length(select_col) - ax = Axis(fig[r, c]; axisOptions...) - # select one topoplot - sel = 1 .== ones(size(data_mean, 1)) # select all - if !isnothing(col) - sel = sel .&& (data_mean[:, col] .== select_col[c]) # subselect - end - if !isnothing(row) - sel = sel .&& (data_mean[:, row] .== select_row[r]) # subselect - end - df_single = data_mean[sel, :] - - # select labels - labels = df_single[:, label] - # select data - d_vec = df_single[:, y] - # plot it - ax2 = eeg_topoplot!(ax, d_vec, labels; topoplot_attributes...) - - if rasterize_heatmap - ax2.plots[1].plots[1].rasterize = true - end - if r == length(select_row) && col_labels - ax.xlabel = string(df_single.time[1]) - ax.xlabelvisible = true - end - if c == 1 && length(select_row)>1 && row_labels - #@show df_single - ax.ylabel = string(df_single.row[1]) - ax.ylabelvisible = true - end - end - end - colgap!(fig.layout, 0) - - return fig -end - -""" -function df_timebin(df,Δbin;col_y=:erp,fun=mean,grouping=[]) -Split/Combine dataframe according to equally spaced time-bins -- `df` AbstractTable with columns `:time` and `col_y` (default `:erp`), and all columns in `grouping` -- `Δbin` bin-size in `:time`-units -- `col_y` default :erp, the column to combine (using `fun`) over -- `fun` function to combine, default is `mean` -- `grouping` (vector of symbols/strings) default empty vector, columns to group the data by, before aggregating. Values of `nothing` are ignored -""" -function df_timebin(df, Δbin; col_y=:erp, fun=mean, grouping=[]) - tmin = minimum(df.time) - tmax = maximum(df.time) - - bins = range(; start=tmin, step=Δbin, stop=tmax) - df = deepcopy(df) # cut seems to change stuff inplace - df.time = cut(df.time, bins; extend=true) - - grouping = grouping[.!isnothing.(grouping)] - - df_m = combine(groupby(df, unique([:time, grouping...])), col_y => fun) - #df_m = combine(groupby(df,Not(y)),y=>fun) - rename!(df_m, names(df_m)[end] => col_y) # remove the _fun part of the new column - return df_m -end \ No newline at end of file diff --git a/src/eeg_series.jl b/src/eeg_series.jl index 5df957b70..ae0691d8e 100644 --- a/src/eeg_series.jl +++ b/src/eeg_series.jl @@ -166,7 +166,9 @@ function eeg_topoplot_series!( push!(axlist, ax) end end - colgap!(fig.layout, 0) + if typeof(fig) != GridLayout + colgap!(fig.layout, 0) + end return fig, axlist end diff --git a/src/plot_circulareegtopoplot.jl b/src/plot_circulareegtopoplot.jl index 69505976a..c3291f899 100644 --- a/src/plot_circulareegtopoplot.jl +++ b/src/plot_circulareegtopoplot.jl @@ -1,11 +1,11 @@ """ - plot_circulareegtopoplot(plotData::DataFrame;kwargs...) - plot_circulareegtopoplot!(figlike, plotData::DataFrame;kwargs...) + plot_circulareegtopoplot(plotData::DataFrame; kwargs...) + plot_circulareegtopoplot!(figlike, plotData::DataFrame; kwargs...) Plot a circular EEG topoplot. ## Arguments: -- `figlike::Union{GridPosition, Figure}`: Figure or GridPosition that the plot should be drawn into +- `figlike::Union{GridPosition, GridLayout, Figure}`: Figure or GridPosition that the plot should be drawn into - `plotData::DataFrame`: Dataframe with keys for data (looks for `:y,:yhat, :estimate`, and :position (looks for `:pos, :positions, :position`), - `predictor` (optional; default :predictor) the circular predictor value, defines position of topoplot, is mapped around `predictorBounds` - `predictorBounds`: Default: `[0,360]` - The bounds of the predictor. This is relevant for the axis labels. @@ -29,7 +29,7 @@ plot_circulareegtopoplot(plotData::DataFrame; kwargs...) = plot_circulareegtopoplot!(f, plotData::DataFrame; kwargs...) = plot_circulareegtopoplot!(f, plotData; kwargs...) function plot_circulareegtopoplot!( - f::Union{GridPosition,Figure}, + f::Union{GridPosition,GridLayout,Figure}, plotData::DataFrame; predictor = :predictor, positions = nothing, diff --git a/src/plot_designmatrix.jl b/src/plot_designmatrix.jl index 8f7e19fbe..ed0ff3805 100644 --- a/src/plot_designmatrix.jl +++ b/src/plot_designmatrix.jl @@ -1,9 +1,11 @@ """ - plot_designmatrix(plotData::Unfold.DesignMatrix;kwargs...) + plot_designmatrix!(f::Union{GridPosition, GridLayout, Figure}, plotData::Unfold.DesignMatrix; kwargs...) + plot_designmatrix(plotData::Unfold.DesignMatrix; kwargs...) Plot a designmatrix. ## Arguments: +- `f::Union{GridPosition, GridLayout, Figure}`: Figure or GridPosition (e.g. f[2, 3]) that the plot should be drawn into. New axis is created. - `plotData::Unfold.DesignMatrix`: Data for the plot visualization. ## kwargs @@ -27,7 +29,7 @@ A figure displaying the designmatrix. plot_designmatrix(plotData::Unfold.DesignMatrix; kwargs...) = plot_designmatrix!(Figure(), plotData; kwargs...) function plot_designmatrix!( - f::Union{GridPosition,Figure}, + f::Union{GridPosition,GridLayout,Figure}, plotData::Unfold.DesignMatrix; xTicks = nothing, sortData = false, diff --git a/src/plot_erp.jl b/src/plot_erp.jl index 9d6d96389..a249e6e74 100644 --- a/src/plot_erp.jl +++ b/src/plot_erp.jl @@ -2,14 +2,14 @@ using DataFrames using TopoPlots using LinearAlgebra """ - plot_erp!(f::Union{GridPosition, Figure}, plotData::DataFrame; kwargs...) + plot_erp!(f::Union{GridPosition, GridLayout, Figure}, plotData::DataFrame; kwargs...) plot_erp(plotData::DataFrame; kwargs...) Plot an ERP plot. ## Arguments: -- `f::Union{GridPosition, Figure}`: Figure or GridPosition that the plot should be drawn into +- `f::Union{GridPosition, GridLayout, Figure}`: Figure or GridPosition that the plot should be drawn into - `plotData::DataFrame`: Data for the line plot visualization. - `kwargs...`: Additional styling behavior. Often used: `plot_erp(df; mapping=(; color=:coefname, col=:conditionA))` @@ -47,23 +47,26 @@ see also [`plot_erp`](@Ref) plot_butterfly(plotData::DataFrame; kwargs...) = plot_butterfly!(Figure(), plotData; kwargs...) -plot_butterfly!(f::Union{GridPosition,<:Figure}, plotData::DataFrame; kwargs...) = - plot_erp!( - f, - plotData; - butterfly = true, - topoLegend = true, - topomarkersize = 10, - topowidth = 0.25, - topoheigth = 0.25, - topoPositionToColorFunction = x -> posToColorRomaO(x), - kwargs..., - ) +plot_butterfly!( + f::Union{GridPosition,GridLayout,<:Figure}, + plotData::DataFrame; + kwargs..., +) = plot_erp!( + f, + plotData; + butterfly = true, + topoLegend = true, + topomarkersize = 10, + topowidth = 0.25, + topoheigth = 0.25, + topoPositionToColorFunction = x -> posToColorRomaO(x), + kwargs..., +) function plot_erp!( - f::Union{GridPosition,Figure}, + f::Union{GridPosition,GridLayout,Figure}, plotData::DataFrame; positions = nothing, labels = nothing, @@ -86,7 +89,6 @@ function plot_erp!( config_kwargs!(config; kwargs...) end - plotData = deepcopy(plotData) # XXX why? # resolve columns with data @@ -184,7 +186,12 @@ function plot_erp!( valign = 0.95, aspect = 1, ) - topoplotLegend(topoAxis, topomarkersize, topoPositionToColorFunction, allPositions) + topoplotLegend( + topoAxis, + topomarkersize, + topoPositionToColorFunction, + allPositions, + ) end # no extra legend mainAxis = Axis(f_grid; config.axis...) @@ -203,8 +210,6 @@ function plot_erp!( end applyLayoutSettings!(config; fig = f, ax = drawing, drawing = drawing)#, drawing = drawing) - - return f end @@ -215,22 +220,10 @@ function eegHeadMatrix(positions, center, radius) oldRadius, _ = findmax(x -> norm(x .- oldCenter), positions) radF = radius / oldRadius return Makie.Mat4f( - radF, - 0, - 0, - 0, - 0, - radF, - 0, - 0, - 0, - 0, - 1, - 0, + radF, 0, 0, 0, 0, + radF, 0, 0, 0, 0, 1, 0, center[1] - oldCenter[1] * radF, - center[2] - oldCenter[2] * radF, - 0, - 1, + center[2] - oldCenter[2] * radF, 0, 1, ) end diff --git a/src/plot_erpgrid.jl b/src/plot_erpgrid.jl index 3e18e6458..de5dbd696 100644 --- a/src/plot_erpgrid.jl +++ b/src/plot_erpgrid.jl @@ -1,10 +1,10 @@ """ - function plot_erpgrid!(f::Union{GridPosition, Figure}, data::Matrix{<:Real}, pos::Vector{Point{2,Float}}; kwargs...) + function plot_erpgrid!(f::Union{GridPosition, GridLayout, 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; +- `f::Union{GridPosition, GridLayout, 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. @@ -21,7 +21,7 @@ plot_erpgrid(plotData::Matrix{<:Real}, pos; kwargs...) = plot_erpgrid!(Figure(), plotData, pos; kwargs...) function plot_erpgrid!( - f::Union{GridPosition,Figure}, + f::Union{GridPosition,GridLayout,Figure}, plotData::Matrix{<:Real}, pos; drawLabels = false, @@ -29,7 +29,6 @@ function plot_erpgrid!( 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]...) diff --git a/src/plot_erpimage.jl b/src/plot_erpimage.jl index 2790cc222..dcfca82c8 100644 --- a/src/plot_erpimage.jl +++ b/src/plot_erpimage.jl @@ -2,12 +2,12 @@ """ - plot_erpimage!(f::Union{GridPosition, Figure}, data::Matrix{Float64}; kwargs...) + plot_erpimage!(f::Union{GridPosition, GridLayout, Figure}, data::Matrix{Float64}; kwargs...) plot_erpimage(data::Matrix{Float64}; kwargs...) Plot an ERP image. ## Arguments: -- `f::Union{GridPosition, Figure}`: Figure or GridPosition that the plot should be drawn into +- `f::Union{GridPosition, GridLayout, Figure}`: Figure or GridPosition that the plot should be drawn into - `plotData::Matrix{Float64}`: Data for the plot visualization ## Keyword Arguments @@ -30,7 +30,7 @@ plot_erpimage(plotData::Matrix{<:Real}; kwargs...) = plot_erpimage!(Figure(), plotData; kwargs...) # no times? -plot_erpimage!(f::Union{GridPosition,Figure}, plotData::Matrix{<:Real}; kwargs...) = +plot_erpimage!(f::Union{GridPosition,GridLayout,Figure}, plotData::Matrix{<:Real}; kwargs...) = plot_erpimage!(f, 1:size(plotData, 1), plotData; kwargs...) @@ -39,7 +39,7 @@ plot_erpimage(times::AbstractVector, plotData::Matrix{<:Real}; kwargs...) = plot_erpimage!(Figure(), times, plotData; kwargs...) function plot_erpimage!( - f::Union{GridPosition,Figure}, + f::Union{GridPosition,GridLayout,Figure}, times::AbstractVector, plotData::Matrix{<:Real}; sortvalues = nothing, diff --git a/src/plot_parallelcoordinates.jl b/src/plot_parallelcoordinates.jl index 27e507d80..52aeaf815 100644 --- a/src/plot_parallelcoordinates.jl +++ b/src/plot_parallelcoordinates.jl @@ -1,28 +1,23 @@ """ - plot_parallelcoordinates!(f::Union{GridPosition, Figure}, plotData::DataFrame, config::PlotConfig; channels::Vector{Int64}) + plot_parallelcoordinates!(f::Union{GridPosition, GridLayout, Figure}, + plotData::DataFrame, config::PlotConfig; channels::Vector{Int64}) Plot a PCP (parallel coordinates plot). ## Arguments: -- `f::Union{GridPosition, Figure}`: Figure or GridPosition that the plot should be drawn into +- `f::Union{GridPosition, GridLayout, Figure}`: Figure or GridPosition that the plot should be drawn into - `plotData::DataFrame`: Data for the plot visualization. - `config::PlotConfig`: Instance of PlotConfig being applied to the visualization. - `channels::Vector{Int64}`: vector with all the channels representing an axis used in the PCP in given order. - PCP has problems with size changes of the view window. By adapting the padding, aspect ratio and tick label size in px for a new use case, the PCP can even be added into a Coordinated Multiple Views System -`pc_aspect_ratio` Default : `0.55` - -`pc_right_padding` Default : `15` - -`pc_left_padding` Default : `25` - -`pc_top_padding` Default : `26` - -`pc_bottom_padding` Default : `16` - -`pc_tick_label_size` Default : `14` +- `pc_aspect_ratio` Default : `0.55` +- `pc_right_padding` Default : `15` +- `pc_left_padding` Default : `25` +- `pc_top_padding` Default : `26` +- `pc_bottom_padding` Default : `16` +- `pc_tick_label_size` Default : `14` $(_docstring(:paracoord)) @@ -32,7 +27,7 @@ The input `f` plot_parallelcoordinates(plotData::DataFrame, channels::Vector{Int64}; kwargs...) = plot_parallelcoordinates!(Figure(), plotData, channels; kwargs...) function plot_parallelcoordinates!( - f::Union{GridPosition,Figure}, + f::Union{GridPosition,GridLayout,Figure}, plotData::DataFrame, channels::Vector{Int64}; pc_aspect_ratio = 0.55, diff --git a/src/plot_topoplot.jl b/src/plot_topoplot.jl index bbd1b4964..18b3b77e9 100644 --- a/src/plot_topoplot.jl +++ b/src/plot_topoplot.jl @@ -1,10 +1,10 @@ """ - plot_topoplot!(f::Union{GridPosition, Figure}, plotData, ; positions=nothing, labels=nothing,kwargs...) - plot_topoplot(plotData,; positions=nothing, labels=nothing,kwargs...) + plot_topoplot!(f::Union{GridPosition, GridLayout, Figure}, plotData, ; positions=nothing, labels=nothing,kwargs...) + plot_topoplot(plotData,; positions=nothing, labels=nothing, kwargs...) Plot a topo plot. ## Arguments: -- `f::Union{GridPosition, Figure}`: Figure or GridPosition (e.g. f[2, 3]) that the plot should be drawn into. New axis is created. +- `f::Union{GridPosition, GridLayout, Figure}`: Figure or GridPosition (e.g. f[2, 3]) that the plot should be drawn into. New axis is created. - `plotData::Union{DataFrame, Vector{Float32}}`: Data for the plot visualization. - `positions::Vector{Point{2, Float32}}=nothing`: positions used if `plotData` is no DataFrame. If this is the case and `positions=nothing` then positions is generated from `labels`. - `labels::Vector{String}=nothing`: labels used if `plotData` is no DataFrame. @@ -19,7 +19,7 @@ A figure displaying the topo plot. plot_topoplot(plotData::Union{DataFrame,Vector{Float32}}; kwargs...) = plot_topoplot!(Figure(), plotData; kwargs...) function plot_topoplot!( - f::Union{GridPosition,Figure}, + f::Union{GridPosition,GridLayout,Figure}, plotData::Union{DataFrame,<:AbstractVector}; positions = nothing, labels = nothing, diff --git a/src/plot_topoplotseries.jl b/src/plot_topoplotseries.jl index 93dcb108e..6248525da 100644 --- a/src/plot_topoplotseries.jl +++ b/src/plot_topoplotseries.jl @@ -1,6 +1,6 @@ """ - plot_topoplotseries!(f::Union{GridPosition, Figure}, plotData::DataFrame,Δbin::Real;kwargs...) - plot_topoplotseries!(plotData::DataFrame, Δbin::Real;kwargs...) + plot_topoplotseries!(f::Union{GridPosition, Figure}, plotData::DataFrame, Δbin::Real; kwargs...) + plot_topoplotseries!(plotData::DataFrame, Δbin::Real; kwargs...) Multiple miniature topoplots in regular distances @@ -25,7 +25,7 @@ plot_topoplotseries(plotData::DataFrame, Δbin::Real; kwargs...) = plot_topoplotseries!(Figure(), plotData, Δbin; kwargs...) function plot_topoplotseries!( - f::Union{GridPosition,Figure}, + f::Union{GridPosition,GridLayout,Figure}, plotData::DataFrame, Δbin; positions = nothing, diff --git a/src/plotconfig.jl b/src/plotconfig.jl index 5476e16d8..addf46d35 100644 --- a/src/plotconfig.jl +++ b/src/plotconfig.jl @@ -140,6 +140,12 @@ function PlotConfig(T::Val{:topoplotseries}) config_kwargs!( cfg, layout = (useColorbar = true,), + colorbar = (; + height = 300, # why even should i made it manually? + flipaxis = true, + labelrotation = 4.7, + label = "Voltage [µV]" + ), visual = (; label_text = false # true doesnt work again ), @@ -179,7 +185,8 @@ function PlotConfig(T::Val{:erp}) config_kwargs!( cfg; mapping = (; color = (:color, :coefname, nothing)), - layout = (; showLegend = true, hidespines = (:r, :t)), + layout = (; showLegend = true, hidespines = (:r, :t)), + legend = (; framevisible = false), ) return cfg @@ -189,7 +196,7 @@ function PlotConfig(T::Val{:erpimage}) config_kwargs!( cfg; layout = (; useColorbar = true), - colorbar = (; label = "Voltage [µV]"), + colorbar = (; label = "Voltage [µV]", labelrotation = 4.7), axis = (xlabel = "Time", ylabel = "Sorted trials"), visual = (; colormap = Reverse("RdBu")), ) diff --git a/test/test_all.jl b/test/test_all.jl index b7b6b7298..2e622a893 100644 --- a/test/test_all.jl +++ b/test/test_all.jl @@ -1,3 +1,109 @@ +@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, t=150) + plot_topoplotseries!(f[2, 2], d_topo, 0.1; positions=positions, layout = (; useColorbar=true)) + plot_erpgrid!(f[3, 1], data, pos) + + + 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)) + + 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" begin include("../docs/example_data.jl") d_topo, positions = example_data("TopoPlots.jl") diff --git a/test/test_butterfly.jl b/test/test_butterfly.jl index ec9f07701..1b786556e 100644 --- a/test/test_butterfly.jl +++ b/test/test_butterfly.jl @@ -5,7 +5,7 @@ plot_butterfly(data; positions = pos) end -@testset "markersize change" begin +@testset "topomarkersize change" begin include("../docs/example_data.jl") data, pos = example_data("TopoPlots.jl") plot_butterfly( diff --git a/test/test_dm.jl b/test/test_dm.jl index 516189ab1..c12bdfd15 100644 --- a/test/test_dm.jl +++ b/test/test_dm.jl @@ -1,11 +1,18 @@ +include("../docs/example_data.jl") +uf = example_data("UnfoldLinearModel") + @testset "basic" begin - include("../docs/example_data.jl") - uf = example_data("UnfoldLinearModel") plot_designmatrix(designmatrix(uf)) end @testset "sort data" begin - include("../docs/example_data.jl") - uf = example_data("UnfoldLinearModel") plot_designmatrix(designmatrix(uf); sortData = true) end + + +@testset "designmatrix plot in GridLayout" begin + f = Figure(resolution=(1200, 1400)) + ga = f[1, 1] = GridLayout() + plot_designmatrix!(ga, designmatrix(uf); sortData = true) + f +end diff --git a/test/test_erp.jl b/test/test_erp.jl index 8a8e53351..30273fcdc 100644 --- a/test/test_erp.jl +++ b/test/test_erp.jl @@ -46,3 +46,93 @@ end categoricalGroup = true, ) end + + +@testset "erp plot in GridLayout" begin + f = Figure(resolution=(1200, 1400)) + ga = f[1, 1] = GridLayout() + + include("../docs/example_data.jl") + uf = example_data("UnfoldLinearModel") + results = coeftable(uf) + + 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!(ga, results, extra=(; + categoricalColor=false, + categoricalGroup=false, + pvalue=pvals, + stderror=true)) + + f +end + + +@testset "erp plot with error bands" begin + data_erp, evts = UnfoldSim.predef_eeg(; noiselevel = 12, return_epoched = true) + data_erp = reshape(data_erp, (1, size(data_erp)...)) + f = @formula 0 ~ 1 + condition + continuous + se_solver = (x, y) -> Unfold.solver_default(x, y, stderror = true); + m = fit( + UnfoldModel, + Dict(Any => (f, 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(results; :stderror=>true) +end + +@testset "erp plot with error bands in GridLayout" begin + f = Figure(resolution=(1200, 1400)) + ga = f[1, 1] = GridLayout() + + 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) + + f +end + +@testset "erp plot with borderless legend" begin + f = Figure(resolution=(1200, 1400)) + ga = f[1, 1] = GridLayout() + + 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)) + + f +end + diff --git a/test/test_erpgrid.jl b/test/test_erpgrid.jl index af8503978..dc2f31d6c 100644 --- a/test/test_erpgrid.jl +++ b/test/test_erpgrid.jl @@ -15,3 +15,10 @@ end f = Figure() plot_erpgrid!(f[1, 1], data, pos) end + +@testset "erpgrid plot in GridLayout" begin + f = Figure(resolution=(1200, 1400)) + ga = f[1, 1] = GridLayout() + plot_erpgrid!(ga, data, pos) + f +end diff --git a/test/test_pcp.jl b/test/test_pcp.jl new file mode 100644 index 000000000..581e808e1 --- /dev/null +++ b/test/test_pcp.jl @@ -0,0 +1,18 @@ + +@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 + 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_plot_circulareegtopoplot.jl b/test/test_plot_circulareegtopoplot.jl index 08e31807c..71db684d2 100644 --- a/test/test_plot_circulareegtopoplot.jl +++ b/test/test_plot_circulareegtopoplot.jl @@ -9,7 +9,7 @@ ) - @test_throws ErrorException plot_circulareegtopoplot(testdf;positions=[Point(1.0,2.0), Point(1.0,2.0), Point(1.0,2.0)],) + @test_throws ErrorException plot_circulareegtopoplot(testdf; positions=[Point(1.0,2.0), Point(1.0,2.0), Point(1.0,2.0)],) end @testset "tooManyBoundsErr" begin @@ -46,3 +46,18 @@ end @test UnfoldMakie.calculateBBox([0, 0], [1000, 1000], -180, [-180, 180]) == BBox(750.0, 950.0, 400.0, 600.0) end +@testset "circularplot plot in GridLayout" begin + f = Figure(resolution=(1200, 1400)) + data, pos = TopoPlots.example_data(); + dat = data[:, 240, 1] + df = DataFrame( + :estimate => eachcol(Float64.(data[:, 100:40:300, 1])), + :circularVariable => [0, 50, 80, 120, 180, 210], + :time => 100:40:300, + ) + df = flatten(df, :estimate); + ga = f[1, 1] = GridLayout() + plot_circulareegtopoplot!(ga, df; positions = pos, + axis = (; label = "Time?!"), predictor = :time, predictorBounds = [80, 320],) + f +end