Skip to content

Commit

Permalink
Modify ui
Browse files Browse the repository at this point in the history
  • Loading branch information
yufongpeng committed Apr 11, 2024
1 parent eeb4a86 commit 339b5a3
Show file tree
Hide file tree
Showing 10 changed files with 154 additions and 100 deletions.
11 changes: 11 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,17 @@ To calculate relative signal, concentration or accuracy and save the result, cal
## User Interface
Use the function `ui_init` which activates an environment for ui and run `interactive_calibrate!` on the batch.

Two windows will pop out.
One is the main GUI.
![image1](ui/main.png "Main GUI")
Calibration curve settings, and the apearance can be modified through the interface. There are also widgets for saving figure, calibration settings.

![image2](ui/point.png "Select or delete calibration points")
Calibration points can be deleted or added back by left click.

Another window is a table containing data for each points.
![image3](ui/table.png "Detailed data")

## Reading and writting data to disk
To use data on disk, user should create a directory in the following structure:
```
Expand Down
54 changes: 24 additions & 30 deletions ui/Manifest.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

julia_version = "1.10.2"
manifest_format = "2.0"
project_hash = "c6f3f7dc7675b3f4eb668a776a9e77869dd8fab4"
project_hash = "95b05fb44ba88b6ef0b9957a153ae34e2e2095d2"

[[deps.AbstractFFTs]]
deps = ["LinearAlgebra"]
Expand Down Expand Up @@ -192,9 +192,9 @@ version = "3.24.0"

[[deps.ColorTypes]]
deps = ["FixedPointNumbers", "Random"]
git-tree-sha1 = "eb7f0f8307f71fac7c606984ea5fb2817275d6e4"
git-tree-sha1 = "b10d0b65641d57b8b4d5e234446582de5047050d"
uuid = "3da002f7-5984-5a60-b8a6-cbb66c0b333f"
version = "0.11.4"
version = "0.11.5"

[[deps.ColorVectorSpace]]
deps = ["ColorTypes", "FixedPointNumbers", "LinearAlgebra", "Requires", "Statistics", "TensorCore"]
Expand Down Expand Up @@ -250,9 +250,9 @@ weakdeps = ["IntervalSets", "StaticArrays"]
ConstructionBaseStaticArraysExt = "StaticArrays"

[[deps.Contour]]
git-tree-sha1 = "d05d9e7b7aedff4e5b51a029dced05cfb6125781"
git-tree-sha1 = "439e35b0b36e2e5881738abc8857bd92ad6ff9a8"
uuid = "d38c429a-6771-53c6-b99e-75d170b6e991"
version = "0.6.2"
version = "0.6.3"

[[deps.Crayons]]
git-tree-sha1 = "249fe38abf76d48563e2f4556bebd215aa317e15"
Expand Down Expand Up @@ -382,9 +382,9 @@ version = "0.1.2"

[[deps.FFMPEG_jll]]
deps = ["Artifacts", "Bzip2_jll", "FreeType2_jll", "FriBidi_jll", "JLLWrappers", "LAME_jll", "Libdl", "Ogg_jll", "OpenSSL_jll", "Opus_jll", "PCRE2_jll", "Zlib_jll", "libaom_jll", "libass_jll", "libfdk_aac_jll", "libvorbis_jll", "x264_jll", "x265_jll"]
git-tree-sha1 = "ab3f7e1819dba9434a3a5126510c8fda3a4e7000"
git-tree-sha1 = "466d45dc38e15794ec7d5d63ec03d776a9aff36e"
uuid = "b22a6f82-2f65-5046-a5b2-351ab43fb4e5"
version = "6.1.1+0"
version = "4.4.4+1"

[[deps.FFTW]]
deps = ["AbstractFFTs", "FFTW_jll", "LinearAlgebra", "MKL_jll", "Preferences", "Reexport"]
Expand Down Expand Up @@ -414,10 +414,10 @@ version = "0.9.21"
uuid = "7b1f6079-737a-58dc-b8bc-7a2ca5c1b5ee"

[[deps.FillArrays]]
deps = ["LinearAlgebra", "Random"]
git-tree-sha1 = "5b93957f6dcd33fc343044af3d48c215be2562f1"
deps = ["LinearAlgebra"]
git-tree-sha1 = "bfe82a708416cf00b73a3198db0859c82f741558"
uuid = "1a297f60-69ca-5386-bcde-b61e274b549b"
version = "1.9.3"
version = "1.10.0"
weakdeps = ["PDMats", "SparseArrays", "Statistics"]

[deps.FillArrays.extensions]
Expand Down Expand Up @@ -483,9 +483,9 @@ version = "2.13.1+0"

[[deps.FreeTypeAbstraction]]
deps = ["ColorVectorSpace", "Colors", "FreeType", "GeometryBasics"]
git-tree-sha1 = "055626e1a35f6771fe99060e835b72ca61a52621"
git-tree-sha1 = "2493cdfd0740015955a8e46de4ef28f49460d8bc"
uuid = "663a7486-cb36-511b-a19d-713bb74d65c9"
version = "0.10.1"
version = "0.10.3"

[[deps.FriBidi_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
Expand Down Expand Up @@ -706,10 +706,10 @@ version = "0.15.1"
Unitful = "1986cc42-f94f-5a68-af5c-568840ba703d"

[[deps.IntervalArithmetic]]
deps = ["CRlibm_jll", "RoundingEmulator"]
git-tree-sha1 = "552505ed27d2a90ff04c15b0ecf4634e0ab5547b"
deps = ["CRlibm_jll", "MacroTools", "RoundingEmulator"]
git-tree-sha1 = "a066535c05e21f8e18b18e759a5d790b7a706399"
uuid = "d1acc4aa-44c8-5952-acd4-ba5d80a2a253"
version = "0.22.9"
version = "0.22.10"
weakdeps = ["DiffRules", "ForwardDiff", "RecipesBase"]

[deps.IntervalArithmetic.extensions]
Expand Down Expand Up @@ -912,9 +912,9 @@ version = "2.54.5+0"

[[deps.Libtiff_jll]]
deps = ["Artifacts", "JLLWrappers", "JpegTurbo_jll", "LERC_jll", "Libdl", "XZ_jll", "Zlib_jll", "Zstd_jll"]
git-tree-sha1 = "6355fb9a4d22d867318db186fd09b09b35bd2ed7"
git-tree-sha1 = "2da088d113af58221c52828a80378e16be7d037a"
uuid = "89763e89-9b03-5906-acba-b20f662cd828"
version = "4.6.0+0"
version = "4.5.1+1"

[[deps.Libuuid_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl"]
Expand Down Expand Up @@ -1021,9 +1021,9 @@ version = "0.4.11"

[[deps.Missings]]
deps = ["DataAPI"]
git-tree-sha1 = "f66bdc5de519e8f8ae43bdc598782d35a25b1272"
git-tree-sha1 = "ec4f7fbeab05d7747bdf98eb74d130a2a2ed298d"
uuid = "e1d29d7a-bbdc-5cf2-9ac0-f12de2c33e28"
version = "1.1.0"
version = "1.2.0"

[[deps.Mmap]]
uuid = "a63ad114-7e13-5084-954f-fe012c677804"
Expand Down Expand Up @@ -1143,10 +1143,10 @@ uuid = "efe28fd5-8261-553b-a9e1-b2916fc3738e"
version = "0.5.5+0"

[[deps.Optim]]
deps = ["Compat", "FillArrays", "ForwardDiff", "LineSearches", "LinearAlgebra", "NLSolversBase", "NaNMath", "PackageExtensionCompat", "Parameters", "PositiveFactorizations", "Printf", "SparseArrays", "StatsBase"]
git-tree-sha1 = "d1223e69af90b6d26cea5b6f3b289b3148ba702c"
deps = ["Compat", "FillArrays", "ForwardDiff", "LineSearches", "LinearAlgebra", "NLSolversBase", "NaNMath", "Parameters", "PositiveFactorizations", "Printf", "SparseArrays", "StatsBase"]
git-tree-sha1 = "d9b79c4eed437421ac4285148fcadf42e0700e89"
uuid = "429524aa-4258-5aef-a3af-852621145aeb"
version = "1.9.3"
version = "1.9.4"

[deps.Optim.extensions]
OptimMOIExt = "MathOptInterface"
Expand Down Expand Up @@ -1182,12 +1182,6 @@ git-tree-sha1 = "67186a2bc9a90f9f85ff3cc8277868961fb57cbd"
uuid = "f57f5aa1-a3ce-4bc8-8ab9-96f992907883"
version = "0.4.3"

[[deps.PackageExtensionCompat]]
git-tree-sha1 = "fb28e33b8a95c4cee25ce296c817d89cc2e53518"
uuid = "65ce6f38-6b18-4e1d-a461-8949797d7930"
version = "1.0.2"
weakdeps = ["Requires", "TOML"]

[[deps.Packing]]
deps = ["GeometryBasics"]
git-tree-sha1 = "ec3edfe723df33528e085e632414499f26650501"
Expand Down Expand Up @@ -1604,9 +1598,9 @@ version = "1.7.0"

[[deps.StatsBase]]
deps = ["DataAPI", "DataStructures", "LinearAlgebra", "LogExpFunctions", "Missings", "Printf", "Random", "SortingAlgorithms", "SparseArrays", "Statistics", "StatsAPI"]
git-tree-sha1 = "1d77abd07f617c4868c33d4f5b9e1dbb2643c9cf"
git-tree-sha1 = "5cf7606d6cef84b543b483848d4ae08ad9832b21"
uuid = "2913bbd2-ae8a-5f71-8c99-4fb6c76f3a91"
version = "0.34.2"
version = "0.34.3"

[[deps.StatsFuns]]
deps = ["HypergeometricFunctions", "IrrationalConstants", "LogExpFunctions", "Reexport", "Rmath", "SpecialFunctions"]
Expand Down
4 changes: 3 additions & 1 deletion ui/Project.toml
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
[deps]
Blink = "ad839575-38b3-5650-b840-f874b8c74a25"
CSV = "336ed68f-0bac-5ca0-87d4-7b16caf5d00b"
GLM = "38e38edf-8417-5370-95a0-9cbb8c7f171a"
GLMakie = "e9467ef8-e4e7-5192-8a1a-b1aee30e663a"
Expand All @@ -9,10 +10,11 @@ PrettyTables = "08abe8d2-0d0c-5749-adfa-8a2ac140af0d"
TypedTables = "9d95f2ec-7b3d-5a63-8d20-e2491e220bb9"

[compat]
Blink = "0.12"
CSV = "0.10"
GLM = "1.9"
GLMakie = "0.8"
Plotly = "0.4"
PrettyTables = "2.2"
TypedTables = "1.4"
julia = "1.10"
julia = "1.10"
Binary file added ui/main.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added ui/point.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
59 changes: 37 additions & 22 deletions ui/src/calplot.jl
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
"""
interactive_calibrate!(batch::Batch;
interactive_calibrate!(batch::Batch;
root = pwd(),
lloq_multiplier = 4//3, dev_acc = 0.15,
fig_attr = Dict{Symbol, Any}(:resolution => (1350, 900)),
axis_attr = cal -> Dict(:title => string(first(cal.analyte)), :xlabel => "Concentration (nM)", :ylabel => "Abundance", :titlesize => 20),
Expand All @@ -14,13 +15,15 @@ Interactively calibrate signal and concentration.
# Arguments
* `batch`: `Batch`.
* `root`: root directory for saving objects.
* `dev_acc`: allowed accuracy deviation.
* `lloq_multiplier`: multiplier for `dev_acc` at LLOQ level.
* `fig_attr`: `Dicti` contains attributes of `Figure`.
* `fig_attr`: `Dict` contains attributes of `Figure`.
* `axis_attr`: a function map each calibtation curve to a `Dict` containing its attributes of `Axis`.
* `plot_attr`: a function map each calibtation curve to a `Dict` containing its attributes of plots (`Line` or `Scatter`).
"""
function interactive_calibrate!(batch::Batch;
function interactive_calibrate!(batch::Batch;
root = pwd(),
lloq_multiplier = 4//3, dev_acc = 0.15,
fig_attr = Dict{Symbol, Any}(:resolution => (1350, 900)),
axis_attr = cal -> Dict(:title => string(first(cal.analyte)), :xlabel => "Concentration (nM)", :ylabel => "Abundance", :titlesize => 20),
Expand All @@ -37,6 +40,7 @@ function interactive_calibrate!(batch::Batch;
axis_attrs = map(axis_attr, batch.calibration)
plot_attrs = map(plot_attr, batch.calibration)
i = 1
info = Window()
function draw()
label_analyte = Label(fig, string(first(batch.calibration[i].analyte)); halign = :left, width = 250)
button_left = Button(fig, label = "<")
Expand All @@ -48,7 +52,7 @@ function interactive_calibrate!(batch::Batch;
default_w = weight_repr(batch.calibration[i])
menu_wt = Menu(fig, options = ["none", "1/√x", "1/x", "1/x²"], default = default_w)
menu_zoom = Menu(fig, options = string.(0:length(unique(batch.calibration[i].table.x))), default = "0", tellwidth = false)
menu_show = Menu(fig, options = ["Cal", "Sample"], default = "Cal"; halign = :left, tellwidth = false)
# menu_show = Menu(fig, options = ["Cal", "Sample"], default = "Cal"; halign = :left, tellwidth = false)
menu_export = Menu(fig, options = ["Fig", "Cal", "Fig&Cal"], default = "Cal"; halign = :left, tellwidth = false)
ax = Axis(fig[1, 1]; axis_attrs[i]...)
sc = scatter!(ax, batch.calibration[i].table.x, batch.calibration[i].table.y; get_point_attr(plot_attrs[i], batch.calibration[i])...)
Expand All @@ -64,17 +68,18 @@ function interactive_calibrate!(batch::Batch;
button_confirm = Button(fig, label = "confirm", halign = :left)
textbox_attr = Textbox(fig, placeholder = "attribute", tellwidth = false, halign = :left)
textbox_value = Textbox(fig, placeholder = "value (julia expression)", tellwidth = false, halign = :left)
button_show = Button(fig, label = "show")
button_show = Button(fig, label = "Table")
button_export = Button(fig, label = "export")
button_save = Button(fig, label = "save batch"; halign = :left)
button_save = Button(fig, label = "Save batch"; halign = :left)
button_saveas = Button(fig, label = "Save batch as")
lzoom = Label(fig, "Zoom")
ltype = Label(fig, "Type")
lzero = Label(fig, "Zero")
lweight = Label(fig, "Weight")
lps = Label(fig, "Plot setting", halign = :left, tellwidth = false)
lc = [label_analyte, button_left, button_right, label_r2, label_formula, lzoom, menu_zoom,
ltype, menu_type, lzero, menu_zero, lweight, menu_wt, lps, tall, menu_obj, textbox_attr, button_confirm, textbox_value,
menu_show, menu_export, button_show, button_export, button_save]
menu_export, button_show, button_export, button_save, button_saveas]
fig[1, 2] = vgrid!(
label_analyte,
hgrid!(button_left, button_right),
Expand All @@ -87,17 +92,17 @@ function interactive_calibrate!(batch::Batch;
hgrid!(lps, tall),
menu_obj,
hgrid!(textbox_attr, button_confirm),
textbox_value,
hgrid!(menu_show, button_show),
hgrid!(menu_export, button_export),
button_save;
textbox_value,
hgrid!(button_show, menu_export, button_export),
hgrid!(button_save, button_saveas);
tellheight = false
)
xr = dynamic_range(batch.calibration[i])
xr = xr .+ (xr[2] - xr[1]) .* (-0.05, 0.05)
yr = signal_range(batch.calibration[i]) .* ((1 - dev_acc * lloq_multiplier), (1 + dev_acc))
yr = yr .+ (yr[2] - yr[1]) .* (-0.05, 0.05)
limits!(ax, xr, yr)
body!(info, viewinfo(batch.calibration[i], batch.data, batch.method; lloq_multiplier, dev_acc))
#display(view_sample(sample; lloq = batch.calibration[i].table.x[findfirst(batch.calibration[i].table.include)], uloq = batch.calibration[i].table.x[findlast(batch.calibration[i].table.include)], lloq_multiplier, dev_acc))
# Main.vscodedisplay(batch.calibration[i].table[batch.calibration[i].table.include])
# fig[1, 3] = vgrid!(map(s -> Label(fig, s; halign = :left), split(sprint(showtable, batch.calibration[i].table), "\n"))...; tellheight = false, width = 250)
Expand All @@ -108,12 +113,13 @@ function interactive_calibrate!(batch::Batch;
label_r2.text = "R² = $(round(r2(batch.calibration[i].model); sigdigits = 4))"
label_formula.text = formula_repr(batch.calibration[i])
#sample.x̂ .= inv_predict(batch.calibration[i], sample)
body!(info, viewinfo(batch.calibration[i], batch.data, batch.method; lloq_multiplier, dev_acc))
end
function update_analyte!()
for x in lc
delete!(x)
end
delete!(ax)
delete!(ax)
draw()
end
on(button_left.clicks) do s
Expand Down Expand Up @@ -219,21 +225,20 @@ function interactive_calibrate!(batch::Batch;
end
end
on(button_show.clicks) do s
if menu_show.selection[] == "Cal"
display(view_cal(batch.calibration[i].table; lloq_multiplier, dev_acc))
else
display(view_sample(batch.data, first(batch.calibration[i].analyte); lloq = batch.calibration[i].table.x[findfirst(batch.calibration[i].table.include)], uloq = batch.calibration[i].table.x[findlast(batch.calibration[i].table.include)], lloq_multiplier, dev_acc))
if !active(info)
info = Window()
body!(info, viewinfo(batch.calibration[i], batch.data, batch.method; lloq_multiplier, dev_acc))
end
#Main.vscodedisplay(batch.calibration[i].table[batch.calibration[i].table.include])
#Main.vscodedisplay(batch.calibration[i].table[batch.calibration[i].table.include])
end
on(button_export.clicks) do s
if menu_export.selection[] == "Fig" || menu_export.selection[] == "Fig&Cal"
save_dialog("Save as", nothing, ["*.png"]; start_folder = pwd()) do f
save_dialog("Save figure as", nothing, ["*.png"]; start_folder = root) do f
f == "" || save(f, fig; update = false)
end
end
if menu_export.selection[] == "Cal" || menu_export.selection[] == "Fig&Cal"
save_dialog("Save as", nothing, ["*.csv"]; start_folder = pwd()) do f
save_dialog("Save calibration as", nothing, ["*.csv"]; start_folder = root) do f
f == "" || CSV.write(f, Table(; formula = [formula_repr_utf8(batch.calibration[i])], weight = [weight_repr_utf8(batch.calibration[i])], LLOQ = [format_number(lloq(batch.calibration[i]))], ULOQ = [format_number(uloq(batch.calibration[i]))], r_squared = [format_number(r2(batch.calibration[i].model))]))
end
end
Expand All @@ -256,14 +261,24 @@ function interactive_calibrate!(batch::Batch;
end
=#
end
on(button_save.clicks) do s
save_dialog("Save as", nothing, ["*.batch"]; start_folder = pwd()) do f
on(button_saveas.clicks) do s
save_dialog("Save as", nothing, ["*.batch"]; start_folder = root) do f
f == "" || ChemistryQuantitativeAnalysis.write(f, batch)
end
end
on(button_save.clicks) do s
if endswith(root, ".batch")
ask_dialog("Save batch?\n$root") && ChemistryQuantitativeAnalysis.write(root, batch)
else
save_dialog("Save as", nothing, ["*.batch"]; start_folder = root) do f
f == "" || ChemistryQuantitativeAnalysis.write(f, batch)
end
end
end
end
draw()
fig
wait(display(fig))
close(info)
end

#get_point_attr(plot_attr::Dict, incl::Bool) = NamedTuple(k => incl ? v[1] : v[2] for (k, v) in get!(plot_attr, :scatter, Dict(:color => [:blue, :red])))
Expand Down
Loading

0 comments on commit 339b5a3

Please sign in to comment.