2d visualization
This commit is contained in:
parent
9996227460
commit
d99771045e
5 changed files with 474 additions and 213 deletions
205
interactive_viz.jl
Normal file
205
interactive_viz.jl
Normal file
|
@ -0,0 +1,205 @@
|
|||
true || include("src/CoordVisualize.jl")
|
||||
true || using GLMakie
|
||||
using CoordVisualize
|
||||
using FileIO
|
||||
using ColorSchemes
|
||||
using ColorTypes
|
||||
|
||||
mappath = "map.png"
|
||||
map = load(mappath)
|
||||
map_height, map_width = size(map)
|
||||
|
||||
fig = Figure(; size = (1000, 700))
|
||||
ax = Axis(
|
||||
fig[1:2, 1],
|
||||
limits = (
|
||||
-map_width ÷ 2 * 1.1,
|
||||
map_width ÷ 2 * 1.1,
|
||||
-map_height ÷ 2 * 1.1,
|
||||
map_height ÷ 2 * 1.1,
|
||||
),
|
||||
aspect = DataAspect(),
|
||||
)
|
||||
|
||||
# Options
|
||||
options_width = 200
|
||||
button_reset = Button(fig, label = "reset view")
|
||||
toggle_inspector = Toggle(fig, active = false, tellwidth = false)
|
||||
menu_lcolormapfunc =
|
||||
Menu(fig, options = ["log", "altitude", "date", "constant"], default = "log")
|
||||
menu_mcolormapfunc =
|
||||
Menu(fig, options = ["log", "altitude", "date", "constant"], default = "log")
|
||||
toggle_line = Toggle(fig, active = true, tellwidth = false)
|
||||
toggle_marker = Toggle(fig, active = false, tellwidth = false)
|
||||
slider_linewidth = Slider(fig, range = unique([1:1:5..., 5:2:15..., 15, 20:10:100...]))
|
||||
slider_markersize = Slider(fig, range = unique([1:1:10..., 10:5:100...]), startvalue = 5)
|
||||
# menu_linecolormap =
|
||||
# Menu(fig, options = string.(keys(ColorSchemes.colorschemes)), default = "viridis")
|
||||
# menu_markercolormap =
|
||||
# Menu(fig, options = string.(keys(ColorSchemes.colorschemes)), default = "viridis")
|
||||
textbox_linecolormap =
|
||||
Textbox(fig, validator = (s -> s in string.(keys(ColorSchemes.colorschemes))))
|
||||
textbox_markercolormap =
|
||||
Textbox(fig, validator = (s -> s in string.(keys(ColorSchemes.colorschemes))))
|
||||
textbox_linecolor = Textbox(fig, validator = (s -> begin
|
||||
try
|
||||
parse(Colorant, s)
|
||||
catch
|
||||
return false
|
||||
end
|
||||
return true
|
||||
end), stored_string = "green")
|
||||
lineconstcolor =
|
||||
@lift(ColorMapFuncs.Constant(parse(Colorant, $(textbox_linecolor.stored_string))))
|
||||
textbox_markercolor = Textbox(fig, validator = (s -> begin
|
||||
try
|
||||
parse(Colorant, s)
|
||||
catch
|
||||
return false
|
||||
end
|
||||
return true
|
||||
end), stored_string = "green")
|
||||
markerconstcolor =
|
||||
@lift(ColorMapFuncs.Constant(parse(Colorant, $(textbox_markercolor.stored_string))))
|
||||
line_options = grid!(
|
||||
[1, 1] => Label(fig, "color"),
|
||||
[1, 2:3] => menu_lcolormapfunc,
|
||||
[2, 1] => Label(fig, "show line"),
|
||||
[2, 2:3] => toggle_line,
|
||||
[3, 1] => Label(fig, "width"),
|
||||
[3, 2] => slider_linewidth,
|
||||
[3, 3] => Label(fig, @lift(string($(slider_linewidth.value)))),
|
||||
[4, 1] => Label(fig, "color scheme"),
|
||||
[4, 2:3] => textbox_linecolormap,
|
||||
[5, 1] => Label(fig, "color"),
|
||||
[5, 2:3] => textbox_linecolor,
|
||||
width = options_width,
|
||||
)
|
||||
marker_options = grid!(
|
||||
[1, 1] => Label(fig, "color"),
|
||||
[1, 2:3] => menu_mcolormapfunc,
|
||||
[2, 1] => Label(fig, "show marker"),
|
||||
[2, 2:3] => toggle_marker,
|
||||
[3, 1] => Label(fig, "size"),
|
||||
[3, 2] => slider_markersize,
|
||||
[3, 3] => Label(fig, @lift(string($(slider_markersize.value)))),
|
||||
[4, 1] => Label(fig, "color scheme"),
|
||||
[4, 2:3] => textbox_markercolormap,
|
||||
[5, 1] => Label(fig, "color"),
|
||||
[5, 2:3] => textbox_markercolor,
|
||||
width = options_width,
|
||||
)
|
||||
inspector_options = grid!(
|
||||
[1, 1] => Label(fig, "inspector"),
|
||||
[1, 2] => toggle_inspector,
|
||||
width = options_width,
|
||||
)
|
||||
fig[1:2, 2] = grid!(
|
||||
[0, :] => Label(fig, "Line", font = :bold),
|
||||
[1, :] => line_options,
|
||||
[2, :] => Label(fig, "Marker", font = :bold),
|
||||
[3, :] => marker_options,
|
||||
[4, :] => Label(fig, "Axis", font = :bold),
|
||||
[5, :] => inspector_options,
|
||||
[6, :] => button_reset,
|
||||
tellheight = false,
|
||||
width = options_width,
|
||||
)
|
||||
|
||||
tlog = vcat(CoordVisualize.parse_log.(["coord_log_5.txt", "coord_log_6.txt"])...)
|
||||
|
||||
# Main
|
||||
heatmap!(
|
||||
ax,
|
||||
(1:map_width) .- map_width ÷ 2 .- 1,
|
||||
(1:map_height) .- map_height ÷ 2 .- 1,
|
||||
rotr90(map),
|
||||
inspectable = false,
|
||||
)
|
||||
|
||||
tr2d = CoordVisualize.trace2ds!(
|
||||
ax,
|
||||
tlog,
|
||||
linewidth = slider_linewidth.value,
|
||||
markersize = slider_markersize.value,
|
||||
)
|
||||
|
||||
# legend
|
||||
cbl = Colorbar(
|
||||
fig,
|
||||
colormap = tr2d.linecolormap,
|
||||
ticks = tr2d.lcolorticks,
|
||||
# ticklabelrotation = π / 2,
|
||||
ticklabelsize = 10,
|
||||
label = menu_lcolormapfunc.selection,
|
||||
# vertical = false,
|
||||
# flipaxis = false,
|
||||
)
|
||||
cbm = Colorbar(
|
||||
fig,
|
||||
colormap = tr2d.markercolormap,
|
||||
ticks = tr2d.mcolorticks,
|
||||
# ticklabelrotation = π / 2,
|
||||
ticklabelsize = 10,
|
||||
label = menu_mcolormapfunc.selection,
|
||||
)
|
||||
fig[1:2, 3] = grid!(
|
||||
[0, 1] => Label(fig, "line", font = :bold),
|
||||
[1, 1] => cbl,
|
||||
[2, 1] => Label(fig, "marker", font = :bold),
|
||||
[3, 1] => cbm,
|
||||
tellheight = true,
|
||||
)
|
||||
|
||||
inspector = DataInspector(tr2d)
|
||||
inspector.attributes.enabled[] = false
|
||||
|
||||
on(menu_lcolormapfunc.selection) do s
|
||||
if s == "log"
|
||||
tr2d.lcolormapfunc[] = ColorMapFuncs.ColorMap()
|
||||
elseif s == "altitude"
|
||||
tr2d.lcolormapfunc[] = ColorMapFuncs.Altitude()
|
||||
elseif s == "date"
|
||||
tr2d.lcolormapfunc[] = ColorMapFuncs.Date()
|
||||
elseif s == "constant"
|
||||
tr2d.lcolormapfunc[] = lineconstcolor[]
|
||||
end
|
||||
end
|
||||
on(lineconstcolor) do c
|
||||
tr2d.lcolormapfunc[] = c
|
||||
end
|
||||
on(menu_mcolormapfunc.selection) do s
|
||||
if s == "log"
|
||||
tr2d.mcolormapfunc[] = ColorMapFuncs.ColorMap()
|
||||
elseif s == "altitude"
|
||||
tr2d.mcolormapfunc[] = ColorMapFuncs.Altitude()
|
||||
elseif s == "date"
|
||||
tr2d.mcolormapfunc[] = ColorMapFuncs.Date()
|
||||
elseif s == "constant"
|
||||
tr2d.mcolormapfunc[] = markerconstcolor[]
|
||||
end
|
||||
end
|
||||
on(markerconstcolor) do c
|
||||
tr2d.mcolormapfunc[] = c
|
||||
end
|
||||
on(button_reset.clicks) do n
|
||||
reset_limits!(ax)
|
||||
# slider_markersize.value[] = 5
|
||||
# slider_linewidth.value[] = 1
|
||||
# toggle_line.active[] = true
|
||||
# toggle_marker.active[] = false
|
||||
end
|
||||
on(textbox_linecolormap.stored_string) do s
|
||||
tr2d.linecolormap[] = ColorSchemes.colorschemes[Symbol(s)]
|
||||
end
|
||||
on(textbox_markercolormap.stored_string) do s
|
||||
tr2d.markercolormap[] = ColorSchemes.colorschemes[Symbol(s)]
|
||||
end
|
||||
on(toggle_inspector.active) do f
|
||||
inspector.attributes.enabled[] = f
|
||||
end
|
||||
|
||||
connect!(tr2d.showline, toggle_line.active)
|
||||
connect!(tr2d.showmarker, toggle_marker.active)
|
||||
|
||||
display(fig)
|
|
@ -3,11 +3,13 @@ module CoordVisualize
|
|||
using Dates
|
||||
|
||||
export CoordLog
|
||||
export ColorMapFuncs
|
||||
|
||||
include("typedef.jl")
|
||||
include("parser.jl")
|
||||
include("edit.jl")
|
||||
include("print.jl")
|
||||
include("recipes.jl")
|
||||
include("visualize.jl")
|
||||
|
||||
end # module CoordVisualize
|
||||
|
|
|
@ -11,10 +11,10 @@ If keyword argument `interactive` is set to `true`, prompts will be shown to
|
|||
receive custom notes for each `CoordLog`.
|
||||
Otherwise the note is set to ""(empty string).
|
||||
"""
|
||||
function parse_log(filepath::AbstractString; interactive=false)::Vector{CoordLog}
|
||||
function parse_log(filepath::AbstractString; interactive=false)::Vector{CoordLog{Float64}}
|
||||
istracing::Bool = false
|
||||
coords_trace = Vector{Vector{Float64}}(undef, 0) # SVector ?
|
||||
ret = Vector{CoordLog}()
|
||||
ret = Vector{CoordLog{Float64}}()
|
||||
log_date = DateTime(0)
|
||||
for (i, l) in enumerate(readlines(filepath))
|
||||
# skip logs not from tracecoord
|
||||
|
|
264
src/recipes.jl
Normal file
264
src/recipes.jl
Normal file
|
@ -0,0 +1,264 @@
|
|||
using GLMakie
|
||||
using ColorTypes
|
||||
using ColorSchemes
|
||||
|
||||
"""
|
||||
Predefined color map functions.
|
||||
|
||||
# Types
|
||||
|
||||
[`ColorMapFunc`](@ref)
|
||||
|
||||
# Interface
|
||||
|
||||
Define these methods for the ColorMapFunc.
|
||||
|
||||
(AbstractVector{CoordLog}) -> Vector{∈ [0, 1]}, ticks
|
||||
"""
|
||||
module ColorMapFuncs
|
||||
|
||||
using ..CoordVisualize: CoordLog, n_coords
|
||||
using ColorTypes
|
||||
using Dates: DateTime, DateFormat, @dateformat_str, format
|
||||
using Makie: wong_colors, Scene
|
||||
|
||||
"""
|
||||
# Methods
|
||||
(f::ColorMapFunc)(cmap, logs)
|
||||
|
||||
Helper method.
|
||||
"""
|
||||
abstract type ColorMapFunc end
|
||||
|
||||
function (f::ColorMapFunc)(cmap, logs, n)
|
||||
steps, ticklabels = f(logs, n)
|
||||
ticks = collect(LinRange(0, 1, n))
|
||||
return get.(Ref(cmap), steps), (ticks, ticklabels)
|
||||
end
|
||||
|
||||
"Use same color."
|
||||
struct Constant <: ColorMapFunc
|
||||
color::Colorant
|
||||
end
|
||||
|
||||
Constant(c::Symbol) = Constant(parse(Colorant, c))
|
||||
|
||||
function (c::Constant)(map, logs, n)
|
||||
# Iterators.repeated(c.color, length(logs))
|
||||
fill(c.color, sum(n_coords, logs)), ([], [])
|
||||
end
|
||||
|
||||
"Use colormap."
|
||||
struct ColorMap <: ColorMapFunc
|
||||
colormap::AbstractVector{<:Colorant}
|
||||
end
|
||||
|
||||
ColorMap() = ColorMap(wong_colors())
|
||||
ColorMap(cmap::Vector{Symbol}) = ColorMap(map(cmap) do s
|
||||
parse(Colorant, s)
|
||||
end)
|
||||
function ColorMap(scene::Scene)
|
||||
ColorMap(theme(scene, :linecolor))
|
||||
end
|
||||
|
||||
function (cm::ColorMap)(map, logs, n)
|
||||
cm = Iterators.cycle(cm.colormap)
|
||||
nlog_s = Iterators.map(n_coords, logs)
|
||||
colors =
|
||||
Iterators.map(zip(cm, nlog_s)) do (color, count)
|
||||
Iterators.repeated(color, count)
|
||||
end |> Iterators.flatten |> collect
|
||||
return colors, ([], [])
|
||||
end
|
||||
|
||||
"Color depending on log date."
|
||||
struct Date <: ColorMapFunc end
|
||||
|
||||
function (::Date)(logs::AbstractVector{CoordLog{T}}, n) where {T}
|
||||
dformat = dateformat"yyyy-m-d"
|
||||
logdates::Vector{DateTime} = map(logs) do log
|
||||
fill(log.logdate, n_coords(log))
|
||||
end |> (v -> vcat(v...))
|
||||
fst, lst = extrema(logdates)
|
||||
normeddate = (logdates .- fst) ./ (lst - fst)
|
||||
diff = (lst - fst) / (n - 1)
|
||||
ticklabels = format.(fst:diff:lst, dformat)
|
||||
return normeddate, ticklabels
|
||||
end
|
||||
|
||||
"Color depending on altitude."
|
||||
struct Altitude <: ColorMapFunc end
|
||||
|
||||
function (f::Altitude)(logs::AbstractVector{CoordLog{T}}, n) where {T}
|
||||
altitudes = map(logs) do log
|
||||
Iterators.map(eachrow(log.coords)) do c
|
||||
c[2]
|
||||
end
|
||||
end |> Iterators.flatten |> collect
|
||||
low, high = extrema(altitudes)
|
||||
normedalt = (altitudes .- low) ./ (high - low)
|
||||
ticklabels = string.(round.(LinRange(low, high, n)))
|
||||
return normedalt, ticklabels
|
||||
end
|
||||
|
||||
end # module ColorMapFunc
|
||||
|
||||
# TODO: alpha?
|
||||
"""
|
||||
trace2ds(log::Vector{CoordLog})
|
||||
|
||||
# Arguments
|
||||
TODO
|
||||
"""
|
||||
@recipe(Trace2Ds, log) do scene
|
||||
Attributes(;
|
||||
showmarker = false,
|
||||
marker = theme(scene, :marker),
|
||||
markercolormap = theme(scene, :colormap),
|
||||
markersize = theme(scene, :markersize),
|
||||
strokewidth = 0,
|
||||
showline = true,
|
||||
linecolormap = theme(scene, :colormap),
|
||||
linestyle = theme(scene, :linestyle),
|
||||
linewidth = theme(scene, :linewidth),
|
||||
inspectable = theme(scene, :inspectable),
|
||||
lcolormapfunc = ColorMapFuncs.ColorMap(), # or func like in ColorMapFunc
|
||||
mcolormapfunc = ColorMapFuncs.ColorMap(),
|
||||
lcolorticks = nothing,
|
||||
nlcolorticks = 5,
|
||||
mcolorticks = nothing,
|
||||
nmcolorticks = 5,
|
||||
)
|
||||
end
|
||||
|
||||
function Makie.plot!(tr2d::Trace2Ds)
|
||||
# @info "logs" tr2d
|
||||
# @info "fieldnames" tr2d.log
|
||||
# @info "" theme(tr2d, :colormap)
|
||||
|
||||
lcolormapfunc = tr2d.lcolormapfunc
|
||||
|
||||
ntraces = length(tr2d.log[]) # number of CoordLog
|
||||
linesegs = Observable(Point2f[])
|
||||
points = Observable(Point2f[])
|
||||
altitudes = Observable(Float64[])
|
||||
notes = Observable(String[])
|
||||
if tr2d.markercolormap[] isa Symbol
|
||||
tr2d.markercolormap[] = getproperty(ColorSchemes, tr2d.markercolormap[])
|
||||
end
|
||||
markercolors = Observable(
|
||||
tr2d.mcolormapfunc[](tr2d.markercolormap[], tr2d.log[], tr2d.nmcolorticks[])[1],
|
||||
)
|
||||
mticks = tr2d.mcolorticks
|
||||
if tr2d.linecolormap[] isa Symbol
|
||||
tr2d.linecolormap[] = getproperty(ColorSchemes, tr2d.linecolormap[])
|
||||
end
|
||||
# @info "lcolormapfunc" lcolormapfunc
|
||||
linecolors =
|
||||
Observable(lcolormapfunc[](tr2d.linecolormap[], tr2d.log[], tr2d.nlcolorticks[])[1])
|
||||
lticks = tr2d.lcolorticks
|
||||
|
||||
# helper function which mutates observables
|
||||
function update_plot(
|
||||
logs::AbstractVector{<:CoordLog{T}},
|
||||
lcolormap,
|
||||
mcolormap,
|
||||
lcolormapfunc, #::Union{Symbol, Tuple{Symbol, Symbol}},
|
||||
mcolormapfunc,
|
||||
) where {T}
|
||||
@info "update_plot"
|
||||
markercolors[]
|
||||
linecolors[]
|
||||
# @info "logs on update_plot" logs
|
||||
# init
|
||||
empty!(linesegs[])
|
||||
empty!(points[])
|
||||
empty!(altitudes[])
|
||||
empty!(markercolors[])
|
||||
if linecolors[] isa AbstractVector
|
||||
empty!(linecolors[])
|
||||
else
|
||||
linecolors[] = []
|
||||
end
|
||||
|
||||
# update
|
||||
colors_count = 1
|
||||
lcolors, lticks[] = lcolormapfunc(lcolormap, logs, tr2d.nlcolorticks[])
|
||||
mcolors, mticks[] = mcolormapfunc(mcolormap, logs, tr2d.nmcolorticks[])
|
||||
for (i, log) in enumerate(logs)
|
||||
first = true
|
||||
for point in eachrow(log.coords)
|
||||
push!(linesegs[], Point2f(point[1], point[3]))
|
||||
push!(linesegs[], Point2f(point[1], point[3]))
|
||||
push!(points[], Point2f(point[1], point[3]))
|
||||
push!(altitudes[], point[2])
|
||||
push!(linecolors[], lcolors[colors_count])
|
||||
push!(linecolors[], lcolors[colors_count])
|
||||
push!(markercolors[], mcolors[colors_count])
|
||||
colors_count += 1
|
||||
|
||||
# # marker
|
||||
# if !isnothing(mcolormapfunc)
|
||||
# push!(markercolors[], mcolormapfunc(logs)[i])
|
||||
# end
|
||||
|
||||
if first
|
||||
pop!(linesegs[])
|
||||
pop!(linecolors[])
|
||||
first = false
|
||||
else
|
||||
# # colors
|
||||
# if !isnothing(lcolormapfunc)
|
||||
# push!(linecolors[], lcolormapfunc(logs)[i])
|
||||
# end
|
||||
end
|
||||
end
|
||||
pop!(linesegs[])
|
||||
pop!(linecolors[])
|
||||
push!(notes[], log.note)
|
||||
end
|
||||
|
||||
markercolors[] = markercolors[]
|
||||
linecolors[] = linecolors[]
|
||||
end
|
||||
|
||||
Makie.Observables.onany(
|
||||
update_plot,
|
||||
tr2d.log,
|
||||
tr2d.linecolormap,
|
||||
tr2d.markercolormap,
|
||||
lcolormapfunc,
|
||||
tr2d.mcolormapfunc,
|
||||
)
|
||||
|
||||
# init
|
||||
update_plot(
|
||||
tr2d.log[],
|
||||
tr2d.linecolormap[],
|
||||
tr2d.markercolormap[],
|
||||
lcolormapfunc[],
|
||||
tr2d.mcolormapfunc[],
|
||||
)
|
||||
|
||||
linesegments!(
|
||||
tr2d,
|
||||
linesegs,
|
||||
color = linecolors,
|
||||
linewidth = tr2d.linewidth,
|
||||
linestyle = tr2d.linestyle,
|
||||
visible = tr2d.showline,
|
||||
# inspector_label = (self, i, pos) ->
|
||||
)
|
||||
scatter!(
|
||||
tr2d,
|
||||
points,
|
||||
color = markercolors,
|
||||
markersize = tr2d.markersize,
|
||||
strokewidth = tr2d.strokewidth,
|
||||
visible = tr2d.showmarker,
|
||||
)
|
||||
# @info "dump" dump(tr2d, maxdepth = 1)
|
||||
# @info "attributes" dump(tr2d.attributes, maxdepth = 3)
|
||||
|
||||
tr2d
|
||||
end
|
212
src/visualize.jl
212
src/visualize.jl
|
@ -10,7 +10,7 @@ function _plot_map!(ax, mappath::AbstractString)
|
|||
heatmap!(
|
||||
ax,
|
||||
(1:width) .- width ÷ 2,
|
||||
(1:heigh) .- width ÷ 2,
|
||||
(1:heigh) .- heigh ÷ 2,
|
||||
rotr90(map),
|
||||
inspectable = false,
|
||||
)
|
||||
|
@ -25,213 +25,3 @@ function view_with_map(log::CoordLog; map = "map.png")
|
|||
return fig
|
||||
end
|
||||
|
||||
"""
|
||||
Predefined color map functions.
|
||||
|
||||
# Interface
|
||||
(map, AbstractVector{CoordLog}) -> Vector{<: Colorant}
|
||||
"""
|
||||
module ColorMapFunc
|
||||
|
||||
using ..CoordVisualize: CoordLog, n_coords
|
||||
using ColorTypes
|
||||
using Dates: DateTime
|
||||
using Makie: wong_colors, Scene
|
||||
|
||||
"Use same color."
|
||||
struct Constant
|
||||
color::Colorant
|
||||
end
|
||||
|
||||
Constant(c::Symbol) = Constant(parse(Colorant, c))
|
||||
|
||||
function (c::Constant)(map, logs)
|
||||
# Iterators.repeated(c.color, length(logs))
|
||||
fill(c.color, sum(n_coords, logs))
|
||||
end
|
||||
|
||||
"Use colormap."
|
||||
struct ColorMap
|
||||
colormap::AbstractVector{<:Colorant}
|
||||
end
|
||||
|
||||
ColorMap() = ColorMap(wong_colors())
|
||||
ColorMap(cmap::Vector{Symbol}) = ColorMap(map(cmap) do s
|
||||
parse(Colorant, s)
|
||||
end)
|
||||
function ColorMap(scene::Scene)
|
||||
ColorMap(theme(scene, :linecolor))
|
||||
end
|
||||
|
||||
function (cm::ColorMap)(map, logs)
|
||||
cm = Iterators.cycle(cm.colormap)
|
||||
nlog_s = Iterators.map(n_coords, logs)
|
||||
Iterators.map(zip(cm, nlog_s)) do (color, count)
|
||||
Iterators.repeated(color, count)
|
||||
end |> Iterators.flatten |> collect
|
||||
end
|
||||
|
||||
"Color depending on log date."
|
||||
function date(cmap, logs::AbstractVector{CoordLog})
|
||||
logdates::Vector{DateTime} = map(logs) do log
|
||||
fill(log.logdate, n_coords(log))
|
||||
end |> (v -> vcat(v...))
|
||||
lst, fst = extrema(logdates)
|
||||
normeddate = (logdates .- lst) ./ (fst - lst)
|
||||
return get.(Ref(cmap), normeddate)
|
||||
end
|
||||
|
||||
"Color depending on altitude."
|
||||
function altitude(cmap, logs::AbstractVector{CoordLog})
|
||||
altitudes = map(logs) do log
|
||||
map(eachrow(log.coords)) do c
|
||||
c[2]
|
||||
end
|
||||
end |> Iterators.flatten |> collect
|
||||
low, high = extrema(altitudes)
|
||||
normedalt = (altitudes .- low) ./ (high - low)
|
||||
return get.(Ref(cmap), normedalt)
|
||||
end
|
||||
|
||||
end # module ColorMapFunc
|
||||
|
||||
# TODO: alpha?
|
||||
"""
|
||||
trace2ds(log::Vector{CoordLog})
|
||||
|
||||
# Arguments
|
||||
TODO
|
||||
"""
|
||||
@recipe(Trace2Ds, log) do scene
|
||||
Attributes(;
|
||||
marker = theme(scene, :marker),
|
||||
markercolormap = theme(scene, :colormap),
|
||||
markersize = theme(scene, :markersize),
|
||||
strokewidth = theme(scene, :strokewidth),
|
||||
linecolormap = theme(scene, :colormap),
|
||||
linestyle = theme(scene, :linestyle),
|
||||
linewidth = theme(scene, :linewidth),
|
||||
inspectable = theme(scene, :inspectable),
|
||||
lcolormapfunc = ColorMapFunc.ColorMap(), # or func like in ColorMapFunc
|
||||
mcolormapfunc = ColorMapFunc.ColorMap(),
|
||||
)
|
||||
end
|
||||
|
||||
function Makie.plot!(tr2d::Trace2Ds)
|
||||
# @info "logs" tr2d
|
||||
# @info "fieldnames" tr2d.log
|
||||
# @info "" theme(tr2d, :colormap)
|
||||
|
||||
lcolormapfunc = tr2d.lcolormapfunc
|
||||
|
||||
ntraces = length(tr2d.log[]) # number of CoordLog
|
||||
linesegs = Observable(Point2f[])
|
||||
points = Observable(Point2f[])
|
||||
notes = Observable(String[])
|
||||
if tr2d.markercolormap[] isa Symbol
|
||||
tr2d.markercolormap[] = getproperty(ColorSchemes, tr2d.markercolormap[])
|
||||
end
|
||||
markercolors = Observable(tr2d.mcolormapfunc[](tr2d.markercolormap[], tr2d.log[]))
|
||||
if tr2d.linecolormap[] isa Symbol
|
||||
tr2d.linecolormap[] = getproperty(ColorSchemes, tr2d.linecolormap[])
|
||||
end
|
||||
# @info "lcolormapfunc" lcolormapfunc
|
||||
linecolors = Observable(lcolormapfunc[](tr2d.linecolormap[], tr2d.log[]))
|
||||
|
||||
# helper function which mutates observables
|
||||
function update_plot(
|
||||
logs::AbstractVector{<:CoordLog},
|
||||
lcolormap,
|
||||
mcolormap,
|
||||
lcolormapfunc, #::Union{Symbol, Tuple{Symbol, Symbol}},
|
||||
mcolormapfunc,
|
||||
)
|
||||
@info "update_plot"
|
||||
markercolors[]
|
||||
linecolors[]
|
||||
# @info "logs on update_plot" logs
|
||||
# init
|
||||
empty!(linesegs[])
|
||||
empty!(points[])
|
||||
empty!(markercolors[])
|
||||
if linecolors[] isa AbstractVector
|
||||
empty!(linecolors[])
|
||||
else
|
||||
linecolors[] = []
|
||||
end
|
||||
|
||||
# update
|
||||
colors_count = 1
|
||||
for (i, log) in enumerate(logs)
|
||||
first = true
|
||||
for point in eachrow(log.coords)
|
||||
push!(linesegs[], Point2f(point[1], point[3]))
|
||||
push!(linesegs[], Point2f(point[1], point[3]))
|
||||
push!(points[], Point2f(point[1], point[3]))
|
||||
push!(linecolors[], lcolormapfunc(lcolormap, logs)[colors_count])
|
||||
push!(linecolors[], lcolormapfunc(lcolormap, logs)[colors_count])
|
||||
push!(markercolors[], mcolormapfunc(mcolormap, logs)[colors_count])
|
||||
colors_count += 1
|
||||
|
||||
# # marker
|
||||
# if !isnothing(mcolormapfunc)
|
||||
# push!(markercolors[], mcolormapfunc(logs)[i])
|
||||
# end
|
||||
|
||||
if first
|
||||
pop!(linesegs[])
|
||||
pop!(linecolors[])
|
||||
first = false
|
||||
else
|
||||
# # colors
|
||||
# if !isnothing(lcolormapfunc)
|
||||
# push!(linecolors[], lcolormapfunc(logs)[i])
|
||||
# end
|
||||
end
|
||||
end
|
||||
pop!(linesegs[])
|
||||
pop!(linecolors[])
|
||||
push!(notes[], log.note)
|
||||
end
|
||||
|
||||
markercolors[] = markercolors[]
|
||||
linecolors[] = linecolors[]
|
||||
end
|
||||
|
||||
Makie.Observables.onany(
|
||||
update_plot,
|
||||
tr2d.log,
|
||||
tr2d.linecolormap,
|
||||
tr2d.markercolormap,
|
||||
lcolormapfunc,
|
||||
tr2d.mcolormapfunc,
|
||||
)
|
||||
|
||||
# init
|
||||
update_plot(
|
||||
tr2d.log[],
|
||||
tr2d.linecolormap[],
|
||||
tr2d.markercolormap[],
|
||||
lcolormapfunc[],
|
||||
tr2d.mcolormapfunc[],
|
||||
)
|
||||
|
||||
linesegments!(
|
||||
tr2d,
|
||||
linesegs,
|
||||
color = linecolors,
|
||||
linewidth = tr2d.linewidth,
|
||||
linestyle = tr2d.linestyle,
|
||||
)
|
||||
scatter!(
|
||||
tr2d,
|
||||
points,
|
||||
color = markercolors,
|
||||
markersize = tr2d.markersize,
|
||||
strokewidth = tr2d.strokewidth,
|
||||
)
|
||||
# @info "dump" dump(tr2d, maxdepth = 1)
|
||||
# @info "attributes" dump(tr2d.attributes, maxdepth = 3)
|
||||
|
||||
tr2d
|
||||
end
|
||||
|
|
Loading…
Reference in a new issue