From ff058a3dc26d0d440476bcd71b1cadf44941c5f2 Mon Sep 17 00:00:00 2001 From: Vladimir Mikheev Date: Fri, 10 Jan 2025 19:37:45 +0100 Subject: [PATCH 1/4] citeation + issue 288 + horizontal colorbars --- CITATION.cff | 37 ++++++++++++++++++++++--------------- src/plot_topoplot.jl | 23 ++++++++++++++++------- src/supportive_defaults.jl | 2 +- test/test_topoplot.jl | 31 +++++++++++++++++++++++++++++++ 4 files changed, 70 insertions(+), 23 deletions(-) diff --git a/CITATION.cff b/CITATION.cff index b837f9203..67935c17c 100644 --- a/CITATION.cff +++ b/CITATION.cff @@ -1,14 +1,5 @@ -# This CITATION.cff file was generated with cffinit. -# Visit https://bit.ly/cffinit to generate yours today! - -cff-version: 1.2.1 -title: 'UnfoldMakie.jl: EEG/ERP visualization package' -message: 'If you use this page, please cite it as below.' -type: software -journal: 'Journal of Open Source Software' -volume : 10 -number: 105 -pages: 7560 +cff-version: 1.2.0 +message: "If you use this software, please cite it as below." authors: - given-names: Vladimir family-names: Mikheev @@ -16,9 +7,25 @@ authors: - given-names: Benedikt family-names: Ehinger orcid: 'https://orcid.org/0000-0002-6276-3332' -identifiers: - - type: doi - value: https://doi.org/10.21105/joss.07560 -repository-code: 'https://github.com/unfoldtoolbox/UnfoldMakie.jl' +title: 'UnfoldMakie.jl: EEG/ERP visualization package' version: 0.5.10 +doi: 10.21105/joss.07560 date-released: '2025-01-10' +url: 'https://github.com/unfoldtoolbox/UnfoldMakie.jl' +preferred-citation: + type: article + authors: + - given-names: Vladimir + family-names: Mikheev + orcid: 'https://orcid.org/0000-0002-4738-6655' + - given-names: Benedikt + family-names: Ehinger + orcid: 'https://orcid.org/0000-0002-6276-3332' + doi: 10.21105/joss.07560 + journal: 'Journal of Open Source Software' + month: 1 + title: 'UnfoldMakie.jl: EEG/ERP visualization package' + volume : 10 + number: 105 + pages: 7560 + year: 2025 \ No newline at end of file diff --git a/src/plot_topoplot.jl b/src/plot_topoplot.jl index 1a8e423de..1312e6622 100644 --- a/src/plot_topoplot.jl +++ b/src/plot_topoplot.jl @@ -56,7 +56,7 @@ function plot_topoplot!( config = PlotConfig(:topoplot) config_kwargs!(config; kwargs...) # potentially should be combined - outer_axis = Axis(f[1, 1]; config.axis...) + outer_axis = Axis(f[1:4, 1]; config.axis...) hidespines!(outer_axis) hidedecorations!(outer_axis, label = false) @@ -72,7 +72,7 @@ function plot_topoplot!( topo_attributes = update_axis(supportive_defaults(:topo_default_attributes); topo_attributes...) topo_axis = update_axis(supportive_defaults(:topo_default_single); topo_axis...) - inner_axis = Axis(f[1, 1]; topo_axis...) + inner_axis = Axis(f[1:4, 1]; topo_axis...) if isa(high_chan, Int) || isa(high_chan, Vector{Int64}) x = zeros(length(positions)) isa(high_chan, Int) ? x[high_chan] = 1 : x[high_chan] .= 1 @@ -100,10 +100,6 @@ function plot_topoplot!( ) end - - if config.layout.use_colorbar == true - Colorbar(f[:, 2]; colormap = config.visual.colormap, config.colorbar...) - end clims = @lift (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. @@ -111,7 +107,20 @@ 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)) else - config_kwargs!(config, colorbar = (; limits = clims)) + ticks = LinRange(clims[][1], clims[][2], 5) + rounded_ticks = round.(ticks, digits = 2) # Round to 2 decimal places + config_kwargs!( + config, + colorbar = (; ticks = (ticks, string.(rounded_ticks)), limits = clims), + ) + end + if config.layout.use_colorbar == true + if config.colorbar.vertical == true + Colorbar(f[1:4, 2]; colormap = config.visual.colormap, config.colorbar...) + else + config_kwargs!(config, colorbar = (; labelrotation = 2π, flipaxis = false)) + Colorbar(f[5, 1]; colormap = config.visual.colormap, config.colorbar...) + end end apply_layout_settings!(config; fig = f) return f diff --git a/src/supportive_defaults.jl b/src/supportive_defaults.jl index f15e2daa6..bf3b7efec 100644 --- a/src/supportive_defaults.jl +++ b/src/supportive_defaults.jl @@ -62,7 +62,7 @@ function supportive_defaults(cfg_symb::Symbol) height = Relative(1), halign = 0.05, valign = 0.95, - aspect = 1, + aspect = DataAspect(), ) elseif cfg_symb == :topo_default_attributes return (; interp_resolution = (128, 128), interpolation = CloughTocher()) diff --git a/test/test_topoplot.jl b/test/test_topoplot.jl index 31bb40a7c..48699c75a 100644 --- a/test/test_topoplot.jl +++ b/test/test_topoplot.jl @@ -104,3 +104,34 @@ end dat_obs[] = dat[:, 30, 1] plot_topoplot(dat_obs; positions = positions) end + + +@testset "topoplot: horizontal colorbar" begin + plot_topoplot( + dat[:, 50, 1]; + positions, + colorbar = (; vertical = false, width = 180, label = "Voltage estimate"), + axis = (; xlabel = "50 ms"), + ) +end + +@testset "topoplot: std errors" begin + f = Figure() + plot_topoplot!( + f[:, 1], + dat[:, 50, 1]; + positions, + colorbar = (; vertical = false, width = 180, label = "Voltage estimate"), + axis = (; xlabel = "50 ms"), + ) + plot_topoplot!( + f[:, 2], + dat[:, 50, 2]; + positions, + colorbar = (; vertical = false, width = 180, label = "Voltage uncertainty"), + axis = (; xlabel = "50 ms"), + visual = (; colormap = :viridis), + ) + colgap!(f.layout, 50) + f +end From c3dc6ab4138d4f4d3e872d7fa6070edd790b92ff Mon Sep 17 00:00:00 2001 From: Vladimir Mikheev Date: Mon, 13 Jan 2025 13:20:53 +0100 Subject: [PATCH 2/4] solving horiz colorbar --- docs/literate/tutorials/topoplot.jl | 10 ++++++++++ src/plot_topoplot.jl | 7 ++++--- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/docs/literate/tutorials/topoplot.jl b/docs/literate/tutorials/topoplot.jl index dc6002bd9..0f3626bb8 100644 --- a/docs/literate/tutorials/topoplot.jl +++ b/docs/literate/tutorials/topoplot.jl @@ -106,6 +106,16 @@ end # # Highlighting channels plot_topoplot(dat[:, 50, 1]; positions, high_chan = [1, 2]) + +# # Horizontal colorbars +# Just switch `colorbar.vertical` to `false` +plot_topoplot( + dat[:, 50, 1]; + positions, + axis = (; xlabel = "50 ms"), + colorbar = (; vertical = false, width = 180, label = "Voltage estimate"), +) + # # Configurations of Topoplot # ```@docs diff --git a/src/plot_topoplot.jl b/src/plot_topoplot.jl index 1312e6622..42c421186 100644 --- a/src/plot_topoplot.jl +++ b/src/plot_topoplot.jl @@ -56,7 +56,7 @@ function plot_topoplot!( config = PlotConfig(:topoplot) config_kwargs!(config; kwargs...) # potentially should be combined - outer_axis = Axis(f[1:4, 1]; config.axis...) + outer_axis = Axis(f[1:4, 1:2]; config.axis...) hidespines!(outer_axis) hidedecorations!(outer_axis, label = false) @@ -72,7 +72,8 @@ function plot_topoplot!( topo_attributes = update_axis(supportive_defaults(:topo_default_attributes); topo_attributes...) topo_axis = update_axis(supportive_defaults(:topo_default_single); topo_axis...) - inner_axis = Axis(f[1:4, 1]; topo_axis...) + inner_axis = Axis(f[1:4, 1:2]; topo_axis...) + if isa(high_chan, Int) || isa(high_chan, Vector{Int64}) x = zeros(length(positions)) isa(high_chan, Int) ? x[high_chan] = 1 : x[high_chan] .= 1 @@ -119,7 +120,7 @@ Note: The identical min and max may cause an interpolation error when plotting t Colorbar(f[1:4, 2]; colormap = config.visual.colormap, config.colorbar...) else config_kwargs!(config, colorbar = (; labelrotation = 2π, flipaxis = false)) - Colorbar(f[5, 1]; colormap = config.visual.colormap, config.colorbar...) + Colorbar(f[5, 1:2]; colormap = config.visual.colormap, config.colorbar...) end end apply_layout_settings!(config; fig = f) From 74cea3c6a5e8d11a645b105612059a62731d2514 Mon Sep 17 00:00:00 2001 From: Vladimir Mikheev Date: Mon, 13 Jan 2025 13:53:16 +0100 Subject: [PATCH 3/4] applying Linrange for ticks in erpimage --- src/plot_erpimage.jl | 20 +++++++++----------- test/test_topoplot.jl | 2 +- 2 files changed, 10 insertions(+), 12 deletions(-) diff --git a/src/plot_erpimage.jl b/src/plot_erpimage.jl index 9278e0753..bf8b9d73f 100644 --- a/src/plot_erpimage.jl +++ b/src/plot_erpimage.jl @@ -93,13 +93,8 @@ function plot_erpimage!( !isnothing(to_value(sortindex)) ? @assert(to_value(sortindex) isa Vector{Int}) : "" ax = Axis(ga[1:4, 1:4]; config.axis...) - ax.yticks = [ - 1, - size(to_value(data), 2) ÷ 4, - size(to_value(data), 2) ÷ 2, - size(to_value(data), 2) - (size(to_value(data), 2) ÷ 4), - size(to_value(data), 2), - ] + ax.yticks = LinRange(1, size(to_value(data), 2), 5) + ax.yticklabelsvisible = true sortindex = sortindex_management(sortindex, sortvalues, data) filtered_data = @lift( @@ -138,10 +133,14 @@ function ei_meanplot(ax, data, config, f, ga, times, meanplot_axis) trace = @lift(mean($data, dims = 2)[:, 1]) meanplot_axis = update_axis(supportive_defaults(:meanplot_default); meanplot_axis...) + xticks = @lift(round.(LinRange(minimum($times), maximum($times), 5), digits = 2)) + yticks = @lift(round.(LinRange(minimum($trace), maximum($trace), 5), digits = 1)) axbottom = Axis( ga[5, 1:4]; ylabel = config.colorbar.label === nothing ? "" : config.colorbar.label, + xticks = xticks, + yticks = yticks, limits = @lift(( minimum($times), maximum($times), @@ -172,10 +171,9 @@ function ei_sortvalue(sortvalues, f, ax, hm, config, sortval_xlabel, sortplot_ax axleft = Axis( gb[1:4, 1:5]; xlabel = sortval_xlabel, - xticks = @lift([ - round(minimum($sortvalues), digits = 2), - round(maximum($sortvalues), digits = 2), - ]), + xticks = @lift( + round.(LinRange(minimum($sortvalues), maximum($sortvalues), 2), digits = 2) + ), limits = @lift(( minimum($sortvalues) - (maximum($sortvalues) / 100 * 3), maximum($sortvalues) + (maximum($sortvalues) / 100 * 3), diff --git a/test/test_topoplot.jl b/test/test_topoplot.jl index 48699c75a..8477b2562 100644 --- a/test/test_topoplot.jl +++ b/test/test_topoplot.jl @@ -132,6 +132,6 @@ end axis = (; xlabel = "50 ms"), visual = (; colormap = :viridis), ) - colgap!(f.layout, 50) + colgap!(f.layout, 0) f end From 42813648307df0dc5ee81a4f04d69260b7fa31de Mon Sep 17 00:00:00 2001 From: Vladimir Mikheev Date: Mon, 13 Jan 2025 14:35:01 +0100 Subject: [PATCH 4/4] workaround for 251 --- docs/literate/intro/speed.jl | 1 + src/eeg_series.jl | 2 +- src/plot_erpimage.jl | 2 +- src/plot_topoplot.jl | 2 +- src/plot_topoplotseries.jl | 2 +- src/supportive_defaults.jl | 8 ++++++-- 6 files changed, 11 insertions(+), 6 deletions(-) diff --git a/docs/literate/intro/speed.jl b/docs/literate/intro/speed.jl index beef46b56..a23740439 100644 --- a/docs/literate/intro/speed.jl +++ b/docs/literate/intro/speed.jl @@ -106,6 +106,7 @@ end # ![](topoplot_animation_UM.gif) # MNE with .gif +# Note that due to some bugs in (probably) `CondaPkg` topoplot is blac and white. @benchmark begin fig, anim = simulated_epochs.animate_topomap( times = Py(timestamps), diff --git a/src/eeg_series.jl b/src/eeg_series.jl index cd509af36..ce6750a74 100644 --- a/src/eeg_series.jl +++ b/src/eeg_series.jl @@ -31,7 +31,7 @@ The function takes the `combinefun = mean` over the `:time` column of `data`. - `topo_attributes::NamedTuple = (;)`\\ Here you can flexibly change configurations of the topoplot interoplation.\\ To see all options just type `?Topoplot.topoplot` in REPL.\\ - Defaults: $(supportive_defaults(:topo_default_attributes)). + Defaults: $(replace(string(supportive_defaults(:topo_default_attributes; docstring = true)), "_" => "\\_")). - `positions::Vector{Point{2, Float32}}`\\ Channel positions. The list of x and y positions for all unique electrodes. diff --git a/src/plot_erpimage.jl b/src/plot_erpimage.jl index bf8b9d73f..99b62868f 100644 --- a/src/plot_erpimage.jl +++ b/src/plot_erpimage.jl @@ -12,7 +12,7 @@ Plot an ERP image. `Figure`, `GridLayout`, or `GridPosition` to draw the plot. - `data::Union{DataFrame, Vector{Float32}}`\\ Data for the plot visualization. - + ## Keyword arguments (kwargs) - `erpblur::Number = 10`\\ Number indicating how much blur is applied to the image. \\ diff --git a/src/plot_topoplot.jl b/src/plot_topoplot.jl index 42c421186..2fe295e16 100644 --- a/src/plot_topoplot.jl +++ b/src/plot_topoplot.jl @@ -22,7 +22,7 @@ Plot a topoplot. - `topo_attributes::NamedTuple = (;)`\\ Here you can flexibly change configurations of the topoplot interoplation.\\ To see all options just type `?Topoplot.topoplot` in REPL.\\ - Defaults: $(supportive_defaults(:topo_default_attributes)) + Defaults: $(replace(string(supportive_defaults(:topo_default_attributes; docstring = true)), "_" => "\\_")) $(_docstring(:topoplot)) **Return Value:** `Figure` displaying the Topoplot. diff --git a/src/plot_topoplotseries.jl b/src/plot_topoplotseries.jl index 1fb471d37..6ca7a83a0 100644 --- a/src/plot_topoplotseries.jl +++ b/src/plot_topoplotseries.jl @@ -47,7 +47,7 @@ Multiple miniature topoplots in regular distances. - `topo_attributes::NamedTuple = (;)`\\ Here you can flexibly change configurations of the topoplot interoplation.\\ To see all options just type `?Topoplot.topoplot` in REPL.\\ - Defaults: $(supportive_defaults(:topo_default_attributes)) + Defaults: $(replace(string(supportive_defaults(:topo_default_attributes; docstring = true)), "_" => "\\_")) $(_docstring(:topoplotseries)) diff --git a/src/supportive_defaults.jl b/src/supportive_defaults.jl index bf3b7efec..6e63bdefe 100644 --- a/src/supportive_defaults.jl +++ b/src/supportive_defaults.jl @@ -8,7 +8,7 @@ Such supporting axes allow users to flexibly see defaults in docstrings and mani For developers: to make them updateable in the function, use `update_axis`. **Return value:** `NamedTuple`. """ -function supportive_defaults(cfg_symb::Symbol) +function supportive_defaults(cfg_symb::Symbol; docstring = false) # plot_splines if cfg_symb == :spline_default return (; @@ -65,7 +65,11 @@ function supportive_defaults(cfg_symb::Symbol) aspect = DataAspect(), ) elseif cfg_symb == :topo_default_attributes - return (; interp_resolution = (128, 128), interpolation = CloughTocher()) + if docstring == false + return (; interp_resolution = (128, 128), interpolation = CloughTocher()) + else + return string("interp_resolution = (128, 128), interpolation = CloughTocher()") + end # plot_topoplotseries elseif cfg_symb == :topo_default_series return (;