Compare commits
10 commits
39b5a334c7
...
efc37be087
Author | SHA1 | Date | |
---|---|---|---|
efc37be087 | |||
69a47a24e8 | |||
49fa679d9a | |||
e5db3cd694 | |||
d99771045e | |||
9996227460 | |||
3a6d0da83e | |||
ecd0d1c7b7 | |||
f03b5f25f3 | |||
bcd54dc673 |
18 changed files with 993 additions and 7 deletions
13
.JuliaFormatter.toml
Normal file
13
.JuliaFormatter.toml
Normal file
|
@ -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
|
|
@ -1,12 +1,19 @@
|
|||
name = "CoordVisualize"
|
||||
uuid = "4c41ebcf-33aa-4478-9aac-83d12758d145"
|
||||
authors = ["qwjyh <urataw421@gmail.com>"]
|
||||
version = "0.1.0"
|
||||
version = "1.0.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]
|
||||
|
|
18
README.adoc
18
README.adoc
|
@ -13,8 +13,24 @@
|
|||
* 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
|
||||
- [ ] Printing
|
||||
- [x] Printing
|
||||
- [ ] visualize
|
||||
- [ ] interactive edit
|
||||
- [ ] doc
|
||||
|
||||
|
|
2
docs/.gitignore
vendored
Normal file
2
docs/.gitignore
vendored
Normal file
|
@ -0,0 +1,2 @@
|
|||
build/
|
||||
site/
|
3
docs/Project.toml
Normal file
3
docs/Project.toml
Normal file
|
@ -0,0 +1,3 @@
|
|||
[deps]
|
||||
CoordVisualize = "4c41ebcf-33aa-4478-9aac-83d12758d145"
|
||||
Documenter = "e30172f5-a6a5-5a46-863b-614d45cd2de4"
|
19
docs/make.jl
Normal file
19
docs/make.jl
Normal file
|
@ -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 = "<repository url>"
|
||||
)=#
|
14
docs/src/apis.md
Normal file
14
docs/src/apis.md
Normal file
|
@ -0,0 +1,14 @@
|
|||
# API list
|
||||
|
||||
```@index
|
||||
```
|
||||
|
||||
```@autodocs
|
||||
Modules = [CoordVisualize]
|
||||
```
|
||||
|
||||
# ColorMapFuncs
|
||||
|
||||
```@autodocs
|
||||
Modules = [CoordVisualize.ColorMapFuncs]
|
||||
```
|
95
docs/src/index.md
Normal file
95
docs/src/index.md
Normal file
|
@ -0,0 +1,95 @@
|
|||
```@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("<exported log file>"))
|
||||
...
|
||||
|
||||
julia> # or
|
||||
|
||||
julia> tlog = Observable(interactive_edit_log("log files", "log file2"))
|
||||
...
|
||||
|
||||
julia> include("<path to root>/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)
|
||||
... <with some prompts>
|
||||
|
||||
julia> iedit_note!(tlog[], 3)
|
||||
... <with some promots>
|
||||
|
||||
julia> ijoin_logs!(tlog[], 5, 7)
|
||||
... <with some prompts>
|
||||
|
||||
```
|
||||
|
||||
### Export the log
|
||||
```julia-repl
|
||||
julia> export_log(tlog[], "<filename>")
|
||||
```
|
||||
|
||||
## 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}`.
|
205
interactive_viz.jl
Normal file
205
interactive_viz.jl
Normal file
|
@ -0,0 +1,205 @@
|
|||
true || include("src/CoordVisualize.jl")
|
||||
true || using GLMakie
|
||||
using CoordVisualize
|
||||
using FileIO
|
||||
using ColorSchemes
|
||||
using ColorTypes
|
||||
|
||||
mappath = "map.png"
|
||||
map = load(mappath)
|
||||
map_height, map_width = size(map)
|
||||
|
||||
fig = Figure(; size = (1000, 700))
|
||||
ax = Axis(
|
||||
fig[1:2, 1],
|
||||
limits = (
|
||||
-map_width ÷ 2 * 1.1,
|
||||
map_width ÷ 2 * 1.1,
|
||||
-map_height ÷ 2 * 1.1,
|
||||
map_height ÷ 2 * 1.1,
|
||||
),
|
||||
aspect = DataAspect(),
|
||||
)
|
||||
|
||||
# Options
|
||||
options_width = 200
|
||||
button_reset = Button(fig, label = "reset view")
|
||||
toggle_inspector = Toggle(fig, active = false, tellwidth = false)
|
||||
menu_lcolormapfunc =
|
||||
Menu(fig, options = ["log", "altitude", "date", "constant"], default = "log")
|
||||
menu_mcolormapfunc =
|
||||
Menu(fig, options = ["log", "altitude", "date", "constant"], default = "log")
|
||||
toggle_line = Toggle(fig, active = true, tellwidth = false)
|
||||
toggle_marker = Toggle(fig, active = false, tellwidth = false)
|
||||
slider_linewidth = Slider(fig, range = unique([1:1:5..., 5:2:15..., 15, 20:10:100...]))
|
||||
slider_markersize = Slider(fig, range = unique([1:1:10..., 10:5:100...]), startvalue = 5)
|
||||
# menu_linecolormap =
|
||||
# Menu(fig, options = string.(keys(ColorSchemes.colorschemes)), default = "viridis")
|
||||
# menu_markercolormap =
|
||||
# Menu(fig, options = string.(keys(ColorSchemes.colorschemes)), default = "viridis")
|
||||
textbox_linecolormap =
|
||||
Textbox(fig, validator = (s -> s in string.(keys(ColorSchemes.colorschemes))))
|
||||
textbox_markercolormap =
|
||||
Textbox(fig, validator = (s -> s in string.(keys(ColorSchemes.colorschemes))))
|
||||
textbox_linecolor = Textbox(fig, validator = (s -> begin
|
||||
try
|
||||
parse(Colorant, s)
|
||||
catch
|
||||
return false
|
||||
end
|
||||
return true
|
||||
end), stored_string = "green")
|
||||
lineconstcolor =
|
||||
@lift(ColorMapFuncs.Constant(parse(Colorant, $(textbox_linecolor.stored_string))))
|
||||
textbox_markercolor = Textbox(fig, validator = (s -> begin
|
||||
try
|
||||
parse(Colorant, s)
|
||||
catch
|
||||
return false
|
||||
end
|
||||
return true
|
||||
end), stored_string = "green")
|
||||
markerconstcolor =
|
||||
@lift(ColorMapFuncs.Constant(parse(Colorant, $(textbox_markercolor.stored_string))))
|
||||
line_options = grid!(
|
||||
[1, 1] => Label(fig, "color"),
|
||||
[1, 2:3] => menu_lcolormapfunc,
|
||||
[2, 1] => Label(fig, "show line"),
|
||||
[2, 2:3] => toggle_line,
|
||||
[3, 1] => Label(fig, "width"),
|
||||
[3, 2] => slider_linewidth,
|
||||
[3, 3] => Label(fig, @lift(string($(slider_linewidth.value)))),
|
||||
[4, 1] => Label(fig, "color scheme"),
|
||||
[4, 2:3] => textbox_linecolormap,
|
||||
[5, 1] => Label(fig, "color"),
|
||||
[5, 2:3] => textbox_linecolor,
|
||||
width = options_width,
|
||||
)
|
||||
marker_options = grid!(
|
||||
[1, 1] => Label(fig, "color"),
|
||||
[1, 2:3] => menu_mcolormapfunc,
|
||||
[2, 1] => Label(fig, "show marker"),
|
||||
[2, 2:3] => toggle_marker,
|
||||
[3, 1] => Label(fig, "size"),
|
||||
[3, 2] => slider_markersize,
|
||||
[3, 3] => Label(fig, @lift(string($(slider_markersize.value)))),
|
||||
[4, 1] => Label(fig, "color scheme"),
|
||||
[4, 2:3] => textbox_markercolormap,
|
||||
[5, 1] => Label(fig, "color"),
|
||||
[5, 2:3] => textbox_markercolor,
|
||||
width = options_width,
|
||||
)
|
||||
inspector_options = grid!(
|
||||
[1, 1] => Label(fig, "inspector"),
|
||||
[1, 2] => toggle_inspector,
|
||||
width = options_width,
|
||||
)
|
||||
fig[1:2, 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)
|
|
@ -2,8 +2,18 @@ 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
|
||||
|
|
33
src/edit.jl
33
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
|
||||
|
|
193
src/interactive_edit.jl
Normal file
193
src/interactive_edit.jl
Normal file
|
@ -0,0 +1,193 @@
|
|||
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
|
|
@ -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
|
||||
|
|
43
src/print.jl
Normal file
43
src/print.jl
Normal file
|
@ -0,0 +1,43 @@
|
|||
"""
|
||||
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
|
||||
|
291
src/recipes.jl
Normal file
291
src/recipes.jl
Normal file
|
@ -0,0 +1,291 @@
|
|||
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
|
|
@ -1,4 +1,8 @@
|
|||
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
|
||||
|
@ -13,3 +17,11 @@ 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
|
||||
|
|
27
src/visualize.jl
Normal file
27
src/visualize.jl
Normal file
|
@ -0,0 +1,27 @@
|
|||
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
|
||||
|
|
@ -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
|
||||
|
|
Loading…
Add table
Reference in a new issue