From 96f8d0b32c35955d5968ef3adf0d7faa901b4541 Mon Sep 17 00:00:00 2001 From: Vladimir Mikheev Date: Wed, 15 Nov 2023 13:42:09 +0000 Subject: [PATCH 01/18] circular topoplot --- docs/literate/tutorials/circTopo.jl | 10 ++-- docs/src/how_to/mult_vis_in_fig.md | 2 +- src/plot_circulareegtopoplot.jl | 80 +++++++++++++-------------- test/test_plot_circulareegtopoplot.jl | 6 +- 4 files changed, 49 insertions(+), 49 deletions(-) diff --git a/docs/literate/tutorials/circTopo.jl b/docs/literate/tutorials/circTopo.jl index 39ca91d3c..3f009663d 100644 --- a/docs/literate/tutorials/circTopo.jl +++ b/docs/literate/tutorials/circTopo.jl @@ -15,18 +15,18 @@ 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], + :circular_variable => [0, 50, 80, 120, 180, 210], :time => 100:40:300, ) df = flatten(df, :estimate); # # Our first plot! -# note how the plots are at the angles of circularVariable` +# note how the plots are at the angles of circular_variable` plot_circulareegtopoplot( df; positions = pos, - axis = (; label = "Sac Incoming"), - predictor = :circularVariable, + axis = (; label = "Incoming saccade"), + predictor = :circular_variable, ) @@ -37,6 +37,6 @@ plot_circulareegtopoplot( positions = pos, axis = (; label = "Time?!"), predictor = :time, - predictorBounds = [80, 320], + predictor_bounds = [80, 320], ) diff --git a/docs/src/how_to/mult_vis_in_fig.md b/docs/src/how_to/mult_vis_in_fig.md index b740d02df..9be617045 100644 --- a/docs/src/how_to/mult_vis_in_fig.md +++ b/docs/src/how_to/mult_vis_in_fig.md @@ -82,7 +82,7 @@ plot_parallelcoordinates!(f[3, 2:3], uf_5chan, [1, 2, 3, 4, 5]; mapping=(; color 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, predictorBounds=[-0.3, 0.5]) + positions=positions, predictor=:time, predictor_bounds=[-0.3, 0.5]) f ``` diff --git a/src/plot_circulareegtopoplot.jl b/src/plot_circulareegtopoplot.jl index c3291f899..5c5f66c6c 100644 --- a/src/plot_circulareegtopoplot.jl +++ b/src/plot_circulareegtopoplot.jl @@ -1,19 +1,19 @@ """ - plot_circulareegtopoplot(plotData::DataFrame; kwargs...) - plot_circulareegtopoplot!(figlike, plotData::DataFrame; kwargs...) + plot_circulareegtopoplot(data::DataFrame; kwargs...) + plot_circulareegtopoplot!(f, data::DataFrame; kwargs...) Plot a circular EEG topoplot. ## Arguments: -- `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. -- `centerlabel`: default "", the text in the center of the cricle -- `positions` (nothing) - positions for the [`plot_topoplot`](@Ref) -- `labels` (nothing) - labels for the [`plot_topoplot`](@Ref) +- `f::Union{GridPosition, GridLayout, Figure}`: Figure, GridLayout or GridPosition that the plot should be drawn into +- `data::DataFrame`: DataFrame with keys for data (looks for `:y, :yhat, :estimate`), and :position (looks for `:pos, :position, :positions`), +- `predictor` (optional; default :predictor): the circular predictor value, defines position of topoplot, is mapped around `predictor_bounds` +- `predictor_bounds` (default: `[0,360]`): the bounds of the predictor. This is relevant for the axis labels. +- `positions` (default: nothing): positions for the [`plot_topoplot`](@Ref) +- `center_label` (default: ""): the text in the center of the cricle +- `labels` (default: nothing): labels for the [`plot_topoplot`](@Ref) -- `kwargs...`: Additional styling behavior, see below. +- `kwargs...`: additional styling behavior, see below. $(_docstring(:circeegtopo)) @@ -24,47 +24,47 @@ $(_docstring(:circeegtopo)) A figure containing the circular topoplot at given layout position """ -plot_circulareegtopoplot(plotData::DataFrame; kwargs...) = - plot_circulareegtopoplot!(Figure(), plotData; kwargs...) -plot_circulareegtopoplot!(f, plotData::DataFrame; kwargs...) = - plot_circulareegtopoplot!(f, plotData; kwargs...) +plot_circulareegtopoplot(data::DataFrame; kwargs...) = + plot_circulareegtopoplot!(Figure(), data; kwargs...) +plot_circulareegtopoplot!(f, data::DataFrame; kwargs...) = + plot_circulareegtopoplot!(f, data; kwargs...) function plot_circulareegtopoplot!( f::Union{GridPosition,GridLayout,Figure}, - plotData::DataFrame; + data::DataFrame; predictor = :predictor, + predictor_bounds = [0, 360], positions = nothing, labels = nothing, - centerlabel = "", - predictorBounds = [0, 360], + center_label = "", kwargs..., ) config = PlotConfig(:circeegtopo) config_kwargs!(config; kwargs...) - config.mapping = resolveMappings(plotData, config.mapping) + config.mapping = resolveMappings(data, config.mapping) positions = getTopoPositions(; positions = positions, labels = labels) # moving the values of the predictor to a different array to perform boolean queries on them - predictorValues = plotData[:, predictor] + predictorValues = data[:, predictor] - if (length(predictorBounds) != 2) - error("predictorBounds needs exactly two values") + if (length(predictor_bounds) != 2) + error("predictor_bounds needs exactly two values") end - if (predictorBounds[1] >= predictorBounds[2]) + if (predictor_bounds[1] >= predictor_bounds[2]) error( - "predictorBounds[1] needs to be smaller than predictorBounds[2]", + "predictor_bounds[1] needs to be smaller than predictor_bounds[2]", ) end if ( - (length(predictorValues[predictorValues.predictorBounds[2]]) != 0) + (length(predictorValues[predictorValues.predictor_bounds[2]]) != 0) ) error( - "all values in the plotData's effect column have to be within the predictorBounds range", + "all values in the data's effect column have to be within the predictor_bounds range", ) end if (all(predictorValues .<= 2 * pi)) - @warn "insert the predictor values in degrees instead of radian, or change predictorBounds" + @warn "insert the predictor values in degrees instead of radian, or change predictor_bounds" end ax = Axis(f[1, 1]; aspect = 1) @@ -72,17 +72,17 @@ function plot_circulareegtopoplot!( hidedecorations!(ax) hidespines!(ax) - plotCircularAxis!(ax, predictorBounds, centerlabel) + plotCircularAxis!(ax, predictor_bounds, center_label) limits!(ax, -3.5, 3.5, -3.5, 3.5) - min, max = calculateGlobalMaxValues(plotData[:, config.mapping.y], predictorValues) + min, max = calculateGlobalMaxValues(data[:, config.mapping.y], predictorValues) positions = getTopoPositions(; positions = positions, labels = labels) plotTopoPlots!( ax, - plotData[:, config.mapping.y], + data[:, config.mapping.y], positions, predictorValues, - predictorBounds, + predictor_bounds, min, max, ) @@ -104,10 +104,10 @@ function plot_circulareegtopoplot!( return f end -function calculateGlobalMaxValues(plotData, predictor) +function calculateGlobalMaxValues(data, predictor) x = combine( - groupby(DataFrame(:e => plotData, :p => predictor), :p), + groupby(DataFrame(:e => data, :p => predictor), :p), :e => (x -> maximum(abs.(quantile!(x, [0.01, 0.99])))) => :localMaxVal, ) @@ -116,7 +116,7 @@ function calculateGlobalMaxValues(plotData, predictor) return (-globalMaxVal, globalMaxVal) end -function plotCircularAxis!(ax, predictorBounds, label) +function plotCircularAxis!(ax, predictor_bounds, label) # the axis position is always the middle of the # screen (means it uses the GridLayout's full size) #circleAxis = Axis(f,aspect = 1)#typeof(f) == Figure ? Axis(f[1:f.layout.size[1],1:f.layout.size[2]], aspect = 1, backgroundcolor = bgcolor) : Axis(f[1,1], aspect = 1, backgroundcolor = bgcolor) @@ -148,7 +148,7 @@ function plotCircularAxis!(ax, predictorBounds, label) ) text!( circlepoints_labels, - text = calculateAxisLabels(predictorBounds), + text = calculateAxisLabels(predictor_bounds), align = (:center, :center), #textsize = round(minsize*0.03) ) @@ -157,12 +157,12 @@ function plotCircularAxis!(ax, predictorBounds, label) end # four labels around the circle, middle values are the 0.25, 0.5, and 0.75 quantiles -function calculateAxisLabels(predictorBounds) - nonboundlabels = quantile(predictorBounds, [0.25, 0.5, 0.75]) +function calculateAxisLabels(predictor_bounds) + nonboundlabels = quantile(predictor_bounds, [0.25, 0.5, 0.75]) # third label is on the left and it tends to cover the circle # so added some blank spaces to tackle that return [ - string(trunc(Int, predictorBounds[1])), + string(trunc(Int, predictor_bounds[1])), string(trunc(Int, nonboundlabels[1])), string(trunc(Int, nonboundlabels[2]), " "), string(trunc(Int, nonboundlabels[3])), @@ -174,7 +174,7 @@ function plotTopoPlots!( data, positions, predictorValues, - predictorBounds, + predictor_bounds, globalmin, globalmax, ) @@ -183,7 +183,7 @@ function plotTopoPlots!( gp = groupby(df, :p) for g in gp - bbox = calculateBBox([0, 0], [1, 1], g.p[1], predictorBounds) + bbox = calculateBBox([0, 0], [1, 1], g.p[1], predictor_bounds) # convet BBox to rect rect = ( diff --git a/test/test_plot_circulareegtopoplot.jl b/test/test_plot_circulareegtopoplot.jl index 1978a8474..203a35322 100644 --- a/test/test_plot_circulareegtopoplot.jl +++ b/test/test_plot_circulareegtopoplot.jl @@ -18,7 +18,7 @@ predictor = [70,80,90], ) - @test_throws ErrorException plot_circulareegtopoplot(testdf; predictorBounds=[0,100,360], positions = [Point(1.0,2.0), Point(1.0,2.0), Point(1.0,2.0)],) + @test_throws ErrorException plot_circulareegtopoplot(testdf; predictor_bounds=[0,100,360], positions = [Point(1.0,2.0), Point(1.0,2.0), Point(1.0,2.0)],) end end @@ -58,7 +58,7 @@ end df = flatten(df, :estimate); ga = f[1, 1] = GridLayout() plot_circulareegtopoplot!(ga, df; positions = pos, - axis = (; label = "Time?!"), predictor = :time, predictorBounds = [80, 320],) + axis = (; label = "Time?!"), predictor = :time, predictor_bounds = [80, 320],) f end @@ -66,6 +66,6 @@ end d_topo, positions = example_data("TopoPlots.jl") f = Figure(resolution=(2000, 2000)) plot_circulareegtopoplot!(f[3:4, 4:5], d_topo[in.(d_topo.time, Ref(-0.3:0.1:0.5)), :]; - positions=positions, predictor=:time, predictorBounds=[-0.3, 0.5]) + positions=positions, predictor=:time, predictor_bounds=[-0.3, 0.5]) f end \ No newline at end of file From bf6324ef14ee663fcf310a595df2898108815ed5 Mon Sep 17 00:00:00 2001 From: Vladimir Mikheev Date: Wed, 15 Nov 2023 14:16:54 +0000 Subject: [PATCH 02/18] design matrix --- docs/src/tutorials/designmatrix.md | 24 +++++------ src/plot_designmatrix.jl | 69 ++++++++++++++---------------- test/test_dm.jl | 4 +- 3 files changed, 46 insertions(+), 51 deletions(-) diff --git a/docs/src/tutorials/designmatrix.md b/docs/src/tutorials/designmatrix.md index 155741133..cabc46d63 100644 --- a/docs/src/tutorials/designmatrix.md +++ b/docs/src/tutorials/designmatrix.md @@ -1,6 +1,6 @@ # [Designmatrix Visualization](@id dm_vis) -Here we discuss designmatrix visualization. +Here we discuss design matrix visualization. Make sure you have looked into the [installation instructions](@ref install_instruct) section. ## Include used Modules @@ -31,20 +31,18 @@ plot_designmatrix(designmatrix(uf)) # kwargs `plot_designmatrix(...; ...)`. -- sortData (boolean,false) - Indicating whether the data is sorted; using sortslices() of Base Julia. +- `sort_data` (bool, `true`): indicates whether the data is sorted; using sortslices() of Base Julia. - -In order to make the designmatrix easier to read, you may want to sort it. +To make the design matrix easier to read, you may want to sort it. ``` plot_designmatrix(designmatrix(uf); sortData=true) ``` -- standardizeData (boolean, false) - Indicating whether the data is standardized, mapping the values between 0 and 1. -- xTicks (number, nothing) - -Indicating the number of labels on the x-axis. Behavior if specified in configuration: - - xTicks = 0: no labels are placed. - - xTicks = 1: first possible label is placed. - - xTicks = 2: first and last possible labels are placed. - - 2 < xTicks < number of labels: xTicks-2 labels are placed between the first and last. - - xTicks ≥ number of labels: all labels are placed. \ No newline at end of file +- `standardize_data` (bool,`true`): indicates whether the data is standardized by pointwise division of the data with its sampled standard deviation. +- `sort_data` (bool, `true`): indicates whether the data is sorted; using sortslices() of Base Julia. +- `xticks` (`nothing`): returns the number of labels on the x-axis. Behavior is set in the configuration: + - xticks = 0: no labels are placed. + - xticks = 1: first possible label is placed. + - xticks = 2: first and last possible labels are placed. + - 2 < xticks < `number of labels`: equally distribute the labels. + - xticks ≥ `number of labels`: all labels are placed. diff --git a/src/plot_designmatrix.jl b/src/plot_designmatrix.jl index ed0ff3805..a72fda643 100644 --- a/src/plot_designmatrix.jl +++ b/src/plot_designmatrix.jl @@ -1,73 +1,70 @@ """ - plot_designmatrix!(f::Union{GridPosition, GridLayout, Figure}, plotData::Unfold.DesignMatrix; kwargs...) - plot_designmatrix(plotData::Unfold.DesignMatrix; kwargs...) + plot_designmatrix!(f::Union{GridPosition, GridLayout, Figure}, data::Unfold.DesignMatrix; kwargs...) + plot_designmatrix(data::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. +- `f::Union{GridPosition, GridLayout, Figure}`: Figure or GridPosition (e.g. f[2, 3]) in which the plot will be placed into. A new axis is created. +- `data::Unfold.DesignMatrix`: data for the plot visualization. ## kwargs -- `standardizeData`: (bool,`true`) - Indicating whether the data is standardized by pointwise division of the data with its sampled standard deviation. -- `sortData`: (bool, `true`) - Indicating whether the data is sorted; using sortslices() of Base Julia. -- `xTicks`: (`nothing`) - -Indicating the number of labels on the x-axis. -Behavior if specified in configuration: -- xTicks = 0: no labels are placed. -- xTicks = 1: first possible label is placed. -- xTicks = 2: first and last possible labels are placed. -- 2 < xTicks < `number of labels`: Equally distribute the labels. -- xTicks ≥ `number of labels`: all labels are placed. +- `standardize_data` (bool,`true`): indicates whether the data is standardized by pointwise division of the data with its sampled standard deviation. +- `sort_data` (bool, `true`): indicates whether the data is sorted; using sortslices() of Base Julia. +- `xticks` (`nothing`): returns the number of labels on the x-axis. Behavior is set in the configuration: + - xticks = 0: no labels are placed. + - xticks = 1: first possible label is placed. + - xticks = 2: first and last possible labels are placed. + - 2 < xticks < `number of labels`: equally distribute the labels. + - xticks ≥ `number of labels`: all labels are placed. $(_docstring(:designmat)) ## Return Value: A figure displaying the designmatrix. """ -plot_designmatrix(plotData::Unfold.DesignMatrix; kwargs...) = - plot_designmatrix!(Figure(), plotData; kwargs...) +plot_designmatrix(data::Unfold.DesignMatrix; kwargs...) = + plot_designmatrix!(Figure(), data; kwargs...) function plot_designmatrix!( f::Union{GridPosition,GridLayout,Figure}, - plotData::Unfold.DesignMatrix; - xTicks = nothing, - sortData = false, - standardizeData = false, + data::Unfold.DesignMatrix; + xticks = nothing, + sort_data = false, + standardize_data = false, kwargs..., ) config = PlotConfig(:designmat) config_kwargs!(config; kwargs...) - designmat = Unfold.get_Xs(plotData) - if standardizeData + designmat = Unfold.get_Xs(data) + if standardize_data designmat = designmat ./ std(designmat, dims = 1) designmat[isinf.(designmat)] .= 1.0 end if isa(designmat, SparseMatrixCSC) - if sortData - @warn "Sorting does not make sense for timeexpanded designmatrices. sortData has been set to `false`" + if sort_data + @warn "Sorting does not make sense for time-expanded designmatrices. sort_data has been set to `false`" - sortData = false + sort_data = false end designmat = Matrix(designmat[end÷2-2000:end÷2+2000, :]) end - if sortData + if sort_data designmat = Base.sortslices(designmat, dims = 1) end - labels = Unfold.get_coefnames(plotData) + labels = Unfold.get_coefnames(data) lLength = length(labels) - # only change xTicks if we want less then all - if (xTicks !== nothing && xTicks < lLength) - @assert(xTicks >= 0, "xTicks shouldn't be negative") - # sections between xTicks - sectionSize = (lLength - 2) / (xTicks - 1) + # only change xticks if we want less then all + if (xticks !== nothing && xticks < lLength) + @assert(xticks >= 0, "xticks shouldn't be negative") + # sections between xticks + sectionSize = (lLength - 2) / (xticks - 1) newLabels = [] # first tick. Empty if 0 ticks - if xTicks >= 1 + if xticks >= 1 push!(newLabels, labels[1]) else push!(newLabels, "") @@ -76,7 +73,7 @@ function plot_designmatrix!( # fill in ticks in the middle for i = 1:(lLength-2) # checks if we're at the end of a section, but NO tick on the very last section - if i % sectionSize < 1 && i < ((xTicks - 1) * sectionSize) + if i % sectionSize < 1 && i < ((xticks - 1) * sectionSize) push!(newLabels, labels[i+1]) else push!(newLabels, "") @@ -84,7 +81,7 @@ function plot_designmatrix!( end # last tick at the end - if xTicks >= 2 + if xticks >= 2 push!(newLabels, labels[lLength-1]) else push!(newLabels, "") diff --git a/test/test_dm.jl b/test/test_dm.jl index c12bdfd15..d5c8340db 100644 --- a/test/test_dm.jl +++ b/test/test_dm.jl @@ -6,13 +6,13 @@ uf = example_data("UnfoldLinearModel") end @testset "sort data" begin - plot_designmatrix(designmatrix(uf); sortData = true) + plot_designmatrix(designmatrix(uf); sort_data = 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) + plot_designmatrix!(ga, designmatrix(uf); sort_data = true) f end From a8513c4365e517d3203099e10d591be15c58939f Mon Sep 17 00:00:00 2001 From: Vladimir Mikheev Date: Wed, 15 Nov 2023 15:20:06 +0000 Subject: [PATCH 03/18] erp and butterfly plots --- docs/literate/tutorials/erp.jl | 23 ++++++----- docs/src/how_to/mult_vis_in_fig.md | 8 ++-- docs/src/tutorials/butterfly.md | 24 +++++------- src/plot_erp.jl | 61 ++++++++++++++++-------------- 4 files changed, 57 insertions(+), 59 deletions(-) diff --git a/docs/literate/tutorials/erp.jl b/docs/literate/tutorials/erp.jl index 3077b7fcb..15b5f370f 100644 --- a/docs/literate/tutorials/erp.jl +++ b/docs/literate/tutorials/erp.jl @@ -1,6 +1,6 @@ # ## [Line Plot Visualization](@id lp_vis) -# Here we discuss line plot visualization. +# Here we discuss ERP plot visualization. # Make sure you have looked into the [installation instructions](@ref install_instruct). # ## Include used Modules @@ -15,7 +15,7 @@ using UnfoldSim using UnfoldMakie # ## Setup -# Let's generate some data and fit a model of a 2-level categorical and a continuous predictor with interaction. +# Let's generate some data. We'll fit a model with a 2 level categorical predictor and a continuous predictor with interaction. data, evts = UnfoldSim.predef_eeg(; noiselevel = 12, return_epoched = true) data = reshape(data, (1, size(data)...)) f = @formula 0 ~ 1 + condition + continuous @@ -40,7 +40,7 @@ plot_erp(results; :stderror => true,) # `plot_erp` use a `DataFrame` as an input, the library needs to know the names of the columns used for plotting. # There are multiple default values, that are checked in that order if they exist in the `DataFrame`, a custom name can be chosen using -# `plot_erp(...;mapping=(; :y=:myEstimate)` +# `plot_erp(...; mapping=(; :y=:my_estimate)` # :x Default is `(:x, :time)`. # :y Default is `(:y, :estimate, :yhat)`. @@ -50,10 +50,11 @@ plot_erp(results; :stderror => true,) # ## key values # `plot_erp(...; =,...)`. -# - categoricalColor (boolean, true) - in case of numeric `:color` column, is color a continuous or categorical variable? -# - categoricalGroup (boolean, true) - in case of numeric `:group` column, treat `:group` as categorical variable by default -# - stderror (boolean, false) - add an error-ribbon based on the `:stderror` column -# - pvalue (see below) +# - categorical_color (boolean, true) - in case of numeric `:color` column, treat `:color` as continuous or categorical variable. +# - categorical_group (boolean, true) - in case of numeric `:group` column, treat `:group` as categorical variable by default. +# - `topolegend` (bool, `false`): add an inlay topoplot with corresponding electrodes. +# - `stderror` (bool, `false`): add an error ribbon, with lower and upper limits based on the `:stderror` column. +# - `pvalue` (Array, `[]`): show a pvalue (see below). # Using some general configurations we can pretty up the default visualization. Here we use the following configuration: @@ -62,12 +63,10 @@ plot_erp( mapping = (; y = :yhat, color = :continuous, group = :continuous), legend = (; nbanks = 2), layout = (; showLegend = true, legendPosition = :right), - categoricalColor = false, categoricalGroup = true, + categorical_color = false, categorical_group = true, ) - - # In the following we will use this "pretty" line plot as a basis for looking into configuration options. # ## pvalue (array) @@ -77,11 +76,11 @@ plot_erp( # # Is an array of p-values. If array not empty, plot shows colored lines under the plot representing the p-values. # Default is `[]` (an empty array). -# Shown below is an example in which `pvalue` are given: +# Below is an example in which `pvalue` are given: # pvals = DataFrame( # from=[0.1,0.3], # to=[0.5,0.7], -# coefname=["(Intercept)","condition: face"] # if coefname not specified, line should be black +# coefname=["(Intercept)", "condition: face"] # if coefname not specified, line should be black # ) # # plot_erp(results; :pvalue=>pvals) diff --git a/docs/src/how_to/mult_vis_in_fig.md b/docs/src/how_to/mult_vis_in_fig.md index 9be617045..1c67de6a8 100644 --- a/docs/src/how_to/mult_vis_in_fig.md +++ b/docs/src/how_to/mult_vis_in_fig.md @@ -26,7 +26,7 @@ This section discusses how users can incorporate multiple plots into a single fi By using the !-version of the plotting function and inserting a grid position instead of an entire figure, we can create multiple coordinated views. -We start by creating a figure with Makie.Figure. +We will start by creating a figure with Makie.Figure. `f = Figure()` @@ -60,8 +60,8 @@ pvals = DataFrame( coefname=["(Intercept)", "category: face"] ) plot_erp!(f[2, 1:2], results, - categoricalColor=false, - categoricalGroup=false, + categorical_color=false, + categorical_group=false, pvalue=pvals, stderror=true) @@ -73,7 +73,7 @@ plot_topoplotseries!(f[4, 1:3], d_topo, 0.1; positions=positions, mapping=(; lab res_effects = effects(Dict(:continuous => -5:0.5:5), uf_deconv) -plot_erp!(f[2, 4:5], res_effects; categoricalColor=false, categoricalGroup=true, +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)) diff --git a/docs/src/tutorials/butterfly.md b/docs/src/tutorials/butterfly.md index 435876bda..0bb090186 100644 --- a/docs/src/tutorials/butterfly.md +++ b/docs/src/tutorials/butterfly.md @@ -37,7 +37,7 @@ plot_butterfly(df; positions=pos) ## Column Mappings for Butterfly Plots -Since butterfly plots use a `DataFrame` as input, the library needs to know the names of the columns used for plotting. You can set these mapping values by calling `plot_butterfly(...; mapping=(; :x=:time,))`, that is, by specifying a `NamedTuple` (note the `;` right after the opening parentheses). +Since butterfly plots use a `DataFrame` as input, the library needs to know the names of the columns used for plotting. You can set these mapping values by calling `plot_butterfly(...; mapping=(; :x=:time))`, that is, by specifying a `NamedTuple` (note the `;` right after the opening parentheses). While there are several default values that will be checked in that order if they exist in the `DataFrame`, a custom name may need to be chosen: @@ -54,21 +54,17 @@ Default is `(:labels, :label, :topoLabels, :sensor, :nothing)` ## Configurations for Butterfly Plots - Here we look into possible options for configuring the butterfly plot visualization using `(...; =, ...)`. -This is the list of unique configuration (key values): - - -- topoLegend (boolean) - -### topoLegend (boolean) -Indicating whether the topo legend is displayed. -Default is `true`. - -For more general options look into the `Plot Configuration` section of the documentation. +## key values +- `butterfly` (bool, `true`): create a butterfly plot. +- `topolegend` (bool, `true`): show an inlay topoplot with corresponding electrodes. +- `topomarkersize` (Real, `10`): change the size of the markers, topoplot-inlay electrodes. +- `topowidth` (Real, `0.25`): change the size of the inlay topoplot width. +- `topoheigth` (Real, `0.25`): change the size of the inlay topoplot height. +- `topopositions_to_color` (function, ´x -> posToColorRomaO(x)´). -Since the configurations for line plots can be applied to butterfly plots as well. -[Here](@ref lp_vis) you can find the configurations for line plots, +Since the configurations for ERP plots can be applied to butterfly plots as well. +[Here](@ref lp_vis) you can find the configurations for ERP plots. diff --git a/src/plot_erp.jl b/src/plot_erp.jl index a249e6e74..8067f93c8 100644 --- a/src/plot_erp.jl +++ b/src/plot_erp.jl @@ -9,17 +9,18 @@ Plot an ERP plot. ## Arguments: -- `f::Union{GridPosition, GridLayout, Figure}`: Figure or GridPosition that the plot should be drawn into +- `f::Union{GridPosition, GridLayout, Figure}`: Figure, GridLayout 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))` +- `kwargs...`: Additional styling behavior. Often used: `plot_erp(df; mapping=(; color=:coefname, col=:conditionA))`. ## kwargs (...; ...): -- `categoricalColor` (bool, `true`) - Indicates whether the column referenced in mapping.color should be used nonnumerically. -- `categoricalGroup` (bool, `true`) - Indicates whether the column referenced in mapping.group should be used nonnumerically. -- `topoLegend` (bool, `false`) - Indicating whether a topo plot is used as a legend. -- `stderror` (bool, `false`) - Indicating whether the plot should show a colored band showing lower and higher estimates based on the stderror. -- `pvalue` (Array, `[]`) - example: `DataFrame(from=[0.1,0.3], to=[0.5,0.7], coefname=["(Intercept)", "condition:face"])` - if coefname not specified, the lines will be black +- `categorical_color` (bool, `true`): in case of numeric `:color` column, treat `:color` as continuous or categorical variable. +- `categorical_group` (bool, `true`): in case of numeric `:group` column, treat `:group` as categorical variable by default. +- `topolegend` (bool, `false`): add an inlay topoplot with corresponding electrodes. +- `stderror` (bool, `false`): add an error ribbon, with lower and upper limits based on the `:stderror` column. +- `pvalue` (Array, `[]`): show a pvalue. + - example: `DataFrame(from=[0.1, 0.3], to=[0.5, 0.7], coefname=["(Intercept)", "condition:face"])` - if coefname is not specified, the lines will be black $(_docstring(:erp)) @@ -32,16 +33,18 @@ $(_docstring(:erp)) plot_erp(plotData::DataFrame; kwargs...) = plot_erp!(Figure(), plotData, ; kwargs...) """ -Plot Butterfly +Plot a butterfly plot -$(_docstring(:butterfly)) - -## key-word arguments +## kwargs (...; ...): -- `topomarkersize` (Real, `10`) - change the size of the markers, topoplot-inlay electrodes -- `topowidth` (Real, `0.25`) - change the size of the inlay topoplot width -- `topoheigth` (Real, `0.25`) - change the size of the inlay topoplot height +- `butterfly` (bool, `true`): create a butterfly plot. +- `topolegend` (bool, `true`): show an inlay topoplot with corresponding electrodes. +- `topomarkersize` (Real, `10`): change the size of the markers, topoplot-inlay electrodes. +- `topowidth` (Real, `0.25`): change the size of the inlay topoplot width. +- `topoheigth` (Real, `0.25`): change the size of the inlay topoplot height. +- `topopositions_to_color` (function, ´x -> posToColorRomaO(x)´). +$(_docstring(:butterfly)) see also [`plot_erp`](@Ref) """ plot_butterfly(plotData::DataFrame; kwargs...) = @@ -55,11 +58,11 @@ plot_butterfly!( f, plotData; butterfly = true, - topoLegend = true, + topolegend = true, topomarkersize = 10, topowidth = 0.25, topoheigth = 0.25, - topoPositionToColorFunction = x -> posToColorRomaO(x), + topopositions_to_color = x -> posToColorRomaO(x), kwargs..., ) @@ -70,16 +73,16 @@ function plot_erp!( plotData::DataFrame; positions = nothing, labels = nothing, - categoricalColor = true, - categoricalGroup = true, + categorical_color = true, + categorical_group = true, stderror = false, # XXX if it exists, should be plotted pvalue = [], butterfly = false, - topoLegend = nothing, + topolegend = nothing, topomarkersize = nothing, topowidth = nothing, topoheigth = nothing, - topoPositionToColorFunction = nothing, + topopositions_to_color = nothing, kwargs..., ) config = PlotConfig(:erp) @@ -117,26 +120,26 @@ function plot_erp!( # Get topocolors for butterfly if (butterfly) if isnothing(positions) && isnothing(labels) - topoLegend = false + topolegend = false #colors = config.visual.colormap# get(colorschemes[config.visual.colormap],range(0,1,length=nrow(plotData))) colors = nothing #config.mapping = merge(config.mapping,(;color=config.)) else allPositions = getTopoPositions(; positions = positions, labels = labels) - colors = getTopoColor(allPositions, topoPositionToColorFunction) + colors = getTopoColor(allPositions, topopositions_to_color) end end # Categorical mapping # convert color column into string, so no wrong grouping happens - if categoricalColor && (:color ∈ keys(config.mapping)) + if categorical_color && (:color ∈ keys(config.mapping)) config.mapping = merge(config.mapping, (; color = config.mapping.color => nonnumeric)) end # converts group column into string - if categoricalGroup && (:group ∈ keys(config.mapping)) + if categorical_group && (:group ∈ keys(config.mapping)) config.mapping = merge(config.mapping, (; group = config.mapping.group => nonnumeric)) end @@ -175,9 +178,9 @@ function plot_erp!( f_grid = f[1, 1] # butterfly plot is drawn slightly different if butterfly - # add topoLegend + # add topolegend - if (topoLegend) + if (topolegend) topoAxis = Axis( f_grid, width = Relative(topowidth), @@ -189,7 +192,7 @@ function plot_erp!( topoplotLegend( topoAxis, topomarkersize, - topoPositionToColorFunction, + topopositions_to_color, allPositions, ) end @@ -227,14 +230,14 @@ function eegHeadMatrix(positions, center, radius) ) end -function topoplotLegend(axis, topomarkersize, topoPositionToColorFunction, allPositions) +function topoplotLegend(axis, topomarkersize, topopositions_to_color, allPositions) allPositions = unique(allPositions) topoMatrix = eegHeadMatrix(allPositions, (0.5, 0.5), 0.5) # colorscheme where first entry is 0, and exactly length(positions)+1 entries specialColors = ColorScheme( - vcat(RGB(1, 1, 1.0), [topoPositionToColorFunction(pos) for pos in allPositions]...), + vcat(RGB(1, 1, 1.0), [topopositions_to_color(pos) for pos in allPositions]...), ) xlims!(low = -0.2, high = 1.2) From f654b9554b48dfd2cf3d85330bb2796905a9600f Mon Sep 17 00:00:00 2001 From: Vladimir Mikheev Date: Wed, 15 Nov 2023 15:27:23 +0000 Subject: [PATCH 04/18] erp plot 2 --- src/plot_erp.jl | 12 ++++++------ test/test_erp.jl | 12 ++++++------ 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/plot_erp.jl b/src/plot_erp.jl index 8067f93c8..d6053a87c 100644 --- a/src/plot_erp.jl +++ b/src/plot_erp.jl @@ -260,15 +260,15 @@ function topoplotLegend(axis, topomarkersize, topopositions_to_color, allPositio return topoplot end -function addPvalues(plotData, pvalue, config) +function addPvalues(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(plotData) - p[!, :group] .= plotData[1, :group] - if length(unique(plotData.group)) > 1 + if "group" ∈ names(data) + p[!, :group] .= data[1, :group] + if length(unique(data.group)) > 1 @warn "multiple groups found, choosing first one" end else @@ -285,10 +285,10 @@ function addPvalues(plotData, pvalue, config) end # define an index to dodge the lines vertically - scaleY = [minimum(plotData.estimate), maximum(plotData.estimate)] + scaleY = [minimum(data.estimate), maximum(data.estimate)] stepY = scaleY[2] - scaleY[1] posY = stepY * -0.05 + scaleY[1] - Δt = diff(plotData.time[1:2])[1] + Δt = diff(data.time[1:2])[1] Δy = 0.01 p[!, :segments] = [ Makie.Rect( diff --git a/test/test_erp.jl b/test/test_erp.jl index 30273fcdc..fab357b52 100644 --- a/test/test_erp.jl +++ b/test/test_erp.jl @@ -42,8 +42,8 @@ end legend = (; nbanks = 2), layout = (; legendPosition = :right), showLegend = true, - categoricalColor = false, - categoricalGroup = true, + categorical_color = false, + categorical_group = true, ) end @@ -62,11 +62,11 @@ end # if coefname not specified, line should be black coefname=["(Intercept)", "category: face"] ) - plot_erp!(ga, results, extra=(; - categoricalColor=false, - categoricalGroup=false, + plot_erp!(ga, results; + categorical_color=false, + categorical_group=false, pvalue=pvals, - stderror=true)) + stderror=true) f end From 8cccc0297d8836c16038acb24650c516173051d0 Mon Sep 17 00:00:00 2001 From: Vladimir Mikheev Date: Wed, 15 Nov 2023 15:36:00 +0000 Subject: [PATCH 05/18] a bit --- test/runtests.jl | 4 ++-- test/test_all.jl | 51 +++++++++++++++++++++--------------------------- 2 files changed, 24 insertions(+), 31 deletions(-) diff --git a/test/runtests.jl b/test/runtests.jl index 73726b65c..8ce7e7ba4 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -10,7 +10,7 @@ end include("test_plot_circulareegtopoplot.jl") end -@testset "TopoSeries" begin +@testset "Topoplot series" begin include("test_toposeries.jl") end @@ -26,6 +26,6 @@ end include("test_butterfly.jl") end -@testset "All plots" begin +@testset "Combined plots" begin include("test_all.jl") end \ No newline at end of file diff --git a/test/test_all.jl b/test/test_all.jl index 42e5637f0..dea892b61 100644 --- a/test/test_all.jl +++ b/test/test_all.jl @@ -81,16 +81,15 @@ end 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_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)) + 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]]) @@ -104,7 +103,7 @@ end end -@testset "testing combined figure" begin +@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") @@ -112,6 +111,8 @@ end 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)) @@ -123,39 +124,31 @@ end # if coefname not specified, line should be black coefname=["(Intercept)", "category: face"] ) - plot_erp!(f[2, 1:2], results, extra=(; + plot_erp!(f[2, 1:2], results, categoricalColor=false, categoricalGroup=false, pvalue=pvals, - stderror=true)) - - + stderror=true) + + plot_designmatrix!(f[2, 3], designmatrix(uf)) - - plot_topoplot!(f[3, 1], collect(1:64); positions=positions, visual=(; colormap=:viridis)) - plot_topoplotseries!(f[4, 1:3], d_topo, 0.1; positions=positions, layout = (; useColorbar=true)) - + + 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; + + plot_erp!(f[2, 4:5], res_effects; categoricalColor=false, categoricalGroup=true, mapping=(; y=:yhat, color=:continuous, group=:continuous), - extra=(; showLegend=true, - categoricalColor=false, - categoricalGroup=true), legend=(; nbanks=2), - layout=(; legendPosition=:right)) - - - + layout=(; showLegend=true, legendPosition=:right)) + plot_parallelcoordinates!(f[3, 2:3], uf_5chan, [1, 2, 3, 4, 5]; mapping=(; color=:coefname), layout=(; legendPosition=:bottom)) - - times = -0.099609375:0.001953125:1.0 + 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, predictorBounds=[-0.3, 0.5]) - + f #save("test.png", f) -end - +end \ No newline at end of file From aae270924f4cbf53f6d73d33f62da49a33bc9238 Mon Sep 17 00:00:00 2001 From: Vladimir Mikheev Date: Wed, 15 Nov 2023 15:45:27 +0000 Subject: [PATCH 06/18] erp grid --- src/plot_erpgrid.jl | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/src/plot_erpgrid.jl b/src/plot_erpgrid.jl index de5dbd696..06abdf879 100644 --- a/src/plot_erpgrid.jl +++ b/src/plot_erpgrid.jl @@ -4,32 +4,32 @@ Plot an ERP image. ## Arguments: -- `f::Union{GridPosition, GridLayout, Figure}`: Figure or GridPosition that the plot should be drawn into; -- `plotData::Matrix{<:Real}`: Data for the plot visualization; +- `f::Union{GridPosition, GridLayout, Figure}`: Figure or GridPosition that the plot should be drawn into. +- `data::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() +- `drawlabels` (bool, `false`): draw channels labels over each waveform. +- `times`: (Vector, `1:size(data, 2)`): vector of size(). ## Return Value: The input `f` """ # no figure? -plot_erpgrid(plotData::Matrix{<:Real}, pos; kwargs...) = - plot_erpgrid!(Figure(), plotData, pos; kwargs...) +plot_erpgrid(data::Matrix{<:Real}, pos; kwargs...) = + plot_erpgrid!(Figure(), data, pos; kwargs...) function plot_erpgrid!( f::Union{GridPosition,GridLayout,Figure}, - plotData::Matrix{<:Real}, + data::Matrix{<:Real}, pos; - drawLabels = false, - times = -1:size(plotData, 2)-2, #arbitrary strat just for fun + drawlabels = false, + times = -1:size(data, 2)-2, #arbitrary strat just for fun kwargs..., ) - chanNum = size(plotData, 1) - plotData = plotData[1:chanNum, :] + chanNum = size(data, 1) + data = data[1:chanNum, :] pos = hcat([[p[1], p[2]] for p in pos]...) pos = pos[:, 1:chanNum] @@ -52,7 +52,7 @@ function plot_erpgrid!( halign = x, valign = y, )# title = raw_ch_names[1:30]) - if drawLabels + if drawlabels text!( ax, rel_zeropoint + 0.1, @@ -72,10 +72,10 @@ function plot_erpgrid!( 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 + times = isnothing(times) ? (1:size(data, 2)) : times # todo: add customizable kwargs - h = lines!.(axlist, Ref(times), eachrow(plotData)) + h = lines!.(axlist, Ref(times), eachrow(data)) linkaxes!(axlist...) hidedecorations!.(axlist) From edb6a5b618a91e1e5bbe9c17244da26ac791aeb4 Mon Sep 17 00:00:00 2001 From: Vladimir Mikheev Date: Wed, 15 Nov 2023 16:05:58 +0000 Subject: [PATCH 07/18] plot_erpimage + bug in erp_plot detected --- docs/src/tutorials/erpimage.md | 8 +++---- src/docstringtemplate.jl | 2 +- src/plot_erpimage.jl | 41 +++++++++++++++++----------------- test/test_all.jl | 9 ++++---- test/test_erpimage.jl | 8 +++---- 5 files changed, 33 insertions(+), 35 deletions(-) diff --git a/docs/src/tutorials/erpimage.md b/docs/src/tutorials/erpimage.md index 6f7e034ad..7ddf5f70a 100644 --- a/docs/src/tutorials/erpimage.md +++ b/docs/src/tutorials/erpimage.md @@ -26,16 +26,16 @@ plot_erpimage(data) Since ERP images use a `Matrix` as an input, the library does not need any informations about the mapping. -- erpBlur (number, 10) - Is a number indicating how much blur is applied to the image; using Gaussian blur of the ImageFiltering module. Negative values deactivate the blur. +- erpblur (number, 10) - Is a number indicating how much blur is applied to the image; using Gaussian blur of the ImageFiltering module. Negative values deactivate the blur. -- sortvalues - Indicating whether the data is sorted; using sortperm() of Base Julia +- sortvalues - Indicating whether the data is sorted; using sortperm() of Base Julia. (sortperm() computes a permutation of the array's indices that puts the array into sorted order). -- meanPlot (bool, false) - Indicating whether the plot should add a line plot below the ERP image, showing the mean of the data. If limits are set in the axis values both plots will be aligned. +- meanplot (bool, false) - Indicating whether the plot should add a line plot below the ERP image, showing the mean of the data. If limits are set in the axis values both plots will be aligned. ```@example main plot_erpimage(data; - meanPlot = true, + meanplot = true, colorbar = (label = "Voltage [µV]",), visual = (colormap = :viridis, colorrange = (-40, 40))) diff --git a/src/docstringtemplate.jl b/src/docstringtemplate.jl index 62999f799..921713b49 100644 --- a/src/docstringtemplate.jl +++ b/src/docstringtemplate.jl @@ -36,7 +36,7 @@ function _docstring(cfgsymb::Symbol) return """## Shared plot configuration options The shared plot options can be used as follows: - `type=(;key=value,...))` - for example `plot_x(...,layout=(showLegend=true,legendPosition=:right))`. Multiple defaults will be cycled until match. + `type=(; key=value,...))` - for example `plot_x(..., layout=(showLegend=true, legendPosition=:right))`. Multiple defaults will be cycled until match. $(out) """ diff --git a/src/plot_erpimage.jl b/src/plot_erpimage.jl index dcfca82c8..fa4bb3495 100644 --- a/src/plot_erpimage.jl +++ b/src/plot_erpimage.jl @@ -8,16 +8,15 @@ Plot an ERP image. ## Arguments: - `f::Union{GridPosition, GridLayout, Figure}`: Figure or GridPosition that the plot should be drawn into -- `plotData::Matrix{Float64}`: Data for the plot visualization +- `plot::Matrix{Float64}`: Data for the plot visualization ## Keyword Arguments -`erpBlur` (Number, `10`) - Number indicating how much blur is applied to the image; using Gaussian blur of the ImageFiltering module. +- `erpblur` (Number, `10`) - Number indicating how much blur is applied to the image; using Gaussian blur of the ImageFiltering module. Non-Positive values deactivate the blur. - -`sortvalues` (bool, `false`) - parameter over which plot will be sorted. Using sortperm() of Base Julia -(sortperm() computes a permutation of the array's indices that puts the array into sorted order). - -`meanPlot`: (bool, `false`) - Indicating whether the plot should add a line plot below the ERP image, showing the mean of the data. +- `sortix` (): . +- `sortvalues` (bool, `false`) - parameter over which plot will be sorted. Using sortperm() of Base Julia. + - sortperm() computes a permutation of the array's indices that puts the array into sorted order. +- `meanplot`: (bool, `false`) - Indicating whether the plot should add a line plot below the ERP image, showing the mean of the data. $(_docstring(:erpimage)) @@ -26,26 +25,26 @@ The input `f` """ # no times + no figure? -plot_erpimage(plotData::Matrix{<:Real}; kwargs...) = - plot_erpimage!(Figure(), plotData; kwargs...) +plot_erpimage(plot::Matrix{<:Real}; kwargs...) = + plot_erpimage!(Figure(), plot; kwargs...) # no times? -plot_erpimage!(f::Union{GridPosition,GridLayout,Figure}, plotData::Matrix{<:Real}; kwargs...) = - plot_erpimage!(f, 1:size(plotData, 1), plotData; kwargs...) +plot_erpimage!(f::Union{GridPosition,GridLayout,Figure}, plot::Matrix{<:Real}; kwargs...) = + plot_erpimage!(f, 1:size(plot, 1), plot; kwargs...) # no figure? -plot_erpimage(times::AbstractVector, plotData::Matrix{<:Real}; kwargs...) = - plot_erpimage!(Figure(), times, plotData; kwargs...) +plot_erpimage(times::AbstractVector, plot::Matrix{<:Real}; kwargs...) = + plot_erpimage!(Figure(), times, plot; kwargs...) function plot_erpimage!( f::Union{GridPosition,GridLayout,Figure}, times::AbstractVector, - plotData::Matrix{<:Real}; + plot::Matrix{<:Real}; sortvalues = nothing, sortix = nothing, - meanPlot = false, - erpBlur = 10, + meanplot = false, + erpblur = 10, kwargs..., ) config = PlotConfig(:erpimage) @@ -56,7 +55,7 @@ function plot_erpimage!( ax = Axis(f[1:4, 1]; config.axis...) if isnothing(sortix) if isnothing(sortvalues) - sortix = 1:size(plotData, 2) + sortix = 1:size(plot, 2) else sortix = sortperm(sortvalues) @@ -64,8 +63,8 @@ function plot_erpimage!( end filtered_data = UnfoldMakie.imfilter( - plotData[:, sortix], - UnfoldMakie.Kernel.gaussian((0, max(erpBlur, 0))), + plot[:, sortix], + UnfoldMakie.Kernel.gaussian((0, max(erpblur, 0))), ) yvals = 1:size(filtered_data, 2) @@ -77,7 +76,7 @@ function plot_erpimage!( UnfoldMakie.applyLayoutSettings!(config; fig = f, hm = hm, ax = ax, plotArea = (4, 1)) - if meanPlot + if meanplot # UserInput subConfig = deepcopy(config) config_kwargs!( @@ -92,7 +91,7 @@ function plot_erpimage!( (config.layout.showLegend && config.layout.legendPosition == :bottom) ? 1 : 0 subAxis = Axis(f[5+axisOffset, 1]; subConfig.axis...) - lines!(subAxis, mean(plotData, dims = 2)[:, 1]) + lines!(subAxis, mean(plot, dims = 2)[:, 1]) applyLayoutSettings!(subConfig; fig = f, ax = subAxis) end diff --git a/test/test_all.jl b/test/test_all.jl index dea892b61..d87c87623 100644 --- a/test/test_all.jl +++ b/test/test_all.jl @@ -125,12 +125,11 @@ end coefname=["(Intercept)", "category: face"] ) plot_erp!(f[2, 1:2], results, - categoricalColor=false, - categoricalGroup=false, + 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) @@ -138,7 +137,7 @@ end res_effects = effects(Dict(:continuous => -5:0.5:5), uf_deconv) - plot_erp!(f[2, 4:5], res_effects; categoricalColor=false, categoricalGroup=true, + 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)) @@ -147,7 +146,7 @@ end 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, predictorBounds=[-0.3, 0.5]) + positions=positions, predictor=:time, predictor_bounds=[-0.3, 0.5]) f #save("test.png", f) diff --git a/test/test_erpimage.jl b/test/test_erpimage.jl index fda7b0e6b..3c209fc6f 100644 --- a/test/test_erpimage.jl +++ b/test/test_erpimage.jl @@ -6,18 +6,18 @@ end @testset "with mean erp plot" begin data, evts = UnfoldSim.predef_eeg(; noiselevel = 10, return_epoched = true) - plot_erpimage(data; meanPlot = true) + plot_erpimage(data; meanplot = true) end -@testset "changing erpBlur to zero" begin +@testset "changing erpblur to zero" begin data, evts = UnfoldSim.predef_eeg(; noiselevel = 10, return_epoched = true) - plot_erpimage(data; meanPlot = true, erpBlur = 0) + plot_erpimage(data; meanplot = true, erpblur = 0) end @testset "GridPosition" begin f = Figure() data, evts = UnfoldSim.predef_eeg(; noiselevel = 10, return_epoched = true) - plot_erpimage!(f[1, 1], data; meanPlot = true) + plot_erpimage!(f[1, 1], data; meanplot = true) #save("erpimage.eps", f) end From d8bd49ef9a7d5e4aaafba866d074273432cec79d Mon Sep 17 00:00:00 2001 From: Vladimir Mikheev Date: Thu, 16 Nov 2023 12:56:50 +0000 Subject: [PATCH 08/18] 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, ) From d958e5eb296fb5f485c64bfc94523287e1e0dd9f Mon Sep 17 00:00:00 2001 From: Vladimir Mikheev Date: Thu, 16 Nov 2023 13:07:50 +0000 Subject: [PATCH 09/18] pcp --- docs/run_liveserver.jl | 6 +++++- src/plot_parallelcoordinates.jl | 22 +++++++++++----------- 2 files changed, 16 insertions(+), 12 deletions(-) diff --git a/docs/run_liveserver.jl b/docs/run_liveserver.jl index 352fd6a33..4a1068d02 100644 --- a/docs/run_liveserver.jl +++ b/docs/run_liveserver.jl @@ -1,3 +1,7 @@ using LiveServer -servedocs(skip_dir=joinpath("src","generated"),literate_dir=joinpath("literate"),literate=joinpath("literate"),foldername=".") +servedocs(skip_dir=joinpath("src","generated"), + literate_dir=joinpath("literate"), + literate=joinpath("literate"), + foldername="." + ) diff --git a/src/plot_parallelcoordinates.jl b/src/plot_parallelcoordinates.jl index 52aeaf815..566432e45 100644 --- a/src/plot_parallelcoordinates.jl +++ b/src/plot_parallelcoordinates.jl @@ -1,11 +1,11 @@ """ plot_parallelcoordinates!(f::Union{GridPosition, GridLayout, Figure}, - plotData::DataFrame, config::PlotConfig; channels::Vector{Int64}) + data::DataFrame, config::PlotConfig; channels::Vector{Int64}) Plot a PCP (parallel coordinates plot). ## Arguments: - `f::Union{GridPosition, GridLayout, Figure}`: Figure or GridPosition that the plot should be drawn into -- `plotData::DataFrame`: Data for the plot visualization. +- `data::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. @@ -24,11 +24,11 @@ $(_docstring(:paracoord)) ## Return Value: The input `f` """ -plot_parallelcoordinates(plotData::DataFrame, channels::Vector{Int64}; kwargs...) = - plot_parallelcoordinates!(Figure(), plotData, channels; kwargs...) +plot_parallelcoordinates(data::DataFrame, channels::Vector{Int64}; kwargs...) = + plot_parallelcoordinates!(Figure(), data, channels; kwargs...) function plot_parallelcoordinates!( f::Union{GridPosition,GridLayout,Figure}, - plotData::DataFrame, + data::DataFrame, channels::Vector{Int64}; pc_aspect_ratio = 0.55, pc_right_padding = 15, @@ -61,9 +61,9 @@ function plot_parallelcoordinates!( # colormap border (prevents from using outer parts of color map) bord = 0 - config.mapping = resolveMappings(plotData, config.mapping) + config.mapping = resolveMappings(data, config.mapping) - color = unique(plotData[:, config.mapping.color]) + color = unique(data[:, config.mapping.color]) catLeng = length(color) chaLeng = length(channels) @@ -97,7 +97,7 @@ function plot_parallelcoordinates!( # get extrema for each channel for cha in channels - tmp = filter(x -> (x[config.mapping.channel] == cha), plotData) + tmp = filter(x -> (x[config.mapping.channel] == cha), data) w = extrema.([tmp[:, config.mapping.y]]) append!(limits, w) append!(l_up, w[1][2]) @@ -130,11 +130,11 @@ function plot_parallelcoordinates!( end # Draw colored line through all channels for each time entry - for time in unique(plotData[:, config.mapping.time]) - tmp1 = filter(x -> (x[config.mapping.time] == time), plotData) #1 timepoint, 10 rows (2 conditions, 5 channels) + for time in unique(data[:, config.mapping.time]) + tmp1 = filter(x -> (x[config.mapping.time] == time), data) #1 timepoint, 10 rows (2 conditions, 5 channels) for cat in color # df with the order of the channels - dfInOrder = plotData[[], :] + dfInOrder = data[[], :] tmp2 = filter(x -> (x[config.mapping.color] == cat), tmp1) # create new dataframe with the right order From 7c5dc9cf4c9d119a9cde14e9bbbede115bc9ff20 Mon Sep 17 00:00:00 2001 From: Vladimir Mikheev Date: Thu, 16 Nov 2023 13:16:22 +0000 Subject: [PATCH 10/18] topoplot --- src/plot_circulareegtopoplot.jl | 2 +- src/plot_parallelcoordinates.jl | 24 ++++++++++++------------ src/plot_topoplot.jl | 26 +++++++++++++------------- 3 files changed, 26 insertions(+), 26 deletions(-) diff --git a/src/plot_circulareegtopoplot.jl b/src/plot_circulareegtopoplot.jl index 5c5f66c6c..2a303e552 100644 --- a/src/plot_circulareegtopoplot.jl +++ b/src/plot_circulareegtopoplot.jl @@ -7,7 +7,7 @@ Plot a circular EEG topoplot. - `f::Union{GridPosition, GridLayout, Figure}`: Figure, GridLayout or GridPosition that the plot should be drawn into - `data::DataFrame`: DataFrame with keys for data (looks for `:y, :yhat, :estimate`), and :position (looks for `:pos, :position, :positions`), -- `predictor` (optional; default :predictor): the circular predictor value, defines position of topoplot, is mapped around `predictor_bounds` +- `predictor` (optional; default: predictor): the circular predictor value, defines position of topoplot, is mapped around `predictor_bounds` - `predictor_bounds` (default: `[0,360]`): the bounds of the predictor. This is relevant for the axis labels. - `positions` (default: nothing): positions for the [`plot_topoplot`](@Ref) - `center_label` (default: ""): the text in the center of the cricle diff --git a/src/plot_parallelcoordinates.jl b/src/plot_parallelcoordinates.jl index 566432e45..3d23dc066 100644 --- a/src/plot_parallelcoordinates.jl +++ b/src/plot_parallelcoordinates.jl @@ -1,23 +1,23 @@ """ - plot_parallelcoordinates!(f::Union{GridPosition, GridLayout, Figure}, + ?\(f::Union{GridPosition, GridLayout, Figure}, data::DataFrame, config::PlotConfig; channels::Vector{Int64}) Plot a PCP (parallel coordinates plot). ## Arguments: -- `f::Union{GridPosition, GridLayout, Figure}`: Figure or GridPosition that the plot should be drawn into -- `data::DataFrame`: Data for the plot visualization. -- `config::PlotConfig`: Instance of PlotConfig being applied to the visualization. +- `f::Union{GridPosition, GridLayout, Figure}`: Figure or GridPosition that the plot should be drawn into. +- `data::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` +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 complex figures. + +- `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)) diff --git a/src/plot_topoplot.jl b/src/plot_topoplot.jl index 5df7a5baa..24dceaccd 100644 --- a/src/plot_topoplot.jl +++ b/src/plot_topoplot.jl @@ -1,13 +1,13 @@ """ - plot_topoplot!(f::Union{GridPosition, GridLayout, Figure}, plotData, ; positions=nothing, labels=nothing,kwargs...) - plot_topoplot(plotData,; positions=nothing, labels=nothing, kwargs...) + plot_topoplot!(f::Union{GridPosition, GridLayout, Figure}, data, ; positions=nothing, labels=nothing,kwargs...) + plot_topoplot(data,; positions=nothing, labels=nothing, kwargs...) Plot a topo plot. ## 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::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. +- `data::Union{DataFrame, Vector{Float32}}`: data for the plot visualization. +- `positions::Vector{Point{2, Float32}}=nothing`: positions used if `data` is not a DataFrame. If this is the case and `positions=nothing` then positions are generated from `labels`. +- `labels::Vector{String} = nothing`: labels used if `data` is not a DataFrame. $(_docstring(:topoplot)) @@ -16,11 +16,11 @@ $(_docstring(:topoplot)) ## Return Value: A figure displaying the topo plot. """ -plot_topoplot(plotData::Union{DataFrame,Vector{Float32}}; kwargs...) = - plot_topoplot!(Figure(), plotData; kwargs...) +plot_topoplot(data::Union{DataFrame,Vector{Float32}}; kwargs...) = + plot_topoplot!(Figure(), data; kwargs...) function plot_topoplot!( f::Union{GridPosition,GridLayout,Figure}, - plotData::Union{DataFrame,<:AbstractVector}; + data::Union{DataFrame,<:AbstractVector}; positions = nothing, labels = nothing, kwargs..., @@ -31,16 +31,16 @@ function plot_topoplot!( axis = Axis(f[1, 1]; config.axis...) - if !(plotData isa Vector) - config.mapping = resolveMappings(plotData, config.mapping) - plotData = plotData[:, config.mapping.y] + if !(data isa Vector) + config.mapping = resolveMappings(data, config.mapping) + data = data[:, config.mapping.y] end positions = getTopoPositions(; positions = positions, labels = labels) - eeg_topoplot!(axis, plotData, labels; positions, config.visual...) + eeg_topoplot!(axis, data, labels; positions, config.visual...) - clims = (min(plotData...), max(plotData...)) + clims = (min(data...), max(data...)) if clims[1] ≈ clims[2] @warn """The min and max of the value represented by the color are the same, it seems that the data values are identical. We disable the color bar in this figure. From b9be61b87a7c532efde54f8dac59d8fa38cc9643 Mon Sep 17 00:00:00 2001 From: Vladimir Mikheev Date: Thu, 16 Nov 2023 13:38:18 +0000 Subject: [PATCH 11/18] toposeries --- docs/src/tutorials/topoplotseries.md | 24 ++++- src/layout_helper.jl | 2 +- src/plot_designmatrix.jl | 10 +- src/plot_erpimage.jl | 2 +- src/plot_topoplot.jl | 2 +- src/plot_topoplotseries.jl | 38 +++---- src/plotconfig.jl | 10 +- test/test_all.jl | 153 --------------------------- test/test_complexplots.jl | 4 +- test/test_toposeries.jl | 4 +- 10 files changed, 56 insertions(+), 193 deletions(-) delete mode 100644 test/test_all.jl diff --git a/docs/src/tutorials/topoplotseries.md b/docs/src/tutorials/topoplotseries.md index ff88fe472..03ab94302 100644 --- a/docs/src/tutorials/topoplotseries.md +++ b/docs/src/tutorials/topoplotseries.md @@ -1,4 +1,4 @@ -# [Topo Plot SeriesVisualization](@id tpseries_vis) +# [Topoplot Series Visualization](@id tpseries_vis) ## Include used Modules @@ -10,9 +10,9 @@ using DataFrames using CairoMakie using TopoPlots ``` -## Plot Topo Plots Series +## Plot Topoplot Series -### Giving the Data +### Example data In case you do not already have data, you can get example data from the `TopoPlots` module. You can do it like this: @@ -26,11 +26,25 @@ nothing #hide Δbin = 80 plot_topoplotseries(df, Δbin; positions = positions) ``` +### Arguments usage -Without colorbar: +- `f::Union{GridPosition, GridLayout, Figure}`: Figure or GridPosition that the plot should be drawn into. +- `data::DataFrame`: DataFrame with data, needs a `time` column. +- `Δbin::Real`: A number for how large one time bin should be. Δbin is in units of the `data.time` column. + +### Key arguments +- `combinefun` (default: `mean`) - can be used to specify how the samples within `Δbin` are combined. +- `rasterize_heatmaps` (default: `true`) - enforce rasterization of the plot heatmap when saving in svg format. + This has the benefit that all lines/points are vectors, except the interpolated heatmap. + This is typically what you want, otherwise you get ~500x500 vectors per topoplot, which makes everything super slow. +- `col_labels`, `row_labels` - shows column and row labels. +- labels (default: `nothing`) - . +- positions (default: `nothing`) - . + +Disabling colorbar: ```@example main -plot_topoplotseries(df, Δbin; positions=positions, layout = (; useColorbar=false)) +plot_topoplotseries(df, Δbin; positions=positions, layout = (; use_colorbar=false)) ``` ### Positions diff --git a/src/layout_helper.jl b/src/layout_helper.jl index 2415c88b2..781f1a47a 100644 --- a/src/layout_helper.jl +++ b/src/layout_helper.jl @@ -11,7 +11,7 @@ function applyLayoutSettings!(config::PlotConfig; fig=nothing, hm=nothing, # set f[] position depending on legendPosition legendPosition = config.layout.legendPosition == :right ? fig[1:plotArea[1], plotArea[2]+1] : fig[plotArea[1]+1, 1:plotArea[2]] if isnothing(drawing) - if (config.layout.useColorbar) + if (config.layout.use_colorbar) if isnothing(hm) Colorbar(legendPosition; colormap=config.visual.colormap, config.colorbar...) else diff --git a/src/plot_designmatrix.jl b/src/plot_designmatrix.jl index a72fda643..50d761fc0 100644 --- a/src/plot_designmatrix.jl +++ b/src/plot_designmatrix.jl @@ -12,11 +12,11 @@ Plot a designmatrix. - `standardize_data` (bool,`true`): indicates whether the data is standardized by pointwise division of the data with its sampled standard deviation. - `sort_data` (bool, `true`): indicates whether the data is sorted; using sortslices() of Base Julia. - `xticks` (`nothing`): returns the number of labels on the x-axis. Behavior is set in the configuration: - - xticks = 0: no labels are placed. - - xticks = 1: first possible label is placed. - - xticks = 2: first and last possible labels are placed. - - 2 < xticks < `number of labels`: equally distribute the labels. - - xticks ≥ `number of labels`: all labels are placed. + - `xticks` = 0: no labels are placed. + - `xticks` = 1: first possible label is placed. + - `xticks` = 2: first and last possible labels are placed. + - 2 < `xticks` < `number of labels`: equally distribute the labels. + - `xticks` ≥ `number of labels`: all labels are placed. $(_docstring(:designmat)) diff --git a/src/plot_erpimage.jl b/src/plot_erpimage.jl index fa4bb3495..b00ec64d1 100644 --- a/src/plot_erpimage.jl +++ b/src/plot_erpimage.jl @@ -13,7 +13,7 @@ Plot an ERP image. ## Keyword Arguments - `erpblur` (Number, `10`) - Number indicating how much blur is applied to the image; using Gaussian blur of the ImageFiltering module. Non-Positive values deactivate the blur. -- `sortix` (): . +- `sortix` (default: `nothing`): . - `sortvalues` (bool, `false`) - parameter over which plot will be sorted. Using sortperm() of Base Julia. - sortperm() computes a permutation of the array's indices that puts the array into sorted order. - `meanplot`: (bool, `false`) - Indicating whether the plot should add a line plot below the ERP image, showing the mean of the data. diff --git a/src/plot_topoplot.jl b/src/plot_topoplot.jl index 24dceaccd..56ad42c29 100644 --- a/src/plot_topoplot.jl +++ b/src/plot_topoplot.jl @@ -45,7 +45,7 @@ function plot_topoplot!( @warn """The min and max of the value represented by the color are the same, it seems that the data values are identical. We disable the color bar in this figure. Note: The identical min and max may cause an interpolation error when plotting the topoplot.""" - config_kwargs!(config, layout = (; useColorbar=false,showLegend=false)) + config_kwargs!(config, layout = (; use_colorbar=false,showLegend=false)) else config_kwargs!(config, colorbar = (; limits = clims)) end diff --git a/src/plot_topoplotseries.jl b/src/plot_topoplotseries.jl index 2758f05e6..d9c826cc1 100644 --- a/src/plot_topoplotseries.jl +++ b/src/plot_topoplotseries.jl @@ -1,19 +1,21 @@ """ - plot_topoplotseries!(f::Union{GridPosition, GridLayout, Figure}, plotData::DataFrame, Δbin::Real; kwargs...) - plot_topoplotseries!(plotData::DataFrame, Δbin::Real; kwargs...) + plot_topoplotseries!(f::Union{GridPosition, GridLayout, Figure}, data::DataFrame, Δbin::Real; kwargs...) + plot_topoplotseries!(data::DataFrame, Δbin::Real; kwargs...) Multiple miniature topoplots in regular distances ## Arguments: -- `f::Union{GridPosition, GridLayout, 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 -- `combinefun` (default `mean`) can be used to specify how the samples within `Δbin` are combined. -- `rasterize_heatmaps` (deault `true`) - enforce rasterization of the plot heatmap when saving in svg format. - This has the benefit that all lines/points are vectors, except the interpolated heatmap. - This is typically what you want, because else you get ~500x500 vectors per topoplot, which makes everything super slow. +- `f::Union{GridPosition, GridLayout, Figure}`: Figure or GridPosition that the plot should be drawn into. +- `data::DataFrame`: DataFrame with data, needs a `time` column. +- `Δbin::Real`: A number for how large one time bin should be. Δbin is in units of the `data.time` column. +- `combinefun` (default: `mean`) - can be used to specify how the samples within `Δbin` are combined. +- `rasterize_heatmaps` (default: `true`) - enforce rasterization of the plot heatmap when saving in svg format. + This has the benefit that all lines/points are vectors, except the interpolated heatmap. + This is typically what you want, otherwise you get ~500x500 vectors per topoplot, which makes everything super slow. - `col_labels`, `row_labels` - shows column and row labels. +- labels (default: `nothing`) - . +- positions (default: `nothing`) - . $(_docstring(:topoplotseries)) @@ -21,12 +23,12 @@ $(_docstring(:topoplotseries)) The input `f` """ -plot_topoplotseries(plotData::DataFrame, Δbin::Real; kwargs...) = - plot_topoplotseries!(Figure(), plotData, Δbin; kwargs...) +plot_topoplotseries(data::DataFrame, Δbin::Real; kwargs...) = + plot_topoplotseries!(Figure(), data, Δbin; kwargs...) function plot_topoplotseries!( f::Union{GridPosition,GridLayout,Figure}, - plotData::DataFrame, + data::DataFrame, Δbin; positions = nothing, labels = nothing, @@ -40,21 +42,21 @@ function plot_topoplotseries!( config = PlotConfig(:topoplotseries) config_kwargs!(config; kwargs...) - plotData = deepcopy(plotData) + data = deepcopy(data) # resolve columns with data - config.mapping = resolveMappings(plotData, config.mapping) + config.mapping = resolveMappings(data, config.mapping) positions = getTopoPositions(; positions = positions, labels = labels) - if "label" ∉ names(plotData) - plotData.label = plotData.channel + if "label" ∉ names(data) + data.label = data.channel end ftopo, axlist = eeg_topoplot_series!( f, - plotData, + data, Δbin; y = config.mapping.y, label = :label, @@ -68,7 +70,7 @@ function plot_topoplotseries!( config.visual..., ) - if config.layout.useColorbar + if config.layout.use_colorbar if typeof(ftopo) == Figure d = ftopo.content[1].scene.plots[1] Colorbar( diff --git a/src/plotconfig.jl b/src/plotconfig.jl index 06efc553c..8ed720e18 100644 --- a/src/plotconfig.jl +++ b/src/plotconfig.jl @@ -31,7 +31,7 @@ function PlotConfig()# defaults legendPosition = :right, xlabelFromMapping = :x, ylabelFromMapping = :y, - useColorbar = false, + use_colorbar = false, ), (#maping x = (:time,), @@ -126,7 +126,7 @@ function PlotConfig(T::Val{:topoplot}) showLegend = true, xlabelFromMapping = nothing, ylabelFromMapping = nothing, - useColorbar = true, + use_colorbar = true, hidespines = (), hidedecorations = (), ), @@ -150,7 +150,7 @@ function PlotConfig(T::Val{:topoplotseries}) cfg = PlotConfig(:topoplot) config_kwargs!( cfg, - layout = (useColorbar = true,), + layout = (use_colorbar = true,), colorbar = (; height = 300, # why even should i made it manually? flipaxis = true, @@ -169,7 +169,7 @@ function PlotConfig(T::Val{:designmat}) config_kwargs!( cfg; layout = (; - useColorbar = true, + use_colorbar = true, xlabelFromMapping = nothing, ylabelFromMapping = nothing, ), @@ -206,7 +206,7 @@ function PlotConfig(T::Val{:erpimage}) cfg = PlotConfig() config_kwargs!( cfg; - layout = (; useColorbar = true), + layout = (; use_colorbar = true), 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 deleted file mode 100644 index d87c87623..000000000 --- a/test/test_all.jl +++ /dev/null @@ -1,153 +0,0 @@ -@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_complexplots.jl b/test/test_complexplots.jl index d87c87623..9a3e9451a 100644 --- a/test/test_complexplots.jl +++ b/test/test_complexplots.jl @@ -39,7 +39,7 @@ 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)) + layout = (; use_colorbar=true)) plot_erpgrid!(ge, data[:, :, 1], positions) plot_erpimage!(gf, times, d_singletrial) plot_parallelcoordinates!(gh, uf_5chan, [1, 2, 3, 4, 5]; @@ -82,7 +82,7 @@ end 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_topoplotseries!(f[2, 2], d_topo, 0.1; positions=positions, visual=(label_scatter=false,), layout = (; use_colorbar=true)) plot_erpgrid!(f[3, 1], data[:, :, 1], positions) times = -0.099609375:0.001953125:1.0 diff --git a/test/test_toposeries.jl b/test/test_toposeries.jl index 161ebd305..df7401bc8 100644 --- a/test/test_toposeries.jl +++ b/test/test_toposeries.jl @@ -13,7 +13,7 @@ end df, Δbin; positions = positions, - layout = (; useColorbar = false), + layout = (; use_colorbar = false), ) end @@ -30,7 +30,7 @@ end df, Δbin; positions = positions, - layout = (; useColorbar = true), + layout = (; use_colorbar = true), ) hidespines!(ax) hidedecorations!(ax, label = false) From 7821270bbacc3a03ce308da929ebc48b3be76205 Mon Sep 17 00:00:00 2001 From: Vladimir Mikheev Date: Thu, 16 Nov 2023 14:55:50 +0000 Subject: [PATCH 12/18] formatting --- docs/example_data.jl | 146 +++++++++++++++++++++++++---------------- docs/make.jl | 31 ++++----- docs/run_liveserver.jl | 12 ++-- 3 files changed, 110 insertions(+), 79 deletions(-) diff --git a/docs/example_data.jl b/docs/example_data.jl index 2cc0d5e09..92106a3e1 100644 --- a/docs/example_data.jl +++ b/docs/example_data.jl @@ -7,60 +7,96 @@ type == "TopoPlots.jl"(default) Returns tidy DataFrame with two conditions, 64 channels and 800ms of data. This is an average over many subjects. """ -function example_data(example="TopoPlots.jl") +function example_data(example = "TopoPlots.jl") - if example == "UnfoldLinearModel" - # load and generate a simulated Unfold Design - data,evts = UnfoldSim.predef_eeg(;noiselevel=10,return_epoched=true) - data = reshape(data,1,size(data)...) - f = @formula 0~1+condition+continuous - # generate ModelStruct - se_solver =(x,y)->Unfold.solver_default(x,y,stderror=true) - return fit(UnfoldModel,(Dict(Any=>(f,range(0,length=size(data,2),step=1/100)))) ,evts,data;solver=se_solver) - elseif example == "UnfoldLinearModelMultiChannel" - # load and generate a simulated Unfold Design - cAll = DataFrame() - sfreq = 100 - for ch = 1:5 - data,evts = UnfoldSim.predef_eeg(;p1 = (p100(;sfreq=sfreq), @formula(0~1),[5],Dict()), - - n1 = (n170(;sfreq=sfreq), @formula(0~1+condition),[5,-ch*0.5],Dict()), - p3 = (p300(;sfreq=sfreq), @formula(0~1+continuous),[ch,1],Dict()), - return_epoched=true) - data = reshape(data,1,size(data)...) - f = @formula 0~1+condition+continuous - # generate ModelStruct - - m= fit(UnfoldModel,(Dict(Any=>(f,range(0,length=size(data,2),step=1/100)))) ,evts,data) - d = coeftable(m) - d.channel .= ch - cAll = append!(cAll,d) - end - return cAll + if example == "UnfoldLinearModel" + # load and generate a simulated Unfold Design + data, evts = UnfoldSim.predef_eeg(; noiselevel = 10, return_epoched = true) + data = reshape(data, 1, size(data)...) + f = @formula 0 ~ 1 + condition + continuous + # generate ModelStruct + se_solver = (x, y) -> Unfold.solver_default(x, y, stderror = true) + return fit( + UnfoldModel, + (Dict(Any => (f, range(0, length = size(data, 2), step = 1 / 100)))), + evts, + data; + solver = se_solver, + ) + elseif example == "UnfoldLinearModelMultiChannel" + # load and generate a simulated Unfold Design + cAll = DataFrame() + sfreq = 100 + for ch = 1:5 + data, evts = UnfoldSim.predef_eeg(; + p1 = (p100(; sfreq = sfreq), @formula(0 ~ 1), [5], Dict()), + n1 = ( + n170(; sfreq = sfreq), + @formula(0 ~ 1 + condition), + [5, -ch * 0.5], + Dict(), + ), + p3 = (p300(; sfreq = sfreq), @formula(0 ~ 1 + continuous), [ch, 1], Dict()), + return_epoched = true, + ) + data = reshape(data, 1, size(data)...) + f = @formula 0 ~ 1 + condition + continuous + # generate ModelStruct - elseif example == "UnfoldLinearModelContinuousTime" - # load and generate a simulated Unfold Design - data,evts = UnfoldSim.predef_eeg(;) - data = reshape(data,1,size(data)...) - f = @formula 0~1+condition+continuous - basis = firbasis([0,0.5],100) - # generate ModelStruct - return fit(UnfoldModel,Dict(Any=>(f,basis)) ,evts,data) - - elseif example == "TopoPlots.jl" - data,chanlocs = TopoPlots.example_data(); - df = DataFrame(estimate=Float64[],time=Float64[],channel=Int64[],coefname=String[],topoPositions=[],se=Float64[],pval=Float64[]) - pos = TopoPlots.points2mat(chanlocs) - for ch = 1:size(data,1) - for t = 1:size(data,2) - append!(df,DataFrame(estimate=data[ch,t,1],se=data[ch,t,2],pval=data[ch,t,3],time=t,channel=ch,coefname="A",topoPositions=(pos[1,ch],pos[2,ch]))) - - - end - end - df.time = range(-0.3,0.5,step=1/500)[Int.(df.time)] - return df,chanlocs - else - error("unknown example data") - end -end \ No newline at end of file + m = fit( + UnfoldModel, + (Dict(Any => (f, range(0, length = size(data, 2), step = 1 / 100)))), + evts, + data, + ) + d = coeftable(m) + d.channel .= ch + cAll = append!(cAll, d) + end + return cAll + + elseif example == "UnfoldLinearModelContinuousTime" + # load and generate a simulated Unfold Design + data, evts = UnfoldSim.predef_eeg(;) + data = reshape(data, 1, size(data)...) + f = @formula 0 ~ 1 + condition + continuous + basis = firbasis([0, 0.5], 100) + # generate ModelStruct + return fit(UnfoldModel, Dict(Any => (f, basis)), evts, data) + + elseif example == "TopoPlots.jl" + data, chanlocs = TopoPlots.example_data() + df = DataFrame( + estimate = Float64[], + time = Float64[], + channel = Int64[], + coefname = String[], + topo_positions = [], + se = Float64[], + pval = Float64[], + ) + pos = TopoPlots.points2mat(chanlocs) + for ch = 1:size(data, 1) + for t = 1:size(data, 2) + append!( + df, + DataFrame( + estimate = data[ch, t, 1], + se = data[ch, t, 2], + pval = data[ch, t, 3], + time = t, + channel = ch, + coefname = "A", + topo_positions = (pos[1, ch], pos[2, ch]), + ), + ) + + + end + end + df.time = range(-0.3, 0.5, step = 1 / 500)[Int.(df.time)] + return df, chanlocs + else + error("unknown example data") + end +end diff --git a/docs/make.jl b/docs/make.jl index 9b42fed8f..1844d78a4 100644 --- a/docs/make.jl +++ b/docs/make.jl @@ -22,20 +22,20 @@ for subfolder ∈ ["explanations", "HowTo", "tutorials", "reference"] end -DocMeta.setdocmeta!(UnfoldMakie, :DocTestSetup, :(using UnfoldMakie); recursive=true) +DocMeta.setdocmeta!(UnfoldMakie, :DocTestSetup, :(using UnfoldMakie); recursive = true) makedocs(; - modules=[UnfoldMakie], - authors="Benedikt Ehinger, Vladimir Mikheev, Daniel Baumgartner, Niklas Gärtner, Sören Döring", - repo="https://github.com/unfoldtoolbox/UnfoldMakie.jl/blob/{commit}{path}#{line}", - sitename="UnfoldMakie.jl", - warnonly = :cross_references, - format=Documenter.HTML(; - prettyurls=get(ENV, "CI", "false") == "true", - canonical="https://unfoldtoolbox.github.io/UnfoldMakie.jl", - assets=String[] + modules = [UnfoldMakie], + authors = "Benedikt Ehinger, Vladimir Mikheev, Daniel Baumgartner, Niklas Gärtner, Sören Döring", + repo = "https://github.com/unfoldtoolbox/UnfoldMakie.jl/blob/{commit}{path}#{line}", + sitename = "UnfoldMakie.jl", + warnonly = :cross_references, + format = Documenter.HTML(; + prettyurls = get(ENV, "CI", "false") == "true", + canonical = "https://unfoldtoolbox.github.io/UnfoldMakie.jl", + assets = String[], ), - pages=[ + pages = [ "UnfoldMakie Documentation" => "index.md", "Visualizations-Types" => [ "ERP plot" => "generated/tutorials/erp.md", @@ -55,16 +55,11 @@ makedocs(; "Show out of Bounds Label" => "how_to/show_oob_labels.md", ], "Reference" => [ - "Convert 3D positions / montages to 2D layouts" => "generated/reference/positions.md" - + "Convert 3D positions / montages to 2D layouts" => "generated/reference/positions.md", ], "API" => "api.md", "Utilities" => "helper.md", ], - ) -deploydocs(; - repo="github.com/unfoldtoolbox/UnfoldMakie.jl", - devbranch="main" -) +deploydocs(; repo = "github.com/unfoldtoolbox/UnfoldMakie.jl", devbranch = "main") diff --git a/docs/run_liveserver.jl b/docs/run_liveserver.jl index 4a1068d02..85879e690 100644 --- a/docs/run_liveserver.jl +++ b/docs/run_liveserver.jl @@ -1,7 +1,7 @@ using LiveServer -servedocs(skip_dir=joinpath("src","generated"), - literate_dir=joinpath("literate"), - literate=joinpath("literate"), - foldername="." - ) - +servedocs( + skip_dir = joinpath("src", "generated"), + literate_dir = joinpath("literate"), + literate = joinpath("literate"), + foldername = ".", +) From aab63d08766a3fae036198cce028dfed42ce2a72 Mon Sep 17 00:00:00 2001 From: Vladimir Mikheev Date: Thu, 16 Nov 2023 14:56:27 +0000 Subject: [PATCH 13/18] plotconfig arguments --- docs/literate/tutorials/erp.jl | 2 +- docs/src/how_to/mult_vis_in_fig.md | 5 +++-- src/docstringtemplate.jl | 6 ++---- src/layout_helper.jl | 16 ++++++++-------- src/plot_erpimage.jl | 4 ++-- src/plot_parallelcoordinates.jl | 2 +- src/plot_topoplot.jl | 2 +- src/plot_topoplotseries.jl | 4 ++-- src/plotconfig.jl | 18 +++++++++--------- test/runtests.jl | 12 ++++++++---- test/test_complexplots.jl | 8 ++++---- test/test_erp.jl | 2 +- test/test_pcp.jl | 2 +- test/test_pp.jl | 2 +- 14 files changed, 44 insertions(+), 41 deletions(-) diff --git a/docs/literate/tutorials/erp.jl b/docs/literate/tutorials/erp.jl index 15b5f370f..e88a08963 100644 --- a/docs/literate/tutorials/erp.jl +++ b/docs/literate/tutorials/erp.jl @@ -62,7 +62,7 @@ plot_erp( res_effects; mapping = (; y = :yhat, color = :continuous, group = :continuous), legend = (; nbanks = 2), - layout = (; showLegend = true, legendPosition = :right), + layout = (; showLegend = true, legend_position = :right), categorical_color = false, categorical_group = true, ) diff --git a/docs/src/how_to/mult_vis_in_fig.md b/docs/src/how_to/mult_vis_in_fig.md index 1c67de6a8..1df4c4f51 100644 --- a/docs/src/how_to/mult_vis_in_fig.md +++ b/docs/src/how_to/mult_vis_in_fig.md @@ -76,9 +76,10 @@ 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)) + layout=(; show_legend=true, legend_position=:right)) -plot_parallelcoordinates!(f[3, 2:3], uf_5chan, [1, 2, 3, 4, 5]; mapping=(; color=:coefname), layout=(; legendPosition=:bottom)) +plot_parallelcoordinates!(f[3, 2:3], uf_5chan, [1, 2, 3, 4, 5]; mapping=(; color=:coefname), + layout=(; legend_position=: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)), :]; diff --git a/src/docstringtemplate.jl b/src/docstringtemplate.jl index 921713b49..aea66ab9d 100644 --- a/src/docstringtemplate.jl +++ b/src/docstringtemplate.jl @@ -36,16 +36,14 @@ function _docstring(cfgsymb::Symbol) return """## Shared plot configuration options The shared plot options can be used as follows: - `type=(; key=value,...))` - for example `plot_x(..., layout=(showLegend=true, legendPosition=:right))`. Multiple defaults will be cycled until match. + `type=(; key=value,...))` - for example `plot_x(..., layout=(show_legend=true, legend_position=:right))`. + Multiple defaults will be cycled until match. $(out) """ end - - - """ $(TYPEDSIGNATURES) $(_docstring(:erp)) diff --git a/src/layout_helper.jl b/src/layout_helper.jl index 781f1a47a..fe21a1540 100644 --- a/src/layout_helper.jl +++ b/src/layout_helper.jl @@ -4,25 +4,25 @@ function applyLayoutSettings!(config::PlotConfig; fig=nothing, hm=nothing, ax = current_axis() end - if (config.layout.showLegend) + if (config.layout.show_legend) if isnothing(fig) @error "Legend needs figure parameter" else - # set f[] position depending on legendPosition - legendPosition = config.layout.legendPosition == :right ? fig[1:plotArea[1], plotArea[2]+1] : fig[plotArea[1]+1, 1:plotArea[2]] + # set f[] position depending on legend_position + legend_position = config.layout.legend_position == :right ? fig[1:plotArea[1], plotArea[2]+1] : fig[plotArea[1]+1, 1:plotArea[2]] if isnothing(drawing) if (config.layout.use_colorbar) if isnothing(hm) - Colorbar(legendPosition; colormap=config.visual.colormap, config.colorbar...) + Colorbar(legend_position; colormap=config.visual.colormap, config.colorbar...) else - Colorbar(legendPosition, hm; config.colorbar...) + Colorbar(legend_position, hm; config.colorbar...) end else - Legend(legendPosition, ax; config.legend...) + Legend(legend_position, ax; config.legend...) end else - legend!(legendPosition, drawing; config.legend...) - colorbar!(legendPosition, drawing; config.colorbar...) + legend!(legend_position, drawing; config.legend...) + colorbar!(legend_position, drawing; config.colorbar...) end end end diff --git a/src/plot_erpimage.jl b/src/plot_erpimage.jl index b00ec64d1..ad2607318 100644 --- a/src/plot_erpimage.jl +++ b/src/plot_erpimage.jl @@ -81,14 +81,14 @@ function plot_erpimage!( subConfig = deepcopy(config) config_kwargs!( subConfig; - layout = (; showLegend = false), + layout = (; show_legend = false), axis = (; ylabel = config.colorbar.label === nothing ? "" : config.colorbar.label ), ) axisOffset = - (config.layout.showLegend && config.layout.legendPosition == :bottom) ? 1 : 0 + (config.layout.show_legend && config.layout.legend_position == :bottom) ? 1 : 0 subAxis = Axis(f[5+axisOffset, 1]; subConfig.axis...) lines!(subAxis, mean(plot, dims = 2)[:, 1]) diff --git a/src/plot_parallelcoordinates.jl b/src/plot_parallelcoordinates.jl index 3d23dc066..116ae70b8 100644 --- a/src/plot_parallelcoordinates.jl +++ b/src/plot_parallelcoordinates.jl @@ -120,7 +120,7 @@ function plot_parallelcoordinates!( labelfont = "Arial", ticklabelfont = "Arial", spinevisible = true, - labelrotation = 0.0, + label_rotation = 0.0, ticklabelsize = tick_label_size, minorticks = IntervalsBetween(2), endpoints = Point2f[(x_values[i], bottom_padding), (x_values[i], y_values[i])], diff --git a/src/plot_topoplot.jl b/src/plot_topoplot.jl index 56ad42c29..166925157 100644 --- a/src/plot_topoplot.jl +++ b/src/plot_topoplot.jl @@ -45,7 +45,7 @@ function plot_topoplot!( @warn """The min and max of the value represented by the color are the same, it seems that the data values are identical. We disable the color bar in this figure. Note: The identical min and max may cause an interpolation error when plotting the topoplot.""" - config_kwargs!(config, layout = (; use_colorbar=false,showLegend=false)) + config_kwargs!(config, layout = (; use_colorbar=false, show_legend=false)) else config_kwargs!(config, colorbar = (; limits = clims)) end diff --git a/src/plot_topoplotseries.jl b/src/plot_topoplotseries.jl index d9c826cc1..7f7c7eb9c 100644 --- a/src/plot_topoplotseries.jl +++ b/src/plot_topoplotseries.jl @@ -79,7 +79,7 @@ function plot_topoplotseries!( colorrange = d.colorrange, height = config.colorbar.height, flipaxis = config.colorbar.flipaxis, - labelrotation = config.colorbar.labelrotation, + label_rotation = config.colorbar.label_rotation, label = config.colorbar.label, ) else @@ -91,7 +91,7 @@ function plot_topoplotseries!( colorrange = d.colorrange, height = config.colorbar.height, flipaxis = config.colorbar.flipaxis, - labelrotation = config.colorbar.labelrotation, + label_rotation = config.colorbar.label_rotation, label = config.colorbar.label, ) end diff --git a/src/plotconfig.jl b/src/plotconfig.jl index 8ed720e18..3c7ec3af5 100644 --- a/src/plotconfig.jl +++ b/src/plotconfig.jl @@ -27,8 +27,8 @@ function PlotConfig()# defaults (;), #figure (;), # axis (; # layout - showLegend = true, - legendPosition = :right, + show_legend = true, + legend_position = :right, xlabelFromMapping = :x, ylabelFromMapping = :y, use_colorbar = false, @@ -90,7 +90,7 @@ function PlotConfig(T::Val{:circeegtopo}) config_kwargs!( cfg; - layout = (; showLegend = false), + layout = (; show_legend = false), colorbar = (; label = "Voltage [µV]", colormap = Reverse(:RdBu)), mapping = (;), axis = (; @@ -123,7 +123,7 @@ function PlotConfig(T::Val{:topoplot}) config_kwargs!( cfg; layout = ( - showLegend = true, + show_legend = true, xlabelFromMapping = nothing, ylabelFromMapping = nothing, use_colorbar = true, @@ -154,7 +154,7 @@ function PlotConfig(T::Val{:topoplotseries}) colorbar = (; height = 300, # why even should i made it manually? flipaxis = true, - labelrotation = 4.7, + label_rotation = 4.7, label = "Voltage [µV]" ), visual = (; @@ -182,10 +182,10 @@ function PlotConfig(T::Val{:butterfly}) cfg = PlotConfig(:erp) config_kwargs!( cfg; - layout = (; showLegend = false), + layout = (; show_legend = false), mapping = (; color = (:channel, :channels, :trial, :trials), - positions = (:pos, :positions, :position, :topoPositions, :x, nothing), + positions = (:pos, :positions, :position, :topo_positions, :x, nothing), labels = (:labels, :label, :topoLabels, :sensor, nothing), ), ) @@ -196,7 +196,7 @@ function PlotConfig(T::Val{:erp}) config_kwargs!( cfg; mapping = (; color = (:color, :coefname, nothing)), - layout = (; showLegend = true, hidespines = (:r, :t)), + layout = (; show_legend = true, hidespines = (:r, :t)), legend = (; framevisible = false), ) @@ -207,7 +207,7 @@ function PlotConfig(T::Val{:erpimage}) config_kwargs!( cfg; layout = (; use_colorbar = true), - colorbar = (; label = "Voltage [µV]", labelrotation = 4.7), + colorbar = (; label = "Voltage [µV]", label_rotation = 4.7), axis = (xlabel = "Time", ylabel = "Sorted trials"), visual = (; colormap = Reverse("RdBu")), ) diff --git a/test/runtests.jl b/test/runtests.jl index 1b2d36f83..e85af7104 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -15,10 +15,6 @@ end include("test_butterfly.jl") end -@testset "Topoplot series" begin - include("test_toposeries.jl") -end - @testset "ERP Image" begin include("test_erpimage.jl") end @@ -27,6 +23,14 @@ end include("test_topoplot.jl") end +@testset "Topoplot series" begin + include("test_toposeries.jl") +end + +@testset "Parallel coordinates plot" begin + include("test_pcp.jl") +end + @testset "Circular EEG topoplot" begin include("test_plot_circulareegtopoplot.jl") end diff --git a/test/test_complexplots.jl b/test/test_complexplots.jl index 9a3e9451a..b570e0d14 100644 --- a/test/test_complexplots.jl +++ b/test/test_complexplots.jl @@ -43,7 +43,7 @@ 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)) + mapping=(; color=:coefname), layout=(; legend_position=: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, @@ -89,7 +89,7 @@ end 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)) + layout=(; legend_position=: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]]) @@ -140,9 +140,9 @@ end 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)) + layout=(; show_legend=true, legend_position=:right)) - plot_parallelcoordinates!(f[3, 2:3], uf_5chan, [1, 2, 3, 4, 5]; mapping=(; color=:coefname), layout=(; legendPosition=:bottom)) + plot_parallelcoordinates!(f[3, 2:3], uf_5chan, [1, 2, 3, 4, 5]; mapping=(; color=:coefname), layout=(; legend_position=: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)), :]; diff --git a/test/test_erp.jl b/test/test_erp.jl index 78fd36833..498b21a33 100644 --- a/test/test_erp.jl +++ b/test/test_erp.jl @@ -40,7 +40,7 @@ end res_effects; mapping = (; y = :yhat, color = :continuous, group = :continuous), legend = (; nbanks = 2), - layout = (; legendPosition = :right, showLegend = false), + layout = (; legend_position = :right, show_legend = false), categorical_color = false, categorical_group = true, ) diff --git a/test/test_pcp.jl b/test/test_pcp.jl index 581e808e1..4e9d6de03 100644 --- a/test/test_pcp.jl +++ b/test/test_pcp.jl @@ -13,6 +13,6 @@ end f = Figure() plot_parallelcoordinates!(f[1, 1], uf_5chan, [1, 2, 3, 4, 5]; - mapping=(; color=:coefname), layout=(; legendPosition=:bottom)) + mapping=(; color=:coefname), layout=(; legend_position=:bottom)) f end \ No newline at end of file diff --git a/test/test_pp.jl b/test/test_pp.jl index 581e808e1..4e9d6de03 100644 --- a/test/test_pp.jl +++ b/test/test_pp.jl @@ -13,6 +13,6 @@ end f = Figure() plot_parallelcoordinates!(f[1, 1], uf_5chan, [1, 2, 3, 4, 5]; - mapping=(; color=:coefname), layout=(; legendPosition=:bottom)) + mapping=(; color=:coefname), layout=(; legend_position=:bottom)) f end \ No newline at end of file From 96fa73ec362cc6011b57e18e70f5bccd67e06275 Mon Sep 17 00:00:00 2001 From: Vladimir Mikheev Date: Thu, 16 Nov 2023 15:06:29 +0000 Subject: [PATCH 14/18] fix error - lablerotation --- src/plot_parallelcoordinates.jl | 2 +- src/plot_topoplotseries.jl | 4 ++-- src/plotconfig.jl | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/plot_parallelcoordinates.jl b/src/plot_parallelcoordinates.jl index 116ae70b8..5f417c714 100644 --- a/src/plot_parallelcoordinates.jl +++ b/src/plot_parallelcoordinates.jl @@ -120,7 +120,7 @@ function plot_parallelcoordinates!( labelfont = "Arial", ticklabelfont = "Arial", spinevisible = true, - label_rotation = 0.0, + labelrotation = 0.0, ticklabelsize = tick_label_size, minorticks = IntervalsBetween(2), endpoints = Point2f[(x_values[i], bottom_padding), (x_values[i], y_values[i])], diff --git a/src/plot_topoplotseries.jl b/src/plot_topoplotseries.jl index 7f7c7eb9c..f920e093d 100644 --- a/src/plot_topoplotseries.jl +++ b/src/plot_topoplotseries.jl @@ -79,7 +79,7 @@ function plot_topoplotseries!( colorrange = d.colorrange, height = config.colorbar.height, flipaxis = config.colorbar.flipaxis, - label_rotation = config.colorbar.label_rotation, + labelrotation = config.colorbar.labelrotation , label = config.colorbar.label, ) else @@ -91,7 +91,7 @@ function plot_topoplotseries!( colorrange = d.colorrange, height = config.colorbar.height, flipaxis = config.colorbar.flipaxis, - label_rotation = config.colorbar.label_rotation, + labelrotation = config.colorbar.labelrotation , label = config.colorbar.label, ) end diff --git a/src/plotconfig.jl b/src/plotconfig.jl index 3c7ec3af5..f7b528201 100644 --- a/src/plotconfig.jl +++ b/src/plotconfig.jl @@ -154,7 +154,7 @@ function PlotConfig(T::Val{:topoplotseries}) colorbar = (; height = 300, # why even should i made it manually? flipaxis = true, - label_rotation = 4.7, + labelrotation = 4.7, label = "Voltage [µV]" ), visual = (; @@ -207,7 +207,7 @@ function PlotConfig(T::Val{:erpimage}) config_kwargs!( cfg; layout = (; use_colorbar = true), - colorbar = (; label = "Voltage [µV]", label_rotation = 4.7), + colorbar = (; label = "Voltage [µV]", labelrotation = 4.7), axis = (xlabel = "Time", ylabel = "Sorted trials"), visual = (; colormap = Reverse("RdBu")), ) From 235074d90bfa8f9305b91b8050712c485208e55a Mon Sep 17 00:00:00 2001 From: Vladimir Mikheev Date: Thu, 16 Nov 2023 15:14:39 +0000 Subject: [PATCH 15/18] misspelling --- src/plot_parallelcoordinates.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plot_parallelcoordinates.jl b/src/plot_parallelcoordinates.jl index 5f417c714..4b5a69cd2 100644 --- a/src/plot_parallelcoordinates.jl +++ b/src/plot_parallelcoordinates.jl @@ -1,5 +1,5 @@ """ - ?\(f::Union{GridPosition, GridLayout, Figure}, + plot_parallelcoordinates!(f::Union{GridPosition, GridLayout, Figure}, data::DataFrame, config::PlotConfig; channels::Vector{Int64}) Plot a PCP (parallel coordinates plot). From 7286bedaaf28d15560fec08607fcaf18edc8efa7 Mon Sep 17 00:00:00 2001 From: Vladimir Mikheev Date: Thu, 16 Nov 2023 16:03:51 +0000 Subject: [PATCH 16/18] upd and tests for topopositions_to_color --- docs/src/how_to/position2color.md | 11 +++++++---- src/plot_parallelcoordinates.jl | 12 ++++++------ src/plotconfig.jl | 4 ++-- test/test_butterfly.jl | 31 +++++++++++++++++++++++++++---- test/test_erp.jl | 29 ++++++++++++++++++++++++++++- test/test_pp.jl | 18 ------------------ 6 files changed, 70 insertions(+), 35 deletions(-) delete mode 100644 test/test_pp.jl diff --git a/docs/src/how_to/position2color.md b/docs/src/how_to/position2color.md index 44daa3fad..2f51b5c6b 100644 --- a/docs/src/how_to/position2color.md +++ b/docs/src/how_to/position2color.md @@ -21,17 +21,20 @@ We can switch the colorscale of the position-map, by giving a function that maps ### Similar to MNE ```@example main -plot_butterfly(results; positions=positions, extra=(; topoPositionToColorFunction = pos -> UnfoldMakie.posToColorRGB(pos))) +plot_butterfly(results; + positions=positions, + topopositions_to_color = pos -> UnfoldMakie.posToColorRGB(pos) +) ``` ### HSV-Space ```@example main -plot_butterfly(results; positions=positions, extra=(; topoPositionToColorFunction=UnfoldMakie.posToColorHSV)) +plot_butterfly(results; positions=positions, topopositions_to_color=UnfoldMakie.posToColorHSV) ``` ### Uniform Color To highlight the flexibility, we can also make all lines `gray`, or any other arbitrary color, or function of electrode-`position`. + ```@example main -using Colors -plot_butterfly(results; positions=positions, extra=(; topoPositionToColorFunction = x -> Colors.RGB(0.5))) +plot_butterfly(results; positions=positions, topopositions_to_color = x -> Colors.RGB(0.5)) ``` \ No newline at end of file diff --git a/src/plot_parallelcoordinates.jl b/src/plot_parallelcoordinates.jl index 4b5a69cd2..1551a0e29 100644 --- a/src/plot_parallelcoordinates.jl +++ b/src/plot_parallelcoordinates.jl @@ -12,12 +12,12 @@ Plot a PCP (parallel coordinates plot). 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 complex figures. -- `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)) diff --git a/src/plotconfig.jl b/src/plotconfig.jl index f7b528201..2f0decd99 100644 --- a/src/plotconfig.jl +++ b/src/plotconfig.jl @@ -65,9 +65,9 @@ function config_kwargs!(cfg::PlotConfig; kwargs...) """ Keyword argument specification (kwargs...) Specified config groups must be NamedTuples', but $(keys(kwargs)[.!is_namedtuple]) was not. Maybe you forgot the semicolon (;) at the beginning of your specification? Compare these strings: - plot_example(...; layout = (; showColorbar=true)) + plot_example(...; layout = (; use_colorbar=true)) - plot_example(...; layout = (showColorbar=true)) + plot_example(...; layout = (use_colorbar=true)) The first is correct and creates a NamedTuple as required. The second is wrong and its call is ignored.""") list = fieldnames(PlotConfig)#[:layout,:visual,:mapping,:legend,:colorbar,:axis] diff --git a/test/test_butterfly.jl b/test/test_butterfly.jl index 1b786556e..cfcabc8fc 100644 --- a/test/test_butterfly.jl +++ b/test/test_butterfly.jl @@ -1,13 +1,14 @@ +include("../docs/example_data.jl") +data, pos = example_data("TopoPlots.jl") +results, positions = example_data("TopoPlots.jl") +using Colors + @testset "basic" begin - include("../docs/example_data.jl") - data, pos = example_data("TopoPlots.jl") plot_butterfly(data; positions = pos) end @testset "topomarkersize change" begin - include("../docs/example_data.jl") - data, pos = example_data("TopoPlots.jl") plot_butterfly( data; positions = pos, @@ -18,4 +19,26 @@ end end +@testset "changing color from ROMA to gray" begin + plot_butterfly( + results; + positions = positions, + topopositions_to_color = x -> Colors.RGB(0.5) + ) +end +@testset "changing color from ROMA to HSV" begin + plot_butterfly( + results; + positions = positions, + topopositions_to_color=UnfoldMakie.posToColorHSV + ) +end + +@testset "changing color from ROMA to RGB" begin + plot_butterfly( + results; + positions = positions, + topopositions_to_color = pos -> UnfoldMakie.posToColorRGB(pos) + ) +end diff --git a/test/test_erp.jl b/test/test_erp.jl index 498b21a33..f7549c9ee 100644 --- a/test/test_erp.jl +++ b/test/test_erp.jl @@ -19,7 +19,7 @@ end -@testset "basic with res_effects" begin +@testset "basic with res_effects without colorbar" begin data, evts = UnfoldSim.predef_eeg(; noiselevel = 12, return_epoched = true) data = reshape(data, (1, size(data)...)) f = @formula 0 ~ 1 + condition + continuous @@ -46,6 +46,33 @@ end ) end +@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 + 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, 2)))), + evts, + data, + solver = se_solver, + ) + results = coeftable(m) + res_effects = effects(Dict(:continuous => -5:0.5:5), m) + + # ## Plot the results + plot_erp( + res_effects; + mapping = (; y = :yhat, color = :continuous, group = :continuous), + legend = (; nbanks = 2), + layout = (; legend_position = :right, show_legend = true), + categorical_color = false, + categorical_group = true, + ) +end + @testset "erp plot in GridLayout" begin f = Figure(resolution=(1200, 1400)) diff --git a/test/test_pp.jl b/test/test_pp.jl deleted file mode 100644 index 4e9d6de03..000000000 --- a/test/test_pp.jl +++ /dev/null @@ -1,18 +0,0 @@ - -@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=(; legend_position=:bottom)) - f -end \ No newline at end of file From c1f13eea28071ee15ba950f879dc362789ac752d Mon Sep 17 00:00:00 2001 From: Vladimir Mikheev Date: Thu, 16 Nov 2023 16:17:48 +0000 Subject: [PATCH 17/18] library was forgotted --- test/setup.jl | 1 + test/test_butterfly.jl | 14 ++++++-------- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/test/setup.jl b/test/setup.jl index 6a53f725a..a11159623 100644 --- a/test/setup.jl +++ b/test/setup.jl @@ -4,5 +4,6 @@ using CairoMakie using GeometryBasics using DataFrames using TopoPlots +using Colors include("../docs/example_data.jl") \ No newline at end of file diff --git a/test/test_butterfly.jl b/test/test_butterfly.jl index cfcabc8fc..fcf1985e5 100644 --- a/test/test_butterfly.jl +++ b/test/test_butterfly.jl @@ -1,7 +1,6 @@ include("../docs/example_data.jl") data, pos = example_data("TopoPlots.jl") -results, positions = example_data("TopoPlots.jl") using Colors @testset "basic" begin @@ -18,27 +17,26 @@ end ) end - @testset "changing color from ROMA to gray" begin plot_butterfly( - results; - positions = positions, + data; + positions = pos, topopositions_to_color = x -> Colors.RGB(0.5) ) end @testset "changing color from ROMA to HSV" begin plot_butterfly( - results; - positions = positions, + data; + positions = pos, topopositions_to_color=UnfoldMakie.posToColorHSV ) end @testset "changing color from ROMA to RGB" begin plot_butterfly( - results; - positions = positions, + data; + positions = pos, topopositions_to_color = pos -> UnfoldMakie.posToColorRGB(pos) ) end From 99a96b59c1fc70de053fcf729f6c46b934dfea38 Mon Sep 17 00:00:00 2001 From: Vladimir Mikheev Date: Thu, 16 Nov 2023 16:38:47 +0000 Subject: [PATCH 18/18] sorted erp added to docs --- docs/src/tutorials/erpimage.md | 32 ++++++++++++++++++++++++-------- src/plot_erpimage.jl | 6 +++--- test/Project.toml | 1 + test/test_butterfly.jl | 1 - 4 files changed, 28 insertions(+), 12 deletions(-) diff --git a/docs/src/tutorials/erpimage.md b/docs/src/tutorials/erpimage.md index 7ddf5f70a..18dcb15da 100644 --- a/docs/src/tutorials/erpimage.md +++ b/docs/src/tutorials/erpimage.md @@ -14,7 +14,7 @@ include("../../example_data.jl") ``` -## Plot ERP Images +## Plot ERP image The following code will result in the default configuration. ```@example main @@ -22,16 +22,15 @@ data, evts = UnfoldSim.predef_eeg(; noiselevel=10, return_epoched=true) plot_erpimage(data) ``` -## Column Mappings for ERP Images +## Column Mappings for ERP image Since ERP images use a `Matrix` as an input, the library does not need any informations about the mapping. -- erpblur (number, 10) - Is a number indicating how much blur is applied to the image; using Gaussian blur of the ImageFiltering module. Negative values deactivate the blur. - -- sortvalues - Indicating whether the data is sorted; using sortperm() of Base Julia. -(sortperm() computes a permutation of the array's indices that puts the array into sorted order). - -- meanplot (bool, false) - Indicating whether the plot should add a line plot below the ERP image, showing the mean of the data. If limits are set in the axis values both plots will be aligned. +- `erpblur` (Number, `10`): number indicating how much blur is applied to the image; using Gaussian blur of the ImageFiltering module. +Non-Positive values deactivate the blur. +- `sortvalues` (bool, `false`): parameter over which plot will be sorted. Using sortperm() of Base Julia. + - sortperm() computes a permutation of the array's indices that puts the array into sorted order. +- `meanplot` (bool, `false`): Indicating whether the plot should add a line plot below the ERP image, showing the mean of the data. ```@example main plot_erpimage(data; @@ -40,3 +39,20 @@ plot_erpimage(data; visual = (colormap = :viridis, colorrange = (-40, 40))) ``` + +## Sorted ERP image + +First, generate a data. Second, specify the necessary sorting parameter. + +```@example main + dat, evts = UnfoldSim.predef_eeg(; + onset=LogNormalOnset(μ=3.5, σ=0.4), + noiselevel=5 + ) + dat_e, times = Unfold.epoch(dat, evts, [-0.1,1], 100) + evts, dat_e = Unfold.dropMissingEpochs(evts, dat_e) + evts.Δlatency = diff(vcat(evts.latency, 0)) + dat_e = dat_e[1,:,:] + + plot_erpimage(times, dat_e; sortvalues=evts.Δlatency) +``` \ No newline at end of file diff --git a/src/plot_erpimage.jl b/src/plot_erpimage.jl index ad2607318..bd1a9de3b 100644 --- a/src/plot_erpimage.jl +++ b/src/plot_erpimage.jl @@ -11,12 +11,12 @@ Plot an ERP image. - `plot::Matrix{Float64}`: Data for the plot visualization ## Keyword Arguments -- `erpblur` (Number, `10`) - Number indicating how much blur is applied to the image; using Gaussian blur of the ImageFiltering module. +- `erpblur` (Number, `10`): number indicating how much blur is applied to the image; using Gaussian blur of the ImageFiltering module. Non-Positive values deactivate the blur. - `sortix` (default: `nothing`): . -- `sortvalues` (bool, `false`) - parameter over which plot will be sorted. Using sortperm() of Base Julia. +- `sortvalues` (bool, `false`): parameter over which plot will be sorted. Using sortperm() of Base Julia. - sortperm() computes a permutation of the array's indices that puts the array into sorted order. -- `meanplot`: (bool, `false`) - Indicating whether the plot should add a line plot below the ERP image, showing the mean of the data. +- `meanplot` (bool, `false`): Indicating whether the plot should add a line plot below the ERP image, showing the mean of the data. $(_docstring(:erpimage)) diff --git a/test/Project.toml b/test/Project.toml index 56a844000..4ab9756ab 100644 --- a/test/Project.toml +++ b/test/Project.toml @@ -1,5 +1,6 @@ [deps] CairoMakie = "13f3f980-e62b-5c42-98c6-ff1f3baf88f0" +Colors = "5ae59095-9a9b-59fe-a467-6f913c188581" DataFrames = "a93c6f00-e57d-5684-b7b6-d8193f3e46c0" GeometryBasics = "5c1252a2-5f33-56bf-86c9-59e7332b4326" Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" diff --git a/test/test_butterfly.jl b/test/test_butterfly.jl index fcf1985e5..1a5a0043b 100644 --- a/test/test_butterfly.jl +++ b/test/test_butterfly.jl @@ -1,7 +1,6 @@ include("../docs/example_data.jl") data, pos = example_data("TopoPlots.jl") -using Colors @testset "basic" begin plot_butterfly(data; positions = pos)