From 1bda154bc0e666962a54a30d54a3469d99ee5814 Mon Sep 17 00:00:00 2001 From: "behinger (s-ccs 001)" Date: Tue, 17 Sep 2024 14:57:02 +0000 Subject: [PATCH 01/13] fix labels, fix #39 --- .gitignore | 1 + docs/src/eeg.md | 6 +++--- src/TopoPlots.jl | 4 ++-- src/eeg.jl | 48 +++++++++++++++++++++++++++++++++--------------- 4 files changed, 39 insertions(+), 20 deletions(-) diff --git a/.gitignore b/.gitignore index f85cbbe..81a331a 100644 --- a/.gitignore +++ b/.gitignore @@ -6,4 +6,5 @@ test/test_images test/Manifest.toml docs/Manifest.toml +docs/.CondaPkg deps/build.log diff --git a/docs/src/eeg.md b/docs/src/eeg.md index 44ab292..baaba71 100644 --- a/docs/src/eeg.md +++ b/docs/src/eeg.md @@ -9,12 +9,12 @@ TopoPlots.eeg_topoplot -So for the standard 10/20 montage, one can drop the `positions` attribute: +For the standard 10/20 montage, one can drop the `positions` attribute: ```@example 1 using TopoPlots, CairoMakie labels = TopoPlots.CHANNELS_10_20 -TopoPlots.eeg_topoplot(rand(19), labels; axis=(aspect=DataAspect(),), label_text=true, label_scatter=(markersize=10, strokewidth=2,)) +TopoPlots.eeg_topoplot(rand(19); labels=labels, axis=(aspect=DataAspect(),), label_text=true, label_scatter=(markersize=10, strokewidth=2,)) ``` If the channels aren't 10/20, one can still plot them, but then the positions need to be passed as well: @@ -22,7 +22,7 @@ If the channels aren't 10/20, one can still plot them, but then the positions ne ```@example 1 data, positions = TopoPlots.example_data() labels = ["s$i" for i in 1:size(data, 1)] -TopoPlots.eeg_topoplot(data[:, 340, 1], labels; positions=positions, axis=(aspect=DataAspect(),)) +TopoPlots.eeg_topoplot(data[:, 340, 1]; labels = labels, label_text = true, positions=positions, axis=(aspect=DataAspect(),)) ``` ```@docs diff --git a/src/TopoPlots.jl b/src/TopoPlots.jl index 10085fd..45efce5 100644 --- a/src/TopoPlots.jl +++ b/src/TopoPlots.jl @@ -63,8 +63,8 @@ export GeomExtrapolation, NullExtrapolation @compile_workload begin # all calls in this block will be precompiled, regardless of whether # they belong to your package or not (on Julia 1.8 and higher) - eeg_topoplot(view(data, :, 340, 1); positions) - eeg_topoplot(data[:, 340, 1]; positions) + eeg_topoplot(view(data, :, 340, 1); positions) + eeg_topoplot(data[:, 340, 1]; positions) end end diff --git a/src/eeg.jl b/src/eeg.jl index 9dd8752..b9f60a5 100644 --- a/src/eeg.jl +++ b/src/eeg.jl @@ -1,12 +1,13 @@ -@recipe(EEG_TopoPlot, data, labels) do scene +@recipe(EEG_TopoPlot, data) do scene return Attributes(; - head = (color=:black, linewidth=3), + head=(color=:black, linewidth=3), + labels=Makie.automatic, positions = Makie.automatic, # overwrite some topoplot defaults default_theme(scene, TopoPlot)..., - label_scatter = true, - contours = true, + label_scatter=true, + contours=true, ) end @@ -16,7 +17,7 @@ end Attributes: * `positions::Vector{<: Point} = Makie.automatic`: Can be calculated from label (channel) names. Currently, only 10/20 montage has default coordinates provided. - +* `labels::Vector{<: String} = Makie.automatic`: Add custom labels, in case `label_text` is set to true. If `positions` is not specified, `labels` are used to look up the 10/20 coordinates. * `head = (color=:black, linewidth=3)`: draw the outline of the head. Set to nothing to not draw the head outline, otherwise set to a namedtuple that get passed down to the `line!` call that draws the shape. # Some attributes from topoplot are set to different defaults: * `label_scatter = true` @@ -33,15 +34,18 @@ function draw_ear_nose!(parent, circle; kw...) diameter = 2GeometryBasics.radius(circle) middle = GeometryBasics.origin(circle) nose = (Point2f[(-0.05, 0.5), (0.0, 0.55), (0.05, 0.5)] .* diameter) .+ (middle,) - push!(points, Point2f(NaN)); append!(points, nose) + push!(points, Point2f(NaN)) + append!(points, nose) ear = (Point2f[ (0.497, 0.0555), (0.51, 0.0775), (0.518, 0.0783), (0.5299, 0.0746), (0.5419, 0.0555), (0.54, -0.0055), (0.547, -0.0932), (0.532, -0.1313), (0.51, -0.1384), (0.489, -0.1199)] .* diameter) - push!(points, Point2f(NaN)); append!(points, ear .+ middle) - push!(points, Point2f(NaN)); append!(points, (ear .* Point2f(-1, 1)) .+ (middle,)) + push!(points, Point2f(NaN)) + append!(points, ear .+ middle) + push!(points, Point2f(NaN)) + append!(points, (ear .* Point2f(-1, 1)) .+ (middle,)) return points end @@ -57,7 +61,7 @@ const CHANNEL_TO_POSITION_10_20 = begin result = Matrix{Float64}(undef, 19, 2) read!(assetpath("layout_10_20.bin"), result) positions = Point2f.(result[:, 1], result[:, 2]) - Dict{String, Point2f}(zip(CHANNELS_10_20, positions)) + Dict{String,Point2f}(zip(CHANNELS_10_20, positions)) end """ @@ -70,26 +74,40 @@ function labels2positions(labels) if haskey(CHANNEL_TO_POSITION_10_20, key) return CHANNEL_TO_POSITION_10_20[key] else - error("Currently only 10_20 is supported. Found: $(label)") + error("Currently only 10_20 is supported. Found label: $(label)") end end end -function Makie.convert_arguments(::Type{<:EEG_TopoPlot}, data::AbstractVector{<: Real}) - return (data, ["sensor $i" for i in 1:length(data)]) -end +#function Makie.convert_arguments(::Type{<:EEG_TopoPlot}, data::AbstractVector{<:Real}) +# return (data, labels2positions(labels))# + + # +#end function Makie.plot!(plot::EEG_TopoPlot) + positions = lift(plot.labels, plot.positions) do labels, positions + if positions isa Makie.Automatic + @assert !isnothing(labels) && labels != Makie.Automatic "Either positions or labels (10/20-lookup) have to be specified" return labels2positions(labels) else # apply same conversion as for e.g. the scatter arguments return convert_arguments(Makie.PointBased(), positions)[1] end end - - tplot = topoplot!(plot, Attributes(plot), plot.data, positions; labels=plot.labels) + labels = lift(plot.labels, plot.positions) do labels, positions + + if isnothing(labels) || labels isa Makie.Automatic + return ["sensor $i" for i in 1:length(positions)] + else + return labels + end + end + plot.labels = labels + + tplot = topoplot!(plot, Attributes(plot), plot.data, positions;) head = plot_or_defaults(to_value(plot.head), Attributes(), :head) if !isnothing(head) draw_ear_nose!(plot, tplot.geometry; head...) From 3ecdeac628b37951de297a28881bf87dc3b2830f Mon Sep 17 00:00:00 2001 From: "behinger (s-ccs 001)" Date: Wed, 18 Sep 2024 14:08:59 +0000 Subject: [PATCH 02/13] added a backward compatability with warning --- src/eeg.jl | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/eeg.jl b/src/eeg.jl index b9f60a5..d6e2808 100644 --- a/src/eeg.jl +++ b/src/eeg.jl @@ -26,7 +26,15 @@ Attributes: Otherwise the recipe just uses the [`topoplot`](@ref) defaults and passes through the attributes. """ eeg_topoplot - + function eeg_topoplot(data,labels;kwargs...) + @warn "labels as positional arguments have been deprecated. Please provide them as keyword arguments" + eeg_topoplot(data;labels=labels,kwargs...) + end + function eeg_topoplot!(fig, data,labels;kwargs...) + @warn "labels as positional arguments have been deprecated. Please provide them as keyword arguments" + eeg_topoplot!(fig,data;labels=labels,kwargs...) + end + function draw_ear_nose!(parent, circle; kw...) # draw circle head_points = lift(circle) do circle From b8a74c0fa482e0928255266d56a911b188e3cf78 Mon Sep 17 00:00:00 2001 From: "behinger (s-ccs 001)" Date: Wed, 18 Sep 2024 14:18:03 +0000 Subject: [PATCH 03/13] removed NaturalNeighbours for now until #55 is fixed --- docs/src/general.md | 4 +- docs/src/topo_series.jl | 180 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 182 insertions(+), 2 deletions(-) create mode 100644 docs/src/topo_series.jl diff --git a/docs/src/general.md b/docs/src/general.md index 1748d0b..c2d5b60 100644 --- a/docs/src/general.md +++ b/docs/src/general.md @@ -42,13 +42,13 @@ using TopoPlots, CairoMakie, ScatteredInterpolation, NaturalNeighbours data, positions = TopoPlots.example_data() -f = Figure(resolution=(1000, 1250)) +f = Figure(size=(1000, 1250)) interpolators = [ DelaunayMesh() CloughTocher(); SplineInterpolator() NullInterpolator(); ScatteredInterpolationMethod(ThinPlate()) ScatteredInterpolationMethod(Shepard(3)); - NaturalNeighboursMethod(Sibson(1)) NaturalNeighboursMethod(Triangle()); + #NaturalNeighboursMethod(Sibson(1)) NaturalNeighboursMethod(Triangle()); ] data_slice = data[:, 360, 1] diff --git a/docs/src/topo_series.jl b/docs/src/topo_series.jl new file mode 100644 index 0000000..0f841aa --- /dev/null +++ b/docs/src/topo_series.jl @@ -0,0 +1,180 @@ +### A Pluto.jl notebook ### +# v0.19.9 + +using Markdown +using InteractiveUtils + +# ╔═╡ 2fafb0da-f3a9-11ec-0ddf-6725344070fe +begin +using Pkg +Pkg.activate("../../devEnv") # docs +#Pkg.add("PyMNE") +#Pkg.add(path="../../../TopoPlotsjl/") +Pkg.develop(path="../../../TopoPlotsjl/") +#Pkg.add("DataFrames") +#Pkg.add("AlgebraOfGraphics") + #Pkg.add("StatsBase") + #Pkg.add("CategoricalArrays") + + #Pkg.add("JLD2") + + #Pkg.add("CairoMakie") +end + +# ╔═╡ c4a25915-c7f5-453a-a4f0-4b40ebedea4c +using Revise + +# ╔═╡ 59b87673-02d2-4deb-90be-74d923d170eb + using TopoPlots + + +# ╔═╡ 452a245c-773a-4303-a970-f2592c3e879f +begin + #using TopoPlots + #using ../../../Topoplotsjl + using CairoMakie + using DataFrames + + +end + + +# ╔═╡ 77dc1ba9-9484-485b-a49d-9aa231ef4983 +using Statistics + +# ╔═╡ 311f10ff-deb8-4f82-8b12-d5b643656828 +using PyMNE + +# ╔═╡ 9fa5c598-3578-4989-9585-29fd32ae1056 +using Distributions + +# ╔═╡ 6cda29dc-7086-4079-83c6-3650204a82ff +pathof(TopoPlots) + +# ╔═╡ e0cc560f-d3e8-415b-b22d-6bca23ef093c +revise(TopoPlots) + +# ╔═╡ f4b81740-d907-42ae-a0df-f46fb2f2cb15 +begin + +data = Array{Float32}(undef, 64, 400, 3) +#read!(TopoPlots.assetpath("example-data.bin"), data) + read!(splitdir(pathof(TopoPlots))[1]*"/../assets/example-data.bin",data) + +positions = Vector{Point2f}(undef, 64) + read!(splitdir(pathof(TopoPlots))[1]*"/../assets/layout64.bin",positions) +#read!(TopoPlots.assetpath("layout64.bin"), positions) + +end; + + +# ╔═╡ 42f7755b-80f4-4185-8d21-42e11730e0fc +begin + using Random + pos = positions[1:10] +eeg_topoplot(rand(MersenneTwister(1),length(pos)), string.(1:length(pos));positions=pos,pad_value=0.) +end + +# ╔═╡ aad784ee-6bb7-4f3c-8444-be050456ddea +eeg_topoplot(data[:, 340, 1], string.(1:length(positions));positions=positions) + +# ╔═╡ 237e4f4a-cdf2-4bac-8096-de8050251745 +eeg_topoplot(data[:, 340, 1], string.(1:length(positions));positions=positions,pad_value=0.1) + +# ╔═╡ f522329b-3653-4059-9955-8cd05570e923 +topoplot(rand(MersenneTwister(1),length(pos)),pos) + +# ╔═╡ a9d2a2e2-6c8c-4cfc-9fed-b5e082cb44af +let +mon = PyMNE.channels.make_standard_montage("standard_1020") + +posMat = (Matrix(hcat(pos...)).-0.5).*0.5 + #pos = PyMNE.channels.make_eeg_layout(mon).pos +PyMNE.viz.plot_topomap(rand(MersenneTwister(1),length(pos)),posMat',cmap="RdBu_r",extrapolate="box",border=-1) +end + +# ╔═╡ c358633f-8d18-4c5e-80f7-ab972e8860be +Pkg.status("TopoPlots") + +# ╔═╡ c0a2ad2e-ccce-4e80-b52c-75f1428ed182 +e1eg_topoplot(data[:, 340, 1], string.(1:length(positions));positions=positions,interpolation = TopoPlots.NormalMixtureInterpolator() ) + +# ╔═╡ d7620a42-d54c-4244-a820-d15aecdae626 +@time TopoPlots.eeg_topoplot_series(data[:,:,1],40;topoplotCfg=(positions=positions,label_scatter=false)) + +# ╔═╡ ec59c704-ae33-4a62-82ce-63acc6b17793 +f, ax, pl = TopoPlots.eeg_topoplot(1:length(TopoPlots.CHANNELS_10_20),TopoPlots.CHANNELS_10_20; interpolation=TopoPlots.NullInterpolator(),) + +# ╔═╡ f3d1f3cc-f7c9-4ef4-ba4f-3d32f2509cad +let + # 4 coordinates with one peak + positions = Point2f[(-1, 0), (0, -1), (1, 0), (0, 1)] + i = 1 + peak_xy = positions[i] + data = zeros(length(positions)) + data[i] = 1.1 + fig = topoplot(data, positions) + # tighten the limits so that the limits of the axis and the data will match + tightlimits!(fig.axis) + + # retrieve the interpolated data + m = fig.plot.plots[].color[] + # get the limits of the axes and data + rect = fig.axis.targetlimits[] + minx, miny = minimum(rect) + maxx, maxy = maximum(rect) + # recreate the coordinates of the data + x = range(minx, maxx, length=size(m, 1)) + y = range(miny, maxy, length=size(m, 2)) + xys = Point2f.(x, y') + + # find the highest point + _, i = findmax(x -> isnan(x) ? -Inf : x, m) + xy = xys[i] + @show peak_xy + @show xy + #@test isapprox(xy, peak_xy; atol=0.02) + @show isapprox(xy, peak_xy; atol=0.02) + fig +end + +# ╔═╡ 872ac6a4-ddaa-4dfb-a40d-9d5ea55bdb3d +let + f = Figure() + axis = Axis(f[1, 1], aspect = 1) + xlims!(low = -2, high = 2) + ylims!(low = -2, high = 2) + + data = [0, 0, 0] + pos1 = [Point2f(-1, -1), Point2f(-1.0, 0.0), Point2f(0, -1)] + pos2 = [Point2f(1, 1), Point2f(1.0, 0.0), Point2f(0, 1)] + + pos1 = pos1 .- mean(pos1) + pos2 = pos2 .- mean(pos2) + eeg_topoplot!(axis, data, positions=pos1) + eeg_topoplot!(axis, data, positions=pos2) + f +end + +# ╔═╡ Cell order: +# ╠═2fafb0da-f3a9-11ec-0ddf-6725344070fe +# ╠═6cda29dc-7086-4079-83c6-3650204a82ff +# ╠═c4a25915-c7f5-453a-a4f0-4b40ebedea4c +# ╠═e0cc560f-d3e8-415b-b22d-6bca23ef093c +# ╠═59b87673-02d2-4deb-90be-74d923d170eb +# ╠═452a245c-773a-4303-a970-f2592c3e879f +# ╠═f4b81740-d907-42ae-a0df-f46fb2f2cb15 +# ╠═77dc1ba9-9484-485b-a49d-9aa231ef4983 +# ╠═aad784ee-6bb7-4f3c-8444-be050456ddea +# ╠═237e4f4a-cdf2-4bac-8096-de8050251745 +# ╠═42f7755b-80f4-4185-8d21-42e11730e0fc +# ╠═f522329b-3653-4059-9955-8cd05570e923 +# ╠═311f10ff-deb8-4f82-8b12-d5b643656828 +# ╠═a9d2a2e2-6c8c-4cfc-9fed-b5e082cb44af +# ╠═c358633f-8d18-4c5e-80f7-ab972e8860be +# ╠═9fa5c598-3578-4989-9585-29fd32ae1056 +# ╠═c0a2ad2e-ccce-4e80-b52c-75f1428ed182 +# ╠═d7620a42-d54c-4244-a820-d15aecdae626 +# ╠═ec59c704-ae33-4a62-82ce-63acc6b17793 +# ╠═f3d1f3cc-f7c9-4ef4-ba4f-3d32f2509cad +# ╠═872ac6a4-ddaa-4dfb-a40d-9d5ea55bdb3d From 2cc6445c287bd0aa4045308b3112506977cefd2c Mon Sep 17 00:00:00 2001 From: Phillip Alday Date: Mon, 30 Sep 2024 10:04:32 -0500 Subject: [PATCH 04/13] undo indent change --- src/TopoPlots.jl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/TopoPlots.jl b/src/TopoPlots.jl index 45efce5..10085fd 100644 --- a/src/TopoPlots.jl +++ b/src/TopoPlots.jl @@ -63,8 +63,8 @@ export GeomExtrapolation, NullExtrapolation @compile_workload begin # all calls in this block will be precompiled, regardless of whether # they belong to your package or not (on Julia 1.8 and higher) - eeg_topoplot(view(data, :, 340, 1); positions) - eeg_topoplot(data[:, 340, 1]; positions) + eeg_topoplot(view(data, :, 340, 1); positions) + eeg_topoplot(data[:, 340, 1]; positions) end end From 0f0be95d921628dd5bee16e40f4bd2da74355827 Mon Sep 17 00:00:00 2001 From: Benedikt Ehinger Date: Thu, 24 Oct 2024 13:15:02 +0200 Subject: [PATCH 05/13] Apply suggestions from code review Co-authored-by: Phillip Alday --- docs/src/eeg.md | 4 ++-- src/eeg.jl | 8 +++++--- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/docs/src/eeg.md b/docs/src/eeg.md index baaba71..a948da4 100644 --- a/docs/src/eeg.md +++ b/docs/src/eeg.md @@ -14,7 +14,7 @@ For the standard 10/20 montage, one can drop the `positions` attribute: using TopoPlots, CairoMakie labels = TopoPlots.CHANNELS_10_20 -TopoPlots.eeg_topoplot(rand(19); labels=labels, axis=(aspect=DataAspect(),), label_text=true, label_scatter=(markersize=10, strokewidth=2,)) +TopoPlots.eeg_topoplot(rand(19); labels, axis=(aspect=DataAspect(),), label_text=true, label_scatter=(markersize=10, strokewidth=2,)) ``` If the channels aren't 10/20, one can still plot them, but then the positions need to be passed as well: @@ -22,7 +22,7 @@ If the channels aren't 10/20, one can still plot them, but then the positions ne ```@example 1 data, positions = TopoPlots.example_data() labels = ["s$i" for i in 1:size(data, 1)] -TopoPlots.eeg_topoplot(data[:, 340, 1]; labels = labels, label_text = true, positions=positions, axis=(aspect=DataAspect(),)) +TopoPlots.eeg_topoplot(data[:, 340, 1]; labels, label_text = true, positions=positions, axis=(aspect=DataAspect(),)) ``` ```@docs diff --git a/src/eeg.jl b/src/eeg.jl index d6e2808..7e99d40 100644 --- a/src/eeg.jl +++ b/src/eeg.jl @@ -17,7 +17,7 @@ end Attributes: * `positions::Vector{<: Point} = Makie.automatic`: Can be calculated from label (channel) names. Currently, only 10/20 montage has default coordinates provided. -* `labels::Vector{<: String} = Makie.automatic`: Add custom labels, in case `label_text` is set to true. If `positions` is not specified, `labels` are used to look up the 10/20 coordinates. +* `labels::AbstractVector{<:AbstractString} = Makie.automatic`: Add custom labels, in case `label_text` is set to true. If `positions` is not specified, `labels` are used to look up the 10/20 coordinates. * `head = (color=:black, linewidth=3)`: draw the outline of the head. Set to nothing to not draw the head outline, otherwise set to a namedtuple that get passed down to the `line!` call that draws the shape. # Some attributes from topoplot are set to different defaults: * `label_scatter = true` @@ -82,7 +82,8 @@ function labels2positions(labels) if haskey(CHANNEL_TO_POSITION_10_20, key) return CHANNEL_TO_POSITION_10_20[key] else - error("Currently only 10_20 is supported. Found label: $(label)") + error("Currently only 10/20 is supported. Found label: $(label)") + end end end @@ -98,7 +99,8 @@ function Makie.plot!(plot::EEG_TopoPlot) positions = lift(plot.labels, plot.positions) do labels, positions if positions isa Makie.Automatic - @assert !isnothing(labels) && labels != Makie.Automatic "Either positions or labels (10/20-lookup) have to be specified" + (!isnothing(labels) && labels != Makie.Automatic) || error("Either positions or labels (10/20-lookup) have to be specified") + return labels2positions(labels) else # apply same conversion as for e.g. the scatter arguments From 9a3211e20e1b5f7a52619f47a2f1642b09c2ba6d Mon Sep 17 00:00:00 2001 From: "behinger (s-ccs 001)" Date: Thu, 24 Oct 2024 13:33:52 +0200 Subject: [PATCH 06/13] fix code-review issues --- Project.toml | 2 +- src/eeg.jl | 11 +++-------- test/runtests.jl | 5 +++++ 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/Project.toml b/Project.toml index 284f29a..536bb12 100644 --- a/Project.toml +++ b/Project.toml @@ -1,7 +1,7 @@ name = "TopoPlots" uuid = "2bdbdf9c-dbd8-403f-947b-1a4e0dd41a7a" authors = ["Benedikt Ehinger", "Simon Danisch", "Beacon Biosignals, Inc."] -version = "0.1.9" +version = "0.2.0-DEV" [deps] CloughTocher2DInterpolation = "b70b374f-000b-463f-88dc-37030f004bd0" diff --git a/src/eeg.jl b/src/eeg.jl index 7e99d40..14106c9 100644 --- a/src/eeg.jl +++ b/src/eeg.jl @@ -26,14 +26,9 @@ Attributes: Otherwise the recipe just uses the [`topoplot`](@ref) defaults and passes through the attributes. """ eeg_topoplot - function eeg_topoplot(data,labels;kwargs...) - @warn "labels as positional arguments have been deprecated. Please provide them as keyword arguments" - eeg_topoplot(data;labels=labels,kwargs...) - end - function eeg_topoplot!(fig, data,labels;kwargs...) - @warn "labels as positional arguments have been deprecated. Please provide them as keyword arguments" - eeg_topoplot!(fig,data;labels=labels,kwargs...) - end + +@deprecate eeg_topoplot(data::AbstractVector{<:Real}, labels::Vector{<:AbstractString}) eeg_topoplot(data; labels) +@deprecate eeg_topoplot!(fig, data::AbstractVector{<:Real}, labels::Vector{<:AbstractString}) eeg_topoplot!(fig, data; labels) function draw_ear_nose!(parent, circle; kw...) # draw circle diff --git a/test/runtests.jl b/test/runtests.jl index f5de00e..4142a00 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -183,3 +183,8 @@ begin lines!(ax, rect_extended, color=:red) @test_figure("test-extrapolate-data-circle", f) end + + +begin + TopoPlots.eeg_topoplot(1:10; labels=TopoPlots.CHANNELS_10_20[1:10]) +end From 703ca98ac9ae4618539762c3e25bb64d49f413d8 Mon Sep 17 00:00:00 2001 From: "behinger (s-ccs 001)" Date: Thu, 24 Oct 2024 13:35:29 +0200 Subject: [PATCH 07/13] removed old file --- docs/src/topo_series.jl | 180 ---------------------------------------- 1 file changed, 180 deletions(-) delete mode 100644 docs/src/topo_series.jl diff --git a/docs/src/topo_series.jl b/docs/src/topo_series.jl deleted file mode 100644 index 0f841aa..0000000 --- a/docs/src/topo_series.jl +++ /dev/null @@ -1,180 +0,0 @@ -### A Pluto.jl notebook ### -# v0.19.9 - -using Markdown -using InteractiveUtils - -# ╔═╡ 2fafb0da-f3a9-11ec-0ddf-6725344070fe -begin -using Pkg -Pkg.activate("../../devEnv") # docs -#Pkg.add("PyMNE") -#Pkg.add(path="../../../TopoPlotsjl/") -Pkg.develop(path="../../../TopoPlotsjl/") -#Pkg.add("DataFrames") -#Pkg.add("AlgebraOfGraphics") - #Pkg.add("StatsBase") - #Pkg.add("CategoricalArrays") - - #Pkg.add("JLD2") - - #Pkg.add("CairoMakie") -end - -# ╔═╡ c4a25915-c7f5-453a-a4f0-4b40ebedea4c -using Revise - -# ╔═╡ 59b87673-02d2-4deb-90be-74d923d170eb - using TopoPlots - - -# ╔═╡ 452a245c-773a-4303-a970-f2592c3e879f -begin - #using TopoPlots - #using ../../../Topoplotsjl - using CairoMakie - using DataFrames - - -end - - -# ╔═╡ 77dc1ba9-9484-485b-a49d-9aa231ef4983 -using Statistics - -# ╔═╡ 311f10ff-deb8-4f82-8b12-d5b643656828 -using PyMNE - -# ╔═╡ 9fa5c598-3578-4989-9585-29fd32ae1056 -using Distributions - -# ╔═╡ 6cda29dc-7086-4079-83c6-3650204a82ff -pathof(TopoPlots) - -# ╔═╡ e0cc560f-d3e8-415b-b22d-6bca23ef093c -revise(TopoPlots) - -# ╔═╡ f4b81740-d907-42ae-a0df-f46fb2f2cb15 -begin - -data = Array{Float32}(undef, 64, 400, 3) -#read!(TopoPlots.assetpath("example-data.bin"), data) - read!(splitdir(pathof(TopoPlots))[1]*"/../assets/example-data.bin",data) - -positions = Vector{Point2f}(undef, 64) - read!(splitdir(pathof(TopoPlots))[1]*"/../assets/layout64.bin",positions) -#read!(TopoPlots.assetpath("layout64.bin"), positions) - -end; - - -# ╔═╡ 42f7755b-80f4-4185-8d21-42e11730e0fc -begin - using Random - pos = positions[1:10] -eeg_topoplot(rand(MersenneTwister(1),length(pos)), string.(1:length(pos));positions=pos,pad_value=0.) -end - -# ╔═╡ aad784ee-6bb7-4f3c-8444-be050456ddea -eeg_topoplot(data[:, 340, 1], string.(1:length(positions));positions=positions) - -# ╔═╡ 237e4f4a-cdf2-4bac-8096-de8050251745 -eeg_topoplot(data[:, 340, 1], string.(1:length(positions));positions=positions,pad_value=0.1) - -# ╔═╡ f522329b-3653-4059-9955-8cd05570e923 -topoplot(rand(MersenneTwister(1),length(pos)),pos) - -# ╔═╡ a9d2a2e2-6c8c-4cfc-9fed-b5e082cb44af -let -mon = PyMNE.channels.make_standard_montage("standard_1020") - -posMat = (Matrix(hcat(pos...)).-0.5).*0.5 - #pos = PyMNE.channels.make_eeg_layout(mon).pos -PyMNE.viz.plot_topomap(rand(MersenneTwister(1),length(pos)),posMat',cmap="RdBu_r",extrapolate="box",border=-1) -end - -# ╔═╡ c358633f-8d18-4c5e-80f7-ab972e8860be -Pkg.status("TopoPlots") - -# ╔═╡ c0a2ad2e-ccce-4e80-b52c-75f1428ed182 -e1eg_topoplot(data[:, 340, 1], string.(1:length(positions));positions=positions,interpolation = TopoPlots.NormalMixtureInterpolator() ) - -# ╔═╡ d7620a42-d54c-4244-a820-d15aecdae626 -@time TopoPlots.eeg_topoplot_series(data[:,:,1],40;topoplotCfg=(positions=positions,label_scatter=false)) - -# ╔═╡ ec59c704-ae33-4a62-82ce-63acc6b17793 -f, ax, pl = TopoPlots.eeg_topoplot(1:length(TopoPlots.CHANNELS_10_20),TopoPlots.CHANNELS_10_20; interpolation=TopoPlots.NullInterpolator(),) - -# ╔═╡ f3d1f3cc-f7c9-4ef4-ba4f-3d32f2509cad -let - # 4 coordinates with one peak - positions = Point2f[(-1, 0), (0, -1), (1, 0), (0, 1)] - i = 1 - peak_xy = positions[i] - data = zeros(length(positions)) - data[i] = 1.1 - fig = topoplot(data, positions) - # tighten the limits so that the limits of the axis and the data will match - tightlimits!(fig.axis) - - # retrieve the interpolated data - m = fig.plot.plots[].color[] - # get the limits of the axes and data - rect = fig.axis.targetlimits[] - minx, miny = minimum(rect) - maxx, maxy = maximum(rect) - # recreate the coordinates of the data - x = range(minx, maxx, length=size(m, 1)) - y = range(miny, maxy, length=size(m, 2)) - xys = Point2f.(x, y') - - # find the highest point - _, i = findmax(x -> isnan(x) ? -Inf : x, m) - xy = xys[i] - @show peak_xy - @show xy - #@test isapprox(xy, peak_xy; atol=0.02) - @show isapprox(xy, peak_xy; atol=0.02) - fig -end - -# ╔═╡ 872ac6a4-ddaa-4dfb-a40d-9d5ea55bdb3d -let - f = Figure() - axis = Axis(f[1, 1], aspect = 1) - xlims!(low = -2, high = 2) - ylims!(low = -2, high = 2) - - data = [0, 0, 0] - pos1 = [Point2f(-1, -1), Point2f(-1.0, 0.0), Point2f(0, -1)] - pos2 = [Point2f(1, 1), Point2f(1.0, 0.0), Point2f(0, 1)] - - pos1 = pos1 .- mean(pos1) - pos2 = pos2 .- mean(pos2) - eeg_topoplot!(axis, data, positions=pos1) - eeg_topoplot!(axis, data, positions=pos2) - f -end - -# ╔═╡ Cell order: -# ╠═2fafb0da-f3a9-11ec-0ddf-6725344070fe -# ╠═6cda29dc-7086-4079-83c6-3650204a82ff -# ╠═c4a25915-c7f5-453a-a4f0-4b40ebedea4c -# ╠═e0cc560f-d3e8-415b-b22d-6bca23ef093c -# ╠═59b87673-02d2-4deb-90be-74d923d170eb -# ╠═452a245c-773a-4303-a970-f2592c3e879f -# ╠═f4b81740-d907-42ae-a0df-f46fb2f2cb15 -# ╠═77dc1ba9-9484-485b-a49d-9aa231ef4983 -# ╠═aad784ee-6bb7-4f3c-8444-be050456ddea -# ╠═237e4f4a-cdf2-4bac-8096-de8050251745 -# ╠═42f7755b-80f4-4185-8d21-42e11730e0fc -# ╠═f522329b-3653-4059-9955-8cd05570e923 -# ╠═311f10ff-deb8-4f82-8b12-d5b643656828 -# ╠═a9d2a2e2-6c8c-4cfc-9fed-b5e082cb44af -# ╠═c358633f-8d18-4c5e-80f7-ab972e8860be -# ╠═9fa5c598-3578-4989-9585-29fd32ae1056 -# ╠═c0a2ad2e-ccce-4e80-b52c-75f1428ed182 -# ╠═d7620a42-d54c-4244-a820-d15aecdae626 -# ╠═ec59c704-ae33-4a62-82ce-63acc6b17793 -# ╠═f3d1f3cc-f7c9-4ef4-ba4f-3d32f2509cad -# ╠═872ac6a4-ddaa-4dfb-a40d-9d5ea55bdb3d From 2ad66380125d64067f07d06012949d2af40c0d68 Mon Sep 17 00:00:00 2001 From: "behinger (s-ccs 001)" Date: Thu, 24 Oct 2024 15:43:40 +0200 Subject: [PATCH 08/13] maybe fix @deprecated fail --- test/runtests.jl | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/test/runtests.jl b/test/runtests.jl index 4142a00..fd52f50 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -49,7 +49,7 @@ function mne_topoplot(fig, data, positions) end function compare_to_mne(data, positions; kw...) - f, ax, pl = TopoPlots.eeg_topoplot(data, nothing; + f, ax, pl = TopoPlots.eeg_topoplot(data; interpolation=CloughTocher( fill_value = NaN, tol = 0.001, @@ -84,13 +84,13 @@ let f = Makie.Figure(resolution=(1000, 1000)) @test_deprecated interpolation = ClaughTochter() - f, ax, pl = TopoPlots.eeg_topoplot(1:length(TopoPlots.CHANNELS_10_20), - TopoPlots.CHANNELS_10_20; interpolation) + f, ax, pl = TopoPlots.eeg_topoplot(1:length(TopoPlots.CHANNELS_10_20); + labels = TopoPlots.CHANNELS_10_20 interpolation) @test_figure("ClaughTochter", f) end begin # empty eeg topoplot - f, ax, pl = TopoPlots.eeg_topoplot(1:length(TopoPlots.CHANNELS_10_20),TopoPlots.CHANNELS_10_20; interpolation=TopoPlots.NullInterpolator(),) + f, ax, pl = TopoPlots.eeg_topoplot(1:length(TopoPlots.CHANNELS_10_20);labels=TopoPlots.CHANNELS_10_20; interpolation=TopoPlots.NullInterpolator(),) @test_figure("nullInterpolator", f) end @@ -103,7 +103,7 @@ begin end TopoPlots.topoplot( f[2, 1], - data_obs, positions, + data_obs; positions, interpolation=DelaunayMesh(), labels = string.(1:length(positions)), colorrange=(-1, 1), @@ -114,7 +114,7 @@ end begin f, ax, pl = TopoPlots.topoplot( - data[:, 340, 1], positions, + data[:, 340, 1]; positions, axis=(; aspect=DataAspect()), colorrange=(-1, 1), bounding_geometry = Rect, From d5fe90fa92b3fc0e3d086bb0a759fd72ccbf2f9f Mon Sep 17 00:00:00 2001 From: "behinger (s-ccs 001)" Date: Thu, 24 Oct 2024 19:01:53 +0200 Subject: [PATCH 09/13] fix test --- test/runtests.jl | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/test/runtests.jl b/test/runtests.jl index fd52f50..f618088 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -85,25 +85,25 @@ let @test_deprecated interpolation = ClaughTochter() f, ax, pl = TopoPlots.eeg_topoplot(1:length(TopoPlots.CHANNELS_10_20); - labels = TopoPlots.CHANNELS_10_20 interpolation) + labels=TopoPlots.CHANNELS_10_20, interpolation) @test_figure("ClaughTochter", f) end begin # empty eeg topoplot - f, ax, pl = TopoPlots.eeg_topoplot(1:length(TopoPlots.CHANNELS_10_20);labels=TopoPlots.CHANNELS_10_20; interpolation=TopoPlots.NullInterpolator(),) + f, ax, pl = TopoPlots.eeg_topoplot(1:length(TopoPlots.CHANNELS_10_20); labels=TopoPlots.CHANNELS_10_20, interpolation=TopoPlots.NullInterpolator(),) @test_figure("nullInterpolator", f) end begin - f = Makie.Figure(resolution=(1000, 1000)) + f = Makie.Figure(size=(1000, 1000)) s = Makie.Slider(f[:, 1], range=1:size(data, 2), startvalue=351) data_obs = map(s.value) do idx data[:, idx, 1] end TopoPlots.topoplot( f[2, 1], - data_obs; positions, + data_obs, positions; interpolation=DelaunayMesh(), labels = string.(1:length(positions)), colorrange=(-1, 1), @@ -114,7 +114,7 @@ end begin f, ax, pl = TopoPlots.topoplot( - data[:, 340, 1]; positions, + data[:, 340, 1], positions; axis=(; aspect=DataAspect()), colorrange=(-1, 1), bounding_geometry = Rect, From dd175bb31a1961ff1c8819e71634284fdaf19df4 Mon Sep 17 00:00:00 2001 From: Phillip Alday Date: Fri, 15 Nov 2024 15:28:31 -0700 Subject: [PATCH 10/13] add missing test --- test/runtests.jl | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/runtests.jl b/test/runtests.jl index f618088..4a9e0fe 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -186,5 +186,6 @@ end begin - TopoPlots.eeg_topoplot(1:10; labels=TopoPlots.CHANNELS_10_20[1:10]) + f = TopoPlots.eeg_topoplot(1:10; labels=TopoPlots.CHANNELS_10_20[1:10]) + @test_figure("test-eeg-channel-labels", f) end From 5533b554f8fbec53ed9aaafa1c676792810b180c Mon Sep 17 00:00:00 2001 From: Phillip Alday Date: Fri, 15 Nov 2024 15:58:23 -0700 Subject: [PATCH 11/13] fix gitignore --- .gitignore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 449aaf8..b26d5a8 100644 --- a/.gitignore +++ b/.gitignore @@ -7,6 +7,6 @@ test/test_images test/Manifest.toml docs/Manifest.toml -docs/.CondaPkg +.CondaPkg/ docs/Manifest-v*.toml deps/build.log From a4aec9e01091c5bb46db8ff23ccb95e4277a99b5 Mon Sep 17 00:00:00 2001 From: Phillip Alday Date: Fri, 15 Nov 2024 16:08:36 -0700 Subject: [PATCH 12/13] CondaPkg tweak --- test/CondaPkg.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/CondaPkg.toml b/test/CondaPkg.toml index b72a254..3cac7b0 100644 --- a/test/CondaPkg.toml +++ b/test/CondaPkg.toml @@ -2,7 +2,7 @@ channels = ["anaconda", "conda-forge"] [deps] matplotlib = "" -python = ">=3.7,<4" +python = ">=3.7, <3.13" # we get segaults on 3.13 on Apple Silicon scipy = ">=1.9" [pip.deps] From 39f71bc2cf2cb19d97d4b3209828495b9a02c6a2 Mon Sep 17 00:00:00 2001 From: Phillip Alday Date: Fri, 15 Nov 2024 16:17:39 -0700 Subject: [PATCH 13/13] labels in test --- src/eeg.jl | 20 +++++++++++--------- test/runtests.jl | 2 +- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/src/eeg.jl b/src/eeg.jl index 14106c9..f29de81 100644 --- a/src/eeg.jl +++ b/src/eeg.jl @@ -17,19 +17,22 @@ end Attributes: * `positions::Vector{<: Point} = Makie.automatic`: Can be calculated from label (channel) names. Currently, only 10/20 montage has default coordinates provided. -* `labels::AbstractVector{<:AbstractString} = Makie.automatic`: Add custom labels, in case `label_text` is set to true. If `positions` is not specified, `labels` are used to look up the 10/20 coordinates. +* `labels::AbstractVector{<:AbstractString} = Makie.automatic`: Add custom labels, when `label_text` is set to true. If `positions` is not specified, `labels` are used to look up the 10/20 coordinates. * `head = (color=:black, linewidth=3)`: draw the outline of the head. Set to nothing to not draw the head outline, otherwise set to a namedtuple that get passed down to the `line!` call that draws the shape. # Some attributes from topoplot are set to different defaults: * `label_scatter = true` * `contours = true` Otherwise the recipe just uses the [`topoplot`](@ref) defaults and passes through the attributes. + +!!! note + You MUST set `label_text=true` for labels to display. """ eeg_topoplot @deprecate eeg_topoplot(data::AbstractVector{<:Real}, labels::Vector{<:AbstractString}) eeg_topoplot(data; labels) @deprecate eeg_topoplot!(fig, data::AbstractVector{<:Real}, labels::Vector{<:AbstractString}) eeg_topoplot!(fig, data; labels) - + function draw_ear_nose!(parent, circle; kw...) # draw circle head_points = lift(circle) do circle @@ -85,14 +88,14 @@ end #function Makie.convert_arguments(::Type{<:EEG_TopoPlot}, data::AbstractVector{<:Real}) # return (data, labels2positions(labels))# - + # #end function Makie.plot!(plot::EEG_TopoPlot) - + positions = lift(plot.labels, plot.positions) do labels, positions - + if positions isa Makie.Automatic (!isnothing(labels) && labels != Makie.Automatic) || error("Either positions or labels (10/20-lookup) have to be specified") @@ -102,16 +105,15 @@ function Makie.plot!(plot::EEG_TopoPlot) return convert_arguments(Makie.PointBased(), positions)[1] end end - labels = lift(plot.labels, plot.positions) do labels, positions - + plot.labels = lift(plot.labels, plot.positions) do labels, positions + if isnothing(labels) || labels isa Makie.Automatic return ["sensor $i" for i in 1:length(positions)] else return labels end end - plot.labels = labels - + tplot = topoplot!(plot, Attributes(plot), plot.data, positions;) head = plot_or_defaults(to_value(plot.head), Attributes(), :head) if !isnothing(head) diff --git a/test/runtests.jl b/test/runtests.jl index 4a9e0fe..2d0f056 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -186,6 +186,6 @@ end begin - f = TopoPlots.eeg_topoplot(1:10; labels=TopoPlots.CHANNELS_10_20[1:10]) + f = TopoPlots.eeg_topoplot(1:10; labels=TopoPlots.CHANNELS_10_20[1:10], label_text=true) @test_figure("test-eeg-channel-labels", f) end