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/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/literate/tutorials/erp.jl b/docs/literate/tutorials/erp.jl index 3077b7fcb..e88a08963 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: @@ -61,13 +62,11 @@ plot_erp( res_effects; mapping = (; y = :yhat, color = :continuous, group = :continuous), legend = (; nbanks = 2), - layout = (; showLegend = true, legendPosition = :right), - categoricalColor = false, categoricalGroup = true, + layout = (; showLegend = true, legend_position = :right), + 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/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 352fd6a33..85879e690 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/docs/src/how_to/mult_vis_in_fig.md b/docs/src/how_to/mult_vis_in_fig.md index b740d02df..1df4c4f51 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,16 +73,17 @@ 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)) + 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)), :]; - positions=positions, predictor=:time, predictorBounds=[-0.3, 0.5]) + positions=positions, predictor=:time, predictor_bounds=[-0.3, 0.5]) f ``` 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/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/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/docs/src/tutorials/erpimage.md b/docs/src/tutorials/erpimage.md index 6f7e034ad..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,21 +22,37 @@ 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; - meanPlot = true, + meanplot = true, colorbar = (label = "Voltage [µV]",), 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/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/docstringtemplate.jl b/src/docstringtemplate.jl index 62999f799..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 2415c88b2..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.useColorbar) + 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_circulareegtopoplot.jl b/src/plot_circulareegtopoplot.jl index c3291f899..2a303e552 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/src/plot_designmatrix.jl b/src/plot_designmatrix.jl index ed0ff3805..50d761fc0 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/src/plot_erp.jl b/src/plot_erp.jl index a249e6e74..317b9fb79 100644 --- a/src/plot_erp.jl +++ b/src/plot_erp.jl @@ -2,24 +2,25 @@ 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 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))` +- `f::Union{GridPosition, GridLayout, Figure}`: Figure, GridLayout or GridPosition that the plot should be drawn into. +- `plot_data::DataFrame`: Data for the line plot visualization. +- `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)) @@ -29,37 +30,39 @@ $(_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 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...) = - 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, + topolegend = true, topomarkersize = 10, topowidth = 0.25, topoheigth = 0.25, - topoPositionToColorFunction = x -> posToColorRomaO(x), + topopositions_to_color = x -> posToColorRomaO(x), kwargs..., ) @@ -67,19 +70,19 @@ plot_butterfly!( function plot_erp!( f::Union{GridPosition,GridLayout,Figure}, - plotData::DataFrame; + plot_data::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) @@ -89,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) @@ -103,40 +106,40 @@ 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))) + topolegend = false + #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 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 @@ -163,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 @@ -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) @@ -257,15 +260,15 @@ function topoplotLegend(axis, topomarkersize, topoPositionToColorFunction, allPo return topoplot end -function addPvalues(plotData, 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(plotData) - p[!, :group] .= plotData[1, :group] - if length(unique(plotData.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 @@ -282,16 +285,17 @@ function addPvalues(plotData, pvalue, config) end # define an index to dodge the lines vertically - scaleY = [minimum(plotData.estimate), maximum(plotData.estimate)] + scaleY = [minimum(plot_data.estimate), maximum(plot_data.estimate)] stepY = scaleY[2] - scaleY[1] posY = stepY * -0.05 + scaleY[1] - Δt = diff(plotData.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/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) diff --git a/src/plot_erpimage.jl b/src/plot_erpimage.jl index dcfca82c8..bd1a9de3b 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` (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. $(_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,22 +76,22 @@ 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!( 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(plotData, dims = 2)[:, 1]) + lines!(subAxis, mean(plot, dims = 2)[:, 1]) applyLayoutSettings!(subConfig; fig = f, ax = subAxis) end diff --git a/src/plot_parallelcoordinates.jl b/src/plot_parallelcoordinates.jl index 52aeaf815..1551a0e29 100644 --- a/src/plot_parallelcoordinates.jl +++ b/src/plot_parallelcoordinates.jl @@ -1,34 +1,34 @@ """ 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. -- `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 +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)) ## 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]) @@ -120,7 +120,7 @@ function plot_parallelcoordinates!( labelfont = "Arial", ticklabelfont = "Arial", spinevisible = true, - labelrotation = 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])], @@ -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 diff --git a/src/plot_topoplot.jl b/src/plot_topoplot.jl index 5df7a5baa..166925157 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,21 +31,21 @@ 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. 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, show_legend=false)) else config_kwargs!(config, colorbar = (; limits = clims)) end diff --git a/src/plot_topoplotseries.jl b/src/plot_topoplotseries.jl index 2758f05e6..f920e093d 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( @@ -77,7 +79,7 @@ function plot_topoplotseries!( colorrange = d.colorrange, height = config.colorbar.height, flipaxis = config.colorbar.flipaxis, - labelrotation = config.colorbar.labelrotation, + labelrotation = config.colorbar.labelrotation , label = config.colorbar.label, ) else @@ -89,7 +91,7 @@ function plot_topoplotseries!( colorrange = d.colorrange, height = config.colorbar.height, flipaxis = config.colorbar.flipaxis, - labelrotation = config.colorbar.labelrotation, + labelrotation = config.colorbar.labelrotation , label = config.colorbar.label, ) end diff --git a/src/plotconfig.jl b/src/plotconfig.jl index 06efc553c..2f0decd99 100644 --- a/src/plotconfig.jl +++ b/src/plotconfig.jl @@ -27,11 +27,11 @@ function PlotConfig()# defaults (;), #figure (;), # axis (; # layout - showLegend = true, - legendPosition = :right, + show_legend = true, + legend_position = :right, xlabelFromMapping = :x, ylabelFromMapping = :y, - useColorbar = false, + use_colorbar = false, ), (#maping x = (:time,), @@ -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] @@ -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,10 +123,10 @@ function PlotConfig(T::Val{:topoplot}) config_kwargs!( cfg; layout = ( - showLegend = true, + show_legend = 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, ), @@ -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), ) @@ -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/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/runtests.jl b/test/runtests.jl index 73726b65c..e85af7104 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -6,12 +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 "TopoSeries" begin - include("test_toposeries.jl") +@testset "Butterfly" begin + include("test_butterfly.jl") end @testset "ERP Image" begin @@ -22,10 +23,18 @@ end include("test_topoplot.jl") end -@testset "Butterfly" begin - include("test_butterfly.jl") +@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 -@testset "All 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/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 1b786556e..1a5a0043b 100644 --- a/test/test_butterfly.jl +++ b/test/test_butterfly.jl @@ -1,13 +1,12 @@ +include("../docs/example_data.jl") +data, pos = example_data("TopoPlots.jl") + @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, @@ -17,5 +16,26 @@ end ) end +@testset "changing color from ROMA to gray" begin + plot_butterfly( + data; + positions = pos, + topopositions_to_color = x -> Colors.RGB(0.5) + ) +end +@testset "changing color from ROMA to HSV" begin + plot_butterfly( + data; + positions = pos, + topopositions_to_color=UnfoldMakie.posToColorHSV + ) +end +@testset "changing color from ROMA to RGB" begin + plot_butterfly( + data; + positions = pos, + topopositions_to_color = pos -> UnfoldMakie.posToColorRGB(pos) + ) +end diff --git a/test/test_all.jl b/test/test_complexplots.jl similarity index 83% rename from test/test_all.jl rename to test/test_complexplots.jl index 42e5637f0..b570e0d14 100644 --- a/test/test_all.jl +++ b/test/test_complexplots.jl @@ -39,11 +39,11 @@ 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]; - 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, @@ -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 = (; use_colorbar=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=(; 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]]) @@ -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,30 @@ end # if coefname not specified, line should be black coefname=["(Intercept)", "category: face"] ) - plot_erp!(f[2, 1:2], results, extra=(; - categoricalColor=false, - categoricalGroup=false, + plot_erp!(f[2, 1:2], results, + categorical_color=false, + categorical_group=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; categorical_color=false, categorical_group=true, mapping=(; y=:yhat, color=:continuous, group=:continuous), - extra=(; showLegend=true, - categoricalColor=false, - categoricalGroup=true), legend=(; nbanks=2), - layout=(; 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 + layout=(; show_legend=true, legend_position=:right)) + + 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)), :]; - positions=positions, predictor=:time, predictorBounds=[-0.3, 0.5]) - + positions=positions, predictor=:time, predictor_bounds=[-0.3, 0.5]) + f #save("test.png", f) -end - +end \ No newline at end of file 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 diff --git a/test/test_erp.jl b/test/test_erp.jl index 30273fcdc..f7549c9ee 100644 --- a/test/test_erp.jl +++ b/test/test_erp.jl @@ -19,6 +19,33 @@ end +@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 + 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 = false), + categorical_color = false, + categorical_group = true, + ) +end + @testset "basic with res_effects" begin data, evts = UnfoldSim.predef_eeg(; noiselevel = 12, return_epoched = true) data = reshape(data, (1, size(data)...)) @@ -40,10 +67,9 @@ end res_effects; mapping = (; y = :yhat, color = :continuous, group = :continuous), legend = (; nbanks = 2), - layout = (; legendPosition = :right), - showLegend = true, - categoricalColor = false, - categoricalGroup = true, + layout = (; legend_position = :right, show_legend = true), + categorical_color = false, + categorical_group = true, ) end @@ -62,11 +88,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 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 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_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 diff --git a/test/test_pp.jl b/test/test_pp.jl deleted file mode 100644 index 581e808e1..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=(; legendPosition=:bottom)) - f -end \ No newline at end of file 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)