diff --git a/.JuliaFormatter.toml b/.JuliaFormatter.toml deleted file mode 100644 index df4710a..0000000 --- a/.JuliaFormatter.toml +++ /dev/null @@ -1,13 +0,0 @@ -# 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 fbaed4b..3150d03 100644 --- a/Project.toml +++ b/Project.toml @@ -1,19 +1,12 @@ name = "CoordVisualize" uuid = "4c41ebcf-33aa-4478-9aac-83d12758d145" authors = ["qwjyh "] -version = "1.0.0" +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" -Printf = "de0858da-6303-5e67-8744-51eddeeeb8d7" -Statistics = "10745b16-79ce-11e8-11f9-7d13ad32a3b2" YAML = "ddb6d928-2868-570f-bddf-ab3f9cf99eb6" [extras] diff --git a/README.adoc b/README.adoc index fdf3658..d0772bd 100644 --- a/README.adoc +++ b/README.adoc @@ -13,24 +13,8 @@ * 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 +- [ ] Printing - [ ] visualize -- [ ] interactive edit - [ ] doc diff --git a/docs/.gitignore b/docs/.gitignore deleted file mode 100644 index a303fff..0000000 --- a/docs/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -build/ -site/ diff --git a/docs/Project.toml b/docs/Project.toml deleted file mode 100644 index c36628f..0000000 --- a/docs/Project.toml +++ /dev/null @@ -1,3 +0,0 @@ -[deps] -CoordVisualize = "4c41ebcf-33aa-4478-9aac-83d12758d145" -Documenter = "e30172f5-a6a5-5a46-863b-614d45cd2de4" diff --git a/docs/make.jl b/docs/make.jl deleted file mode 100644 index 4371c07..0000000 --- a/docs/make.jl +++ /dev/null @@ -1,19 +0,0 @@ -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 deleted file mode 100644 index 6f203de..0000000 --- a/docs/src/apis.md +++ /dev/null @@ -1,14 +0,0 @@ -# API list - -```@index -``` - -```@autodocs -Modules = [CoordVisualize] -``` - -# ColorMapFuncs - -```@autodocs -Modules = [CoordVisualize.ColorMapFuncs] -``` diff --git a/docs/src/index.md b/docs/src/index.md deleted file mode 100644 index 293bc14..0000000 --- a/docs/src/index.md +++ /dev/null @@ -1,95 +0,0 @@ -```@meta -CurrentModule = CoordVisualize -``` - -# CoordVisualize.jl - -Documentation for CoordVisualize.jl - -## Tutorial -Readers are expected to be familiar with basics of julia. - -### Preparing -This will take a few minutes. - -```julia-repl -julia> # type ] - -(@v1.10) Pkg> activate . - -(CoordVisualize) Pkg> instantiate -``` - -### Parse log -```julia-repl -julia> using CoordVisualize - -julia> iedit_log("coord_log_1.txt", "coord_log_2.txt") -... - Follow the instruction -... -``` - -### Visualize the log -Get map image file and place it as "map.png" beforehand. - -```julia-repl -julia> using GLMakie, CoordVisualize - -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 - -### 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). - -### 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/interactive_viz.jl b/interactive_viz.jl deleted file mode 100644 index 18e7c9c..0000000 --- a/interactive_viz.jl +++ /dev/null @@ -1,205 +0,0 @@ -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, 3] = 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, 2] = 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 5726392..e0a8927 100644 --- a/src/CoordVisualize.jl +++ b/src/CoordVisualize.jl @@ -2,18 +2,8 @@ module CoordVisualize using Dates -export CoordLog -export iedit_log -export isplit_log!, iedit_note!, ijoin_logs! -export export_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") end # module CoordVisualize diff --git a/src/edit.jl b/src/edit.jl index 7a432dd..3458d34 100644 --- a/src/edit.jl +++ b/src/edit.jl @@ -3,12 +3,7 @@ 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), @@ -16,15 +11,11 @@ function split_log( ) 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) @@ -33,21 +24,3 @@ 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 deleted file mode 100644 index b92fb50..0000000 --- a/src/interactive_edit.jl +++ /dev/null @@ -1,193 +0,0 @@ -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[] - 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{Float64}[] - 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 - -""" - 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, - 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 - -""" - 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))")) - printstyled("new note for the log: ", color = :green, italic = true) - note = readline() - 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))")) - 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/parser.jl b/src/parser.jl index 8881a97..3b9d5e5 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{Float64}} +function parse_log(filepath::AbstractString; interactive=false)::Vector{CoordLog} istracing::Bool = false coords_trace = Vector{Vector{Float64}}(undef, 0) # SVector ? - ret = Vector{CoordLog{Float64}}() + ret = Vector{CoordLog}() log_date = DateTime(0) for (i, l) in enumerate(readlines(filepath)) # skip logs not from tracecoord diff --git a/src/print.jl b/src/print.jl deleted file mode 100644 index 035f76c..0000000 --- a/src/print.jl +++ /dev/null @@ -1,43 +0,0 @@ -""" -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{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) -""" -function export_log(io::IO, log) - write(io, export_log(log)) -end - -""" - export_log(file::AbstractString, log) -""" -function export_log(file::AbstractString, log) - open(file, "w") do f - export_log(f, log) - end -end - diff --git a/src/recipes.jl b/src/recipes.jl deleted file mode 100644 index 76c87a1..0000000 --- a/src/recipes.jl +++ /dev/null @@ -1,291 +0,0 @@ -using GLMakie -using ColorTypes -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) is a supertype of all of these. - -# Interface - -Define these methods for the ColorMapFunc. - - (cmap, logs, n) -> Vector{Colorant}, 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 struct for those use vector of 0 to 1 floats. -Example functions are [`Date`](@ref) and [`Altitude`](@ref). -""" -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[]) - point_ids = Observable(Tuple{Int64, Int64}[]) - 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!(point_ids[]) - 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 (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]) - 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, - 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) - - tr2d -end diff --git a/src/typedef.jl b/src/typedef.jl index 8ee6182..7f722ba 100644 --- a/src/typedef.jl +++ b/src/typedef.jl @@ -1,8 +1,4 @@ using Dates -import Base -""" -Stores a set of logs with its taken date datetime and supplemental note. -""" mutable struct CoordLog{T <: AbstractFloat} coords::Matrix{T} logdate::DateTime @@ -17,11 +13,3 @@ 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 - -function Base.getindex(log::CoordLog{T}, i) where {T} - log.coords[i, :] -end diff --git a/src/visualize.jl b/src/visualize.jl deleted file mode 100644 index 1288422..0000000 --- a/src/visualize.jl +++ /dev/null @@ -1,27 +0,0 @@ -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) .- heigh ÷ 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 - diff --git a/test/runtests.jl b/test/runtests.jl index 1e42e9a..3639d3b 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -5,15 +5,11 @@ 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 @@ -53,9 +49,4 @@ 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