From bcd54dc6736f4949c6ee271ef559849edb6d8879 Mon Sep 17 00:00:00 2001 From: qwjyh Date: Sun, 12 Nov 2023 09:57:28 +0900 Subject: [PATCH 01/10] adding doc --- Project.toml | 1 + docs/.gitignore | 2 ++ docs/Project.toml | 2 ++ docs/make.jl | 19 +++++++++++++++++++ docs/src/apis.md | 8 ++++++++ docs/src/index.md | 27 +++++++++++++++++++++++++++ src/CoordVisualize.jl | 1 + src/print.jl | 0 src/typedef.jl | 3 +++ 9 files changed, 63 insertions(+) create mode 100644 docs/.gitignore create mode 100644 docs/Project.toml create mode 100644 docs/make.jl create mode 100644 docs/src/apis.md create mode 100644 docs/src/index.md create mode 100644 src/print.jl diff --git a/Project.toml b/Project.toml index 3150d03..4741e43 100644 --- a/Project.toml +++ b/Project.toml @@ -6,6 +6,7 @@ version = "0.1.0" [deps] ColorSchemes = "35d6a980-a343-548e-a6ea-1d62b119f2f4" Dates = "ade2ca70-3891-5945-98fb-dc099432e06a" +Documenter = "e30172f5-a6a5-5a46-863b-614d45cd2de4" GLMakie = "e9467ef8-e4e7-5192-8a1a-b1aee30e663a" YAML = "ddb6d928-2868-570f-bddf-ab3f9cf99eb6" diff --git a/docs/.gitignore b/docs/.gitignore new file mode 100644 index 0000000..a303fff --- /dev/null +++ b/docs/.gitignore @@ -0,0 +1,2 @@ +build/ +site/ diff --git a/docs/Project.toml b/docs/Project.toml new file mode 100644 index 0000000..dfa65cd --- /dev/null +++ b/docs/Project.toml @@ -0,0 +1,2 @@ +[deps] +Documenter = "e30172f5-a6a5-5a46-863b-614d45cd2de4" diff --git a/docs/make.jl b/docs/make.jl new file mode 100644 index 0000000..4371c07 --- /dev/null +++ b/docs/make.jl @@ -0,0 +1,19 @@ +using Documenter +using CoordVisualize + +makedocs( + sitename = "CoordVisualize", + format = Documenter.HTML(), + modules = [CoordVisualize], + pages = [ + "Top" => "index.md", + "API list" => "apis.md" + ] +) + +# Documenter can also automatically deploy documentation to gh-pages. +# See "Hosting Documentation" and deploydocs() in the Documenter manual +# for more information. +#=deploydocs( + repo = "" +)=# diff --git a/docs/src/apis.md b/docs/src/apis.md new file mode 100644 index 0000000..ab2478d --- /dev/null +++ b/docs/src/apis.md @@ -0,0 +1,8 @@ +# API list + +```@index +``` + +```@autodocs +Modules = [CoordVisualize] +``` diff --git a/docs/src/index.md b/docs/src/index.md new file mode 100644 index 0000000..f3b47c1 --- /dev/null +++ b/docs/src/index.md @@ -0,0 +1,27 @@ +```@meta +CurrentModule = CoordVisualize +``` + +# CoordVisualize.jl + +Documentation for CoordVisualize.jl + +## Tutorial +Readers are expected to be familiar with basics of julia. + +### Log structure +CoordVisualize.jl treats coordination trace log with some additional information, +datetime when log was taken and supplemental note to annotate the log. +This set of log is represented by the type [`CoordLog`](@ref). + +### Parsing Log +Use [`parse_log`](@ref) to parse log files generated with Tracecoords CSM mod. +Set the keyword argument `interactive` to `true` to supply notes interactively. +It automatically get datetime. +Notes can be also supplied in the following section. + +### Editing +You sometimes want to split logs and to give more appropriate notes for each of them. +You can do this with [`split_log`](@ref) function. + +You can also edit existing notes with [`assign_note!`](@ref). diff --git a/src/CoordVisualize.jl b/src/CoordVisualize.jl index e0a8927..a6660aa 100644 --- a/src/CoordVisualize.jl +++ b/src/CoordVisualize.jl @@ -5,5 +5,6 @@ using Dates include("typedef.jl") include("parser.jl") include("edit.jl") +include("print.jl") end # module CoordVisualize diff --git a/src/print.jl b/src/print.jl new file mode 100644 index 0000000..e69de29 diff --git a/src/typedef.jl b/src/typedef.jl index 7f722ba..83f125a 100644 --- a/src/typedef.jl +++ b/src/typedef.jl @@ -1,4 +1,7 @@ using Dates +""" +Stores a set of logs with its taken date datetime and supplemental note. +""" mutable struct CoordLog{T <: AbstractFloat} coords::Matrix{T} logdate::DateTime From f03b5f25f32c069db5aa4580eaabca0bbf2d1111 Mon Sep 17 00:00:00 2001 From: qwjyh Date: Tue, 14 Nov 2023 00:28:22 +0900 Subject: [PATCH 02/10] add export --- docs/src/index.md | 4 ++++ src/CoordVisualize.jl | 2 ++ src/print.jl | 30 ++++++++++++++++++++++++++++++ src/typedef.jl | 5 +++++ test/runtests.jl | 9 +++++++++ 5 files changed, 50 insertions(+) diff --git a/docs/src/index.md b/docs/src/index.md index f3b47c1..de514c8 100644 --- a/docs/src/index.md +++ b/docs/src/index.md @@ -25,3 +25,7 @@ You sometimes want to split logs and to give more appropriate notes for each of You can do this with [`split_log`](@ref) function. You can also edit existing notes with [`assign_note!`](@ref). + +### Exporting +Use [`export_log`](@ref) to export log to `io` or `file`. + diff --git a/src/CoordVisualize.jl b/src/CoordVisualize.jl index a6660aa..081a90f 100644 --- a/src/CoordVisualize.jl +++ b/src/CoordVisualize.jl @@ -2,6 +2,8 @@ module CoordVisualize using Dates +export CoordLog + include("typedef.jl") include("parser.jl") include("edit.jl") diff --git a/src/print.jl b/src/print.jl index e69de29..8c173ca 100644 --- a/src/print.jl +++ b/src/print.jl @@ -0,0 +1,30 @@ +""" +Export `log` to a file or `io::IO`. +""" +function export_log end + +function export_log(log::CoordLog) + """ + CoordLog( + $(log.coords), + Dates.DateTime("$(log.logdate)"), "$(log.note)" + )""" +end + +function export_log(logs::Vector{CoordLog}) + logs .|> + export_log |> + (vs -> join(vs, ",\n")) |> + (s -> "[\n" * s * "\n]") +end + +function export_log(io::IO, log::CoordLog) + write(io, export_log(log)) +end + +function export_log(file::AbstractString, log::CoordLog) + open(file, "w") do f + export_log(f, log) + end +end + diff --git a/src/typedef.jl b/src/typedef.jl index 83f125a..20ce80c 100644 --- a/src/typedef.jl +++ b/src/typedef.jl @@ -1,4 +1,5 @@ using Dates +import Base """ Stores a set of logs with its taken date datetime and supplemental note. """ @@ -16,3 +17,7 @@ Get number of coordinates in `log`. function n_coords(log::CoordLog)::Integer size(log.coords)[1] end + +Base.:(==)(x::CoordLog, y::CoordLog) = begin + x.note == y.note && x.logdate == y.logdate && x.coords == y.coords +end diff --git a/test/runtests.jl b/test/runtests.jl index 3639d3b..1e42e9a 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -5,11 +5,15 @@ using Test @testset "CoordVisualize" begin "Must be same as the first log in `sample_log.txt`" sample_log_1 = CoordVisualize.CoordLog[CoordVisualize.CoordLog{Float64}([-54.0 -10.000000953674 -35.000003814697; -54.0 -10.000000953674 -35.000003814697; -54.0 -10.000000953674 -36.013381958008; -54.0 -10.000000953674 -37.615753173828; -54.0 -10.000000953674 -39.261665344238; -54.0 -10.000000953674 -40.727695465088; -54.0 -10.000000953674 -42.168701171875; -54.0 -10.000000953674 -43.820377349854; -54.0 -11.018865585327 -47.018901824951; -54.0 -14.0 -51.176284790039; -54.663269042969 -14.0 -55.0; -58.297706604004 -14.0 -55.0; -63.16588973999 -16.0 -55.0; -66.000007629395 -16.0 -55.526763916016; -66.000007629395 -16.0 -59.460041046143; -66.000007629395 -16.0 -63.24658203125; -66.000007629395 -16.0 -67.261924743652; -66.000007629395 -16.0 -71.199310302734], Dates.DateTime("2023-10-22T10:02:04"), "")] + sample_log_1_2 = CoordVisualize.CoordLog[CoordVisualize.CoordLog{Float64}([-54.0 -10.000000953674 -35.000003814697; -54.0 -10.000000953674 -35.000003814697; -54.0 -10.000000953674 -36.013381958008; -54.0 -10.000000953674 -37.615753173828; -54.0 -10.000000953674 -39.261665344238; -54.0 -10.000000953674 -40.727695465088; -54.0 -10.000000953674 -42.168701171875; -54.0 -10.000000953674 -43.820377349854; -54.0 -11.018865585327 -47.018901824951; -54.0 -14.0 -51.176284790039; -54.663269042969 -14.0 -55.0; -58.297706604004 -14.0 -55.0; -63.16588973999 -16.0 -55.0; -66.000007629395 -16.0 -55.526763916016; -66.000007629395 -16.0 -59.460041046143; -66.000007629395 -16.0 -63.24658203125; -66.000007629395 -16.0 -67.261924743652; -66.000007629395 -16.0 -71.199310302734], Dates.DateTime("2023-10-22T10:02:04"), "")] "Must be same as the second log in `sample_log.txt`" sample_log_2 = CoordVisualize.CoordLog{Float64}([895.0 7.0 -978.0; 895.0 7.0 -978.0; 895.0 7.0 -977.38684082031; 895.0 7.0 -975.71923828125; 897.0 7.0 -974.39855957031; 898.80633544922 7.0 -973.0; 901.38275146484 7.0 -973.0; 904.18518066406 7.0 -973.0; 907.25793457031 7.0 -973.0; 911.19061279297 7.0 -973.0; 915.05682373047 7.0 -973.0; 919.1259765625 7.0 -973.0; 923.12609863281 7.0 -973.0; 926.94378662109 7.0 -973.0; 930.82952880859 7.0 -973.0; 934.84539794922 7.0 -973.0; 938.83020019531 7.0 -973.0; 944.04681396484 8.0 -973.0; 948.01483154297 8.0148372650146 -973.0; 951.48193359375 9.0000009536743 -973.0; 955.5927734375 10.000000953674 -973.0; 954.96008300781 10.000000953674 -973.0; 958.39764404297 11.000000953674 -973.0; 962.41009521484 12.000000953674 -973.0; 966.17108154297 12.000000953674 -973.0; 969.40936279297 12.000000953674 -973.0; 969.47576904297 13.0 -973.0; 973.32684326172 13.0 -973.0; 977.21990966797 13.0 -973.0; 981.09814453125 13.0 -973.0; 985.05871582031 13.0 -973.0; 989.03479003906 13.0 -973.0; 992.83026123047 13.0 -973.0; 996.90203857422 13.0 -973.0], DateTime("0000-01-01T00:00:00"), "") sample_result = CoordVisualize.parse_log("sample_log.txt"; interactive=false) + @testset "equality" begin + @test sample_log_1 == sample_log_1_2 + end @testset "parse" begin @debug sample_result @testset "parse with datetime" begin @@ -49,4 +53,9 @@ using Test @test splitted_2.note == "latter one" end end + + @testset "export" begin + re_evaled_log = CoordVisualize.export_log(sample_log_1) |> Meta.parse |> eval + @test re_evaled_log[1] == sample_log_1[1] + end end From ecd0d1c7b7f8c6b34d4f1fece9b4277a0cd47765 Mon Sep 17 00:00:00 2001 From: qwjyh Date: Tue, 2 Jan 2024 08:33:46 +0900 Subject: [PATCH 03/10] update to 1.10 & add doc for print, importing --- README.adoc | 3 ++- docs/Project.toml | 1 + docs/src/index.md | 2 ++ src/print.jl | 10 ++++++++-- 4 files changed, 13 insertions(+), 3 deletions(-) diff --git a/README.adoc b/README.adoc index d0772bd..ef39de9 100644 --- a/README.adoc +++ b/README.adoc @@ -14,7 +14,8 @@ ** Inspecting with GUI == TODO -- [ ] Printing +- [x] Printing - [ ] visualize +- [ ] interactive edit - [ ] doc diff --git a/docs/Project.toml b/docs/Project.toml index dfa65cd..c36628f 100644 --- a/docs/Project.toml +++ b/docs/Project.toml @@ -1,2 +1,3 @@ [deps] +CoordVisualize = "4c41ebcf-33aa-4478-9aac-83d12758d145" Documenter = "e30172f5-a6a5-5a46-863b-614d45cd2de4" diff --git a/docs/src/index.md b/docs/src/index.md index de514c8..f3ac26f 100644 --- a/docs/src/index.md +++ b/docs/src/index.md @@ -29,3 +29,5 @@ You can also edit existing notes with [`assign_note!`](@ref). ### Exporting Use [`export_log`](@ref) to export log to `io` or `file`. +### Importing +Do `using Dates` first and just `include("filename")` and it will return `Vector{CoordLog}`. diff --git a/src/print.jl b/src/print.jl index 8c173ca..f10c038 100644 --- a/src/print.jl +++ b/src/print.jl @@ -18,11 +18,17 @@ function export_log(logs::Vector{CoordLog}) (s -> "[\n" * s * "\n]") end -function export_log(io::IO, log::CoordLog) +""" + export_log(io::IO, log) +""" +function export_log(io::IO, log) write(io, export_log(log)) end -function export_log(file::AbstractString, log::CoordLog) +""" + export_log(file::AbstractString, log) +""" +function export_log(file::AbstractString, log) open(file, "w") do f export_log(f, log) end From 3a6d0da83edbbac55ef93e811ff45d3ff901f5bf Mon Sep 17 00:00:00 2001 From: qwjyh Date: Fri, 5 Jan 2024 22:03:13 +0900 Subject: [PATCH 04/10] (WIP) partial recipe for Trace2d --- .JuliaFormatter.toml | 13 +++ Project.toml | 4 + src/CoordVisualize.jl | 1 + src/visualize.jl | 237 ++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 255 insertions(+) create mode 100644 .JuliaFormatter.toml create mode 100644 src/visualize.jl diff --git a/.JuliaFormatter.toml b/.JuliaFormatter.toml new file mode 100644 index 0000000..df4710a --- /dev/null +++ b/.JuliaFormatter.toml @@ -0,0 +1,13 @@ +# See https://domluna.github.io/JuliaFormatter.jl/stable/ for a list of options +whitespace_ops_in_indices = true +remove_extra_newlines = true +always_for_in = true +whitespace_typedefs = true +normalize_line_endings = "unix" +# format_docstrings = true +# format_markdown = true +align_assignment = true +align_struct_field = true +align_conditional = true +align_pair_arrow = true +align_matrix = true diff --git a/Project.toml b/Project.toml index 4741e43..b3560ca 100644 --- a/Project.toml +++ b/Project.toml @@ -5,9 +5,13 @@ version = "0.1.0" [deps] ColorSchemes = "35d6a980-a343-548e-a6ea-1d62b119f2f4" +ColorTypes = "3da002f7-5984-5a60-b8a6-cbb66c0b333f" Dates = "ade2ca70-3891-5945-98fb-dc099432e06a" Documenter = "e30172f5-a6a5-5a46-863b-614d45cd2de4" +FileIO = "5789e2e9-d7fb-5bc7-8068-2c6fae9b9549" GLMakie = "e9467ef8-e4e7-5192-8a1a-b1aee30e663a" +Makie = "ee78f7c6-11fb-53f2-987a-cfe4a2b5a57a" +MakieCore = "20f20a25-4f0e-4fdf-b5d1-57303727442b" YAML = "ddb6d928-2868-570f-bddf-ab3f9cf99eb6" [extras] diff --git a/src/CoordVisualize.jl b/src/CoordVisualize.jl index 081a90f..213e425 100644 --- a/src/CoordVisualize.jl +++ b/src/CoordVisualize.jl @@ -8,5 +8,6 @@ include("typedef.jl") include("parser.jl") include("edit.jl") include("print.jl") +include("visualize.jl") end # module CoordVisualize diff --git a/src/visualize.jl b/src/visualize.jl new file mode 100644 index 0000000..321c66e --- /dev/null +++ b/src/visualize.jl @@ -0,0 +1,237 @@ +using GLMakie +using ColorTypes +using ColorSchemes +using FileIO + +function _plot_map!(ax, mappath::AbstractString) + map = load(mappath) + let + heigh, width = size(map) + heatmap!( + ax, + (1:width) .- width ÷ 2, + (1:heigh) .- width ÷ 2, + rotr90(map), + inspectable = false, + ) + end +end + +function view_with_map(log::CoordLog; map = "map.png") + fig = Figure() + ax = Axis(fig[1, 1], aspect = AxisAspect(1)) + _plot_map!(ax, map) + + 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), + strokecolor = theme(scene, :strokecolor), + 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[]) + 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[])) + on(linecolors) do lc + @info "linecolors update" + end + @info "linecolors" linecolors + + # helper function which mutates observables + function update_plot( + logs::AbstractVector{<:CoordLog}, + lcolormap, + mcolormap, + lcolormapfunc, #::Union{Symbol, Tuple{Symbol, Symbol}}, + mcolormapfunc, + ) + @info "update_plot" + linecolors[] + # @info "logs on update_plot" logs + # init + empty!(linesegs[]) + if !isnothing(mcolormapfunc) + # if markercolors[] isa AbstractVector + # empty!(markercolors[]) + # else + # markercolors[] = [] + # end + markercolors[] = mcolormapfunc(mcolormap, logs) + end + if linecolors[] isa AbstractVector + empty!(linecolors[]) + else + linecolors[] = [] + end + + # update + linecolors_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!(linecolors[], lcolormapfunc(lcolormap, logs)[linecolors_count]) + push!(linecolors[], lcolormapfunc(lcolormap, logs)[linecolors_count]) + linecolors_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 + + linecolors[] = linecolors[] + end + + Makie.Observables.onany( + update_plot, + tr2d.log, + tr2d.linecolormap, + tr2d.markercolormap, + lcolormapfunc, + tr2d.mcolormapfunc, + ) + @info "tr2d" lcolormapfunc + + # init + update_plot( + tr2d.log[], + tr2d.linecolormap[], + tr2d.markercolormap[], + lcolormapfunc[], + tr2d.mcolormapfunc[], + ) + + linesegments!( + tr2d, + linesegs, + color = linecolors, + linewidth = tr2d.linewidth, + linestyle = tr2d.linestyle, + ) + # @info "dump" dump(tr2d, maxdepth = 1) + # @info "attributes" dump(tr2d.attributes, maxdepth = 3) + + tr2d +end From 9996227460f23b18c413a1539a11c22764197f36 Mon Sep 17 00:00:00 2001 From: qwjyh Date: Fri, 5 Jan 2024 23:06:58 +0900 Subject: [PATCH 05/10] recipe Trace2d --- src/visualize.jl | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/src/visualize.jl b/src/visualize.jl index 321c66e..e36c076 100644 --- a/src/visualize.jl +++ b/src/visualize.jl @@ -107,7 +107,6 @@ TODO marker = theme(scene, :marker), markercolormap = theme(scene, :colormap), markersize = theme(scene, :markersize), - strokecolor = theme(scene, :strokecolor), strokewidth = theme(scene, :strokewidth), linecolormap = theme(scene, :colormap), linestyle = theme(scene, :linestyle), @@ -127,6 +126,7 @@ function Makie.plot!(tr2d::Trace2Ds) 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[]) @@ -137,10 +137,6 @@ function Makie.plot!(tr2d::Trace2Ds) end # @info "lcolormapfunc" lcolormapfunc linecolors = Observable(lcolormapfunc[](tr2d.linecolormap[], tr2d.log[])) - on(linecolors) do lc - @info "linecolors update" - end - @info "linecolors" linecolors # helper function which mutates observables function update_plot( @@ -151,18 +147,13 @@ function Makie.plot!(tr2d::Trace2Ds) mcolormapfunc, ) @info "update_plot" + markercolors[] linecolors[] # @info "logs on update_plot" logs # init empty!(linesegs[]) - if !isnothing(mcolormapfunc) - # if markercolors[] isa AbstractVector - # empty!(markercolors[]) - # else - # markercolors[] = [] - # end - markercolors[] = mcolormapfunc(mcolormap, logs) - end + empty!(points[]) + empty!(markercolors[]) if linecolors[] isa AbstractVector empty!(linecolors[]) else @@ -170,15 +161,17 @@ function Makie.plot!(tr2d::Trace2Ds) end # update - linecolors_count = 1 + 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!(linecolors[], lcolormapfunc(lcolormap, logs)[linecolors_count]) - push!(linecolors[], lcolormapfunc(lcolormap, logs)[linecolors_count]) - linecolors_count += 1 + 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) @@ -201,6 +194,7 @@ function Makie.plot!(tr2d::Trace2Ds) push!(notes[], log.note) end + markercolors[] = markercolors[] linecolors[] = linecolors[] end @@ -212,7 +206,6 @@ function Makie.plot!(tr2d::Trace2Ds) lcolormapfunc, tr2d.mcolormapfunc, ) - @info "tr2d" lcolormapfunc # init update_plot( @@ -230,6 +223,13 @@ function Makie.plot!(tr2d::Trace2Ds) 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) From d99771045efdde12ad1ba0fcf155cfac69daae63 Mon Sep 17 00:00:00 2001 From: qwjyh Date: Sat, 6 Jan 2024 23:46:51 +0900 Subject: [PATCH 06/10] 2d visualization --- interactive_viz.jl | 205 ++++++++++++++++++++++++++++++++ src/CoordVisualize.jl | 2 + src/parser.jl | 4 +- src/recipes.jl | 264 ++++++++++++++++++++++++++++++++++++++++++ src/visualize.jl | 212 +-------------------------------- 5 files changed, 474 insertions(+), 213 deletions(-) create mode 100644 interactive_viz.jl create mode 100644 src/recipes.jl diff --git a/interactive_viz.jl b/interactive_viz.jl new file mode 100644 index 0000000..c37fed8 --- /dev/null +++ b/interactive_viz.jl @@ -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) diff --git a/src/CoordVisualize.jl b/src/CoordVisualize.jl index 213e425..74b0457 100644 --- a/src/CoordVisualize.jl +++ b/src/CoordVisualize.jl @@ -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 diff --git a/src/parser.jl b/src/parser.jl index 3b9d5e5..8881a97 100644 --- a/src/parser.jl +++ b/src/parser.jl @@ -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 diff --git a/src/recipes.jl b/src/recipes.jl new file mode 100644 index 0000000..b18f1ea --- /dev/null +++ b/src/recipes.jl @@ -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 diff --git a/src/visualize.jl b/src/visualize.jl index e36c076..1288422 100644 --- a/src/visualize.jl +++ b/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 From e5db3cd694f46a2b53b84fb3404b28ebe3188a89 Mon Sep 17 00:00:00 2001 From: qwjyh Date: Sun, 7 Jan 2024 01:49:50 +0900 Subject: [PATCH 07/10] new: interactive edit --- Project.toml | 2 + docs/src/index.md | 34 ++++++++++++ interactive_viz.jl | 2 +- src/CoordVisualize.jl | 2 + src/interactive_edit.jl | 114 ++++++++++++++++++++++++++++++++++++++++ 5 files changed, 153 insertions(+), 1 deletion(-) create mode 100644 src/interactive_edit.jl diff --git a/Project.toml b/Project.toml index b3560ca..c61f0d6 100644 --- a/Project.toml +++ b/Project.toml @@ -12,6 +12,8 @@ FileIO = "5789e2e9-d7fb-5bc7-8068-2c6fae9b9549" GLMakie = "e9467ef8-e4e7-5192-8a1a-b1aee30e663a" Makie = "ee78f7c6-11fb-53f2-987a-cfe4a2b5a57a" MakieCore = "20f20a25-4f0e-4fdf-b5d1-57303727442b" +Printf = "de0858da-6303-5e67-8744-51eddeeeb8d7" +Statistics = "10745b16-79ce-11e8-11f9-7d13ad32a3b2" YAML = "ddb6d928-2868-570f-bddf-ab3f9cf99eb6" [extras] diff --git a/docs/src/index.md b/docs/src/index.md index f3ac26f..eeeaa19 100644 --- a/docs/src/index.md +++ b/docs/src/index.md @@ -9,6 +9,40 @@ Documentation for CoordVisualize.jl ## Tutorial Readers are expected to be familiar with basics of julia. +### Preparing +This will take a few minutes. + +```juliarepl +julia> # type ] + +(@v1.10) Pkg> activate . + +(CoordVisualize) Pkg> instantiate +``` + +### Parse log +```juliarepl +julia> using CoordVisualize + +julia> interactive_edit_log("coord_log_1.txt", "coord_log_2.txt") +... + Follow the instruction +... +``` + +### CoordVisualize +Get map image file and place it as "map.png". + +```juliarepl +julia> using GLMakie, CoordVisualize + +julia> tlog = include(""); + +julia> include("/interactive_viz.jl") +``` + +## Low level + ### Log structure CoordVisualize.jl treats coordination trace log with some additional information, datetime when log was taken and supplemental note to annotate the log. diff --git a/interactive_viz.jl b/interactive_viz.jl index c37fed8..4fa85f4 100644 --- a/interactive_viz.jl +++ b/interactive_viz.jl @@ -106,7 +106,7 @@ fig[1:2, 2] = grid!( width = options_width, ) -tlog = vcat(CoordVisualize.parse_log.(["coord_log_5.txt", "coord_log_6.txt"])...) +# tlog = vcat(CoordVisualize.parse_log.(["coord_log_5.txt", "coord_log_6.txt"])...) # Main heatmap!( diff --git a/src/CoordVisualize.jl b/src/CoordVisualize.jl index 74b0457..e848564 100644 --- a/src/CoordVisualize.jl +++ b/src/CoordVisualize.jl @@ -3,11 +3,13 @@ module CoordVisualize using Dates export CoordLog +export interactive_edit_log export ColorMapFuncs include("typedef.jl") include("parser.jl") include("edit.jl") +include("interactive_edit.jl") include("print.jl") include("recipes.jl") include("visualize.jl") diff --git a/src/interactive_edit.jl b/src/interactive_edit.jl new file mode 100644 index 0000000..1277c44 --- /dev/null +++ b/src/interactive_edit.jl @@ -0,0 +1,114 @@ +using Statistics +using Dates +using Printf + +function interactive_edit_log(filenames...; writetofile = true) + printstyled(stdout, "[CoordLog Editor] \n", color = :blue, bold = true) + logs = CoordLog[] + printstyled(stdout, "loading log files\n", color = :blue) + for file in filenames + append!(logs, parse_log(file)) + end + printstyled(stdout, "all files loaded\n", color = :blue) + edited_logs = CoordLog[] + for (i, log) in enumerate(logs) + printstyled(stdout, "LogEdit: editing log $(i) / $(length(logs))\n", color = :blue) + printstyled(stdout, "summary\n", color = :cyan) + println( + stdout, + """ + mean : $(mean(eachrow(log.coords)) .|> round |> Tuple) + start : $(log.coords[1, :] .|> round |> Tuple) + end : $(log.coords[end, :] .|> round |> Tuple) + datetime : $(Dates.format(log.logdate, DateFormat("yyyy-mm-dd HH:MM:SS"))) + number of coords: $(size(log.coords)[1]) + """, + ) + @label ask + printstyled(stdout, "split log?(y/N): ", color = :green, italic = true) + ans = readline(stdin) + if ans == "y" || ans == "Y" + while true + maximum = size(log.coords)[1] + printstyled( + stdout, + "split at where (1 to n, n to end), max = $(maximum): ", + color = :green, + italic = true, + ) + at = try + parse(UInt64, readline(stdin)) + catch + printstyled("invalid input, please type number\n", color = :red) + continue + end + if at ≥ maximum + printstyled("too large number; max = $(maximum)\n", color = :red) + continue + end + if at == 0 + printstyled("must be larger than 0\n", color = :red) + continue + end + print(""" + summary of the first log: + mean : $(mean(eachrow(log.coords)[1:at]) .|> round |> Tuple) + start : $(log.coords[1, :] .|> round |> Tuple) + end : $(log.coords[at, :] .|> round |> Tuple) + """) + printstyled("note for the first log: ", color = :green, italic = true) + note_1 = readline(stdin) + new_log, log = split_log(log, at, note_1, "") + push!(edited_logs, new_log) + print(""" + summary of the remaining log: + mean : $(mean(eachrow(log.coords)) .|> round |> Tuple) + start : $(log.coords[1, :] .|> round |> Tuple) + end : $(log.coords[end, :] .|> round |> Tuple) + datetime : $(Dates.format(log.logdate, DateFormat("yyyy-mm-dd HH:MM:SS"))) + number of coords: $(size(log.coords)[1]) + """) + @goto ask + end + elseif ans == "n" || ans == "N" || ans == "" + printstyled("note for the log: ", color = :green, italic = true) + note = readline() + assign_note!(log, note) + push!(edited_logs, log) + else + printstyled("invalid ans; type y or n\n", color = :red) + @goto ask + end + end + println() + printstyled("Finish editing\n", color = :blue, bold = true) + printstyled("number of logs: $(length(edited_logs))\n", color = :cyan) + printstyled("summary: length, note\n", color = :cyan) + len_ncoords = maximum(ndigits.(n_coords.(edited_logs))) + for log in edited_logs + println(" ", lpad(n_coords(log), len_ncoords), " ", log.note) + end + if writetofile + printstyled("Writing to file\n", color = :blue, bold = true) + printstyled("filename: ", color = :green, italic = true) + filename = readline() + if filename in readdir() + printstyled("$(filename) already exists.", color = :magenta) + printstyled("Are you sure to overwrite? (y/N)", color = :magenta, italic = true) + ans = readline() + if ans == "y" || ans == "Y" + elseif ans == "n" || ans == "N" || ans == "" + printstyled("Skip exporting to a file. Please export the returned log manually.\n", color = :magenta) + @goto finish + end + end + open(filename, "w") do f + println(f, "using Dates") + println(f, export_log(edited_logs)) + end + printstyled("Exported log to the file: $(filename)\n", color = :blue) + end + @label finish + printstyled("Edit completed.\n", color = :blue, bold = true) + return edited_logs +end From 49fa679d9a5a0318413f9614f05cfcb454f5faad Mon Sep 17 00:00:00 2001 From: qwjyh Date: Sun, 7 Jan 2024 18:28:38 +0900 Subject: [PATCH 08/10] interactive edits --- src/CoordVisualize.jl | 4 ++- src/edit.jl | 33 +++++++++++++++-- src/interactive_edit.jl | 79 +++++++++++++++++++++++++++++++++++------ src/print.jl | 9 ++++- src/recipes.jl | 15 +++++++- src/typedef.jl | 4 +++ 6 files changed, 127 insertions(+), 17 deletions(-) diff --git a/src/CoordVisualize.jl b/src/CoordVisualize.jl index e848564..5726392 100644 --- a/src/CoordVisualize.jl +++ b/src/CoordVisualize.jl @@ -3,7 +3,9 @@ module CoordVisualize using Dates export CoordLog -export interactive_edit_log +export iedit_log +export isplit_log!, iedit_note!, ijoin_logs! +export export_log export ColorMapFuncs include("typedef.jl") diff --git a/src/edit.jl b/src/edit.jl index 3458d34..7a432dd 100644 --- a/src/edit.jl +++ b/src/edit.jl @@ -3,7 +3,12 @@ Split `log` at `at`, i.e. to `1:at` and `(at + 1):end` then assign `notes_1` and `notes_2` to notes for each other. """ -function split_log(log::CoordLog, at::Unsigned, notes_1::AbstractString, notes_2::AbstractString)::Tuple{CoordLog, CoordLog} +function split_log( + log::CoordLog, + at::Unsigned, + notes_1::AbstractString, + notes_2::AbstractString, +)::Tuple{CoordLog, CoordLog} @assert at < size(log.coords)[1] "Split index must be less than original log length($(size(log.coords)[1]))" ( CoordLog(log.coords[1:at, :], log.logdate, notes_1), @@ -11,11 +16,15 @@ function split_log(log::CoordLog, at::Unsigned, notes_1::AbstractString, notes_2 ) end -function split_log(log::CoordLog, at::Integer, notes_1::AbstractString, notes_2::AbstractString)::Tuple{CoordLog, CoordLog} +function split_log( + log::CoordLog, + at::Integer, + notes_1::AbstractString, + notes_2::AbstractString, +)::Tuple{CoordLog, CoordLog} split_log(log, UInt(at), notes_1, notes_2) end - """ assign_note!(log::CoordLog, new_note::AbstractString) @@ -24,3 +33,21 @@ Replace `note` in `log` with `new_note`. function assign_note!(log::CoordLog, new_note::AbstractString) log.note = new_note end + +""" + join_log( + log1::CoordLog{T}, + log2::CoordLog{T}, + note::AbstractString, + )::CoordLog{T} where {T} + +Join two logs. +""" +function join_log( + log1::CoordLog{T}, + log2::CoordLog{T}, + note::AbstractString, +)::CoordLog{T} where {T} + newdate = min(log1.logdate, log2.logdate) + CoordLog(vcat(log1.coords, log2.coords), newdate, note) +end diff --git a/src/interactive_edit.jl b/src/interactive_edit.jl index 1277c44..298a8f8 100644 --- a/src/interactive_edit.jl +++ b/src/interactive_edit.jl @@ -2,7 +2,7 @@ using Statistics using Dates using Printf -function interactive_edit_log(filenames...; writetofile = true) +function iedit_log(filenames...; writetofile = true) printstyled(stdout, "[CoordLog Editor] \n", color = :blue, bold = true) logs = CoordLog[] printstyled(stdout, "loading log files\n", color = :blue) @@ -10,7 +10,7 @@ function interactive_edit_log(filenames...; writetofile = true) append!(logs, parse_log(file)) end printstyled(stdout, "all files loaded\n", color = :blue) - edited_logs = CoordLog[] + edited_logs = CoordLog{Float64}[] for (i, log) in enumerate(logs) printstyled(stdout, "LogEdit: editing log $(i) / $(length(logs))\n", color = :blue) printstyled(stdout, "summary\n", color = :cyan) @@ -60,14 +60,16 @@ function interactive_edit_log(filenames...; writetofile = true) note_1 = readline(stdin) new_log, log = split_log(log, at, note_1, "") push!(edited_logs, new_log) - print(""" - summary of the remaining log: - mean : $(mean(eachrow(log.coords)) .|> round |> Tuple) - start : $(log.coords[1, :] .|> round |> Tuple) - end : $(log.coords[end, :] .|> round |> Tuple) - datetime : $(Dates.format(log.logdate, DateFormat("yyyy-mm-dd HH:MM:SS"))) - number of coords: $(size(log.coords)[1]) - """) + print( + """ + summary of the remaining log: + mean : $(mean(eachrow(log.coords)) .|> round |> Tuple) + start : $(log.coords[1, :] .|> round |> Tuple) + end : $(log.coords[end, :] .|> round |> Tuple) + datetime : $(Dates.format(log.logdate, DateFormat("yyyy-mm-dd HH:MM:SS"))) + number of coords: $(size(log.coords)[1]) + """, + ) @goto ask end elseif ans == "n" || ans == "N" || ans == "" @@ -98,7 +100,10 @@ function interactive_edit_log(filenames...; writetofile = true) ans = readline() if ans == "y" || ans == "Y" elseif ans == "n" || ans == "N" || ans == "" - printstyled("Skip exporting to a file. Please export the returned log manually.\n", color = :magenta) + printstyled( + "Skip exporting to a file. Please export the returned log manually.\n", + color = :magenta, + ) @goto finish end end @@ -112,3 +117,55 @@ function interactive_edit_log(filenames...; writetofile = true) printstyled("Edit completed.\n", color = :blue, bold = true) return edited_logs end + +function isplit_log!( + logs::AbstractVector{CoordLog{T}}, + logid::Integer, + pointid::Integer, +) where {T} + 1 ≤ logid ≤ length(logs) || + throw(ArgumentError("logid out of index: ¬ 1 ≤ $(logid) ≤ $(length(logid))")) + if !(1 < pointid < n_coords(logs[logid])) + throw( + ArgumentError( + "pointid($(pointid)) out of index: min=2, max=$(n_coords(logs[logid]) - 1)", + ), + ) + end + + log = popat!(logs, logid) + printstyled("note for the first log: ", color = :green, italic = true) + note_1 = readline() + printstyled("note for the second log: ", color = :green, italic = true) + note_2 = readline() + new_logs = split_log(log, pointid, note_1, note_2) + insert!(logs, logid, new_logs[1]) + insert!(logs, logid + 1, new_logs[2]) +end + +function iedit_note!(logs::AbstractVector{CoordLog{T}}, logid::Integer) where {T} + 1 ≤ logid ≤ length(logs) || + throw(ArgumentError("logid out of index: ¬ 1 ≤ $(logid) ≤ $(length(logid))")) + printstyled("new note for the log: ", color = :green, italic = true) + note = readline() + logs[logid].note = note +end + +function ijoin_logs!(logs::AbstractVector{CoordLog{T}}, logid1::Integer, logid2::Integer) where {T} + 1 ≤ logid1 ≤ length(logs) || + throw(ArgumentError("logid1 out of index: ¬ 1 ≤ $(logid1) ≤ $(length(logid1))")) + 1 ≤ logid2 ≤ length(logs) || + throw(ArgumentError("logid2 out of index: ¬ 1 ≤ $(logid2) ≤ $(length(logid2))")) + logid1 == logid2 && throw(ArgumentError("logid1 and logid2 cannot be the same")) + if logid1 > logid2 + logid1, logid2 = logid2, logid1 + end + + log_1 = popat!(logs, logid1) + log_2 = popat!(logs, logid2 - 1) + + printstyled("note for the new log: ", color = :green, italic = true) + note = readline() + log = join_log(log_1, log_2, note) + insert!(logs, logid1, log) +end diff --git a/src/print.jl b/src/print.jl index f10c038..035f76c 100644 --- a/src/print.jl +++ b/src/print.jl @@ -11,13 +11,20 @@ function export_log(log::CoordLog) )""" end -function export_log(logs::Vector{CoordLog}) +function export_log(logs::Vector{CoordLog{T}}) where {T} logs .|> export_log |> (vs -> join(vs, ",\n")) |> (s -> "[\n" * s * "\n]") end +function export_log(logs::Vector{CoordLog{T}}, filename::AbstractString) where {T} + open(filename, "w") do f + println(f, "using Dates") + println(f, export_log(logs)) + end +end + """ export_log(io::IO, log) """ diff --git a/src/recipes.jl b/src/recipes.jl index b18f1ea..813c30c 100644 --- a/src/recipes.jl +++ b/src/recipes.jl @@ -142,6 +142,7 @@ function Makie.plot!(tr2d::Trace2Ds) linesegs = Observable(Point2f[]) points = Observable(Point2f[]) altitudes = Observable(Float64[]) + point_ids = Observable(Tuple{Int64, Int64}[]) notes = Observable(String[]) if tr2d.markercolormap[] isa Symbol tr2d.markercolormap[] = getproperty(ColorSchemes, tr2d.markercolormap[]) @@ -174,6 +175,7 @@ function Makie.plot!(tr2d::Trace2Ds) empty!(linesegs[]) empty!(points[]) empty!(altitudes[]) + empty!(point_ids[]) empty!(markercolors[]) if linecolors[] isa AbstractVector empty!(linecolors[]) @@ -187,11 +189,12 @@ function Makie.plot!(tr2d::Trace2Ds) mcolors, mticks[] = mcolormapfunc(mcolormap, logs, tr2d.nmcolorticks[]) for (i, log) in enumerate(logs) first = true - for point in eachrow(log.coords) + for (j, point) in enumerate(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!(point_ids[], (i, j)) push!(linecolors[], lcolors[colors_count]) push!(linecolors[], lcolors[colors_count]) push!(markercolors[], mcolors[colors_count]) @@ -256,6 +259,16 @@ function Makie.plot!(tr2d::Trace2Ds) markersize = tr2d.markersize, strokewidth = tr2d.strokewidth, visible = tr2d.showmarker, + inspector_label = (self, i, pos) -> begin + logid, pointid = point_ids[][i] + """ + log: $(logid), point: $(pointid) + x: $(lpad(round(pos[1], digits = 1), 7)) + y: $(lpad(round(altitudes[][i], digits = 1), 7)) + z: $(lpad(round(pos[2], digits = 1), 7)) + $(tr2d.log[][logid].note) + """ + end, ) # @info "dump" dump(tr2d, maxdepth = 1) # @info "attributes" dump(tr2d.attributes, maxdepth = 3) diff --git a/src/typedef.jl b/src/typedef.jl index 20ce80c..8ee6182 100644 --- a/src/typedef.jl +++ b/src/typedef.jl @@ -21,3 +21,7 @@ end Base.:(==)(x::CoordLog, y::CoordLog) = begin x.note == y.note && x.logdate == y.logdate && x.coords == y.coords end + +function Base.getindex(log::CoordLog{T}, i) where {T} + log.coords[i, :] +end From 69a47a24e893ffe99d9365a778a1ea150f37ab00 Mon Sep 17 00:00:00 2001 From: qwjyh Date: Sun, 7 Jan 2024 18:58:29 +0900 Subject: [PATCH 09/10] update doc --- README.adoc | 15 +++++++++++++++ docs/src/apis.md | 6 ++++++ docs/src/index.md | 42 ++++++++++++++++++++++++++++++++++------- interactive_viz.jl | 4 ++-- src/interactive_edit.jl | 22 +++++++++++++++++++++ src/recipes.jl | 20 +++++++++++++++++--- 6 files changed, 97 insertions(+), 12 deletions(-) diff --git a/README.adoc b/README.adoc index ef39de9..fdf3658 100644 --- a/README.adoc +++ b/README.adoc @@ -13,6 +13,21 @@ * Visualize with GLMakie (or CairoMakie) ** Inspecting with GUI +== Docs +Clone this repo, and +```sh +$ cd docs + +$ julia --project -e 'using Pkg; Pkg.instantiate()' + +$ julia --project make.jl + +$ cd build + +$ python -m http.server --bind localhost + +``` + == TODO - [x] Printing - [ ] visualize diff --git a/docs/src/apis.md b/docs/src/apis.md index ab2478d..6f203de 100644 --- a/docs/src/apis.md +++ b/docs/src/apis.md @@ -6,3 +6,9 @@ ```@autodocs Modules = [CoordVisualize] ``` + +# ColorMapFuncs + +```@autodocs +Modules = [CoordVisualize.ColorMapFuncs] +``` diff --git a/docs/src/index.md b/docs/src/index.md index eeeaa19..293bc14 100644 --- a/docs/src/index.md +++ b/docs/src/index.md @@ -12,7 +12,7 @@ Readers are expected to be familiar with basics of julia. ### Preparing This will take a few minutes. -```juliarepl +```julia-repl julia> # type ] (@v1.10) Pkg> activate . @@ -21,24 +21,52 @@ julia> # type ] ``` ### Parse log -```juliarepl +```julia-repl julia> using CoordVisualize -julia> interactive_edit_log("coord_log_1.txt", "coord_log_2.txt") +julia> iedit_log("coord_log_1.txt", "coord_log_2.txt") ... Follow the instruction ... ``` -### CoordVisualize -Get map image file and place it as "map.png". +### Visualize the log +Get map image file and place it as "map.png" beforehand. -```juliarepl +```julia-repl julia> using GLMakie, CoordVisualize -julia> tlog = include(""); +julia> tlog = Observable(include("")) +... + +julia> # or + +julia> tlog = Observable(interactive_edit_log("log files", "log file2")) +... julia> include("/interactive_viz.jl") +... +``` + +Available colorschemes at https://juliagraphics.github.io/ColorSchemes.jl/stable/catalogue/ . +Available colors at https://juliagraphics.github.io/Colors.jl/stable/constructionandconversion/#Color-Parsing and https://juliagraphics.github.io/Colors.jl/stable/namedcolors/ . + +### Edit the log +```julia-repl +julia> isplit_log!(tlog[], 3, 30) +... + +julia> iedit_note!(tlog[], 3) +... + +julia> ijoin_logs!(tlog[], 5, 7) +... + +``` + +### Export the log +```julia-repl +julia> export_log(tlog[], "") ``` ## Low level diff --git a/interactive_viz.jl b/interactive_viz.jl index 4fa85f4..18e7c9c 100644 --- a/interactive_viz.jl +++ b/interactive_viz.jl @@ -94,7 +94,7 @@ inspector_options = grid!( [1, 2] => toggle_inspector, width = options_width, ) -fig[1:2, 2] = grid!( +fig[1:2, 3] = grid!( [0, :] => Label(fig, "Line", font = :bold), [1, :] => line_options, [2, :] => Label(fig, "Marker", font = :bold), @@ -143,7 +143,7 @@ cbm = Colorbar( ticklabelsize = 10, label = menu_mcolormapfunc.selection, ) -fig[1:2, 3] = grid!( +fig[1:2, 2] = grid!( [0, 1] => Label(fig, "line", font = :bold), [1, 1] => cbl, [2, 1] => Label(fig, "marker", font = :bold), diff --git a/src/interactive_edit.jl b/src/interactive_edit.jl index 298a8f8..b92fb50 100644 --- a/src/interactive_edit.jl +++ b/src/interactive_edit.jl @@ -2,6 +2,9 @@ using Statistics using Dates using Printf +""" +Interactively parse log files and edit the log. +""" function iedit_log(filenames...; writetofile = true) printstyled(stdout, "[CoordLog Editor] \n", color = :blue, bold = true) logs = CoordLog[] @@ -118,6 +121,15 @@ function iedit_log(filenames...; writetofile = true) return edited_logs end +""" + isplit_log!( + logs::AbstractVector{CoordLog{T}}, + logid::Integer, + pointid::Integer, + ) where {T} + +Split the log. Supply notes interactively. +""" function isplit_log!( logs::AbstractVector{CoordLog{T}}, logid::Integer, @@ -143,6 +155,11 @@ function isplit_log!( insert!(logs, logid + 1, new_logs[2]) end +""" + iedit_note!(logs::AbstractVector{CoordLog{T}}, logid::Integer) where {T} + +Edit the note at `logid`. Supply new note interactively. +""" function iedit_note!(logs::AbstractVector{CoordLog{T}}, logid::Integer) where {T} 1 ≤ logid ≤ length(logs) || throw(ArgumentError("logid out of index: ¬ 1 ≤ $(logid) ≤ $(length(logid))")) @@ -151,6 +168,11 @@ function iedit_note!(logs::AbstractVector{CoordLog{T}}, logid::Integer) where {T logs[logid].note = note end +""" + ijoin_logs!(logs::AbstractVector{CoordLog{T}}, logid1::Integer, logid2::Integer) where {T} + +Join the logs at `logid1` and `logid2`. Supply new note interactively. +""" function ijoin_logs!(logs::AbstractVector{CoordLog{T}}, logid1::Integer, logid2::Integer) where {T} 1 ≤ logid1 ≤ length(logs) || throw(ArgumentError("logid1 out of index: ¬ 1 ≤ $(logid1) ≤ $(length(logid1))")) diff --git a/src/recipes.jl b/src/recipes.jl index 813c30c..76c87a1 100644 --- a/src/recipes.jl +++ b/src/recipes.jl @@ -4,16 +4,29 @@ using ColorSchemes """ Predefined color map functions. +Receives +- `cmap`: colormap +- `logs`: vector of `CoordLog` +- `n`: number of returning ticks + +and returns tuple of +1. vector of `Colorant` +2. ticks to pass to `Colorbar`, which is a Tuple of + 1. vector of tick location (0 to 1) + 2. vector of tick labels (strings) + +Any function (or struct) which behaves like this can be used for +`lcolormapfunc` and `mcolormapfunc` kwargs of `trace2ds`. # Types -[`ColorMapFunc`](@ref) +[`ColorMapFunc`](@ref) is a supertype of all of these. # Interface Define these methods for the ColorMapFunc. - (AbstractVector{CoordLog}) -> Vector{∈ [0, 1]}, ticks + (cmap, logs, n) -> Vector{Colorant}, ticks """ module ColorMapFuncs @@ -26,7 +39,8 @@ using Makie: wong_colors, Scene # Methods (f::ColorMapFunc)(cmap, logs) -Helper method. +Helper struct for those use vector of 0 to 1 floats. +Example functions are [`Date`](@ref) and [`Altitude`](@ref). """ abstract type ColorMapFunc end From efc37be0879d7892d691dabe60d7f13756edb627 Mon Sep 17 00:00:00 2001 From: qwjyh Date: Sun, 7 Jan 2024 19:03:29 +0900 Subject: [PATCH 10/10] bump version --- Project.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Project.toml b/Project.toml index c61f0d6..fbaed4b 100644 --- a/Project.toml +++ b/Project.toml @@ -1,7 +1,7 @@ name = "CoordVisualize" uuid = "4c41ebcf-33aa-4478-9aac-83d12758d145" authors = ["qwjyh "] -version = "0.1.0" +version = "1.0.0" [deps] ColorSchemes = "35d6a980-a343-548e-a6ea-1d62b119f2f4"