Skip to content

Commit

Permalink
"8 plots -2" (#101)
Browse files Browse the repository at this point in the history
* revised topoplotseries and  test all

* erp image sorted in test_all

* first draft

* Update plot_channelimage.jl

* first successfull test

* upd to main

* channelimage in complex plot

* strange bug fix

* small inconsistency in tests

* reverse ERP image trials and sorted ERP image into combined plot

* more example_data

* del
  • Loading branch information
vladdez authored Nov 30, 2023
1 parent 6599355 commit acff4b9
Show file tree
Hide file tree
Showing 17 changed files with 171 additions and 152 deletions.
8 changes: 8 additions & 0 deletions docs/example_data.jl
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,14 @@ function example_data(example = "TopoPlots.jl")
end
df.time = range(-0.3, 0.5, step = 1 / 500)[Int.(df.time)]
return df, chanlocs
elseif example == "sort_data"
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)) *-1
dat_e = dat_e[1, :, :]
return dat_e, evts, times
else
error("unknown example data")
end
Expand Down
5 changes: 2 additions & 3 deletions docs/src/how_to/mult_vis_in_fig.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,8 @@ uf_deconv = example_data("UnfoldLinearModelContinuousTime")
uf = example_data("UnfoldLinearModel")
results = coeftable(uf)
uf_5chan = example_data("UnfoldLinearModelMultiChannel")
d_singletrial, _ = UnfoldSim.predef_eeg(; return_epoched=true)
times = -0.099609375:0.001953125:1.0
data, positions = TopoPlots.example_data()
dat_e, evts, times = example_data("sort_data")
nothing #hide
```
This section discusses how users can incorporate multiple plots into a single figure.
Expand Down Expand Up @@ -81,7 +80,7 @@ plot_erp!(f[2, 4:5], res_effects; categorical_color=false, categorical_group=tru
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_erpimage!(f[1, 4:5], times, dat_e; sortvalues=evts.Δlatency)
plot_circulareegtopoplot!(f[3:4, 4:5], d_topo[in.(d_topo.time, Ref(-0.3:0.1:0.5)), :];
positions=positions, predictor=:time, predictor_bounds=[-0.3, 0.5])
Expand Down
2 changes: 1 addition & 1 deletion docs/src/tutorials/erpimage.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ First, generate a data. Second, specify the necessary sorting parameter.
)
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))
evts.Δlatency = diff(vcat(evts.latency, 0)) *-1
dat_e = dat_e[1,:,:]
plot_erpimage(times, dat_e; sortvalues=evts.Δlatency)
Expand Down
3 changes: 3 additions & 0 deletions src/UnfoldMakie.jl
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ include("plot_erpimage.jl")
include("plot_parallelcoordinates.jl")
include("plot_circulareegtopoplot.jl")
include("plot_erpgrid.jl")
include("plot_channelimage.jl")

include("layout_helper.jl")
include("eeg_positions.jl")
Expand Down Expand Up @@ -71,6 +72,8 @@ export plot_topoplotseries
export plot_topoplotseries!
export plot_erpgrid
export plot_erpgrid!
export plot_channelimage
export plot_channelimage!

export to_positions
export nonnumeric # reexport from AoG
Expand Down
13 changes: 7 additions & 6 deletions src/docstringtemplate.jl
Original file line number Diff line number Diff line change
@@ -1,31 +1,32 @@
function _docstring(cfgsymb::Symbol)
function _docstring(cfg_symb::Symbol)
#pad = maximum(length(string(f)) for f in fieldnames(T))
cfg = PlotConfig(cfgsymb)
cfg = PlotConfig(cfg_symb)
fn = fieldnames(PlotConfig)
out = ""

visuallink = Dict(
:erp =>`Makie.lines`,
:butterfly =>`Makie.lines`,
:paracoord =>`Makie.lines`,
:erpgrid =>`Makie.lines`,
:designmat => `Makie.heatmap`,
:erpimage => `Makie.heatmap`,
:channelimage => `Makie.heatmap`,
:circeegtopo => `Topoplot.eeg_topoplot`,
:topoplot => `Topoplot.eeg_topoplot`,
:topoplotseries => `Topoplot.eeg_topoplot`
)
cbarstring = (cfgsymb == :erp || cfgsymb == :butterfly) ? "[`AlgebraOfGraphics.colobar!`](@ref)" : "[`Makie.Colorbar`](@ref)"
cbarstring = (cfg_symb == :erp || cfg_symb == :butterfly) ? "[`AlgebraOfGraphics.colobar!`](@ref)" : "[`Makie.Colorbar`](@ref)"
link = Dict(
:figure => "use `kwargs...` of [`Makie.Figure`](@ref)",
:axis => "use `kwargs...` of [`Makie.Axis`](@ref)",
:legend => "use `kwargs...` of [`Makie.Legend`](@ref)",
:colorbar => "use `kwargs...` of $cbarstring",
:visual => "use `kwargs...` of [`$(visuallink[cfgsymb])`](@ref)",
:visual => "use `kwargs...` of [`$(visuallink[cfg_symb])`](@ref)",

)
for k = 1:length(fn)
namedtpl = Base.getfield(cfg,fn[k])
namedtpl = Base.getfield(cfg, fn[k])
addlink = ""
try
addlink = "- *"*link[fn[k]]*"*"
Expand All @@ -36,7 +37,7 @@ function _docstring(cfgsymb::Symbol)

return """## Shared plot configuration options
The shared plot options can be used as follows:
`type=(; key=value,...))` - for example `plot_x(..., layout=(show_legend=true, legend_position=:right))`.
`type = (; key=value, ...))` - for example `plot_x(..., layout = (show_legend=true, legend_position=:right))`.
Multiple defaults will be cycled until match.
$(out)
Expand Down
60 changes: 60 additions & 0 deletions src/plot_channelimage.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
"""
plot_channelimage!(f::Union{GridPosition, GridLayout, Figure}, data::Matrix{<:Real}, position::Vector{Point{2,Float32}}, ch_names::Vector{String}; kwargs...)
plot_channelimage(data::Matrix{<:Real}, position::Vector{Point{2,Float32}}, ch_names::Vector{String}; kwargs...)
Channel image
## Arguments:
- `f::Union{GridPosition, GridLayout, Figure}`: Figure, GridLayout or GridPosition that the plot should be drawn into.
- `data::DataFrame`: DataFrame with data.
- `position` (Vector{Point{2,Float32}}): a vector with EEG layout coordinates.
- `ch_names` (Vector{String}): vector with channel names.
$(_docstring(:channelimage))
## Return Value:
A figure displaying channel image
"""

plot_channelimage(data::Matrix{<:Real}, position::Vector{Point{2,Float32}}, ch_names::Vector{String}; kwargs...) =
plot_channelimage!(Figure(), data, position, ch_names; kwargs...)

function plot_channelimage!(
f::Union{GridPosition,GridLayout,Figure},
data::Matrix{<:Real},
position::Vector{Point{2,Float32}},
ch_names::Vector{String};
kwargs...,
)
config = PlotConfig(:channelimage)
config_kwargs!(config; kwargs...)


x = [i[1] for i in position]
y = [i[2] for i in position]

x = round.(x; digits = 2)
y = Integer.(round.((y .- mean(y)) * 20)) * -1
x = Integer.(round.((x .- mean(x)) * 20))
d = zip(x, y, ch_names, 1:20)
a = sort!(DataFrame(d), [:2, :1], rev = [true, false])
b = a[!, :4]
c = a[!, :3]
c = [string(x) for x in c]

ix = range(-0.3, 1.2, length = size(data, 2))
iy = 1:20
iz = mean(data, dims = 3)[b, :, 1]'

gin = f[1, 1] = GridLayout()
ax = Axis(gin[1, 1], xlabel = config.axis.xlabel, ylabel = config.axis.ylabel)
hm = Makie.heatmap!(ix, iy, iz, colormap = config.visual.colormap)
ax.yticks = iy
ax.ytickformat = xc -> c
ax.yticklabelsize = config.axis.yticklabelsize

Makie.Colorbar(gin[1, 2], hm, label = config.colorbar.label, labelrotation = config.colorbar.labelrotation)
return f
end
3 changes: 2 additions & 1 deletion src/plot_circulareegtopoplot.jl
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
"""
plot_circulareegtopoplot(data::DataFrame; kwargs...)
plot_circulareegtopoplot!(f, data::DataFrame; kwargs...)
plot_circulareegtopoplot(data::DataFrame; kwargs...)
Plot a circular EEG topoplot.
## Arguments:
Expand Down
3 changes: 2 additions & 1 deletion src/plot_erpgrid.jl
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,9 @@ Plot an ERP image.
- `drawlabels` (bool, `false`): draw channels labels over each waveform.
- `times`: (Vector, `1:size(data, 2)`): vector of size().
## Return Value:
The input `f`
The figure displaying ERP grid
"""

# no figure?
Expand Down
3 changes: 1 addition & 2 deletions src/plot_erpimage.jl
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,7 @@ The input `f`
"""

# no times + no figure?
plot_erpimage(plot::Matrix{<:Real}; kwargs...) =
plot_erpimage!(Figure(), plot; kwargs...)
plot_erpimage(plot::Matrix{<:Real}; kwargs...) = plot_erpimage!(Figure(), plot; kwargs...)

# no times?
plot_erpimage!(f::Union{GridPosition,GridLayout,Figure}, plot::Matrix{<:Real}; kwargs...) =
Expand Down
2 changes: 1 addition & 1 deletion src/plot_topoplot.jl
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
"""
plot_topoplot!(f::Union{GridPosition, GridLayout, Figure}, data, ; positions=nothing, labels=nothing,kwargs...)
plot_topoplot(data,; positions=nothing, labels=nothing, kwargs...)
plot_topoplot(data; positions=nothing, labels=nothing, kwargs...)
Plot a topo plot.
## Arguments:
Expand Down
6 changes: 2 additions & 4 deletions src/plot_topoplotseries.jl
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
"""
plot_topoplotseries!(f::Union{GridPosition, GridLayout, Figure}, data::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
Expand Down Expand Up @@ -77,7 +77,6 @@ function plot_topoplotseries!(
f[1, end+1],
colormap = d.colormap,
colorrange = d.colorrange,
height = config.colorbar.height,
flipaxis = config.colorbar.flipaxis,
labelrotation = config.colorbar.labelrotation ,
label = config.colorbar.label,
Expand All @@ -89,7 +88,6 @@ function plot_topoplotseries!(
f[:, :][1, length(axlist)+1],
colormap = d.colormap,
colorrange = d.colorrange,
height = config.colorbar.height,
flipaxis = config.colorbar.flipaxis,
labelrotation = config.colorbar.labelrotation ,
label = config.colorbar.label,
Expand All @@ -98,4 +96,4 @@ function plot_topoplotseries!(
end
return f

end
end
59 changes: 31 additions & 28 deletions src/plotconfig.jl
Original file line number Diff line number Diff line change
Expand Up @@ -51,28 +51,31 @@ function PlotConfig()# defaults
tellheight = false,
),
)

end


"""
Takes a kwargs named tuple of Key => NamedTuple and merges the fields with the defaults
"""
function config_kwargs!(cfg::PlotConfig; kwargs...)
is_namedtuple = [isa(t,NamedTuple) for t in values(kwargs)]
is_namedtuple = [isa(t, NamedTuple) for t in values(kwargs)]
@debug is_namedtuple
@assert(all(is_namedtuple),
""" 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 = (; use_colorbar=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]
@assert(
all(is_namedtuple),
""" 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 = (; use_colorbar=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]
keyList = collect(keys(kwargs))
:extra keyList ? @warn("Extra is deprecated in 0.4 and extra-keyword args have to be used directly as key-word arguments") : ""
:extra keyList ?
@warn(
"Extra is deprecated in 0.4 and extra-keyword args have to be used directly as key-word arguments"
) : ""
applyTo = keyList[in.(keyList, Ref(list))]
for k applyTo
setfield!(cfg, k, merge(getfield(cfg, k), kwargs[k]))
Expand Down Expand Up @@ -105,13 +108,7 @@ end
function PlotConfig(T::Val{:topoarray})
cfg = PlotConfig(:erp)

config_kwargs!(
cfg;
layout = (;),
colorbar = (;),
mapping = (;),
axis = (;),
)
config_kwargs!(cfg; layout = (;), colorbar = (;), mapping = (;), axis = (;))
return cfg
end

Expand Down Expand Up @@ -151,12 +148,7 @@ function PlotConfig(T::Val{:topoplotseries})
config_kwargs!(
cfg,
layout = (use_colorbar = true,),
colorbar = (;
height = 300, # why even should i made it manually?
flipaxis = true,
labelrotation = 4.7,
label = "Voltage [µV]"
),
colorbar = (; flipaxis = true, labelrotation = -π / 2, label = "Voltage [µV]"),
visual = (;
label_text = false # true doesnt work again
),
Expand Down Expand Up @@ -196,12 +188,23 @@ function PlotConfig(T::Val{:erp})
config_kwargs!(
cfg;
mapping = (; color = (:color, :coefname, nothing)),
layout = (; show_legend = true, hidespines = (:r, :t)),
layout = (; show_legend = true, hidespines = (:r, :t)),
legend = (; framevisible = false),
)

return cfg
end
function PlotConfig(T::Val{:channelimage})
cfg = PlotConfig()
config_kwargs!(
cfg;
#layout = (; use_colorbar = true),
colorbar = (; label = "Voltage [µV]", labelrotation = 4.7),
axis = (xlabel = "Time [s]", ylabel = "Channels", yticklabelsize = 14),
visual = (; colormap = Reverse("RdBu")), #cork
)
return cfg
end
function PlotConfig(T::Val{:erpimage})
cfg = PlotConfig()
config_kwargs!(
Expand Down
6 changes: 5 additions & 1 deletion test/runtests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,14 @@ end
include("test_butterfly.jl")
end

@testset "ERP Image" begin
@testset "ERP image" begin
include("test_erpimage.jl")
end

@testset "Channel image" begin
include("test_channelimage.jl")
end

@testset "Topoplot" begin
include("test_topoplot.jl")
end
Expand Down
17 changes: 17 additions & 0 deletions test/test_channelimage.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
data, pos = TopoPlots.example_data()
data = data[:, :, 1]
pos = pos[1:30]
raw_ch_names = ["FP1", "F3", "F7", "FC3", "C3", "C5", "P3", "P7", "P9", "PO7",
"PO3", "O1", "Oz", "Pz", "CPz", "FP2", "Fz", "F4", "F8", "FC4", "FCz", "Cz",
"C4", "C6", "P4", "P8", "P10", "PO8", "PO4", "O2"]

@testset "channel image basic" begin
plot_channelimage(data, pos, raw_ch_names; )

end

@testset "channel image with Figure" begin
f = Figure()
plot_channelimage!(f, data, pos, raw_ch_names; )

end
Loading

0 comments on commit acff4b9

Please sign in to comment.