Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

"8 plots -2" #101

Merged
merged 15 commits into from
Nov 30, 2023
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
Loading