diff --git a/.gitignore b/.gitignore index 6832527..0bec6dd 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,10 @@ public/* public/css/imgOver.png !public/css/ -!public/css/autogenerated.css -!public/css/LABI_logo.png +!public/css/masks/static.txt +public/css/masks/* log/* +R_original_scripts/ +test/results/ +test/binarization_results/ +Manifest.toml \ No newline at end of file diff --git a/Manifest.toml b/Manifest.toml index 319d86f..adde889 100644 --- a/Manifest.toml +++ b/Manifest.toml @@ -1,14 +1,19 @@ # This file is machine-generated - editing it directly is not advised -julia_version = "1.11.3" +julia_version = "1.11.7" manifest_format = "2.0" -project_hash = "e1be01554a547da63b1504fb440ab6cc4855bc9d" +project_hash = "4955dfdbb7a233ddefa69e3cce2833f416ffe1bc" + +[[deps.ANSIColoredPrinters]] +git-tree-sha1 = "574baf8110975760d391c710b6341da1afa48d8c" +uuid = "a4c015fc-c6ff-483c-b24f-f7ea428134e9" +version = "0.0.1" [[deps.ATK_jll]] deps = ["Artifacts", "Glib_jll", "JLLWrappers", "Libdl"] -git-tree-sha1 = "a2ecb68d240333fe63bea1965b71884e98c2d0f0" +git-tree-sha1 = "c0a10eaf3a7e1e909ef8fe45971a73524bfce1bf" uuid = "7b86fcea-f67b-53e1-809c-8f1719c154e8" -version = "2.38.0+0" +version = "2.38.1+0" [[deps.AbstractFFTs]] deps = ["LinearAlgebra"] @@ -26,14 +31,39 @@ git-tree-sha1 = "2d9c9a55f9c93e8887ad391fbae72f8ef55e1177" uuid = "1520ce14-60c1-5f80-bbc7-55ef81b5835c" version = "0.4.5" +[[deps.Accessors]] +deps = ["CompositionsBase", "ConstructionBase", "Dates", "InverseFunctions", "MacroTools"] +git-tree-sha1 = "3b86719127f50670efe356bc11073d84b4ed7a5d" +uuid = "7d9f7c33-5ae7-4f3b-8dc6-eff91059b697" +version = "0.1.42" + + [deps.Accessors.extensions] + AxisKeysExt = "AxisKeys" + IntervalSetsExt = "IntervalSets" + LinearAlgebraExt = "LinearAlgebra" + StaticArraysExt = "StaticArrays" + StructArraysExt = "StructArrays" + TestExt = "Test" + UnitfulExt = "Unitful" + + [deps.Accessors.weakdeps] + AxisKeys = "94b1ba4f-4ee9-5380-92f1-94cde586c3c5" + IntervalSets = "8197267c-284f-5f27-9208-e0e47529a953" + LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" + StaticArrays = "90137ffa-7385-5640-81b9-e52037218182" + StructArrays = "09ab397b-f2b6-538f-b94a-2f83cf4a842a" + Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" + Unitful = "1986cc42-f94f-5a68-af5c-568840ba703d" + [[deps.Adapt]] deps = ["LinearAlgebra", "Requires"] -git-tree-sha1 = "50c3c56a52972d78e8be9fd135bfb91c9574c140" +git-tree-sha1 = "7e35fca2bdfba44d797c53dfe63a51fabf39bfc0" uuid = "79e6a3ab-5dfb-504d-930d-738a2a938a0e" -version = "4.1.1" -weakdeps = ["StaticArrays"] +version = "4.4.0" +weakdeps = ["SparseArrays", "StaticArrays"] [deps.Adapt.extensions] + AdaptSparseArraysExt = "SparseArrays" AdaptStaticArraysExt = "StaticArrays" [[deps.AdaptivePredicates]] @@ -71,18 +101,19 @@ version = "0.4.0" [[deps.ArrayInterface]] deps = ["Adapt", "LinearAlgebra"] -git-tree-sha1 = "017fcb757f8e921fb44ee063a7aafe5f89b86dd1" +git-tree-sha1 = "d81ae5489e13bc03567d4fbbb06c546a5e53c857" uuid = "4fba245c-0d91-5ea0-9b3e-6abc04ee57a9" -version = "7.18.0" +version = "7.22.0" [deps.ArrayInterface.extensions] ArrayInterfaceBandedMatricesExt = "BandedMatrices" ArrayInterfaceBlockBandedMatricesExt = "BlockBandedMatrices" ArrayInterfaceCUDAExt = "CUDA" - ArrayInterfaceCUDSSExt = "CUDSS" + ArrayInterfaceCUDSSExt = ["CUDSS", "CUDA"] ArrayInterfaceChainRulesCoreExt = "ChainRulesCore" ArrayInterfaceChainRulesExt = "ChainRules" ArrayInterfaceGPUArraysCoreExt = "GPUArraysCore" + ArrayInterfaceMetalExt = "Metal" ArrayInterfaceReverseDiffExt = "ReverseDiff" ArrayInterfaceSparseArraysExt = "SparseArrays" ArrayInterfaceStaticArraysCoreExt = "StaticArraysCore" @@ -96,6 +127,7 @@ version = "7.18.0" ChainRules = "082447d4-558c-5d27-93f4-14fc19e9eca2" ChainRulesCore = "d360d2e6-b24c-11e9-a2a3-2a2ae2dbcce4" GPUArraysCore = "46192b85-c4d5-4398-a991-12ede77f4527" + Metal = "dde4c033-4e86-420c-a63e-0dd931031962" ReverseDiff = "37e2e3b7-166d-5795-8a7a-e32c996b4267" SparseArrays = "2f01184e-e22b-5df5-ae63-d93ebab69eaf" StaticArraysCore = "1e83bf80-4336-4d27-bf5d-d5a4f845583c" @@ -119,14 +151,24 @@ version = "1.1.0" [[deps.AxisArrays]] deps = ["Dates", "IntervalSets", "IterTools", "RangeArrays"] -git-tree-sha1 = "16351be62963a67ac4083f748fdb3cca58bfd52f" +git-tree-sha1 = "4126b08903b777c88edf1754288144a0492c05ad" uuid = "39de3d68-74b9-583c-8d2d-e117c070f3a9" -version = "0.4.7" +version = "0.4.8" [[deps.Base64]] uuid = "2a0f44e3-6c83-55bd-87e4-b1978d98bd5f" version = "1.11.0" +[[deps.BaseDirs]] +git-tree-sha1 = "bca794632b8a9bbe159d56bf9e31c422671b35e0" +uuid = "18cc8868-cbac-4acf-b575-c8ff214dc66f" +version = "1.3.2" + +[[deps.Bessels]] +git-tree-sha1 = "4435559dc39793d53a9e3d278e185e920b4619ef" +uuid = "0e736298-9ec6-45e8-9647-e4fc86a2fe38" +version = "0.2.8" + [[deps.BitFlags]] git-tree-sha1 = "0691e34b3bb8be9307330f88d1a3c3f25466c24d" uuid = "d1d4a3ce-64b1-5f1a-9ba4-7e7e69966f35" @@ -144,10 +186,10 @@ uuid = "e1450e63-4bb3-523b-b2a4-4ffa8c0fd77d" version = "1.2.2" [[deps.Bzip2_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] -git-tree-sha1 = "8873e196c2eb87962a2048b3b8e08946535864a1" +deps = ["Artifacts", "JLLWrappers", "Libdl"] +git-tree-sha1 = "1b96ea4a01afe0ea4090c5c8039690672dd13f2e" uuid = "6e34b625-4abd-537c-b88f-471c36dfa7a0" -version = "1.0.8+4" +version = "1.0.9+0" [[deps.CEnum]] git-tree-sha1 = "389ad5c84de1ae7cf0e28e381131c98ea87d54fc" @@ -155,15 +197,21 @@ uuid = "fa961155-64e5-5f13-b03f-caf6b980ea82" version = "0.5.0" [[deps.CPUSummary]] -deps = ["CpuId", "IfElse", "PrecompileTools", "Static"] -git-tree-sha1 = "5a97e67919535d6841172016c9530fd69494e5ec" +deps = ["CpuId", "IfElse", "PrecompileTools", "Preferences", "Static"] +git-tree-sha1 = "f3a21d7fc84ba618a779d1ed2fcca2e682865bab" uuid = "2a0fbf3d-bb9c-48f3-b0a9-814d99fd7ab9" -version = "0.2.6" +version = "0.2.7" [[deps.CRC32c]] uuid = "8bf52ea8-c179-5cab-976a-9e18b702a9bc" version = "1.11.0" +[[deps.CRlibm]] +deps = ["CRlibm_jll"] +git-tree-sha1 = "66188d9d103b92b6cd705214242e27f5737a1e5e" +uuid = "96374032-68de-5a5b-8d9e-752f78720389" +version = "1.0.2" + [[deps.CRlibm_jll]] deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] git-tree-sha1 = "e329286945d0cfc04456972ea732551869af1cfc" @@ -176,6 +224,12 @@ git-tree-sha1 = "0157e592151e39fa570645e2b2debcdfb8a0f112" uuid = "00ebfdb7-1f24-5e51-bd34-a7502290713f" version = "3.4.3" +[[deps.CSV]] +deps = ["CodecZlib", "Dates", "FilePathsBase", "InlineStrings", "Mmap", "Parsers", "PooledArrays", "PrecompileTools", "SentinelArrays", "Tables", "Unicode", "WeakRefStrings", "WorkerUtilities"] +git-tree-sha1 = "deddd8725e5e1cc49ee205a1964256043720a6c3" +uuid = "336ed68f-0bac-5ca0-87d4-7b16caf5d00b" +version = "0.10.15" + [[deps.Cairo]] deps = ["Cairo_jll", "Colors", "Glib_jll", "Graphics", "Libdl", "Pango_jll"] git-tree-sha1 = "71aa551c5c33f1a4415867fe06b7844faadb0ae9" @@ -184,15 +238,15 @@ version = "1.1.1" [[deps.CairoMakie]] deps = ["CRC32c", "Cairo", "Cairo_jll", "Colors", "FileIO", "FreeType", "GeometryBasics", "LinearAlgebra", "Makie", "PrecompileTools"] -git-tree-sha1 = "6d76f05dbc8b7a52deaa7cdabe901735ae7b6724" +git-tree-sha1 = "9bd45574379e50579a78774334f4a1f1238c0af5" uuid = "13f3f980-e62b-5c42-98c6-ff1f3baf88f0" -version = "0.13.1" +version = "0.13.10" [[deps.Cairo_jll]] deps = ["Artifacts", "Bzip2_jll", "CompilerSupportLibraries_jll", "Fontconfig_jll", "FreeType2_jll", "Glib_jll", "JLLWrappers", "LZO_jll", "Libdl", "Pixman_jll", "Xorg_libXext_jll", "Xorg_libXrender_jll", "Zlib_jll", "libpng_jll"] -git-tree-sha1 = "009060c9a6168704143100f36ab08f06c2af4642" +git-tree-sha1 = "fde3bf89aead2e723284a8ff9cdf5b551ed700e8" uuid = "83423d85-b0ee-5818-9007-b63ccbeb887a" -version = "1.18.2+1" +version = "1.18.5+0" [[deps.CatIndices]] deps = ["CustomUnitRanges", "OffsetArrays"] @@ -202,14 +256,31 @@ version = "0.2.2" [[deps.ChainRulesCore]] deps = ["Compat", "LinearAlgebra"] -git-tree-sha1 = "1713c74e00545bfe14605d2a2be1712de8fbcb58" +git-tree-sha1 = "e4c6a16e77171a5f5e25e9646617ab1c276c5607" uuid = "d360d2e6-b24c-11e9-a2a3-2a2ae2dbcce4" -version = "1.25.1" +version = "1.26.0" weakdeps = ["SparseArrays"] [deps.ChainRulesCore.extensions] ChainRulesCoreSparseArraysExt = "SparseArrays" +[[deps.ChunkCodecCore]] +git-tree-sha1 = "51f4c10ee01bda57371e977931de39ee0f0cdb3e" +uuid = "0b6fb165-00bc-4d37-ab8b-79f91016dbe1" +version = "1.0.0" + +[[deps.ChunkCodecLibZlib]] +deps = ["ChunkCodecCore", "Zlib_jll"] +git-tree-sha1 = "cee8104904c53d39eb94fd06cbe60cb5acde7177" +uuid = "4c0bbee4-addc-4d73-81a0-b6caacae83c8" +version = "1.0.0" + +[[deps.ChunkCodecLibZstd]] +deps = ["ChunkCodecCore", "Zstd_jll"] +git-tree-sha1 = "34d9873079e4cb3d0c62926a225136824677073f" +uuid = "55437552-ac27-4d47-9aa3-63184e8fd398" +version = "1.0.0" + [[deps.CloseOpenIntervals]] deps = ["Static", "StaticArrayInterface"] git-tree-sha1 = "05ba0d07cd4fd8b7a39541e31a7b0254704ea581" @@ -224,27 +295,33 @@ version = "0.15.8" [[deps.CodeTracking]] deps = ["InteractiveUtils", "UUIDs"] -git-tree-sha1 = "7eee164f122511d3e4e1ebadb7956939ea7e1c77" +git-tree-sha1 = "9ce926a33a8608421a4d45c012884165b3fcd3ee" uuid = "da1fd8a2-8d9e-5ec2-8556-3022fb5608a2" -version = "1.3.6" +version = "2.0.2" + +[[deps.CodecBase]] +deps = ["TranscodingStreams"] +git-tree-sha1 = "40956acdbef3d8c7cc38cba42b56034af8f8581a" +uuid = "6c391c72-fb7b-5838-ba82-7cfb1bcfecbf" +version = "0.3.4" [[deps.CodecZlib]] deps = ["TranscodingStreams", "Zlib_jll"] -git-tree-sha1 = "bce6804e5e6044c6daab27bb533d1295e4a2e759" +git-tree-sha1 = "962834c22b66e32aa10f7611c08c8ca4e20749a9" uuid = "944b1d66-785c-5afd-91f1-9de20f533193" -version = "0.7.6" +version = "0.7.8" [[deps.ColorBrewer]] deps = ["Colors", "JSON"] -git-tree-sha1 = "e771a63cc8b539eca78c85b0cabd9233d6c8f06f" +git-tree-sha1 = "07da79661b919001e6863b81fc572497daa58349" uuid = "a2cac450-b92f-5266-8821-25eda20663c8" -version = "0.4.1" +version = "0.4.2" [[deps.ColorSchemes]] deps = ["ColorTypes", "ColorVectorSpace", "Colors", "FixedPointNumbers", "PrecompileTools", "Random"] -git-tree-sha1 = "26ec26c98ae1453c692efded2b17e15125a5bea1" +git-tree-sha1 = "b0fd3f56fa442f81e0a47815c92245acfaaa4e34" uuid = "35d6a980-a343-548e-a6ea-1d62b119f2f4" -version = "3.28.0" +version = "3.31.0" [[deps.ColorTypes]] deps = ["FixedPointNumbers", "Random"] @@ -270,9 +347,9 @@ version = "0.12.11" [[deps.CommonMark]] deps = ["Crayons", "PrecompileTools"] -git-tree-sha1 = "3faae67b8899797592335832fccf4b3c80bb04fa" +git-tree-sha1 = "5fdf00d1979fd4883b44b754fc3423175c9504b4" uuid = "a80b9123-70ca-4bc0-993e-6e3bcb318db6" -version = "0.8.15" +version = "0.8.16" [[deps.CommonWorldInvalidations]] git-tree-sha1 = "ae52d1c52048455e85a387fbee9be553ec2b68d0" @@ -281,19 +358,33 @@ version = "1.0.0" [[deps.Compat]] deps = ["TOML", "UUIDs"] -git-tree-sha1 = "8ae8d32e09f0dcf42a36b90d4e17f5dd2e4c4215" +git-tree-sha1 = "9d8a54ce4b17aa5bdce0ea5c34bc5e7c340d16ad" uuid = "34da2185-b29b-5c13-b0c7-acf172513d20" -version = "4.16.0" +version = "4.18.1" weakdeps = ["Dates", "LinearAlgebra"] [deps.Compat.extensions] CompatLinearAlgebraExt = "LinearAlgebra" +[[deps.Compiler]] +git-tree-sha1 = "382d79bfe72a406294faca39ef0c3cef6e6ce1f1" +uuid = "807dbc54-b67e-4c79-8afb-eafe4df6f2e1" +version = "0.1.1" + [[deps.CompilerSupportLibraries_jll]] deps = ["Artifacts", "Libdl"] uuid = "e66e0078-7015-5450-92f7-15fbd957f2ae" version = "1.1.1+0" +[[deps.CompositionsBase]] +git-tree-sha1 = "802bb88cd69dfd1509f6670416bd4434015693ad" +uuid = "a33af91c-f02d-484b-be07-31d278c5ca2b" +version = "0.1.2" +weakdeps = ["InverseFunctions"] + + [deps.CompositionsBase.extensions] + CompositionsBaseInverseFunctionsExt = "InverseFunctions" + [[deps.ComputationalResources]] git-tree-sha1 = "52cb3ec90e8a8bea0e62e275ba577ad0f74821f7" uuid = "ed09eef8-17a6-5b46-8889-db040fac31e3" @@ -301,15 +392,9 @@ version = "0.3.2" [[deps.ConcurrentUtilities]] deps = ["Serialization", "Sockets"] -git-tree-sha1 = "f36e5e8fdffcb5646ea5da81495a5a7566005127" +git-tree-sha1 = "d9d26935a0bcffc87d2613ce14c527c99fc543fd" uuid = "f0e56b4a-5159-44fe-b623-3e5288b988bb" -version = "2.4.3" - -[[deps.Conda]] -deps = ["Downloads", "JSON", "VersionParsing"] -git-tree-sha1 = "b19db3927f0db4151cb86d073689f2428e524576" -uuid = "8f4d0f93-b110-5947-807f-2305c1781a2d" -version = "1.10.2" +version = "2.5.0" [[deps.Configurations]] deps = ["ExproniconLite", "OrderedCollections", "TOML"] @@ -318,9 +403,9 @@ uuid = "5218b696-f38b-4ac9-8b61-a12ec717816d" version = "0.17.6" [[deps.ConstructionBase]] -git-tree-sha1 = "76219f1ed5771adbb096743bff43fb5fdd4c1157" +git-tree-sha1 = "b4b092499347b18a015186eae3042f72267106cb" uuid = "187b0558-2788-49d3-abe0-74a17ed4e7c9" -version = "1.5.8" +version = "1.6.0" weakdeps = ["IntervalSets", "LinearAlgebra", "StaticArrays"] [deps.ConstructionBase.extensions] @@ -328,16 +413,32 @@ weakdeps = ["IntervalSets", "LinearAlgebra", "StaticArrays"] ConstructionBaseLinearAlgebraExt = "LinearAlgebra" ConstructionBaseStaticArraysExt = "StaticArrays" +[[deps.ContinuousWavelets]] +deps = ["AbstractFFTs", "Documenter", "FFTW", "Interpolations", "LinearAlgebra", "SpecialFunctions", "Wavelets"] +git-tree-sha1 = "6e883d34f7040ab2ec36c60c738ae53864819508" +uuid = "96eb917e-2868-4417-9cb6-27e7ff17528f" +version = "1.1.7" + [[deps.Contour]] git-tree-sha1 = "439e35b0b36e2e5881738abc8857bd92ad6ff9a8" uuid = "d38c429a-6771-53c6-b99e-75d170b6e991" version = "0.6.3" +[[deps.ConvexHulls2d]] +deps = ["LinearAlgebra"] +git-tree-sha1 = "cd7759cfeaf855fed46ec26a26fb323ac3a5501e" +uuid = "438b5665-92b0-42e6-bc36-e4ac8449fa2d" +version = "0.1.1" +weakdeps = ["Makie"] + + [deps.ConvexHulls2d.extensions] + ConvexHulls2dMakieExt = "Makie" + [[deps.CoordinateTransformations]] deps = ["LinearAlgebra", "StaticArrays"] -git-tree-sha1 = "f9d7112bfff8a19a3a4ea4e03a8e6a91fe8456bf" +git-tree-sha1 = "a692f5e257d332de1e554e4566a4e5a8a72de2b2" uuid = "150eb455-5306-5404-9cee-2592286d6298" -version = "0.6.3" +version = "0.6.4" [[deps.CpuId]] deps = ["Markdown"] @@ -355,6 +456,16 @@ git-tree-sha1 = "1a3f97f907e6dd8983b744d2642651bb162a3f7a" uuid = "dc8bdbbb-1ca9-579f-8c36-e416f6a65cce" version = "1.0.2" +[[deps.DSP]] +deps = ["Bessels", "FFTW", "IterTools", "LinearAlgebra", "Polynomials", "Random", "Reexport", "SpecialFunctions", "Statistics"] +git-tree-sha1 = "5989debfc3b38f736e69724818210c67ffee4352" +uuid = "717857b8-e6f2-59f4-9121-6e50c889abd2" +version = "0.8.4" +weakdeps = ["OffsetArrays"] + + [deps.DSP.extensions] + OffsetArraysExt = "OffsetArrays" + [[deps.DataAPI]] git-tree-sha1 = "abe83f3a2f1b857aac70ef8b269080af17764bbe" uuid = "9a962f9c-6df0-11e9-0e5d-c546b8b5ee8a" @@ -362,15 +473,15 @@ version = "1.16.0" [[deps.DataFrames]] deps = ["Compat", "DataAPI", "DataStructures", "Future", "InlineStrings", "InvertedIndices", "IteratorInterfaceExtensions", "LinearAlgebra", "Markdown", "Missings", "PooledArrays", "PrecompileTools", "PrettyTables", "Printf", "Random", "Reexport", "SentinelArrays", "SortingAlgorithms", "Statistics", "TableTraits", "Tables", "Unicode"] -git-tree-sha1 = "fb61b4812c49343d7ef0b533ba982c46021938a6" +git-tree-sha1 = "d8928e9169ff76c6281f39a659f9bca3a573f24c" uuid = "a93c6f00-e57d-5684-b7b6-d8193f3e46c0" -version = "1.7.0" +version = "1.8.1" [[deps.DataStructures]] deps = ["Compat", "InteractiveUtils", "OrderedCollections"] -git-tree-sha1 = "1d0a14036acb104d9e89698bd408f63ab58cdc82" +git-tree-sha1 = "4e1fe97fdaed23e9dc21d4d664bea76b65fc50a0" uuid = "864edb3b-99cc-5e75-8d2d-829cb0a9cfe8" -version = "0.18.20" +version = "0.18.22" [[deps.DataValueInterfaces]] git-tree-sha1 = "bfc1187b79289637fa0ef6d4436ebdfe6905cbd6" @@ -384,15 +495,15 @@ version = "1.11.0" [[deps.Dbus_jll]] deps = ["Artifacts", "Expat_jll", "JLLWrappers", "Libdl"] -git-tree-sha1 = "fc173b380865f70627d7dd1190dc2fce6cc105af" +git-tree-sha1 = "473e9afc9cf30814eb67ffa5f2db7df82c3ad9fd" uuid = "ee1fde0b-3d02-5ea6-8484-8dfef6360eab" -version = "1.14.10+0" +version = "1.16.2+0" [[deps.DelaunayTriangulation]] deps = ["AdaptivePredicates", "EnumX", "ExactPredicates", "Random"] -git-tree-sha1 = "5620ff4ee0084a6ab7097a27ba0c19290200b037" +git-tree-sha1 = "783b21581a051ac91a3921ee37e26a23ed7f57a6" uuid = "927a84f5-c5f4-47a5-9785-b46e178433df" -version = "1.6.4" +version = "1.6.5" [[deps.DelimitedFiles]] deps = ["Mmap"] @@ -418,9 +529,9 @@ version = "1.11.0" [[deps.Distributions]] deps = ["AliasTables", "FillArrays", "LinearAlgebra", "PDMats", "Printf", "QuadGK", "Random", "SpecialFunctions", "Statistics", "StatsAPI", "StatsBase", "StatsFuns"] -git-tree-sha1 = "03aa5d44647eaec98e1920635cdfed5d5560a8b9" +git-tree-sha1 = "3bc002af51045ca3b47d2e1787d6ce02e68b943a" uuid = "31c24e10-a181-5473-b8eb-7969acd0382f" -version = "0.25.117" +version = "0.25.122" [deps.Distributions.extensions] DistributionsChainRulesCoreExt = "ChainRulesCore" @@ -433,10 +544,15 @@ version = "0.25.117" Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" [[deps.DocStringExtensions]] -deps = ["LibGit2"] -git-tree-sha1 = "2fb1e02f2b635d0845df5d7c167fec4dd739b00d" +git-tree-sha1 = "7442a5dfe1ebb773c29cc2962a8980f47221d76c" uuid = "ffbed154-4ef7-542d-bbb7-c09d3a79fcae" -version = "0.9.3" +version = "0.9.5" + +[[deps.Documenter]] +deps = ["ANSIColoredPrinters", "AbstractTrees", "Base64", "CodecZlib", "Dates", "DocStringExtensions", "Downloads", "Git", "IOCapture", "InteractiveUtils", "JSON", "Logging", "Markdown", "MarkdownAST", "Pkg", "PrecompileTools", "REPL", "RegistryInstances", "SHA", "TOML", "Test", "Unicode"] +git-tree-sha1 = "70c521ca3a23c576e12655d15963977c9766c26b" +uuid = "e30172f5-a6a5-5a46-863b-614d45cd2de4" +version = "1.16.0" [[deps.DotEnv]] deps = ["PrecompileTools"] @@ -456,9 +572,9 @@ uuid = "5ae413db-bbd1-5e63-b57d-d24a61df00f5" version = "2.2.4+0" [[deps.EnumX]] -git-tree-sha1 = "bdb1942cd4c45e3c678fd11569d5cccd80976237" +git-tree-sha1 = "bddad79635af6aec424f53ed8aad5d7555dc6f00" uuid = "4e289a0a-7415-4d19-859d-a7e5c4648b56" -version = "1.0.4" +version = "1.0.5" [[deps.EpollShim_jll]] deps = ["Artifacts", "JLLWrappers", "Libdl"] @@ -468,9 +584,9 @@ version = "0.0.20230411+1" [[deps.ExactPredicates]] deps = ["IntervalArithmetic", "Random", "StaticArrays"] -git-tree-sha1 = "b3f2ff58735b5f024c392fde763f29b057e4b025" +git-tree-sha1 = "83231673ea4d3d6008ac74dc5079e77ab2209d8f" uuid = "429591f6-91af-11e9-00e2-59fbe8cec110" -version = "2.2.8" +version = "2.2.9" [[deps.ExceptionUnwrapping]] deps = ["Test"] @@ -480,42 +596,31 @@ version = "0.1.11" [[deps.Expat_jll]] deps = ["Artifacts", "JLLWrappers", "Libdl"] -git-tree-sha1 = "e51db81749b0777b2147fbe7b783ee79045b8e99" +git-tree-sha1 = "27af30de8b5445644e8ffe3bcb0d72049c089cf1" uuid = "2e619515-83b5-522b-bb60-26c02a35a201" -version = "2.6.4+3" - -[[deps.ExpressionExplorer]] -git-tree-sha1 = "71d0768dd78ad62d3582091bf338d98af8bbda67" -uuid = "21656369-7473-754a-2065-74616d696c43" -version = "1.1.1" +version = "2.7.3+0" [[deps.ExproniconLite]] -git-tree-sha1 = "4c9ed87a6b3cd90acf24c556f2119533435ded38" +git-tree-sha1 = "c13f0b150373771b0fdc1713c97860f8df12e6c2" uuid = "55351af7-c7e9-48d6-89ff-24e801d99491" -version = "0.10.13" +version = "0.10.14" [[deps.Extents]] -git-tree-sha1 = "063512a13dbe9c40d999c439268539aa552d1ae6" +git-tree-sha1 = "b309b36a9e02fe7be71270dd8c0fd873625332b4" uuid = "411431e0-e8b7-467b-b5e0-f676ba4f2910" -version = "0.1.5" +version = "0.1.6" [[deps.EzXML]] deps = ["Printf", "XML2_jll"] -git-tree-sha1 = "380053d61bb9064d6aa4a9777413b40429c79901" +git-tree-sha1 = "7ea1aa5869e2626ccae84480e4f37185bc6f41d3" uuid = "8f5d6c58-4d21-5cfd-889c-e3ad7ee6a615" -version = "1.2.0" - -[[deps.FFMPEG]] -deps = ["FFMPEG_jll"] -git-tree-sha1 = "53ebe7511fa11d33bec688a9178fac4e49eeee00" -uuid = "c87230d0-a227-11e9-1b43-d7ebe4e7570a" -version = "0.4.2" +version = "1.2.3" [[deps.FFMPEG_jll]] -deps = ["Artifacts", "Bzip2_jll", "FreeType2_jll", "FriBidi_jll", "JLLWrappers", "LAME_jll", "Libdl", "Ogg_jll", "OpenSSL_jll", "Opus_jll", "PCRE2_jll", "Pkg", "Zlib_jll", "libaom_jll", "libass_jll", "libfdk_aac_jll", "libvorbis_jll", "x264_jll", "x265_jll"] -git-tree-sha1 = "74faea50c1d007c85837327f6775bea60b5492dd" +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 = "eaa040768ea663ca695d442be1bc97edfe6824f2" uuid = "b22a6f82-2f65-5046-a5b2-351ab43fb4e5" -version = "4.4.2+2" +version = "6.1.3+0" [[deps.FFTViews]] deps = ["CustomUnitRanges", "FFTW"] @@ -524,22 +629,22 @@ uuid = "4f61f5a4-77b1-5117-aa51-3ab5ef4ef0cd" version = "0.3.2" [[deps.FFTW]] -deps = ["AbstractFFTs", "FFTW_jll", "LinearAlgebra", "MKL_jll", "Preferences", "Reexport"] -git-tree-sha1 = "7de7c78d681078f027389e067864a8d53bd7c3c9" +deps = ["AbstractFFTs", "FFTW_jll", "Libdl", "LinearAlgebra", "MKL_jll", "Preferences", "Reexport"] +git-tree-sha1 = "97f08406df914023af55ade2f843c39e99c5d969" uuid = "7a1cc6ca-52ef-59f5-83cd-3a7055c09341" -version = "1.8.1" +version = "1.10.0" [[deps.FFTW_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] -git-tree-sha1 = "4d81ed14783ec49ce9f2e168208a12ce1815aa25" +deps = ["Artifacts", "JLLWrappers", "Libdl"] +git-tree-sha1 = "6d6219a004b8cf1e0b4dbe27a2860b8e04eba0be" uuid = "f5851436-0d7a-5f13-b9de-f02708fd171a" -version = "3.3.10+3" +version = "3.3.11+0" [[deps.FileIO]] deps = ["Pkg", "Requires", "UUIDs"] -git-tree-sha1 = "2dd20384bf8c6d411b5c7370865b1e9b26cb2ea3" +git-tree-sha1 = "d60eb76f37d7e5a40cc2e7c36974d864b82dc802" uuid = "5789e2e9-d7fb-5bc7-8068-2c6fae9b9549" -version = "1.16.6" +version = "1.17.1" weakdeps = ["HTTP"] [deps.FileIO.extensions] @@ -553,9 +658,9 @@ version = "0.8.3" [[deps.FilePathsBase]] deps = ["Compat", "Dates"] -git-tree-sha1 = "7878ff7172a8e6beedd1dea14bd27c3c6340d361" +git-tree-sha1 = "3bab2c5aa25e7840a4b065805c0cdfc01f3068d2" uuid = "48062228-2e41-5def-b9a4-89aafe57970f" -version = "0.9.22" +version = "0.9.24" weakdeps = ["Mmap", "Test"] [deps.FilePathsBase.extensions] @@ -568,9 +673,9 @@ version = "1.11.0" [[deps.FillArrays]] deps = ["LinearAlgebra"] -git-tree-sha1 = "6a70198746448456524cb442b8af316927ff3e1a" +git-tree-sha1 = "5bfcd42851cf2f1b303f51525a54dc5e98d408a3" uuid = "1a297f60-69ca-5386-bcde-b61e274b549b" -version = "1.13.0" +version = "1.15.0" weakdeps = ["PDMats", "SparseArrays", "Statistics"] [deps.FillArrays.extensions] @@ -586,9 +691,9 @@ version = "0.8.5" [[deps.Fontconfig_jll]] deps = ["Artifacts", "Bzip2_jll", "Expat_jll", "FreeType2_jll", "JLLWrappers", "Libdl", "Libuuid_jll", "Zlib_jll"] -git-tree-sha1 = "21fac3c77d7b5a9fc03b0ec503aa1a6392c34d2b" +git-tree-sha1 = "f85dac9a96a01087df6e3a749840015a0ca3817d" uuid = "a3f928ae-7b40-5064-980b-68af3947d34b" -version = "2.15.0+0" +version = "2.17.1+0" [[deps.Format]] git-tree-sha1 = "9c68794ef81b08086aeb32eeaf33531668d5f5fc" @@ -603,32 +708,32 @@ version = "4.1.1" [[deps.FreeType2_jll]] deps = ["Artifacts", "Bzip2_jll", "JLLWrappers", "Libdl", "Zlib_jll"] -git-tree-sha1 = "786e968a8d2fb167f2e4880baba62e0e26bd8e4e" +git-tree-sha1 = "2c5512e11c791d1baed2049c5652441b28fc6a31" uuid = "d7e528f0-a631-5988-bf34-fe36492bcfd7" -version = "2.13.3+1" +version = "2.13.4+0" [[deps.FreeTypeAbstraction]] -deps = ["ColorVectorSpace", "Colors", "FreeType", "GeometryBasics"] -git-tree-sha1 = "d52e255138ac21be31fa633200b65e4e71d26802" +deps = ["BaseDirs", "ColorVectorSpace", "Colors", "FreeType", "GeometryBasics", "Mmap"] +git-tree-sha1 = "4ebb930ef4a43817991ba35db6317a05e59abd11" uuid = "663a7486-cb36-511b-a19d-713bb74d65c9" -version = "0.10.6" +version = "0.10.8" [[deps.FriBidi_jll]] deps = ["Artifacts", "JLLWrappers", "Libdl"] -git-tree-sha1 = "846f7026a9decf3679419122b49f8a1fdb48d2d5" +git-tree-sha1 = "7a214fdac5ed5f59a22c2d9a885a16da1c74bbc7" uuid = "559328eb-81f9-559d-9380-de523a88c83c" -version = "1.0.16+0" +version = "1.0.17+0" [[deps.Future]] deps = ["Random"] uuid = "9fa8497b-333b-5362-9e8d-4d0656e87820" version = "1.11.0" -[[deps.FuzzyCompletions]] -deps = ["REPL"] -git-tree-sha1 = "be713866335f48cfb1285bff2d0cbb8304c1701c" -uuid = "fb4132e2-a121-4a70-b8a1-d5b831dcdcc2" -version = "0.5.5" +[[deps.GLFW]] +deps = ["GLFW_jll"] +git-tree-sha1 = "40412e58ec374029de3d4ad7c13e1a52aa1e149f" +uuid = "f7f18e0c-5ee9-5ccd-a5bf-e8befd85ed98" +version = "3.4.5" [[deps.GLFW_jll]] deps = ["Artifacts", "JLLWrappers", "Libdl", "Libglvnd_jll", "Xorg_libXcursor_jll", "Xorg_libXi_jll", "Xorg_libXinerama_jll", "Xorg_libXrandr_jll", "libdecor_jll", "xkbcommon_jll"] @@ -636,23 +741,17 @@ git-tree-sha1 = "fcb0584ff34e25155876418979d4c8971243bb89" uuid = "0656b61e-2033-5cc2-a64a-77c0f6c09b89" version = "3.4.0+2" +[[deps.GLMakie]] +deps = ["ColorTypes", "Colors", "FileIO", "FixedPointNumbers", "FreeTypeAbstraction", "GLFW", "GeometryBasics", "LinearAlgebra", "Makie", "Markdown", "MeshIO", "ModernGL", "Observables", "PrecompileTools", "Printf", "ShaderAbstractions", "StaticArrays"] +git-tree-sha1 = "d16b3b912164f0fd90a393e8c3b6f5a4ec073fde" +uuid = "e9467ef8-e4e7-5192-8a1a-b1aee30e663a" +version = "0.11.11" + [[deps.GMP_jll]] deps = ["Artifacts", "Libdl"] uuid = "781609d7-10c4-51f6-84f2-b8444358ff6d" version = "6.3.0+0" -[[deps.GR]] -deps = ["Artifacts", "Base64", "DelimitedFiles", "Downloads", "GR_jll", "HTTP", "JSON", "Libdl", "LinearAlgebra", "Pkg", "Preferences", "Printf", "Random", "Serialization", "Sockets", "TOML", "Tar", "Test", "UUIDs", "p7zip_jll"] -git-tree-sha1 = "8e2d86e06ceb4580110d9e716be26658effc5bfd" -uuid = "28b8d3ca-fb5f-59d9-8090-bfdbd6d07a71" -version = "0.72.8" - -[[deps.GR_jll]] -deps = ["Artifacts", "Bzip2_jll", "Cairo_jll", "FFMPEG_jll", "Fontconfig_jll", "GLFW_jll", "JLLWrappers", "JpegTurbo_jll", "Libdl", "Libtiff_jll", "Pixman_jll", "Qt5Base_jll", "Zlib_jll", "libpng_jll"] -git-tree-sha1 = "da121cbdc95b065da07fbb93638367737969693f" -uuid = "d2c73de3-f751-5644-a686-071e5b155ba9" -version = "0.72.8+0" - [[deps.GTK3_jll]] deps = ["ATK_jll", "Artifacts", "Cairo_jll", "Fontconfig_jll", "FreeType2_jll", "FriBidi_jll", "Glib_jll", "HarfBuzz_jll", "JLLWrappers", "Libdl", "Libepoxy_jll", "Pango_jll", "Pkg", "Wayland_jll", "Xorg_libX11_jll", "Xorg_libXcomposite_jll", "Xorg_libXcursor_jll", "Xorg_libXdamage_jll", "Xorg_libXext_jll", "Xorg_libXfixes_jll", "Xorg_libXi_jll", "Xorg_libXinerama_jll", "Xorg_libXrandr_jll", "Xorg_libXrender_jll", "at_spi2_atk_jll", "gdk_pixbuf_jll", "iso_codes_jll", "xkbcommon_jll"] git-tree-sha1 = "b080a592525632d287aee4637a62682576b7f5e4" @@ -667,9 +766,9 @@ version = "0.5.1" [[deps.Genie]] deps = ["ArgParse", "Base64", "Dates", "Distributed", "DotEnv", "EzXML", "FilePathsBase", "HTTP", "HttpCommon", "Inflector", "JSON3", "JuliaFormatter", "Logging", "LoggingExtras", "LoweredCodeUtils", "MIMEs", "Markdown", "Millboard", "Nettle", "OrderedCollections", "Pkg", "REPL", "Random", "Reexport", "Revise", "SHA", "Serialization", "Sockets", "UUIDs", "Unicode", "XML2_jll", "YAML"] -git-tree-sha1 = "6b1283b541f467ae6830d6066535bd6f73a3e808" +git-tree-sha1 = "86356a37e97b135ee86ec1f0e1dd8fc52830dcff" uuid = "c43c736e-a2d1-11e8-161f-af95117fbd1e" -version = "5.31.1" +version = "5.33.17" [[deps.GenieAutoReload]] deps = ["Distributed", "Genie", "Logging", "Revise"] @@ -679,15 +778,15 @@ version = "2.2.5" [[deps.GenieDevTools]] deps = ["Dates", "Genie", "RemoteREPL", "Revise", "Stipple", "StippleUI", "Tables"] -git-tree-sha1 = "21ca67d9d8a9f5676c85be3cf16337b7dcdac2db" +git-tree-sha1 = "5c84de04cde55e272e760e7ef021bb645f53bd67" uuid = "4e5d9629-6565-4102-a9ff-45c707eb060e" -version = "2.12.0" +version = "2.12.1" [[deps.GenieFramework]] deps = ["GarishPrint", "Genie", "GenieAutoReload", "GenieDevTools", "GeniePackageManager", "Reexport", "Revise", "Stipple", "StipplePivotTable", "StipplePlotly", "StippleTable", "StippleTabs", "StippleUI"] -git-tree-sha1 = "d35a79434728f5d04ed0d07ff19a250821133da6" +git-tree-sha1 = "4dcc51e8dbaf7d02ba80a2dbebc7b05eb477cc03" uuid = "a59fdf5c-6bf0-4f5d-949c-a137c9e2f353" -version = "2.8.0" +version = "2.10.0" [[deps.GeniePackageManager]] deps = ["Base64", "Genie", "Pkg"] @@ -707,34 +806,29 @@ git-tree-sha1 = "5f5ffc33251d0d5f110072f7a0c07717c9453c97" uuid = "5c4fdc26-39e3-47cf-9034-e533e09961c2" version = "1.1.0" -[[deps.GeoFormatTypes]] -git-tree-sha1 = "8e233d5167e63d708d41f87597433f59a0f213fe" -uuid = "68eda718-8dee-11e9-39e7-89f7f65f511f" -version = "0.4.4" - -[[deps.GeoInterface]] -deps = ["DataAPI", "Extents", "GeoFormatTypes"] -git-tree-sha1 = "294e99f19869d0b0cb71aef92f19d03649d028d5" -uuid = "cf35fbd7-0cd7-5166-be24-54bfbe79505f" -version = "1.4.1" - [[deps.GeometryBasics]] -deps = ["EarCut_jll", "Extents", "GeoInterface", "IterTools", "LinearAlgebra", "PrecompileTools", "Random", "StaticArrays"] -git-tree-sha1 = "c1a9c159c3ac53aa09663d8662c7277ef3fa508d" +deps = ["EarCut_jll", "Extents", "IterTools", "LinearAlgebra", "PrecompileTools", "Random", "StaticArrays"] +git-tree-sha1 = "1f5a80f4ed9f5a4aada88fc2db456e637676414b" uuid = "5c1252a2-5f33-56bf-86c9-59e7332b4326" -version = "0.5.1" +version = "0.5.10" -[[deps.Gettext_jll]] -deps = ["Artifacts", "CompilerSupportLibraries_jll", "JLLWrappers", "Libdl", "Libiconv_jll", "Pkg", "XML2_jll"] -git-tree-sha1 = "9b02998aba7bf074d14de89f9d37ca24a1a0b046" -uuid = "78b55507-aeef-58d4-861c-77aaff3498b1" -version = "0.21.0+0" + [deps.GeometryBasics.extensions] + GeometryBasicsGeoInterfaceExt = "GeoInterface" + + [deps.GeometryBasics.weakdeps] + GeoInterface = "cf35fbd7-0cd7-5166-be24-54bfbe79505f" + +[[deps.GettextRuntime_jll]] +deps = ["Artifacts", "CompilerSupportLibraries_jll", "JLLWrappers", "Libdl", "Libiconv_jll"] +git-tree-sha1 = "45288942190db7c5f760f59c04495064eedf9340" +uuid = "b0724c58-0f36-5564-988d-3bb0596ebc4a" +version = "0.22.4+0" [[deps.Ghostscript_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] -git-tree-sha1 = "43ba3d3c82c18d88471cfd2924931658838c9d8f" +deps = ["Artifacts", "JLLWrappers", "JpegTurbo_jll", "Libdl", "Zlib_jll"] +git-tree-sha1 = "38044a04637976140074d0b0621c1edf0eb531fd" uuid = "61579ee1-b43e-5ca0-a5da-69d92c66a64b" -version = "9.55.0+4" +version = "9.55.1+0" [[deps.Giflib_jll]] deps = ["Artifacts", "JLLWrappers", "Libdl"] @@ -742,11 +836,29 @@ git-tree-sha1 = "6570366d757b50fabae9f4315ad74d2e40c0560a" uuid = "59f7168a-df46-5410-90c8-f2779963d0ec" version = "5.2.3+0" +[[deps.Git]] +deps = ["Git_LFS_jll", "Git_jll", "JLLWrappers", "OpenSSH_jll"] +git-tree-sha1 = "824a1890086880696fc908fe12a17bcf61738bd8" +uuid = "d7ba0133-e1db-5d97-8f8c-041e4b3a1eb2" +version = "1.5.0" + +[[deps.Git_LFS_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl"] +git-tree-sha1 = "bb8471f313ed941f299aa53d32a94ab3bee08844" +uuid = "020c3dae-16b3-5ae5-87b3-4cb189e250b2" +version = "3.7.0+0" + +[[deps.Git_jll]] +deps = ["Artifacts", "Expat_jll", "JLLWrappers", "LibCURL_jll", "Libdl", "Libiconv_jll", "OpenSSL_jll", "PCRE2_jll", "Zlib_jll"] +git-tree-sha1 = "b6a684587ebe896d9f68ae777f648205940f0f70" +uuid = "f8c6e375-362e-5223-8a59-34ff63f689eb" +version = "2.51.3+0" + [[deps.Glib_jll]] -deps = ["Artifacts", "Gettext_jll", "JLLWrappers", "Libdl", "Libffi_jll", "Libiconv_jll", "Libmount_jll", "PCRE2_jll", "Zlib_jll"] -git-tree-sha1 = "b0036b392358c80d2d2124746c2bf3d48d457938" +deps = ["Artifacts", "GettextRuntime_jll", "JLLWrappers", "Libdl", "Libffi_jll", "Libiconv_jll", "Libmount_jll", "PCRE2_jll", "Zlib_jll"] +git-tree-sha1 = "50c11ffab2a3d50192a228c313f05b5b5dc5acb2" uuid = "7746bdde-850d-59dc-9ae8-88ece973131d" -version = "2.82.4+0" +version = "2.86.0+0" [[deps.Glob]] git-tree-sha1 = "97285bbd5230dd766e9ef6749b80fc617126d496" @@ -760,22 +872,22 @@ uuid = "a2bd30eb-e257-5431-a919-1863eab51364" version = "1.1.3" [[deps.Graphite2_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] -git-tree-sha1 = "01979f9b37367603e2848ea225918a3b3861b606" +deps = ["Artifacts", "JLLWrappers", "Libdl"] +git-tree-sha1 = "8a6dbda1fd736d60cc477d99f2e7a042acfa46e8" uuid = "3b182d85-2403-5c21-9c21-1e1f0cc25472" -version = "1.3.14+1" +version = "1.3.15+0" [[deps.Graphs]] -deps = ["ArnoldiMethod", "Compat", "DataStructures", "Distributed", "Inflate", "LinearAlgebra", "Random", "SharedArrays", "SimpleTraits", "SparseArrays", "Statistics"] -git-tree-sha1 = "1dc470db8b1131cfc7fb4c115de89fe391b9e780" +deps = ["ArnoldiMethod", "DataStructures", "Distributed", "Inflate", "LinearAlgebra", "Random", "SharedArrays", "SimpleTraits", "SparseArrays", "Statistics"] +git-tree-sha1 = "7a98c6502f4632dbe9fb1973a4244eaa3324e84d" uuid = "86223c79-3864-5bf0-83f7-82e725a168b6" -version = "1.12.0" +version = "1.13.1" [[deps.GridLayoutBase]] deps = ["GeometryBasics", "InteractiveUtils", "Observables"] -git-tree-sha1 = "dc6bed05c15523624909b3953686c5f5ffa10adc" +git-tree-sha1 = "93d5c27c8de51687a2c70ec0716e6e76f298416f" uuid = "3955a311-db13-416c-9275-1d80ed98e5e9" -version = "0.11.1" +version = "0.11.2" [[deps.Grisu]] git-tree-sha1 = "53bb909d1151e57e2484c3d1b53e19552b887fb2" @@ -784,15 +896,20 @@ version = "1.0.2" [[deps.HTTP]] deps = ["Base64", "CodecZlib", "ConcurrentUtilities", "Dates", "ExceptionUnwrapping", "Logging", "LoggingExtras", "MbedTLS", "NetworkOptions", "OpenSSL", "PrecompileTools", "Random", "SimpleBufferStream", "Sockets", "URIs", "UUIDs"] -git-tree-sha1 = "c67b33b085f6e2faf8bf79a61962e7339a81129c" +git-tree-sha1 = "5e6fe50ae7f23d171f44e311c2960294aaa0beb5" uuid = "cd3eb016-35fb-5094-929b-558a96fad6f3" -version = "1.10.15" +version = "1.10.19" [[deps.HarfBuzz_jll]] deps = ["Artifacts", "Cairo_jll", "Fontconfig_jll", "FreeType2_jll", "Glib_jll", "Graphite2_jll", "JLLWrappers", "Libdl", "Libffi_jll"] -git-tree-sha1 = "55c53be97790242c29031e5cd45e8ac296dadda3" +git-tree-sha1 = "f923f9a774fcf3f5cb761bfa43aeadd689714813" uuid = "2e76f6c2-a576-52d4-95c1-20adfe4de566" -version = "8.5.0+0" +version = "8.5.1+0" + +[[deps.HashArrayMappedTries]] +git-tree-sha1 = "2eaa69a7cab70a52b9687c8bf950a5a93ec895ae" +uuid = "076d061b-32b6-4027-95e0-9a2c6f6d7e74" +version = "0.2.0" [[deps.HistogramThresholding]] deps = ["ImageBase", "LinearAlgebra", "MappedArrays"] @@ -814,15 +931,15 @@ version = "0.5.0" [[deps.HypergeometricFunctions]] deps = ["LinearAlgebra", "OpenLibm_jll", "SpecialFunctions"] -git-tree-sha1 = "4f0a6a9f57c0d0cc7590a6e47c0f641814917f2a" +git-tree-sha1 = "68c173f4f449de5b438ee67ed0c9c748dc31a2ec" uuid = "34004b35-14d8-5ef3-9330-4cdb6864b03a" -version = "0.3.26" +version = "0.3.28" -[[deps.HypertextLiteral]] -deps = ["Tricks"] -git-tree-sha1 = "7134810b1afce04bbc1045ca1985fbe81ce17653" -uuid = "ac1192a8-f4b3-4bfe-ba22-af5b92cd3ab2" -version = "0.9.5" +[[deps.IOCapture]] +deps = ["Logging", "Random"] +git-tree-sha1 = "0ee181ec08df7d7c911901ea38baf16f755114dc" +uuid = "b5f81e59-6552-4d32-b1f0-c071b021bf89" +version = "1.0.0" [[deps.IfElse]] git-tree-sha1 = "debdd00ffef04665ccbb3e150747a77560e8fad1" @@ -847,6 +964,12 @@ git-tree-sha1 = "33485b4e40d1df46c806498c73ea32dc17475c59" uuid = "cbc4b850-ae4b-5111-9e64-df94c024a13d" version = "0.3.1" +[[deps.ImageComponentAnalysis]] +deps = ["AbstractTrees", "ConvexHulls2d", "DataFrames", "DataStructures", "ImageFiltering", "LeftChildRightSiblingTrees", "LinearAlgebra", "OffsetArrays", "Parameters", "StaticArrays"] +git-tree-sha1 = "0f1e954d54bafec3df4aa9d1ce1f110e311a9043" +uuid = "d9b9e9a0-1569-11e9-2cb5-bbca914b0e89" +version = "0.2.2" + [[deps.ImageContrastAdjustment]] deps = ["ImageBase", "ImageCore", "ImageTransformations", "Parameters"] git-tree-sha1 = "eb3d4365a10e3f3ecb3b115e9d12db131d28a386" @@ -873,9 +996,9 @@ version = "0.2.17" [[deps.ImageFiltering]] deps = ["CatIndices", "ComputationalResources", "DataStructures", "FFTViews", "FFTW", "ImageBase", "ImageCore", "LinearAlgebra", "OffsetArrays", "PrecompileTools", "Reexport", "SparseArrays", "StaticArrays", "Statistics", "TiledIteration"] -git-tree-sha1 = "33cb509839cc4011beb45bde2316e64344b0f92b" +git-tree-sha1 = "52116260a234af5f69969c5286e6a5f8dc3feab8" uuid = "6a3955dd-da59-5b1f-98d4-e7296123deb5" -version = "0.7.9" +version = "0.7.12" [[deps.ImageIO]] deps = ["FileIO", "IndirectArrays", "JpegTurbo", "LazyModules", "Netpbm", "OpenEXR", "PNGFiles", "QOI", "Sixel", "TiffImages", "UUIDs", "WebP"] @@ -885,15 +1008,15 @@ version = "0.6.9" [[deps.ImageMagick]] deps = ["FileIO", "ImageCore", "ImageMagick_jll", "InteractiveUtils"] -git-tree-sha1 = "c5c5478ae8d944c63d6de961b19e6d3324812c35" +git-tree-sha1 = "8e64ab2f0da7b928c8ae889c514a52741debc1c2" uuid = "6218d12a-5da1-5696-b52f-db25d2ecc6d1" -version = "1.4.0" +version = "1.4.2" [[deps.ImageMagick_jll]] -deps = ["Artifacts", "Ghostscript_jll", "JLLWrappers", "JpegTurbo_jll", "Libdl", "Libtiff_jll", "OpenJpeg_jll", "Zlib_jll", "libpng_jll"] -git-tree-sha1 = "fa01c98985be12e5d75301c4527fff2c46fa3e0e" +deps = ["Artifacts", "Bzip2_jll", "FFTW_jll", "Ghostscript_jll", "JLLWrappers", "JpegTurbo_jll", "Libdl", "Libtiff_jll", "OpenJpeg_jll", "Zlib_jll", "Zstd_jll", "libpng_jll", "libwebp_jll", "libzip_jll"] +git-tree-sha1 = "d670e8e3adf0332f57054955422e85a4aec6d0b0" uuid = "c73af94c-d91f-53ed-93a7-00f77d67a9d7" -version = "7.1.1+1" +version = "7.1.2005+0" [[deps.ImageMetadata]] deps = ["AxisArrays", "ImageAxes", "ImageBase", "ImageCore"] @@ -903,9 +1026,9 @@ version = "0.9.10" [[deps.ImageMorphology]] deps = ["DataStructures", "ImageCore", "LinearAlgebra", "LoopVectorization", "OffsetArrays", "Requires", "TiledIteration"] -git-tree-sha1 = "6f0a801136cb9c229aebea0df296cdcd471dbcd1" +git-tree-sha1 = "cffa21df12f00ca1a365eb8ed107614b40e8c6da" uuid = "787d08f9-d448-5407-9aad-5290dd7ab264" -version = "0.4.5" +version = "0.4.6" [[deps.ImageQualityIndexes]] deps = ["ImageContrastAdjustment", "ImageCore", "ImageDistances", "ImageFiltering", "LazyModules", "OffsetArrays", "PrecompileTools", "Statistics"] @@ -915,9 +1038,9 @@ version = "0.3.7" [[deps.ImageSegmentation]] deps = ["Clustering", "DataStructures", "Distances", "Graphs", "ImageCore", "ImageFiltering", "ImageMorphology", "LinearAlgebra", "MetaGraphs", "RegionTrees", "SimpleWeightedGraphs", "StaticArrays", "Statistics"] -git-tree-sha1 = "b217d9ded4a95052ffc09acc41ab781f7f72c7ba" +git-tree-sha1 = "7196039573b6f312864547eb7a74360d6c0ab8e6" uuid = "80713f31-8817-5129-9cf8-209ff8fb23e1" -version = "1.8.3" +version = "1.9.0" [[deps.ImageShow]] deps = ["Base64", "ColorSchemes", "FileIO", "ImageBase", "ImageCore", "OffsetArrays", "StackViews"] @@ -927,9 +1050,9 @@ version = "0.3.8" [[deps.ImageTransformations]] deps = ["AxisAlgorithms", "CoordinateTransformations", "ImageBase", "ImageCore", "Interpolations", "OffsetArrays", "Rotations", "StaticArrays"] -git-tree-sha1 = "e0884bdf01bbbb111aea77c348368a86fb4b5ab6" +git-tree-sha1 = "dfde81fafbe5d6516fb864dc79362c5c6b973c82" uuid = "02fcd773-0e25-5acc-982a-7f6622650795" -version = "0.10.1" +version = "0.10.2" [[deps.Images]] deps = ["Base64", "FileIO", "Graphics", "ImageAxes", "ImageBase", "ImageBinarization", "ImageContrastAdjustment", "ImageCore", "ImageCorners", "ImageDistances", "ImageFiltering", "ImageIO", "ImageMagick", "ImageMetadata", "ImageMorphology", "ImageQualityIndexes", "ImageSegmentation", "ImageShow", "ImageTransformations", "IndirectArrays", "IntegralArrays", "Random", "Reexport", "SparseArrays", "StaticArrays", "Statistics", "StatsBase", "TiledIteration"] @@ -960,9 +1083,9 @@ uuid = "6d011eab-0732-4556-8808-e463c76bf3b6" version = "1.1.0" [[deps.InlineStrings]] -git-tree-sha1 = "45521d31238e87ee9f9732561bfee12d4eebd52d" +git-tree-sha1 = "8f3d257792a522b4601c24a577954b0a8cd7334d" uuid = "842dd82b-1e85-43dc-bf29-5d0ee9dffc48" -version = "1.4.2" +version = "1.4.5" [deps.InlineStrings.extensions] ArrowTypesExt = "ArrowTypes" @@ -980,9 +1103,9 @@ version = "0.1.6" [[deps.IntelOpenMP_jll]] deps = ["Artifacts", "JLLWrappers", "LazyArtifacts", "Libdl"] -git-tree-sha1 = "0f14a5456bdc6b9731a5682f439a672750a09e48" +git-tree-sha1 = "ec1debd61c300961f98064cfb21287613ad7f303" uuid = "1d5cc7b8-4909-519e-a0f8-d0f5ad9712d0" -version = "2025.0.4+0" +version = "2025.2.0+0" [[deps.InteractiveUtils]] deps = ["Markdown"] @@ -1000,30 +1123,37 @@ weakdeps = ["Unitful"] InterpolationsUnitfulExt = "Unitful" [[deps.IntervalArithmetic]] -deps = ["CRlibm_jll", "LinearAlgebra", "MacroTools", "RoundingEmulator"] -git-tree-sha1 = "ffb76d09ab0dc9f5a27edac2acec13c74a876cc6" +deps = ["CRlibm", "MacroTools", "OpenBLASConsistentFPCSR_jll", "Printf", "Random", "RoundingEmulator"] +git-tree-sha1 = "02b61501dbe6da3b927cc25dacd7ce32390ee970" uuid = "d1acc4aa-44c8-5952-acd4-ba5d80a2a253" -version = "0.22.21" +version = "1.0.2" [deps.IntervalArithmetic.extensions] + IntervalArithmeticArblibExt = "Arblib" IntervalArithmeticDiffRulesExt = "DiffRules" IntervalArithmeticForwardDiffExt = "ForwardDiff" IntervalArithmeticIntervalSetsExt = "IntervalSets" + IntervalArithmeticLinearAlgebraExt = "LinearAlgebra" IntervalArithmeticRecipesBaseExt = "RecipesBase" + IntervalArithmeticSparseArraysExt = "SparseArrays" [deps.IntervalArithmetic.weakdeps] + Arblib = "fb37089c-8514-4489-9461-98f9c8763369" DiffRules = "b552c78f-8df3-52c6-915a-8e097449b14b" ForwardDiff = "f6369f11-7733-5829-9624-2563aa707210" IntervalSets = "8197267c-284f-5f27-9208-e0e47529a953" + LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" RecipesBase = "3cdcf5f2-1ef4-517c-9805-6587b60abb01" + SparseArrays = "2f01184e-e22b-5df5-ae63-d93ebab69eaf" [[deps.IntervalSets]] -git-tree-sha1 = "dba9ddf07f77f60450fe5d2e2beb9854d9a49bd0" +git-tree-sha1 = "03b4f40b4987baa6a653a21f6f33f902af6255f3" uuid = "8197267c-284f-5f27-9208-e0e47529a953" -version = "0.7.10" -weakdeps = ["Random", "RecipesBase", "Statistics"] +version = "0.7.12" +weakdeps = ["Printf", "Random", "RecipesBase", "Statistics"] [deps.IntervalSets.extensions] + IntervalSetsPrintfExt = "Printf" IntervalSetsRandomExt = "Random" IntervalSetsRecipesBaseExt = "RecipesBase" IntervalSetsStatisticsExt = "Statistics" @@ -1044,9 +1174,9 @@ uuid = "41ab1584-1d38-5bbf-9106-f11c6c58b48f" version = "1.3.1" [[deps.IrrationalConstants]] -git-tree-sha1 = "630b497eafcc20001bba38a4651b327dcfc491d2" +git-tree-sha1 = "b2d91fe939cae05960e760110b328288867b5758" uuid = "92d709cd-6900-40b7-9082-c6be49f344b6" -version = "0.2.2" +version = "0.2.6" [[deps.Isoband]] deps = ["isoband_jll"] @@ -1065,22 +1195,20 @@ uuid = "82899510-4779-5014-852e-03e436cf321d" version = "1.0.0" [[deps.JLD2]] -deps = ["FileIO", "MacroTools", "Mmap", "OrderedCollections", "PrecompileTools", "Requires", "TranscodingStreams"] -git-tree-sha1 = "91d501cb908df6f134352ad73cde5efc50138279" +deps = ["ChunkCodecLibZlib", "ChunkCodecLibZstd", "FileIO", "MacroTools", "Mmap", "OrderedCollections", "PrecompileTools", "ScopedValues"] +git-tree-sha1 = "da2e9b4d1abbebdcca0aa68afa0aa272102baad7" uuid = "033835bb-8acc-5ee8-8aae-3f567f8a3819" -version = "0.5.11" +version = "0.6.2" +weakdeps = ["UnPack"] -[[deps.JLFzf]] -deps = ["Pipe", "REPL", "Random", "fzf_jll"] -git-tree-sha1 = "71b48d857e86bf7a1838c4736545699974ce79a2" -uuid = "1019f520-868f-41f5-a6de-eb00f4b6a39c" -version = "0.1.9" + [deps.JLD2.extensions] + UnPackExt = "UnPack" [[deps.JLLWrappers]] deps = ["Artifacts", "Preferences"] -git-tree-sha1 = "a007feb38b422fbdab534406aeca1b86823cb4d6" +git-tree-sha1 = "0533e564aae234aff59ab625543145446d8b6ec2" uuid = "692b3bcd-3c85-4b1f-b108-f13ce0eb3210" -version = "1.7.0" +version = "1.7.1" [[deps.JSON]] deps = ["Dates", "Mmap", "Parsers", "Unicode"] @@ -1090,9 +1218,9 @@ version = "0.21.4" [[deps.JSON3]] deps = ["Dates", "Mmap", "Parsers", "PrecompileTools", "StructTypes", "UUIDs"] -git-tree-sha1 = "1d322381ef7b087548321d3f878cb4c9bd8f8f9b" +git-tree-sha1 = "411eccfe8aba0814ffa0fdf4860913ed09c34975" uuid = "0f8b85d8-7281-11e9-16c2-39a750bddbf1" -version = "1.14.1" +version = "1.14.3" [deps.JSON3.extensions] JSON3ArrowExt = ["ArrowTypes"] @@ -1102,15 +1230,15 @@ version = "1.14.1" [[deps.JpegTurbo]] deps = ["CEnum", "FileIO", "ImageCore", "JpegTurbo_jll", "TOML"] -git-tree-sha1 = "fa6d0bcff8583bac20f1ffa708c3913ca605c611" +git-tree-sha1 = "9496de8fb52c224a2e3f9ff403947674517317d9" uuid = "b835a17e-a41a-41e7-81f0-2f016b05efe0" -version = "0.1.5" +version = "0.1.6" [[deps.JpegTurbo_jll]] deps = ["Artifacts", "JLLWrappers", "Libdl"] -git-tree-sha1 = "eac1206917768cb54957c65a615460d87b455fc1" +git-tree-sha1 = "4255f0032eafd6451d707a51d5f0248b8a165e4d" uuid = "aacddb02-875f-59d6-b918-886e6ef4fbf8" -version = "3.1.1+0" +version = "3.1.3+0" [[deps.JuliaFormatter]] deps = ["CSTParser", "CommonMark", "DataStructures", "Glob", "PrecompileTools", "TOML", "Tokenize"] @@ -1120,33 +1248,33 @@ version = "1.0.62" [[deps.JuliaInterpreter]] deps = ["CodeTracking", "InteractiveUtils", "Random", "UUIDs"] -git-tree-sha1 = "10da5154188682e5c0726823c2b5125957ec3778" +git-tree-sha1 = "b6c76964c65ebf8309460fb8f0f437b4a59d809b" uuid = "aa1ae85d-cabe-5617-a682-6adf51b2e16a" -version = "0.9.38" +version = "0.10.7" [[deps.KernelDensity]] deps = ["Distributions", "DocStringExtensions", "FFTW", "Interpolations", "StatsBase"] -git-tree-sha1 = "7d703202e65efa1369de1279c162b915e245eed1" +git-tree-sha1 = "ba51324b894edaf1df3ab16e2cc6bc3280a2f1a7" uuid = "5ab0869b-81aa-558d-bb23-cbf5423bbe9b" -version = "0.6.9" +version = "0.6.10" [[deps.LAME_jll]] deps = ["Artifacts", "JLLWrappers", "Libdl"] -git-tree-sha1 = "170b660facf5df5de098d866564877e119141cbd" +git-tree-sha1 = "059aabebaa7c82ccb853dd4a0ee9d17796f7e1bc" uuid = "c1c5ebd0-6772-5130-a774-d5fcae4a789d" -version = "3.100.2+0" +version = "3.100.3+0" [[deps.LERC_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] -git-tree-sha1 = "bf36f528eec6634efc60d7ec062008f171071434" +deps = ["Artifacts", "JLLWrappers", "Libdl"] +git-tree-sha1 = "aaafe88dccbd957a8d82f7d05be9b69172e0cee3" uuid = "88015f11-f218-50d7-93a8-a6af411a945d" -version = "3.0.0+1" +version = "4.0.1+0" [[deps.LLVMOpenMP_jll]] deps = ["Artifacts", "JLLWrappers", "Libdl"] -git-tree-sha1 = "78211fb6cbc872f77cad3fc0b6cf647d923f4929" +git-tree-sha1 = "eb62a3deb62fc6d8822c0c4bef73e4412419c5d8" uuid = "1d63c593-3942-5779-bab2-d838dc0a180e" -version = "18.1.7+0" +version = "18.1.8+0" [[deps.LZO_jll]] deps = ["Artifacts", "JLLWrappers", "Libdl"] @@ -1159,22 +1287,6 @@ git-tree-sha1 = "dda21b8cbd6a6c40d9d02a73230f9d70fed6918c" uuid = "b964fa9f-0449-5b57-a5c2-d3ea65f4040f" version = "1.4.0" -[[deps.Latexify]] -deps = ["Format", "InteractiveUtils", "LaTeXStrings", "MacroTools", "Markdown", "OrderedCollections", "Requires"] -git-tree-sha1 = "ce5f5621cac23a86011836badfedf664a612cee4" -uuid = "23fbe1c1-3f47-55db-b15f-69d7ec21a316" -version = "0.16.5" - - [deps.Latexify.extensions] - DataFramesExt = "DataFrames" - SparseArraysExt = "SparseArrays" - SymEngineExt = "SymEngine" - - [deps.Latexify.weakdeps] - DataFrames = "a93c6f00-e57d-5684-b7b6-d8193f3e46c0" - SparseArrays = "2f01184e-e22b-5df5-ae63-d93ebab69eaf" - SymEngine = "123dc426-2d89-5057-bbad-38513e3affd8" - [[deps.LayoutPointers]] deps = ["ArrayInterface", "LinearAlgebra", "ManualMemory", "SIMDTypes", "Static", "StaticArrayInterface"] git-tree-sha1 = "a9eaadb366f5493a5654e843864c13d8b107548c" @@ -1196,6 +1308,12 @@ git-tree-sha1 = "a560dd966b386ac9ae60bdd3a3d3a326062d3c3e" uuid = "8cdb02fc-e678-4876-92c5-9defec4f444e" version = "0.3.1" +[[deps.LeftChildRightSiblingTrees]] +deps = ["AbstractTrees"] +git-tree-sha1 = "95ba48564903b43b2462318aa243ee79d81135ff" +uuid = "1d6d02ad-be62-4b6b-8a6d-2f90e265016e" +version = "0.2.1" + [[deps.LibCURL]] deps = ["LibCURL_jll", "MozillaCACerts_jll"] uuid = "b27032c2-a3e7-50c8-80cd-2d36dbcbfd21" @@ -1226,34 +1344,22 @@ uuid = "8f399da3-3557-5675-b5ff-fb832c97cbdb" version = "1.11.0" [[deps.Libepoxy_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl", "Libglvnd_jll", "Pkg", "Xorg_libX11_jll"] -git-tree-sha1 = "7a0158b71f8be5c771e7a273183b2d0ac35278c5" +deps = ["Artifacts", "JLLWrappers", "Libdl", "Libglvnd_jll", "Xorg_libX11_jll"] +git-tree-sha1 = "94d068f57b4241dd090693b6aba63416892298de" uuid = "42c93a91-0102-5b3f-8f9d-e41de60ac950" -version = "1.5.10+0" +version = "1.5.11+0" [[deps.Libffi_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] -git-tree-sha1 = "27ecae93dd25ee0909666e6835051dd684cc035e" +deps = ["Artifacts", "JLLWrappers", "Libdl"] +git-tree-sha1 = "c8da7e6a91781c41a863611c7e966098d783c57a" uuid = "e9f186c6-92d2-5b65-8a66-fee21dc1b490" -version = "3.2.2+2" - -[[deps.Libgcrypt_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl", "Libgpg_error_jll"] -git-tree-sha1 = "8be878062e0ffa2c3f67bb58a595375eda5de80b" -uuid = "d4300ac3-e22c-5743-9152-c294e39db1e4" -version = "1.11.0+0" +version = "3.4.7+0" [[deps.Libglvnd_jll]] deps = ["Artifacts", "JLLWrappers", "Libdl", "Xorg_libX11_jll", "Xorg_libXext_jll"] -git-tree-sha1 = "ff3b4b9d35de638936a525ecd36e86a8bb919d11" +git-tree-sha1 = "d36c21b9e7c172a44a10484125024495e2625ac0" uuid = "7e76a0d4-f3c7-5321-8279-8d96eeed0f29" -version = "1.7.0+0" - -[[deps.Libgpg_error_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl"] -git-tree-sha1 = "df37206100d39f79b3376afb6b9cee4970041c61" -uuid = "7add5ba3-2f88-524e-9cd5-f83b8a55f7b8" -version = "1.51.1+0" +version = "1.7.1+1" [[deps.Libiconv_jll]] deps = ["Artifacts", "JLLWrappers", "Libdl"] @@ -1263,21 +1369,21 @@ version = "1.18.0+0" [[deps.Libmount_jll]] deps = ["Artifacts", "JLLWrappers", "Libdl"] -git-tree-sha1 = "89211ea35d9df5831fca5d33552c02bd33878419" +git-tree-sha1 = "3acf07f130a76f87c041cfb2ff7d7284ca67b072" uuid = "4b2f31a3-9ecc-558c-b454-b3730dcb73e9" -version = "2.40.3+0" +version = "2.41.2+0" [[deps.Libtiff_jll]] -deps = ["Artifacts", "JLLWrappers", "JpegTurbo_jll", "LERC_jll", "Libdl", "Pkg", "Zlib_jll", "Zstd_jll"] -git-tree-sha1 = "3eb79b0ca5764d4799c06699573fd8f533259713" +deps = ["Artifacts", "JLLWrappers", "JpegTurbo_jll", "LERC_jll", "Libdl", "XZ_jll", "Zlib_jll", "Zstd_jll"] +git-tree-sha1 = "f04133fe05eff1667d2054c53d59f9122383fe05" uuid = "89763e89-9b03-5906-acba-b20f662cd828" -version = "4.4.0+0" +version = "4.7.2+0" [[deps.Libuuid_jll]] deps = ["Artifacts", "JLLWrappers", "Libdl"] -git-tree-sha1 = "e888ad02ce716b319e6bdb985d2ef300e7089889" +git-tree-sha1 = "2a7a12fc0a4e7fb773450d17975322aa77142106" uuid = "38a345b3-de98-5d2b-a5d3-14cd9215e700" -version = "2.40.3+0" +version = "2.41.2+0" [[deps.Libz]] deps = ["BufferedStreams", "Random", "Test"] @@ -1291,10 +1397,16 @@ uuid = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" version = "1.11.0" [[deps.LittleCMS_jll]] -deps = ["Artifacts", "JLLWrappers", "JpegTurbo_jll", "Libdl", "Libtiff_jll", "Pkg"] -git-tree-sha1 = "110897e7db2d6836be22c18bffd9422218ee6284" +deps = ["Artifacts", "JLLWrappers", "JpegTurbo_jll", "Libdl", "Libtiff_jll"] +git-tree-sha1 = "8e6a74641caf3b84800f2ccd55dc7ab83893c10b" uuid = "d3a379c0-f9a3-5b72-a4c0-6bf4d2e8af0f" -version = "2.12.0+0" +version = "2.17.0+0" + +[[deps.Loess]] +deps = ["Distances", "LinearAlgebra", "Statistics", "StatsAPI"] +git-tree-sha1 = "f749e7351f120b3566e5923fefdf8e52ba5ec7f9" +uuid = "4345ca2d-374a-55d4-8d30-97f9976e7612" +version = "0.6.4" [[deps.LogExpFunctions]] deps = ["DocStringExtensions", "IrrationalConstants", "LinearAlgebra"] @@ -1318,64 +1430,60 @@ version = "1.11.0" [[deps.LoggingExtras]] deps = ["Dates", "Logging"] -git-tree-sha1 = "f02b56007b064fbfddb4c9cd60161b6dd0f40df3" +git-tree-sha1 = "f00544d95982ea270145636c181ceda21c4e2575" uuid = "e6f89c97-d47a-5376-807f-9c37f3926c36" -version = "1.1.0" +version = "1.2.0" [[deps.LoopVectorization]] deps = ["ArrayInterface", "CPUSummary", "CloseOpenIntervals", "DocStringExtensions", "HostCPUFeatures", "IfElse", "LayoutPointers", "LinearAlgebra", "OffsetArrays", "PolyesterWeave", "PrecompileTools", "SIMDTypes", "SLEEFPirates", "Static", "StaticArrayInterface", "ThreadingUtilities", "UnPack", "VectorizationBase"] -git-tree-sha1 = "8084c25a250e00ae427a379a5b607e7aed96a2dd" +git-tree-sha1 = "a9fc7883eb9b5f04f46efb9a540833d1fad974b3" uuid = "bdcacae8-1622-11e9-2a5c-532679323890" -version = "0.12.171" +version = "0.12.173" [deps.LoopVectorization.extensions] ForwardDiffExt = ["ChainRulesCore", "ForwardDiff"] + ForwardDiffNNlibExt = ["ForwardDiff", "NNlib"] SpecialFunctionsExt = "SpecialFunctions" [deps.LoopVectorization.weakdeps] ChainRulesCore = "d360d2e6-b24c-11e9-a2a3-2a2ae2dbcce4" ForwardDiff = "f6369f11-7733-5829-9624-2563aa707210" + NNlib = "872c559c-99b0-510c-b3b7-b6c96a88d5cd" SpecialFunctions = "276daf66-3868-5448-9aa4-cd146d93841b" [[deps.LoweredCodeUtils]] -deps = ["JuliaInterpreter"] -git-tree-sha1 = "688d6d9e098109051ae33d126fcfc88c4ce4a021" +deps = ["CodeTracking", "Compiler", "JuliaInterpreter"] +git-tree-sha1 = "e24491cb83551e44a69b9106c50666dea9d953ab" uuid = "6f1432cf-f94c-5a45-995e-cdbf5db27b0b" -version = "3.1.0" +version = "3.4.4" [[deps.MIMEs]] -git-tree-sha1 = "65f28ad4b594aebe22157d6fac869786a255b7eb" +git-tree-sha1 = "c64d943587f7187e751162b3b84445bbbd79f691" uuid = "6c6e2e6c-3030-632d-7369-2d6c69616d65" -version = "0.1.4" +version = "1.1.0" [[deps.MKL_jll]] deps = ["Artifacts", "IntelOpenMP_jll", "JLLWrappers", "LazyArtifacts", "Libdl", "oneTBB_jll"] -git-tree-sha1 = "ed4097130e3dd3721814b5f277da72f48905e80c" +git-tree-sha1 = "282cadc186e7b2ae0eeadbd7a4dffed4196ae2aa" uuid = "856f044c-d86e-5d09-b602-aeab76dc8ba7" -version = "2025.0.1+0" +version = "2025.2.0+0" [[deps.MacroTools]] -git-tree-sha1 = "72aebe0b5051e5143a079a4685a46da330a40472" +git-tree-sha1 = "1e0228a030642014fe5cfe68c2c0a818f9e3f522" uuid = "1914dd2f-81c6-5fcd-8719-6d5c9610ff09" -version = "0.5.15" +version = "0.5.16" [[deps.Makie]] deps = ["Animations", "Base64", "CRC32c", "ColorBrewer", "ColorSchemes", "ColorTypes", "Colors", "Contour", "Dates", "DelaunayTriangulation", "Distributions", "DocStringExtensions", "Downloads", "FFMPEG_jll", "FileIO", "FilePaths", "FixedPointNumbers", "Format", "FreeType", "FreeTypeAbstraction", "GeometryBasics", "GridLayoutBase", "ImageBase", "ImageIO", "InteractiveUtils", "Interpolations", "IntervalSets", "InverseFunctions", "Isoband", "KernelDensity", "LaTeXStrings", "LinearAlgebra", "MacroTools", "MakieCore", "Markdown", "MathTeXEngine", "Observables", "OffsetArrays", "PNGFiles", "Packing", "PlotUtils", "PolygonOps", "PrecompileTools", "Printf", "REPL", "Random", "RelocatableFolders", "Scratch", "ShaderAbstractions", "Showoff", "SignedDistanceFields", "SparseArrays", "Statistics", "StatsBase", "StatsFuns", "StructArrays", "TriplotBase", "UnicodeFun", "Unitful"] -git-tree-sha1 = "9680336a5b67f9f9f6eaa018f426043a8cd68200" +git-tree-sha1 = "1d7d16f0e02ec063becd7a140f619b2ffe5f2b11" uuid = "ee78f7c6-11fb-53f2-987a-cfe4a2b5a57a" -version = "0.22.1" +version = "0.22.10" [[deps.MakieCore]] deps = ["ColorTypes", "GeometryBasics", "IntervalSets", "Observables"] -git-tree-sha1 = "c731269d5a2c85ffdc689127a9ba6d73e978a4b1" +git-tree-sha1 = "c3159eb1e3aa3e409edbb71f4035ed8b1fc16e23" uuid = "20f20a25-4f0e-4fdf-b5d1-57303727442b" -version = "0.9.0" - -[[deps.Malt]] -deps = ["Distributed", "Logging", "RelocatableFolders", "Serialization", "Sockets"] -git-tree-sha1 = "02a728ada9d6caae583a0f87c1dd3844f99ec3fd" -uuid = "36869731-bdee-424d-aa32-cab38c994e3b" -version = "1.1.2" +version = "0.9.5" [[deps.ManualMemory]] git-tree-sha1 = "bcaef4fc7a0cfe2cba636d84cda54b5e4e4ca3cd" @@ -1392,11 +1500,17 @@ deps = ["Base64"] uuid = "d6f4376e-aef5-505a-96c1-9c027394607a" version = "1.11.0" +[[deps.MarkdownAST]] +deps = ["AbstractTrees", "Markdown"] +git-tree-sha1 = "465a70f0fc7d443a00dcdc3267a497397b8a3899" +uuid = "d0879d2d-cac2-40c8-9cee-1863dc0c7391" +version = "0.1.2" + [[deps.MathTeXEngine]] deps = ["AbstractTrees", "Automa", "DataStructures", "FreeTypeAbstraction", "GeometryBasics", "LaTeXStrings", "REPL", "RelocatableFolders", "UnicodeFun"] -git-tree-sha1 = "f45c8916e8385976e1ccd055c9874560c257ab13" +git-tree-sha1 = "7eb8cdaa6f0e8081616367c10b31b9d9b34bb02a" uuid = "0a4f8689-d25c-4efe-a92b-7142dfc1aa53" -version = "0.6.2" +version = "0.6.7" [[deps.MbedTLS]] deps = ["Dates", "MbedTLS_jll", "MozillaCACerts_jll", "NetworkOptions", "Random", "Sockets"] @@ -1409,16 +1523,17 @@ deps = ["Artifacts", "Libdl"] uuid = "c8ffd9c3-330d-5841-b78e-0817d7145fa1" version = "2.28.6+0" -[[deps.Measures]] -git-tree-sha1 = "c13304c81eec1ed3af7fc20e75fb6b26092a1102" -uuid = "442fdcdd-2543-5da2-b0f3-8c86c306513e" -version = "0.3.2" +[[deps.MeshIO]] +deps = ["ColorTypes", "FileIO", "GeometryBasics", "Printf"] +git-tree-sha1 = "c009236e222df68e554c7ce5c720e4a33cc0c23f" +uuid = "7269a6da-0436-5bbc-96c2-40638cbb6118" +version = "0.5.3" [[deps.MetaGraphs]] deps = ["Graphs", "JLD2", "Random"] -git-tree-sha1 = "e9650bea7f91c3397eb9ae6377343963a22bf5b8" +git-tree-sha1 = "3a8f462a180a9d735e340f4e8d5f364d411da3a4" uuid = "626554b9-1ddb-594c-aa3c-2596fe9399a5" -version = "0.8.0" +version = "0.8.1" [[deps.Millboard]] git-tree-sha1 = "ea6a5b7e56e76d8051023faaa11d91d1d881dac3" @@ -1441,6 +1556,12 @@ version = "0.1.2" uuid = "a63ad114-7e13-5084-954f-fe012c677804" version = "1.11.0" +[[deps.ModernGL]] +deps = ["Libdl"] +git-tree-sha1 = "ac6cb1d8807a05cf1acc9680e09d2294f9d33956" +uuid = "66fc600b-dfda-50eb-8b99-91cfa97b1301" +version = "1.1.8" + [[deps.MosaicViews]] deps = ["MappedArrays", "OffsetArrays", "PaddedViews", "StackViews"] git-tree-sha1 = "7b86a5d4d70a9f5cdf2dacb3cbe6d251d1a61dbe" @@ -1451,17 +1572,11 @@ version = "0.3.4" uuid = "14a3606d-f60d-562e-9121-12d972cd8159" version = "2023.12.12" -[[deps.MsgPack]] -deps = ["Serialization"] -git-tree-sha1 = "f5db02ae992c260e4826fe78c942954b48e1d9c2" -uuid = "99f44e22-a591-53d1-9472-aa23ef4bd671" -version = "1.2.1" - [[deps.NaNMath]] deps = ["OpenLibm_jll"] -git-tree-sha1 = "dbad50672562ce422a406d172fb19fc1f0166f06" +git-tree-sha1 = "9b8215b1ee9e78a293f99797cd31375471b2bcae" uuid = "77ba4419-2d1f-58cd-9bb1-8ffee604a2e3" -version = "1.1.0" +version = "1.1.3" [[deps.NativeFileDialog]] deps = ["FilePathsBase", "NativeFileDialog_jll"] @@ -1482,9 +1597,9 @@ version = "1.0.0" [[deps.NearestNeighbors]] deps = ["Distances", "StaticArrays"] -git-tree-sha1 = "8a3271d8309285f4db73b4f662b1b290c715e85e" +git-tree-sha1 = "17399deebfc0ef7d7a97225776571d13adf01a36" uuid = "b8a86587-4115-5ab1-83bc-aa920d37bbce" -version = "0.4.21" +version = "0.4.23" [[deps.Netpbm]] deps = ["FileIO", "ImageCore", "ImageMetadata"] @@ -1519,19 +1634,25 @@ uuid = "510215fc-4207-5dde-b226-833fc4488ee2" version = "0.5.5" [[deps.OffsetArrays]] -git-tree-sha1 = "5e1897147d1ff8d98883cda2be2187dcf57d8f0c" +git-tree-sha1 = "117432e406b5c023f665fa73dc26e79ec3630151" uuid = "6fe1bfb0-de20-5000-8ca7-80f57d26f881" -version = "1.15.0" +version = "1.17.0" weakdeps = ["Adapt"] [deps.OffsetArrays.extensions] OffsetArraysAdaptExt = "Adapt" [[deps.Ogg_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] -git-tree-sha1 = "887579a3eb005446d514ab7aeac5d1d027658b8f" +deps = ["Artifacts", "JLLWrappers", "Libdl"] +git-tree-sha1 = "b6aa4566bb7ae78498a5e68943863fa8b5231b59" uuid = "e7412a2a-1a6e-54c0-be00-318e2571c051" -version = "1.3.5+1" +version = "1.3.6+0" + +[[deps.OpenBLASConsistentFPCSR_jll]] +deps = ["Artifacts", "CompilerSupportLibraries_jll", "JLLWrappers", "Libdl"] +git-tree-sha1 = "567515ca155d0020a45b05175449b499c63e7015" +uuid = "6cdc7f73-28fd-5e50-80fb-958a8875b1af" +version = "0.3.29+0" [[deps.OpenBLAS_jll]] deps = ["Artifacts", "CompilerSupportLibraries_jll", "Libdl"] @@ -1551,33 +1672,33 @@ uuid = "18a262bb-aa17-5467-a713-aee519bc75cb" version = "3.2.4+0" [[deps.OpenJpeg_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl", "Libtiff_jll", "LittleCMS_jll", "Pkg", "libpng_jll"] -git-tree-sha1 = "76374b6e7f632c130e78100b166e5a48464256f8" +deps = ["Artifacts", "JLLWrappers", "Libdl", "Libtiff_jll", "LittleCMS_jll", "libpng_jll"] +git-tree-sha1 = "215a6666fee6d6b3a6e75f2cc22cb767e2dd393a" uuid = "643b3616-a352-519d-856d-80112ee9badc" -version = "2.4.0+0" +version = "2.5.5+0" [[deps.OpenLibm_jll]] deps = ["Artifacts", "Libdl"] uuid = "05823500-19ac-5b8b-9628-191a04bc5112" -version = "0.8.1+2" +version = "0.8.5+0" [[deps.OpenSSH_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl", "OpenSSL_jll", "Pkg", "Zlib_jll"] -git-tree-sha1 = "1b2f042897343a9dfdcc9366e4ecbd3d00780c49" +deps = ["Artifacts", "JLLWrappers", "Libdl", "OpenSSL_jll", "Zlib_jll"] +git-tree-sha1 = "cf28501224f22b2b4d237d3cc7215c7c0cb52f6a" uuid = "9bd350c2-7e96-507f-8002-3f2e150b4e1b" -version = "8.9.0+1" +version = "9.9.2+0" [[deps.OpenSSL]] -deps = ["BitFlags", "Dates", "MozillaCACerts_jll", "OpenSSL_jll", "Sockets"] -git-tree-sha1 = "38cb508d080d21dc1128f7fb04f20387ed4c0af4" +deps = ["BitFlags", "Dates", "MozillaCACerts_jll", "NetworkOptions", "OpenSSL_jll", "Sockets"] +git-tree-sha1 = "386b47442468acfb1add94bf2d85365dea10cbab" uuid = "4d8831e6-92b7-49fb-bdf8-b643e874388c" -version = "1.4.3" +version = "1.6.0" [[deps.OpenSSL_jll]] deps = ["Artifacts", "JLLWrappers", "Libdl"] -git-tree-sha1 = "ad31332567b189f508a3ea8957a2640b1147ab00" +git-tree-sha1 = "2ae7d4ddec2e13ad3bddf5c0796f7547cf682391" uuid = "458c3c95-2e84-50aa-8efc-19380b2a3a95" -version = "1.1.23+1" +version = "3.5.2+0" [[deps.OpenSpecFun_jll]] deps = ["Artifacts", "CompilerSupportLibraries_jll", "JLLWrappers", "Libdl"] @@ -1587,14 +1708,14 @@ version = "0.5.6+0" [[deps.Opus_jll]] deps = ["Artifacts", "JLLWrappers", "Libdl"] -git-tree-sha1 = "6703a85cb3781bd5909d48730a67205f3f31a575" +git-tree-sha1 = "c392fc5dd032381919e3b22dd32d6443760ce7ea" uuid = "91d4177d-7536-5919-b921-800302f37372" -version = "1.3.3+0" +version = "1.5.2+0" [[deps.OrderedCollections]] -git-tree-sha1 = "12f1439c4f986bb868acda6ea33ebc78e19b95ad" +git-tree-sha1 = "05868e21324cede2207c6f0f466b4bfef6d5e7ee" uuid = "bac558e1-5e72-5ebc-8fee-abe8a469f55d" -version = "1.7.0" +version = "1.8.1" [[deps.PCRE2_jll]] deps = ["Artifacts", "Libdl"] @@ -1603,15 +1724,19 @@ version = "10.42.0+1" [[deps.PDMats]] deps = ["LinearAlgebra", "SparseArrays", "SuiteSparse"] -git-tree-sha1 = "966b85253e959ea89c53a9abebbf2e964fbf593b" +git-tree-sha1 = "d922b4d80d1e12c658da7785e754f4796cc1d60d" uuid = "90014a1f-27ba-587c-ab20-58faa44d9150" -version = "0.11.32" +version = "0.11.36" +weakdeps = ["StatsBase"] + + [deps.PDMats.extensions] + StatsBaseExt = "StatsBase" [[deps.PNGFiles]] deps = ["Base64", "CEnum", "ImageCore", "IndirectArrays", "OffsetArrays", "libpng_jll"] -git-tree-sha1 = "67186a2bc9a90f9f85ff3cc8277868961fb57cbd" +git-tree-sha1 = "cf181f0b1e6a18dfeb0ee8acc4a9d1672499626c" uuid = "f57f5aa1-a3ce-4bc8-8ab9-96f992907883" -version = "0.4.3" +version = "0.4.4" [[deps.Packing]] deps = ["GeometryBasics"] @@ -1627,9 +1752,9 @@ version = "0.5.12" [[deps.Pango_jll]] deps = ["Artifacts", "Cairo_jll", "Fontconfig_jll", "FreeType2_jll", "FriBidi_jll", "Glib_jll", "HarfBuzz_jll", "JLLWrappers", "Libdl"] -git-tree-sha1 = "ed6834e95bd326c52d5675b4181386dfbe885afb" +git-tree-sha1 = "0662b083e11420952f2e62e17eddae7fc07d5997" uuid = "36c8627f-9965-5494-a995-c6b170f724f3" -version = "1.55.5+0" +version = "1.57.0+0" [[deps.Parameters]] deps = ["OrderedCollections", "UnPack"] @@ -1639,20 +1764,15 @@ version = "0.12.3" [[deps.Parsers]] deps = ["Dates", "PrecompileTools", "UUIDs"] -git-tree-sha1 = "8489905bcdbcfac64d1daa51ca07c0d8f0283821" +git-tree-sha1 = "7d2f8f21da5db6a806faf7b9b292296da42b2810" uuid = "69de0a69-1ddd-5017-9359-2bf0b02dc9f0" -version = "2.8.1" - -[[deps.Pipe]] -git-tree-sha1 = "6842804e7867b115ca9de748a0cf6b364523c16d" -uuid = "b98c9c47-44ae-5843-9183-064241ee97a0" -version = "1.3.0" +version = "2.8.3" [[deps.Pixman_jll]] deps = ["Artifacts", "CompilerSupportLibraries_jll", "JLLWrappers", "LLVMOpenMP_jll", "Libdl"] -git-tree-sha1 = "35621f10a7531bc8fa58f74610b1bfb70a3cfc6b" +git-tree-sha1 = "db76b1ecd5e9715f3d043cec13b2ec93ce015d53" uuid = "30392449-352a-5448-841d-b1acce4e97dc" -version = "0.43.4+0" +version = "0.44.2+0" [[deps.Pkg]] deps = ["Artifacts", "Dates", "Downloads", "FileWatching", "LibGit2", "Libdl", "Logging", "Markdown", "Printf", "Random", "SHA", "TOML", "Tar", "UUIDs", "p7zip_jll"] @@ -1669,55 +1789,29 @@ git-tree-sha1 = "f9501cc0430a26bc3d156ae1b5b0c1b47af4d6da" uuid = "eebad327-c553-4316-9ea0-9fa01ccd7688" version = "0.3.3" -[[deps.PlotThemes]] -deps = ["PlotUtils", "Statistics"] -git-tree-sha1 = "41031ef3a1be6f5bbbf3e8073f210556daeae5ca" -uuid = "ccf2f8ad-2431-5c83-bf29-c5338b663b6a" -version = "3.3.0" - [[deps.PlotUtils]] deps = ["ColorSchemes", "Colors", "Dates", "PrecompileTools", "Printf", "Random", "Reexport", "StableRNGs", "Statistics"] -git-tree-sha1 = "3ca9a356cd2e113c420f2c13bea19f8d3fb1cb18" +git-tree-sha1 = "26ca162858917496748aad52bb5d3be4d26a228a" uuid = "995b91a9-d308-5afd-9ec6-746e21dbc043" -version = "1.4.3" +version = "1.4.4" [[deps.PlotlyBase]] -deps = ["ColorSchemes", "Dates", "DelimitedFiles", "DocStringExtensions", "JSON", "LaTeXStrings", "Logging", "Parameters", "Pkg", "REPL", "Requires", "Statistics", "UUIDs"] -git-tree-sha1 = "56baf69781fc5e61607c3e46227ab17f7040ffa2" +deps = ["ColorSchemes", "Colors", "Dates", "DelimitedFiles", "DocStringExtensions", "JSON", "LaTeXStrings", "Logging", "Parameters", "Pkg", "REPL", "Requires", "Statistics", "UUIDs"] +git-tree-sha1 = "28278bb0053da0fd73537be94afd1682cc5a0a83" uuid = "a03496cd-edff-5a9b-9e67-9cda94a718b5" -version = "0.8.19" +version = "0.8.21" -[[deps.Plots]] -deps = ["Base64", "Contour", "Dates", "Downloads", "FFMPEG", "FixedPointNumbers", "GR", "JLFzf", "JSON", "LaTeXStrings", "Latexify", "LinearAlgebra", "Measures", "NaNMath", "Pkg", "PlotThemes", "PlotUtils", "PrecompileTools", "Printf", "REPL", "Random", "RecipesBase", "RecipesPipeline", "Reexport", "RelocatableFolders", "Requires", "Scratch", "Showoff", "SparseArrays", "Statistics", "StatsBase", "TOML", "UUIDs", "UnicodeFun", "UnitfulLatexify", "Unzip"] -git-tree-sha1 = "f202a1ca4f6e165238d8175df63a7e26a51e04dc" -uuid = "91a5bcdd-55d7-5caf-9e0b-520d859cae80" -version = "1.40.7" - - [deps.Plots.extensions] - FileIOExt = "FileIO" - GeometryBasicsExt = "GeometryBasics" + [deps.PlotlyBase.extensions] + DataFramesExt = "DataFrames" + DistributionsExt = "Distributions" IJuliaExt = "IJulia" - ImageInTerminalExt = "ImageInTerminal" - UnitfulExt = "Unitful" + JSON3Ext = "JSON3" - [deps.Plots.weakdeps] - FileIO = "5789e2e9-d7fb-5bc7-8068-2c6fae9b9549" - GeometryBasics = "5c1252a2-5f33-56bf-86c9-59e7332b4326" + [deps.PlotlyBase.weakdeps] + DataFrames = "a93c6f00-e57d-5684-b7b6-d8193f3e46c0" + Distributions = "31c24e10-a181-5473-b8eb-7969acd0382f" IJulia = "7073ff75-c697-5162-941a-fcdaad2a7d2a" - ImageInTerminal = "d8c32880-2388-543b-8c61-d9f865259254" - Unitful = "1986cc42-f94f-5a68-af5c-568840ba703d" - -[[deps.Pluto]] -deps = ["Base64", "Configurations", "Dates", "Downloads", "ExpressionExplorer", "FileWatching", "FuzzyCompletions", "HTTP", "HypertextLiteral", "InteractiveUtils", "Logging", "LoggingExtras", "MIMEs", "Malt", "Markdown", "MsgPack", "Pkg", "PlutoDependencyExplorer", "PrecompileSignatures", "PrecompileTools", "REPL", "RegistryInstances", "RelocatableFolders", "Scratch", "Sockets", "TOML", "Tables", "URIs", "UUIDs"] -git-tree-sha1 = "b5509a2e4d4c189da505b780e3f447d1e38a0350" -uuid = "c3e4b0f8-55cb-11ea-2926-15256bba5781" -version = "0.20.4" - -[[deps.PlutoDependencyExplorer]] -deps = ["ExpressionExplorer", "InteractiveUtils", "Markdown"] -git-tree-sha1 = "e0864c15334d2c4bac8137ce3359f1174565e719" -uuid = "72656b73-756c-7461-726b-72656b6b696b" -version = "1.2.0" + JSON3 = "0f8b85d8-7281-11e9-16c2-39a750bddbf1" [[deps.PolyesterWeave]] deps = ["BitTwiddlingConvenienceFunctions", "CPUSummary", "IfElse", "Static", "ThreadingUtilities"] @@ -1732,9 +1826,9 @@ version = "0.1.2" [[deps.Polynomials]] deps = ["LinearAlgebra", "OrderedCollections", "RecipesBase", "Requires", "Setfield", "SparseArrays"] -git-tree-sha1 = "27f6107dc202e2499f0750c628a848ce5d6e77f5" +git-tree-sha1 = "2660ba4e0e9354cf0f3deeefb61531bbdac5495d" uuid = "f27b6e38-b328-58d1-80ce-0feddd5e7a45" -version = "4.0.13" +version = "4.0.21" [deps.Polynomials.extensions] PolynomialsChainRulesCoreExt = "ChainRulesCore" @@ -1754,11 +1848,6 @@ git-tree-sha1 = "36d8b4b899628fb92c2749eb488d884a926614d3" uuid = "2dfb63ee-cc39-5dd5-95bd-886bf059d720" version = "1.4.3" -[[deps.PrecompileSignatures]] -git-tree-sha1 = "18ef344185f25ee9d51d80e179f8dad33dc48eb1" -uuid = "91cefc8d-f054-46dc-8f8c-26e11d7c5411" -version = "3.0.3" - [[deps.PrecompileTools]] deps = ["Preferences"] git-tree-sha1 = "5aa36f7049a63a1528fe8f7c3f2113413ffd4e1f" @@ -1767,15 +1856,15 @@ version = "1.2.1" [[deps.Preferences]] deps = ["TOML"] -git-tree-sha1 = "9306f6085165d270f7e3db02af26a400d580f5c6" +git-tree-sha1 = "0f27480397253da18fe2c12a4ba4eb9eb208bf3d" uuid = "21216c6a-2e73-6563-6e65-726566657250" -version = "1.4.3" +version = "1.5.0" [[deps.PrettyTables]] -deps = ["Crayons", "LaTeXStrings", "Markdown", "PrecompileTools", "Printf", "Reexport", "StringManipulation", "Tables"] -git-tree-sha1 = "1101cd475833706e4d0e7b122218257178f48f34" +deps = ["Crayons", "LaTeXStrings", "Markdown", "PrecompileTools", "Printf", "REPL", "Reexport", "StringManipulation", "Tables"] +git-tree-sha1 = "6b8e2f0bae3f678811678065c09571c1619da219" uuid = "08abe8d2-0d0c-5749-adfa-8a2ac140af0d" -version = "2.4.0" +version = "3.1.0" [[deps.Printf]] deps = ["Unicode"] @@ -1784,44 +1873,26 @@ version = "1.11.0" [[deps.ProgressMeter]] deps = ["Distributed", "Printf"] -git-tree-sha1 = "8f6bc219586aef8baf0ff9a5fe16ee9c70cb65e4" +git-tree-sha1 = "fbb92c6c56b34e1a2c4c36058f68f332bec840e7" uuid = "92933f4c-e287-5a05-a399-4b506db050ca" -version = "1.10.2" +version = "1.11.0" [[deps.PtrArrays]] git-tree-sha1 = "1d36ef11a9aaf1e8b74dacc6a731dd1de8fd493d" uuid = "43287f4e-b6f4-7ad1-bb20-aadabca52c3d" version = "1.3.0" -[[deps.PyCall]] -deps = ["Conda", "Dates", "Libdl", "LinearAlgebra", "MacroTools", "Serialization", "VersionParsing"] -git-tree-sha1 = "9816a3826b0ebf49ab4926e2b18842ad8b5c8f04" -uuid = "438e738f-606a-5dbb-bf0a-cddfbfd45ab0" -version = "1.96.4" - -[[deps.PyPlot]] -deps = ["Colors", "LaTeXStrings", "PyCall", "Sockets", "Test", "VersionParsing"] -git-tree-sha1 = "0371ca706e3f295481cbf94c8c36692b072285c2" -uuid = "d330b81b-6aea-500a-939a-2ce795aea3ee" -version = "2.11.5" - [[deps.QOI]] deps = ["ColorTypes", "FileIO", "FixedPointNumbers"] git-tree-sha1 = "8b3fc30bc0390abdce15f8822c889f669baed73d" uuid = "4b34888f-f399-49d4-9bb3-47ed5cae4e65" version = "1.0.1" -[[deps.Qt5Base_jll]] -deps = ["Artifacts", "CompilerSupportLibraries_jll", "Fontconfig_jll", "Glib_jll", "JLLWrappers", "Libdl", "Libglvnd_jll", "OpenSSL_jll", "Pkg", "Xorg_libXext_jll", "Xorg_libxcb_jll", "Xorg_xcb_util_image_jll", "Xorg_xcb_util_keysyms_jll", "Xorg_xcb_util_renderutil_jll", "Xorg_xcb_util_wm_jll", "Zlib_jll", "xkbcommon_jll"] -git-tree-sha1 = "0c03844e2231e12fda4d0086fd7cbe4098ee8dc5" -uuid = "ea2cea3b-5b76-57ae-a6ef-0a8af62496e1" -version = "5.15.3+2" - [[deps.QuadGK]] deps = ["DataStructures", "LinearAlgebra"] -git-tree-sha1 = "cda3b045cf9ef07a08ad46731f5a3165e56cf3da" +git-tree-sha1 = "9da16da70037ba9d701192e27befedefb91ec284" uuid = "1fd47b50-473d-5c70-9696-f719f8f3bcdc" -version = "2.11.1" +version = "2.11.2" [deps.QuadGK.extensions] QuadGKEnzymeExt = "Enzyme" @@ -1872,12 +1943,6 @@ git-tree-sha1 = "5c3d09cc4f31f5fc6af001c250bf1278733100ff" uuid = "3cdcf5f2-1ef4-517c-9805-6587b60abb01" version = "1.3.4" -[[deps.RecipesPipeline]] -deps = ["Dates", "NaNMath", "PlotUtils", "PrecompileTools", "RecipesBase"] -git-tree-sha1 = "45cf9fd0ca5839d06ef333c8201714e888486342" -uuid = "01d81517-befc-4cb6-b9ec-a95719d0359c" -version = "0.6.12" - [[deps.Reexport]] git-tree-sha1 = "45e428421666073eab6f2da5c9d310d99bb12f9b" uuid = "189a3867-3050-52da-a836-e630ba90ab69" @@ -1902,10 +1967,10 @@ uuid = "05181044-ff0b-4ac5-8273-598c1e38db00" version = "1.0.1" [[deps.RemoteREPL]] -deps = ["Logging", "OpenSSH_jll", "REPL", "ReplMaker", "Serialization", "Sockets"] -git-tree-sha1 = "42618f51c9c813f0c665dc4fe56dc2d5d90baab9" +deps = ["Logging", "OpenSSH_jll", "REPL", "ReplMaker", "Serialization", "Sockets", "UUIDs"] +git-tree-sha1 = "1d75634838e7a07872c3339aed8b86bfce9afafc" uuid = "1bd9f7bb-701c-4338-bec7-ac987af7c555" -version = "0.2.17" +version = "0.3.0" [[deps.ReplMaker]] deps = ["REPL", "Unicode"] @@ -1915,15 +1980,15 @@ version = "0.2.7" [[deps.Requires]] deps = ["UUIDs"] -git-tree-sha1 = "838a3a4188e2ded87a4f9f184b4b0d78a1e91cb7" +git-tree-sha1 = "62389eeff14780bfe55195b7204c0d8738436d64" uuid = "ae029012-a4dd-5104-9daa-d747884805df" -version = "1.3.0" +version = "1.3.1" [[deps.Revise]] deps = ["CodeTracking", "FileWatching", "JuliaInterpreter", "LibGit2", "LoweredCodeUtils", "OrderedCollections", "REPL", "Requires", "UUIDs", "Unicode"] -git-tree-sha1 = "9bb80533cb9769933954ea4ffbecb3025a783198" +git-tree-sha1 = "85d94c2be31f58728cd69d13f2e0bdd7ecf6dfe9" uuid = "295af30f-e4ad-537b-8983-00126c2a3abe" -version = "3.7.2" +version = "3.12.1" weakdeps = ["Distributed"] [deps.Revise.extensions] @@ -1931,9 +1996,9 @@ weakdeps = ["Distributed"] [[deps.Rmath]] deps = ["Random", "Rmath_jll"] -git-tree-sha1 = "852bd0f55565a9e973fcfee83a84413270224dc4" +git-tree-sha1 = "5b3d50eb374cea306873b371d3f8d3915a018f0b" uuid = "79098fc4-a85e-5d69-aa6a-4863f24498fa" -version = "0.8.0" +version = "0.9.0" [[deps.Rmath_jll]] deps = ["Artifacts", "JLLWrappers", "Libdl"] @@ -1962,9 +2027,9 @@ version = "0.7.0" [[deps.SIMD]] deps = ["PrecompileTools"] -git-tree-sha1 = "fea870727142270bdf7624ad675901a1ee3b4c87" +git-tree-sha1 = "e24dc23107d426a096d3eae6c165b921e74c18e4" uuid = "fdea26ae-647d-5447-a871-4b548cad5224" -version = "3.7.1" +version = "3.7.2" [[deps.SIMDTypes]] git-tree-sha1 = "330289636fb8107c5f32088d2741e9fd7a061a5c" @@ -1977,11 +2042,28 @@ git-tree-sha1 = "456f610ca2fbd1c14f5fcf31c6bfadc55e7d66e0" uuid = "476501e8-09a2-5ece-8869-fb82de89a1fa" version = "0.6.43" +[[deps.SavitzkyGolay]] +deps = ["LinearAlgebra"] +git-tree-sha1 = "7bbc5949a42f53f4fca1a0157c72f9d3f78050d1" +uuid = "c4bf5708-b6a6-4fbe-bcd0-6850ed671584" +version = "0.9.1" + +[[deps.SciMLPublic]] +git-tree-sha1 = "ed647f161e8b3f2973f24979ec074e8d084f1bee" +uuid = "431bcebd-1456-4ced-9d72-93c2757fff0b" +version = "1.0.0" + +[[deps.ScopedValues]] +deps = ["HashArrayMappedTries", "Logging"] +git-tree-sha1 = "c3b2323466378a2ba15bea4b2f73b081e022f473" +uuid = "7e506255-f358-4e82-b7e4-beb19740aa63" +version = "1.5.0" + [[deps.Scratch]] deps = ["Dates"] -git-tree-sha1 = "3bac05bc7e74a75fd9cba4295cde4045d9fe2386" +git-tree-sha1 = "9b81b8393e50b7d4e6d0a9f14e192294d3b7c109" uuid = "6c6a2e73-6563-6170-7368-637461726353" -version = "1.2.1" +version = "1.3.0" [[deps.SentinelArrays]] deps = ["Dates", "Random"] @@ -1995,9 +2077,9 @@ version = "1.11.0" [[deps.Setfield]] deps = ["ConstructionBase", "Future", "MacroTools", "StaticArraysCore"] -git-tree-sha1 = "e2cc6d8c88613c05e1defb55170bf5ff211fbeac" +git-tree-sha1 = "c5391c6ace3bc430ca630251d02ea9687169ca68" uuid = "efcf1570-3423-57d1-acb7-fd33fddbac46" -version = "1.1.1" +version = "1.1.2" [[deps.ShaderAbstractions]] deps = ["ColorTypes", "FixedPointNumbers", "GeometryBasics", "LinearAlgebra", "Observables", "StaticArrays"] @@ -2029,21 +2111,21 @@ version = "1.2.0" [[deps.SimpleTraits]] deps = ["InteractiveUtils", "MacroTools"] -git-tree-sha1 = "5d7e3f4e11935503d3ecaf7186eac40602e7d231" +git-tree-sha1 = "be8eeac05ec97d379347584fa9fe2f5f76795bcb" uuid = "699a6c99-e7fa-54fc-8d76-47d257e15c1d" -version = "0.9.4" +version = "0.9.5" [[deps.SimpleWeightedGraphs]] deps = ["Graphs", "LinearAlgebra", "Markdown", "SparseArrays"] -git-tree-sha1 = "4b33e0e081a825dbfaf314decf58fa47e53d6acb" +git-tree-sha1 = "3e5f165e58b18204aed03158664c4982d691f454" uuid = "47aef6b3-ad0c-573a-a1e2-d07658019622" -version = "1.4.0" +version = "1.5.0" [[deps.Sixel]] deps = ["Dates", "FileIO", "ImageCore", "IndirectArrays", "OffsetArrays", "REPL", "libsixel_jll"] -git-tree-sha1 = "2da10356e31327c7096832eb9cd86307a50b1eb6" +git-tree-sha1 = "0494aed9501e7fb65daba895fb7fd57cc38bc743" uuid = "45858cf5-a6b0-47a3-bbea-62219f50df47" -version = "0.1.3" +version = "0.1.5" [[deps.Sockets]] uuid = "6462fe0b-24de-5631-8697-dd941f90decc" @@ -2051,9 +2133,9 @@ version = "1.11.0" [[deps.SortingAlgorithms]] deps = ["DataStructures"] -git-tree-sha1 = "66e0a8e672a0bdfca2c3f5937efb8538b9ddc085" +git-tree-sha1 = "64d974c2e6fdf07f8155b5b2ca2ffa9069b608d9" uuid = "a2af1166-a08f-5f64-846c-94a0d3cef48c" -version = "1.2.1" +version = "1.2.2" [[deps.SparseArrays]] deps = ["Libdl", "LinearAlgebra", "Random", "Serialization", "SuiteSparse_jll"] @@ -2062,9 +2144,9 @@ version = "1.11.0" [[deps.SpecialFunctions]] deps = ["IrrationalConstants", "LogExpFunctions", "OpenLibm_jll", "OpenSpecFun_jll"] -git-tree-sha1 = "64cca0c26b4f31ba18f13f6c12af7c85f478cfde" +git-tree-sha1 = "f2685b435df2613e25fc10ad8c26dddb8640f547" uuid = "276daf66-3868-5448-9aa4-cd146d93841b" -version = "2.5.0" +version = "2.6.1" weakdeps = ["ChainRulesCore"] [deps.SpecialFunctions.extensions] @@ -2072,21 +2154,21 @@ weakdeps = ["ChainRulesCore"] [[deps.StableRNGs]] deps = ["Random"] -git-tree-sha1 = "83e6cce8324d49dfaf9ef059227f91ed4441a8e5" +git-tree-sha1 = "4f96c596b8c8258cc7d3b19797854d368f243ddc" uuid = "860ef19b-820b-49d6-a774-d7a799459cd3" -version = "1.0.2" +version = "1.0.4" [[deps.StackViews]] deps = ["OffsetArrays"] -git-tree-sha1 = "46e589465204cd0c08b4bd97385e4fa79a0c770c" +git-tree-sha1 = "be1cf4eb0ac528d96f5115b4ed80c26a8d8ae621" uuid = "cae243ae-269e-4f55-b966-ac2d0dc13c15" -version = "0.1.1" +version = "0.1.2" [[deps.Static]] -deps = ["CommonWorldInvalidations", "IfElse", "PrecompileTools"] -git-tree-sha1 = "87d51a3ee9a4b0d2fe054bdd3fc2436258db2603" +deps = ["CommonWorldInvalidations", "IfElse", "PrecompileTools", "SciMLPublic"] +git-tree-sha1 = "49440414711eddc7227724ae6e570c7d5559a086" uuid = "aedffcd0-7271-4cad-89d0-dc628f76c6d3" -version = "1.1.1" +version = "1.3.1" [[deps.StaticArrayInterface]] deps = ["ArrayInterface", "Compat", "IfElse", "LinearAlgebra", "PrecompileTools", "Static"] @@ -2101,9 +2183,9 @@ weakdeps = ["OffsetArrays", "StaticArrays"] [[deps.StaticArrays]] deps = ["LinearAlgebra", "PrecompileTools", "Random", "StaticArraysCore"] -git-tree-sha1 = "47091a0340a675c738b1304b58161f3b0839d454" +git-tree-sha1 = "b8693004b385c842357406e3af647701fe783f98" uuid = "90137ffa-7385-5640-81b9-e52037218182" -version = "1.9.10" +version = "1.9.15" weakdeps = ["ChainRulesCore", "Statistics"] [deps.StaticArrays.extensions] @@ -2111,9 +2193,9 @@ weakdeps = ["ChainRulesCore", "Statistics"] StaticArraysStatisticsExt = "Statistics" [[deps.StaticArraysCore]] -git-tree-sha1 = "192954ef1208c7019899fbf8049e717f92959682" +git-tree-sha1 = "6ab403037779dae8c514bad259f32a447262455a" uuid = "1e83bf80-4336-4d27-bf5d-d5a4f845583c" -version = "1.4.3" +version = "1.4.4" [[deps.Statistics]] deps = ["LinearAlgebra"] @@ -2127,21 +2209,21 @@ weakdeps = ["SparseArrays"] [[deps.StatsAPI]] deps = ["LinearAlgebra"] -git-tree-sha1 = "1ff449ad350c9c4cbc756624d6f8a8c3ef56d3ed" +git-tree-sha1 = "9d72a13a3f4dd3795a195ac5a44d7d6ff5f552ff" uuid = "82ae8749-77ed-4fe6-ae5f-f523153014b0" -version = "1.7.0" +version = "1.7.1" [[deps.StatsBase]] deps = ["AliasTables", "DataAPI", "DataStructures", "LinearAlgebra", "LogExpFunctions", "Missings", "Printf", "Random", "SortingAlgorithms", "SparseArrays", "Statistics", "StatsAPI"] -git-tree-sha1 = "29321314c920c26684834965ec2ce0dacc9cf8e5" +git-tree-sha1 = "064b532283c97daae49e544bb9cb413c26511f8c" uuid = "2913bbd2-ae8a-5f71-8c99-4fb6c76f3a91" -version = "0.34.4" +version = "0.34.8" [[deps.StatsFuns]] deps = ["HypergeometricFunctions", "IrrationalConstants", "LogExpFunctions", "Reexport", "Rmath", "SpecialFunctions"] -git-tree-sha1 = "b423576adc27097764a90e163157bcfc9acf0f46" +git-tree-sha1 = "91f091a8716a6bb38417a6e6f274602a19aaa685" uuid = "4c63d2b9-4356-54db-8cca-17b64c39e42c" -version = "1.3.2" +version = "1.5.2" weakdeps = ["ChainRulesCore", "InverseFunctions"] [deps.StatsFuns.extensions] @@ -2150,9 +2232,9 @@ weakdeps = ["ChainRulesCore", "InverseFunctions"] [[deps.Stipple]] deps = ["Dates", "FilePathsBase", "Genie", "GenieSession", "GenieSessionFileSession", "JSON3", "Logging", "MacroTools", "Mixers", "Observables", "OrderedCollections", "Parameters", "Pkg", "PrecompileTools", "Random", "Reexport", "Requires", "StructTypes", "Tables"] -git-tree-sha1 = "0a32740b08234a7876cdfdf1714673d64c9dd148" +git-tree-sha1 = "9455fc54d50b4a6e6cb986eda7e8a0d09938ba06" uuid = "4acbeb90-81a0-11ea-1966-bdaff8155998" -version = "0.28.22" +version = "0.28.23" weakdeps = ["DataFrames", "JSON", "OffsetArrays"] [deps.Stipple.extensions] @@ -2162,9 +2244,9 @@ weakdeps = ["DataFrames", "JSON", "OffsetArrays"] [[deps.StipplePivotTable]] deps = ["Stipple", "StippleUI", "Tables"] -git-tree-sha1 = "02c29d8464f1c26f659d1aa94d69a986ecaafea4" +git-tree-sha1 = "98d96b177125630eb5d273b3e705aec22bb4ec86" uuid = "adab0226-ee3c-44de-8f2f-393b1bf1e936" -version = "0.3.1" +version = "0.4.3" [[deps.StipplePlotly]] deps = ["DataFrames", "Genie", "Requires", "Stipple"] @@ -2178,21 +2260,21 @@ weakdeps = ["PlotlyBase"] [[deps.StippleTable]] deps = ["Stipple", "StippleUI"] -git-tree-sha1 = "c3a06836672a19fafdb8c600acc077746a4200b2" +git-tree-sha1 = "f4a36ed4b56181d459b47bd16429308a03e05c1c" uuid = "5bb4b094-0818-496d-ae94-fd777e10e8ba" -version = "1.0.1" +version = "1.0.3" [[deps.StippleTabs]] deps = ["Stipple", "StippleUI"] -git-tree-sha1 = "f8721b7491bfd239c69eace4c4acb0e74962c28f" +git-tree-sha1 = "cf1440b0d7510c98553ed75c7ba0842780a45319" uuid = "29f11006-3202-4091-a17b-0a26282d76dd" -version = "1.0.0" +version = "1.1.0" [[deps.StippleUI]] deps = ["Colors", "Dates", "Genie", "OrderedCollections", "PrecompileTools", "Stipple", "Tables"] -git-tree-sha1 = "099e2678af62149317b0ae69874dd617924182bc" +git-tree-sha1 = "fb442128bab27a90c9356f9e5ed39dada2b3d207" uuid = "a3c5d34a-b254-4859-a8fa-b86abb7e84a3" -version = "0.23.5" +version = "0.23.7" weakdeps = ["DataFrames"] [deps.StippleUI.extensions] @@ -2206,15 +2288,15 @@ version = "0.3.7" [[deps.StringManipulation]] deps = ["PrecompileTools"] -git-tree-sha1 = "a6b1675a536c5ad1a60e5a5153e1fee12eb146e3" +git-tree-sha1 = "725421ae8e530ec29bcbdddbe91ff8053421d023" uuid = "892a3eda-7b42-436c-8928-eab12a02cf0e" -version = "0.4.0" +version = "0.4.1" [[deps.StructArrays]] deps = ["ConstructionBase", "DataAPI", "Tables"] -git-tree-sha1 = "5a3a31c41e15a1e042d60f2f4942adccba05d3c9" +git-tree-sha1 = "a2c37d815bf00575332b7bd0389f771cb7987214" uuid = "09ab397b-f2b6-538f-b94a-2f83cf4a842a" -version = "0.7.0" +version = "0.7.2" [deps.StructArrays.extensions] StructArraysAdaptExt = "Adapt" @@ -2263,9 +2345,9 @@ version = "1.0.1" [[deps.Tables]] deps = ["DataAPI", "DataValueInterfaces", "IteratorInterfaceExtensions", "OrderedCollections", "TableTraits"] -git-tree-sha1 = "598cd7c1f68d1e205689b1c2fe65a9f85846f297" +git-tree-sha1 = "f2c1efbc8f3a609aadf318094f8fc5204bdaf344" uuid = "bd369af6-aec1-5ad0-b16a-f7cc5008161c" -version = "1.12.0" +version = "1.12.1" [[deps.Tar]] deps = ["ArgTools", "SHA"] @@ -2290,15 +2372,15 @@ version = "1.0.2" [[deps.ThreadingUtilities]] deps = ["ManualMemory"] -git-tree-sha1 = "eda08f7e9818eb53661b3deb74e3159460dfbc27" +git-tree-sha1 = "d969183d3d244b6c33796b5ed01ab97328f2db85" uuid = "8290d209-cae3-49c0-8002-c8c24d57dab5" -version = "0.5.2" +version = "0.5.5" [[deps.TiffImages]] -deps = ["ColorTypes", "DataStructures", "DocStringExtensions", "FileIO", "FixedPointNumbers", "IndirectArrays", "Inflate", "Mmap", "OffsetArrays", "PkgVersion", "ProgressMeter", "SIMD", "UUIDs"] -git-tree-sha1 = "3c0faa42f2bd3c6d994b06286bba2328eae34027" +deps = ["ColorTypes", "DataStructures", "DocStringExtensions", "FileIO", "FixedPointNumbers", "IndirectArrays", "Inflate", "Mmap", "OffsetArrays", "PkgVersion", "PrecompileTools", "ProgressMeter", "SIMD", "UUIDs"] +git-tree-sha1 = "98b9352a24cb6a2066f9ababcc6802de9aed8ad8" uuid = "731e570b-9d59-4bfa-96dc-6df516fadf69" -version = "0.11.2" +version = "0.11.6" [[deps.TiledIteration]] deps = ["OffsetArrays", "StaticArrayInterface"] @@ -2316,11 +2398,6 @@ git-tree-sha1 = "0c45878dcfdcfa8480052b6ab162cdd138781742" uuid = "3bb67fe8-82b1-5028-8e26-92a6c54297fa" version = "0.11.3" -[[deps.Tricks]] -git-tree-sha1 = "6cae795a5a9313bbb4f60683f7263318fc7d1505" -uuid = "410a4b4d-49e4-4fbc-ab6d-cb71b17b3775" -version = "0.1.10" - [[deps.TriplotBase]] git-tree-sha1 = "4d4ed7f294cda19382ff7de4c137d24d16adc89b" uuid = "981d1d27-644d-49a2-9326-4793e63143c3" @@ -2333,9 +2410,9 @@ uuid = "30578b45-9adc-5946-b283-645ec420af67" version = "0.4.1" [[deps.URIs]] -git-tree-sha1 = "67db6cc7b3821e19ebe75791a9dd19c9b1188f2b" +git-tree-sha1 = "bef26fb046d031353ef97a82e3fdb6afe7f21b1a" uuid = "5c2747f8-b7ea-4ff2-ba2e-563bfd36b1d4" -version = "1.5.1" +version = "1.6.1" [[deps.UUIDs]] deps = ["Random", "SHA"] @@ -2359,48 +2436,48 @@ version = "0.4.1" [[deps.Unitful]] deps = ["Dates", "LinearAlgebra", "Random"] -git-tree-sha1 = "c0667a8e676c53d390a09dc6870b3d8d6650e2bf" +git-tree-sha1 = "83360bda12f61c250835830cc40b64f487cc2230" uuid = "1986cc42-f94f-5a68-af5c-568840ba703d" -version = "1.22.0" -weakdeps = ["ConstructionBase", "InverseFunctions"] +version = "1.25.1" [deps.Unitful.extensions] ConstructionBaseUnitfulExt = "ConstructionBase" + ForwardDiffExt = "ForwardDiff" InverseFunctionsUnitfulExt = "InverseFunctions" + LatexifyExt = ["Latexify", "LaTeXStrings"] + PrintfExt = "Printf" -[[deps.UnitfulLatexify]] -deps = ["LaTeXStrings", "Latexify", "Unitful"] -git-tree-sha1 = "975c354fcd5f7e1ddcc1f1a23e6e091d99e99bc8" -uuid = "45397f5d-5981-4c77-b2b3-fc36d6e9b728" -version = "1.6.4" - -[[deps.Unzip]] -git-tree-sha1 = "ca0969166a028236229f63514992fc073799bb78" -uuid = "41fe7b60-77ed-43a1-b4f0-825fd5a5650d" -version = "0.2.0" + [deps.Unitful.weakdeps] + ConstructionBase = "187b0558-2788-49d3-abe0-74a17ed4e7c9" + ForwardDiff = "f6369f11-7733-5829-9624-2563aa707210" + InverseFunctions = "3587e190-3f89-42d0-90ee-14403ec27112" + LaTeXStrings = "b964fa9f-0449-5b57-a5c2-d3ea65f4040f" + Latexify = "23fbe1c1-3f47-55db-b15f-69d7ec21a316" + Printf = "de0858da-6303-5e67-8744-51eddeeeb8d7" [[deps.VectorizationBase]] deps = ["ArrayInterface", "CPUSummary", "HostCPUFeatures", "IfElse", "LayoutPointers", "Libdl", "LinearAlgebra", "SIMDTypes", "Static", "StaticArrayInterface"] -git-tree-sha1 = "4ab62a49f1d8d9548a1c8d1a75e5f55cf196f64e" +git-tree-sha1 = "d1d9a935a26c475ebffd54e9c7ad11627c43ea85" uuid = "3d5dd08c-fd9d-11e8-17fa-ed2836048c2f" -version = "0.21.71" +version = "0.21.72" -[[deps.VersionParsing]] -git-tree-sha1 = "58d6e80b4ee071f5efd07fda82cb9fbe17200868" -uuid = "81def892-9a0e-5fdd-b105-ffc91e053289" -version = "1.3.0" +[[deps.Wavelets]] +deps = ["DSP", "FFTW", "LinearAlgebra", "Reexport", "SpecialFunctions", "Statistics"] +git-tree-sha1 = "d0ec97a100abbe47a5e9a02361841da49cce6029" +uuid = "29a6e085-ba6d-5f35-a997-948ac2efa89a" +version = "0.10.1" [[deps.Wayland_jll]] -deps = ["Artifacts", "EpollShim_jll", "Expat_jll", "JLLWrappers", "Libdl", "Libffi_jll", "Pkg", "XML2_jll"] -git-tree-sha1 = "85c7811eddec9e7f22615371c3cc81a504c508ee" +deps = ["Artifacts", "EpollShim_jll", "Expat_jll", "JLLWrappers", "Libdl", "Libffi_jll"] +git-tree-sha1 = "96478df35bbc2f3e1e791bc7a3d0eeee559e60e9" uuid = "a2964d1f-97da-50d4-b82a-358c7fce9d89" -version = "1.21.0+2" +version = "1.24.0+0" -[[deps.Wayland_protocols_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] -git-tree-sha1 = "5db3e9d307d32baba7067b13fc7b5aa6edd4a19a" -uuid = "2381bf8a-dfd0-557d-9999-79630e7b1b91" -version = "1.36.0+0" +[[deps.WeakRefStrings]] +deps = ["DataAPI", "InlineStrings", "Parsers"] +git-tree-sha1 = "b1be2855ed9ed8eac54e5caff2afcdb442d52c23" +uuid = "ea10d353-3f73-51f8-a26c-33c1cb351aa5" +version = "1.4.2" [[deps.WebP]] deps = ["CEnum", "ColorTypes", "FileIO", "FixedPointNumbers", "ImageCore", "libwebp_jll"] @@ -2414,167 +2491,136 @@ git-tree-sha1 = "c1a7aa6219628fcd757dede0ca95e245c5cd9511" uuid = "efce3f68-66dc-5838-9240-27a6d6f5f9b6" version = "1.0.0" +[[deps.WorkerUtilities]] +git-tree-sha1 = "cd1659ba0d57b71a464a29e64dbc67cfe83d54e7" +uuid = "76eceee3-57b5-4d4a-8e66-0e911cebbf60" +version = "1.6.1" + [[deps.XML2_jll]] deps = ["Artifacts", "JLLWrappers", "Libdl", "Libiconv_jll", "Zlib_jll"] -git-tree-sha1 = "04a51d15436a572301b5abbb9d099713327e9fc4" +git-tree-sha1 = "80d3930c6347cfce7ccf96bd3bafdf079d9c0390" uuid = "02c8fc9c-b97f-50b9-bbe4-9be30ff0a78a" -version = "2.10.4+0" +version = "2.13.9+0" -[[deps.XSLT_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl", "Libgcrypt_jll", "Libgpg_error_jll", "Libiconv_jll", "XML2_jll", "Zlib_jll"] -git-tree-sha1 = "7d1671acbe47ac88e981868a078bd6b4e27c5191" -uuid = "aed1982a-8fda-507f-9586-7b0439959a61" -version = "1.1.42+0" +[[deps.XZ_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl"] +git-tree-sha1 = "fee71455b0aaa3440dfdd54a9a36ccef829be7d4" +uuid = "ffd25f8a-64ca-5728-b0f7-c24cf3aae800" +version = "5.8.1+0" [[deps.Xorg_libX11_jll]] deps = ["Artifacts", "JLLWrappers", "Libdl", "Xorg_libxcb_jll", "Xorg_xtrans_jll"] -git-tree-sha1 = "9dafcee1d24c4f024e7edc92603cedba72118283" +git-tree-sha1 = "b5899b25d17bf1889d25906fb9deed5da0c15b3b" uuid = "4f6342f7-b3d2-589e-9d20-edeb45f2b2bc" -version = "1.8.6+3" +version = "1.8.12+0" [[deps.Xorg_libXau_jll]] deps = ["Artifacts", "JLLWrappers", "Libdl"] -git-tree-sha1 = "e9216fdcd8514b7072b43653874fd688e4c6c003" +git-tree-sha1 = "aa1261ebbac3ccc8d16558ae6799524c450ed16b" uuid = "0c0b7dd1-d40b-584c-a123-a41640f87eec" -version = "1.0.12+0" +version = "1.0.13+0" [[deps.Xorg_libXcomposite_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_libXfixes_jll"] -git-tree-sha1 = "7c688ca9c957837539bbe1c53629bb871025e423" +deps = ["Artifacts", "JLLWrappers", "Libdl", "Xorg_libXfixes_jll"] +git-tree-sha1 = "a630cfb0c2018a616d52f30e34cffa071ce93d42" uuid = "3c9796d7-64a0-5134-86ad-79f8eb684845" -version = "0.4.5+4" +version = "0.4.6+0" [[deps.Xorg_libXcursor_jll]] deps = ["Artifacts", "JLLWrappers", "Libdl", "Xorg_libXfixes_jll", "Xorg_libXrender_jll"] -git-tree-sha1 = "807c226eaf3651e7b2c468f687ac788291f9a89b" +git-tree-sha1 = "6c74ca84bbabc18c4547014765d194ff0b4dc9da" uuid = "935fb764-8cf2-53bf-bb30-45bb1f8bf724" -version = "1.2.3+0" +version = "1.2.4+0" [[deps.Xorg_libXdamage_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_libXfixes_jll"] -git-tree-sha1 = "fe4ffb2024ba3eddc862c6e1d70e2b070cd1c2bf" +deps = ["Artifacts", "JLLWrappers", "Libdl", "Xorg_libXfixes_jll"] +git-tree-sha1 = "534ed7d299469f3438b2c136d7beb0b50da88ce0" uuid = "0aeada51-83db-5f97-b67e-184615cfc6f6" -version = "1.1.5+4" +version = "1.1.6+0" [[deps.Xorg_libXdmcp_jll]] deps = ["Artifacts", "JLLWrappers", "Libdl"] -git-tree-sha1 = "89799ae67c17caa5b3b5a19b8469eeee474377db" +git-tree-sha1 = "52858d64353db33a56e13c341d7bf44cd0d7b309" uuid = "a3789734-cfe1-5b06-b2d0-1dd0d9d62d05" -version = "1.1.5+0" +version = "1.1.6+0" [[deps.Xorg_libXext_jll]] deps = ["Artifacts", "JLLWrappers", "Libdl", "Xorg_libX11_jll"] -git-tree-sha1 = "d7155fea91a4123ef59f42c4afb5ab3b4ca95058" +git-tree-sha1 = "a4c0ee07ad36bf8bbce1c3bb52d21fb1e0b987fb" uuid = "1082639a-0dae-5f34-9b06-72781eeb8cb3" -version = "1.3.6+3" +version = "1.3.7+0" [[deps.Xorg_libXfixes_jll]] deps = ["Artifacts", "JLLWrappers", "Libdl", "Xorg_libX11_jll"] -git-tree-sha1 = "6fcc21d5aea1a0b7cce6cab3e62246abd1949b86" +git-tree-sha1 = "75e00946e43621e09d431d9b95818ee751e6b2ef" uuid = "d091e8ba-531a-589c-9de9-94069b037ed8" -version = "6.0.0+0" +version = "6.0.2+0" [[deps.Xorg_libXi_jll]] deps = ["Artifacts", "JLLWrappers", "Libdl", "Xorg_libXext_jll", "Xorg_libXfixes_jll"] -git-tree-sha1 = "984b313b049c89739075b8e2a94407076de17449" +git-tree-sha1 = "a376af5c7ae60d29825164db40787f15c80c7c54" uuid = "a51aa0fd-4e3c-5386-b890-e753decda492" -version = "1.8.2+0" +version = "1.8.3+0" [[deps.Xorg_libXinerama_jll]] deps = ["Artifacts", "JLLWrappers", "Libdl", "Xorg_libXext_jll"] -git-tree-sha1 = "a1a7eaf6c3b5b05cb903e35e8372049b107ac729" +git-tree-sha1 = "a5bc75478d323358a90dc36766f3c99ba7feb024" uuid = "d1454406-59df-5ea1-beac-c340f2130bc3" -version = "1.1.5+0" +version = "1.1.6+0" [[deps.Xorg_libXrandr_jll]] deps = ["Artifacts", "JLLWrappers", "Libdl", "Xorg_libXext_jll", "Xorg_libXrender_jll"] -git-tree-sha1 = "b6f664b7b2f6a39689d822a6300b14df4668f0f4" +git-tree-sha1 = "aff463c82a773cb86061bce8d53a0d976854923e" uuid = "ec84b674-ba8e-5d96-8ba1-2a689ba10484" -version = "1.5.4+0" +version = "1.5.5+0" [[deps.Xorg_libXrender_jll]] deps = ["Artifacts", "JLLWrappers", "Libdl", "Xorg_libX11_jll"] -git-tree-sha1 = "a490c6212a0e90d2d55111ac956f7c4fa9c277a6" +git-tree-sha1 = "7ed9347888fac59a618302ee38216dd0379c480d" uuid = "ea2f1a96-1ddc-540d-b46f-429655e07cfa" -version = "0.9.11+1" +version = "0.9.12+0" [[deps.Xorg_libXtst_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_libXext_jll", "Xorg_libXfixes_jll", "Xorg_libXi_jll"] -git-tree-sha1 = "0c0a60851f44add2a64069ddf213e941c30ed93c" +deps = ["Artifacts", "JLLWrappers", "Libdl", "Xorg_libXext_jll", "Xorg_libXfixes_jll", "Xorg_libXi_jll"] +git-tree-sha1 = "58c2e8f49733034d33b461d45a7e874b4135b644" uuid = "b6f176f1-7aea-5357-ad67-1d3e565ea1c6" -version = "1.2.3+4" - -[[deps.Xorg_libpthread_stubs_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl"] -git-tree-sha1 = "c57201109a9e4c0585b208bb408bc41d205ac4e9" -uuid = "14d82f49-176c-5ed1-bb49-ad3f5cbd8c74" -version = "0.1.2+0" +version = "1.2.5+0" [[deps.Xorg_libxcb_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl", "XSLT_jll", "Xorg_libXau_jll", "Xorg_libXdmcp_jll", "Xorg_libpthread_stubs_jll"] -git-tree-sha1 = "1a74296303b6524a0472a8cb12d3d87a78eb3612" +deps = ["Artifacts", "JLLWrappers", "Libdl", "Xorg_libXau_jll", "Xorg_libXdmcp_jll"] +git-tree-sha1 = "bfcaf7ec088eaba362093393fe11aa141fa15422" uuid = "c7cfdc94-dc32-55de-ac96-5a1b8d977c5b" -version = "1.17.0+3" +version = "1.17.1+0" [[deps.Xorg_libxkbfile_jll]] deps = ["Artifacts", "JLLWrappers", "Libdl", "Xorg_libX11_jll"] -git-tree-sha1 = "dbc53e4cf7701c6c7047c51e17d6e64df55dca94" +git-tree-sha1 = "e3150c7400c41e207012b41659591f083f3ef795" uuid = "cc61e674-0454-545c-8b26-ed2c68acab7a" -version = "1.1.2+1" - -[[deps.Xorg_xcb_util_image_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_xcb_util_jll"] -git-tree-sha1 = "0fab0a40349ba1cba2c1da699243396ff8e94b97" -uuid = "12413925-8142-5f55-bb0e-6d7ca50bb09b" -version = "0.4.0+1" - -[[deps.Xorg_xcb_util_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_libxcb_jll"] -git-tree-sha1 = "e7fd7b2881fa2eaa72717420894d3938177862d1" -uuid = "2def613f-5ad1-5310-b15b-b15d46f528f5" -version = "0.4.0+1" - -[[deps.Xorg_xcb_util_keysyms_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_xcb_util_jll"] -git-tree-sha1 = "d1151e2c45a544f32441a567d1690e701ec89b00" -uuid = "975044d2-76e6-5fbe-bf08-97ce7c6574c7" -version = "0.4.0+1" - -[[deps.Xorg_xcb_util_renderutil_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_xcb_util_jll"] -git-tree-sha1 = "dfd7a8f38d4613b6a575253b3174dd991ca6183e" -uuid = "0d47668e-0667-5a69-a72c-f761630bfb7e" -version = "0.3.9+1" - -[[deps.Xorg_xcb_util_wm_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_xcb_util_jll"] -git-tree-sha1 = "e78d10aab01a4a154142c5006ed44fd9e8e31b67" -uuid = "c22f9ab0-d5fe-5066-847c-f4bb1cd4e361" -version = "0.4.1+1" +version = "1.1.3+0" [[deps.Xorg_xkbcomp_jll]] deps = ["Artifacts", "JLLWrappers", "Libdl", "Xorg_libxkbfile_jll"] -git-tree-sha1 = "ab2221d309eda71020cdda67a973aa582aa85d69" +git-tree-sha1 = "801a858fc9fb90c11ffddee1801bb06a738bda9b" uuid = "35661453-b289-5fab-8a00-3d9160c6a3a4" -version = "1.4.6+1" +version = "1.4.7+0" [[deps.Xorg_xkeyboard_config_jll]] deps = ["Artifacts", "JLLWrappers", "Libdl", "Xorg_xkbcomp_jll"] -git-tree-sha1 = "691634e5453ad362044e2ad653e79f3ee3bb98c3" +git-tree-sha1 = "00af7ebdc563c9217ecc67776d1bbf037dbcebf4" uuid = "33bec58e-1273-512f-9401-5d533626f822" -version = "2.39.0+0" +version = "2.44.0+0" [[deps.Xorg_xtrans_jll]] deps = ["Artifacts", "JLLWrappers", "Libdl"] -git-tree-sha1 = "6dba04dbfb72ae3ebe5418ba33d087ba8aa8cb00" +git-tree-sha1 = "a63799ff68005991f9d9491b6e95bd3478d783cb" uuid = "c5fb5394-a638-5e4d-96e5-b29de1b5cf10" -version = "1.5.1+0" +version = "1.6.0+0" [[deps.YAML]] deps = ["Base64", "Dates", "Printf", "StringEncodings"] -git-tree-sha1 = "dea63ff72079443240fbd013ba006bcbc8a9ac00" +git-tree-sha1 = "a1c0c7585346251353cddede21f180b96388c403" uuid = "ddb6d928-2868-570f-bddf-ab3f9cf99eb6" -version = "0.4.12" +version = "0.4.16" [[deps.Zlib_jll]] deps = ["Libdl"] @@ -2583,39 +2629,33 @@ version = "1.2.13+1" [[deps.Zstd_jll]] deps = ["Artifacts", "JLLWrappers", "Libdl"] -git-tree-sha1 = "622cf78670d067c738667aaa96c553430b65e269" +git-tree-sha1 = "446b23e73536f84e8037f5dce465e92275f6a308" uuid = "3161d3a3-bdf6-5164-811a-617609db77b4" -version = "1.5.7+0" +version = "1.5.7+1" [[deps.at_spi2_atk_jll]] -deps = ["ATK_jll", "Artifacts", "JLLWrappers", "Libdl", "Pkg", "XML2_jll", "Xorg_libX11_jll", "at_spi2_core_jll"] -git-tree-sha1 = "f16ae690aca4761f33d2cb338ee9899e541f5eae" +deps = ["ATK_jll", "Artifacts", "JLLWrappers", "Libdl", "XML2_jll", "Xorg_libX11_jll", "at_spi2_core_jll"] +git-tree-sha1 = "249ab7c4da34d86d3d66b524705b1c07fe96b815" uuid = "de012916-1e3f-58c2-8f29-df3ef51d412d" -version = "2.34.1+4" +version = "2.38.0+0" [[deps.at_spi2_core_jll]] -deps = ["Artifacts", "Dbus_jll", "Glib_jll", "JLLWrappers", "Libdl", "Pkg", "Xorg_libXtst_jll"] -git-tree-sha1 = "d2d540cd145f2b2933614649c029d222fe125188" +deps = ["Artifacts", "Dbus_jll", "Glib_jll", "JLLWrappers", "Libdl", "Xorg_libXtst_jll"] +git-tree-sha1 = "87819499fbacf7606859f6d7f31fa97d5db5452a" uuid = "0fc3237b-ac94-5853-b45c-d43d59a06200" -version = "2.34.0+4" - -[[deps.fzf_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl"] -git-tree-sha1 = "6e50f145003024df4f5cb96c7fce79466741d601" -uuid = "214eeab7-80f7-51ab-84ad-2988db7cef09" -version = "0.56.3+0" +version = "2.58.1+0" [[deps.gdk_pixbuf_jll]] -deps = ["Artifacts", "Glib_jll", "JLLWrappers", "JpegTurbo_jll", "Libdl", "Libtiff_jll", "Pkg", "Xorg_libX11_jll", "libpng_jll"] -git-tree-sha1 = "e9190f9fb03f9c3b15b9fb0c380b0d57a3c8ea39" +deps = ["Artifacts", "Glib_jll", "JLLWrappers", "JpegTurbo_jll", "Libdl", "Libtiff_jll", "Xorg_libX11_jll", "libpng_jll"] +git-tree-sha1 = "895f21b699121d1a57ecac57e65a852caf569254" uuid = "da03df04-f53b-5353-a52f-6a8b0620ced0" -version = "2.42.8+0" +version = "2.42.13+0" [[deps.iso_codes_jll]] deps = ["Artifacts", "JLLWrappers", "Libdl"] -git-tree-sha1 = "d837a5d2a19d54243dafb6cc98d0f590a603dfa1" +git-tree-sha1 = "9200917315ff176d445ccc759945ea3fdb7c49c3" uuid = "bf975903-5238-5d20-8243-bc370bc1e7e5" -version = "4.15.1+0" +version = "4.18.0+0" [[deps.isoband_jll]] deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] @@ -2623,25 +2663,17 @@ git-tree-sha1 = "51b5eeb3f98367157a7a12a1fb0aa5328946c03c" uuid = "9a68df92-36a6-505f-a73e-abb412b6bfb4" version = "0.2.3+0" -[[deps.julia_mzML_imzML]] -deps = ["Compat", "Libz", "Plots", "Pluto", "PyPlot"] -git-tree-sha1 = "e1aceca0a4b5fad50f5947d3dd5b22a759ff86f3" -repo-rev = "master" -repo-url = "https://github.com/CINVESTAV-LABI/julia_mzML_imzML" -uuid = "38eb50d3-2fb6-4afa-992a-964ed8562ed9" -version = "0.0.1-DEV" - [[deps.libaom_jll]] deps = ["Artifacts", "JLLWrappers", "Libdl"] -git-tree-sha1 = "522c1df09d05a71785765d19c9524661234738e9" +git-tree-sha1 = "371cc681c00a3ccc3fbc5c0fb91f58ba9bec1ecf" uuid = "a4ae2306-e953-59d6-aa16-d00cac43593b" -version = "3.11.0+0" +version = "3.13.1+0" [[deps.libass_jll]] deps = ["Artifacts", "Bzip2_jll", "FreeType2_jll", "FriBidi_jll", "HarfBuzz_jll", "JLLWrappers", "Libdl", "Zlib_jll"] -git-tree-sha1 = "e17c115d55c5fbb7e52ebedb427a0dca79d4484e" +git-tree-sha1 = "125eedcb0a4a0bba65b657251ce1d27c8714e9d6" uuid = "0ac62f75-1d6f-5e53-bd7c-93b484bb37c0" -version = "0.15.2+0" +version = "0.17.4+0" [[deps.libblastrampoline_jll]] deps = ["Artifacts", "Libdl"] @@ -2656,15 +2688,15 @@ version = "0.2.2+0" [[deps.libfdk_aac_jll]] deps = ["Artifacts", "JLLWrappers", "Libdl"] -git-tree-sha1 = "8a22cf860a7d27e4f3498a0fe0811a7957badb38" +git-tree-sha1 = "646634dd19587a56ee2f1199563ec056c5f228df" uuid = "f638f0a6-7fb0-5443-88ba-1cc74229b280" -version = "2.0.3+0" +version = "2.0.4+0" [[deps.libpng_jll]] deps = ["Artifacts", "JLLWrappers", "Libdl", "Zlib_jll"] -git-tree-sha1 = "d7b5bbf1efbafb5eca466700949625e07533aff2" +git-tree-sha1 = "07b6a107d926093898e82b3b1db657ebe33134ec" uuid = "b53b4c65-9356-5827-b1ea-8c7a1a84506f" -version = "1.6.45+1" +version = "1.6.50+0" [[deps.libsixel_jll]] deps = ["Artifacts", "JLLWrappers", "JpegTurbo_jll", "Libdl", "libpng_jll"] @@ -2673,16 +2705,22 @@ uuid = "075b6546-f08a-558a-be8f-8157d0f608a5" version = "1.10.5+0" [[deps.libvorbis_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl", "Ogg_jll", "Pkg"] -git-tree-sha1 = "490376214c4721cdaca654041f635213c6165cb3" +deps = ["Artifacts", "JLLWrappers", "Libdl", "Ogg_jll"] +git-tree-sha1 = "11e1772e7f3cc987e9d3de991dd4f6b2602663a5" uuid = "f27f6e37-5d2b-51aa-960f-b287f2bc3b7a" -version = "1.3.7+2" +version = "1.3.8+0" [[deps.libwebp_jll]] deps = ["Artifacts", "Giflib_jll", "JLLWrappers", "JpegTurbo_jll", "Libdl", "Libglvnd_jll", "Libtiff_jll", "libpng_jll"] -git-tree-sha1 = "ccbb625a89ec6195856a50aa2b668a5c08712c94" +git-tree-sha1 = "4e4282c4d846e11dce56d74fa8040130b7a95cb3" uuid = "c5f90fcd-3b7e-5836-afba-fc50a0988cb2" -version = "1.4.0+0" +version = "1.6.0+0" + +[[deps.libzip_jll]] +deps = ["Artifacts", "Bzip2_jll", "JLLWrappers", "Libdl", "OpenSSL_jll", "XZ_jll", "Zlib_jll", "Zstd_jll"] +git-tree-sha1 = "86addc139bca85fdf9e7741e10977c45785727b7" +uuid = "337d8026-41b4-5cde-a456-74a10e5b31d1" +version = "1.11.3+0" [[deps.nghttp2_jll]] deps = ["Artifacts", "Libdl"] @@ -2690,10 +2728,10 @@ uuid = "8e850ede-7688-5339-a07c-302acd2aaf8d" version = "1.59.0+0" [[deps.oneTBB_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl"] -git-tree-sha1 = "7d0ea0f4895ef2f5cb83645fa689e52cb55cf493" +deps = ["Artifacts", "JLLWrappers", "LazyArtifacts", "Libdl"] +git-tree-sha1 = "1350188a69a6e46f799d3945beef36435ed7262f" uuid = "1317d2d5-d96f-522e-a858-c73665f53c3e" -version = "2021.12.0+0" +version = "2022.0.0+1" [[deps.p7zip_jll]] deps = ["Artifacts", "Libdl"] @@ -2701,19 +2739,19 @@ uuid = "3f19e933-33d8-53b3-aaab-bd5110c3b7a0" version = "17.4.0+2" [[deps.x264_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] -git-tree-sha1 = "4fea590b89e6ec504593146bf8b988b2c00922b2" +deps = ["Artifacts", "JLLWrappers", "Libdl"] +git-tree-sha1 = "14cc7083fc6dff3cc44f2bc435ee96d06ed79aa7" uuid = "1270edf5-f2f9-52d2-97e9-ab00b5d0237a" -version = "2021.5.5+0" +version = "10164.0.1+0" [[deps.x265_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] -git-tree-sha1 = "ee567a171cce03570d77ad3a43e90218e38937a9" +deps = ["Artifacts", "JLLWrappers", "Libdl"] +git-tree-sha1 = "e7b67590c14d487e734dcb925924c5dc43ec85f3" uuid = "dfaa095f-4041-5dcd-9319-2fabd8486b76" -version = "3.5.0+0" +version = "4.1.0+0" [[deps.xkbcommon_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Wayland_jll", "Wayland_protocols_jll", "Xorg_libxcb_jll", "Xorg_xkeyboard_config_jll"] -git-tree-sha1 = "63406453ed9b33a0df95d570816d5366c92b7809" +deps = ["Artifacts", "JLLWrappers", "Libdl", "Xorg_libxcb_jll", "Xorg_xkeyboard_config_jll"] +git-tree-sha1 = "fbf139bce07a534df0e699dbb5f5cc9346f95cc1" uuid = "d8fb68d0-12a3-5cfd-a85a-d49703b185fd" -version = "1.4.1+2" +version = "1.9.2+0" diff --git a/Project.toml b/Project.toml index 2909ef6..72450c3 100644 --- a/Project.toml +++ b/Project.toml @@ -1,14 +1,94 @@ +name = "MSI_src" +authors = ["JJSA"] +version = "0.1.0" + [deps] +Accessors = "7d9f7c33-5ae7-4f3b-8dc6-eff91059b697" +Base64 = "2a0f44e3-6c83-55bd-87e4-b1978d98bd5f" +CSV = "336ed68f-0bac-5ca0-87d4-7b16caf5d00b" CairoMakie = "13f3f980-e62b-5c42-98c6-ff1f3baf88f0" +CodecBase = "6c391c72-fb7b-5838-ba82-7cfb1bcfecbf" +ColorSchemes = "35d6a980-a343-548e-a6ea-1d62b119f2f4" Colors = "5ae59095-9a9b-59fe-a467-6f913c188581" +ContinuousWavelets = "96eb917e-2868-4417-9cb6-27e7ff17528f" +DataFrames = "a93c6f00-e57d-5684-b7b6-d8193f3e46c0" +Dates = "ade2ca70-3891-5945-98fb-dc099432e06a" +FileIO = "5789e2e9-d7fb-5bc7-8068-2c6fae9b9549" +GLMakie = "e9467ef8-e4e7-5192-8a1a-b1aee30e663a" Genie = "c43c736e-a2d1-11e8-161f-af95117fbd1e" GenieFramework = "a59fdf5c-6bf0-4f5d-949c-a137c9e2f353" +HistogramThresholding = "2c695a8d-9458-5d45-9878-1b8a99cf7853" +ImageBinarization = "cbc4b850-ae4b-5111-9e64-df94c024a13d" +ImageComponentAnalysis = "d9b9e9a0-1569-11e9-2cb5-bbca914b0e89" +ImageContrastAdjustment = "f332f351-ec65-5f6a-b3d1-319c6670881a" +ImageCore = "a09fc81d-aa75-5fe9-8630-4744c3626534" +ImageFiltering = "6a3955dd-da59-5b1f-98d4-e7296123deb5" +ImageMorphology = "787d08f9-d448-5407-9aad-5290dd7ab264" +ImageSegmentation = "80713f31-8817-5129-9cf8-209ff8fb23e1" Images = "916415d5-f1e6-5110-898d-aaa5f9f070e0" +Interpolations = "a98d9a8b-a2ab-59e6-89dd-64a1c18fca59" +JLD2 = "033835bb-8acc-5ee8-8aae-3f567f8a3819" +JSON = "682c06a0-de6a-54ab-a142-c8b1cf79cde6" Libz = "2ec943e9-cfe8-584d-b93d-64dcb6d567b7" LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" +Loess = "4345ca2d-374a-55d4-8d30-97f9976e7612" +Mmap = "a63ad114-7e13-5084-954f-fe012c677804" NativeFileDialog = "e1fe445b-aa65-4df4-81c1-2041507f0fd4" NaturalSort = "c020b1a1-e9b0-503a-9c33-f039bfc54a85" +Parameters = "d96e819e-fc66-5662-9728-84c9c7592b0a" PlotlyBase = "a03496cd-edff-5a9b-9e67-9cda94a718b5" +Printf = "de0858da-6303-5e67-8744-51eddeeeb8d7" +ProgressMeter = "92933f4c-e287-5a05-a399-4b506db050ca" +SavitzkyGolay = "c4bf5708-b6a6-4fbe-bcd0-6850ed671584" +Serialization = "9e88b42a-f829-5b0c-bbe9-9e923198166b" +Setfield = "efcf1570-3423-57d1-acb7-fd33fddbac46" Statistics = "10745b16-79ce-11e8-11f9-7d13ad32a3b2" +StatsBase = "2913bbd2-ae8a-5f71-8c99-4fb6c76f3a91" StipplePlotly = "ec984513-233d-481d-95b0-a3b58b97af2b" -julia_mzML_imzML = "38eb50d3-2fb6-4afa-992a-964ed8562ed9" +UUIDs = "cf7118a7-6976-5b1a-9a39-7adc72f591a4" + +[compat] +Accessors = "0.1" +Base64 = "1.11" +CSV = "0.10" +CairoMakie = "0.13" +ColorSchemes = "3.30" +Colors = "0.12" +CodecBase = "0.3" +ContinuousWavelets = "1.1" +DataFrames = "1.7" +Dates = "1.11" +FileIO = "1.17" +GLMakie = "0.11" +Genie = "5.31" +GenieFramework = "2.8" +HistogramThresholding = "0.3" +Interpolations = "0.15" +ImageBinarization = "0.3" +ImageComponentAnalysis = "0.2" +ImageContrastAdjustment = "0.3" +ImageCore = "0.10" +ImageFiltering = "0.7" +ImageMorphology = "0.4" +ImageSegmentation = "1.9" +Images = "0.26" +JLD2 = "0.6" +JSON = "0.21" +Libz = "1.0" +LinearAlgebra = "1.11" +Loess = "0.6" +Mmap = "1.11" +NativeFileDialog = "0.2" +NaturalSort = "1.0" +Parameters = "0.12" +PlotlyBase = "0.8" +Printf = "1.11" +ProgressMeter = "1.11" +SavitzkyGolay = "0.9" +Serialization = "1.11" +Setfield = "1.1" +Statistics = "1.11" +StatsBase = "0.34" +StipplePlotly = "0.13" +UUIDs = "1.11" +julia = "1.11, 1.12" diff --git a/README.md b/README.md index 2affa30..f85afc9 100644 --- a/README.md +++ b/README.md @@ -6,6 +6,7 @@ https://codeberg.org/LabABI/JuliaMSI 1. Make sure you have Julia installed and at least Julia version 1.6, If not, follow the next installation guide which contains the latest files and instructions for [juliaup](https://github.com/JuliaLang/juliaup) (recommended) alternatively, you can follow the official Julia installation instructions at [julia](https://julialang.org/downloads/platform/). 2. Download and decompress the following repository (You can download the repository from [download](https://codeberg.org/LabABI/JuliaMSI/archive/main.zip) or locate the option manually at the top right of the page, in the box with [•••] (More operations). For a more advanced method using Git, use this link: https://codeberg.org/LabABI/JuliaMSI.git). 3. Ensure that you have decompressed the ZIP file and know the working directory where it is located (the folder on your computer where you saved the JuliaMSI files). +4. Julia Version 1.11 is required. You might need to downgrade your whole Julia installation to support it. ## Load User Interface 1. Set the working directory to where JuliaMSI is located (the specific location of the folder on your computer where you decompressed the ZIP) in your terminal.
@@ -22,7 +23,7 @@ https://codeberg.org/LabABI/JuliaMSI ~/Downloads/JuliaMSI-main/juliamsi 2. Without entering the Julia environment, launch the project in your terminal with the following command (which works for all operating systems): ``` - julia --project=. start_MSI_GUI.jl + julia --threads auto --project=. start_MSI_GUI.jl ``` 3. After the script has finished loading, you can open a [page](http://127.0.0.1:1481/) in your browser with the web app running. diff --git a/app.jl b/app.jl index aaa9767..a99a9b4 100644 --- a/app.jl +++ b/app.jl @@ -1,12 +1,14 @@ +# app.jl + module App # ==Packages == -using GenieFramework # Set up Genie development environment. +using GenieFramework using Pkg using Libz using PlotlyBase using CairoMakie using Colors -using julia_mzML_imzML +using MSI_src # Import the new MSIData library using Statistics using NaturalSort using Images @@ -14,189 +16,543 @@ using LinearAlgebra using NativeFileDialog # Opens the file explorer depending on the OS using StipplePlotly using Base.Filesystem: mv # To rename files in the system -include("./julia_imzML_visual.jl") +using Printf # Required for @sprintf macro in colorbar generation +using JSON +using Dates +using Base.Threads + +# Bring MSIData into App module's scope +using .MSI_src: MSIData, OpenMSIData, process_spectrum, IterateSpectra, ImzMLSource, _iterate_spectra_fast, MzMLSource, find_mass, ViridisPalette, get_mz_slice, get_multiple_mz_slices, quantize_intensity, save_bitmap, median_filter, save_bitmap, downsample_spectrum, TrIQ, precompute_analytics, ImportMzmlFile, generate_colorbar_image, load_and_prepare_mask, set_global_mz_range!, main_precalculation, MutableSpectrum, execute_full_preprocessing + +if !@isdefined(increment_image) + include("./julia_imzML_visual.jl") +end + +# --- Memory Validation Logging --- +if get(ENV, "GENIE_ENV", "dev") != "prod" + function get_rss_mb() + if !Sys.islinux() + return 0.0 + end + try + pid = getpid() + cmd = `ps -p $pid -o rss=` + rss_kb_str = read(cmd, String) + rss_kb = parse(Int, strip(rss_kb_str)) + return round(rss_kb / 1024, digits=2) + catch e + @warn "Could not get RSS via `ps` command. Error: $e" + return 0.0 + end + end + + function log_memory_usage(context::String, msi_data_val) + rss_mb = get_rss_mb() + + msi_data_size_mb = 0 + if msi_data_val !== nothing + msi_data_size_mb = round(Base.summarysize(msi_data_val) / (1024^2), digits=2) + end + + gc_time_s = round(GC.time(), digits=3) + + println("--- MEMORY LOG [$(context)] ---") + println(" Timestamp: $(now())") + println(" Process RSS: $(rss_mb) MB") + println(" msi_data size: $(msi_data_size_mb) MB") + println(" Cumulative GC time: $(gc_time_s) s") + println("--------------------------") + end +else + log_memory_usage(context::String, msi_data_val) = nothing # No-op for production +end + +function validate_parse(validation_errors::Vector{String}, param_str::String, param_name::String, target_type::Type, step_name::String) + println("DEBUG: Validating ($step_name) Parameter '$param_name'. Received value: '$param_str'") + if isempty(param_str) + push!(validation_errors, "($step_name) Parameter '$param_name' is empty.") + return nothing + end + val = tryparse(target_type, param_str) + if val === nothing + push!(validation_errors, "($step_name) Parameter '$param_name' ('$param_str') is not a valid $(target_type).") + return nothing + end + return val +end + +# Helper function to check if a pipeline step is enabled +function is_step_enabled(step_name::String, pipeline_order::Vector{Dict{String, Any}}) + for step in pipeline_order + if get(step, "name", "") == step_name + return get(step, "enabled", false) + end + end + return false # Default to disabled if step not found +end + +function get_processed_mean_spectrum(spectra::Vector{MutableSpectrum}; num_bins=2000) + # 1. Find global m/z range from all spectra + min_mz, max_mz = Inf, -Inf + for s in spectra + if !isempty(s.mz) + min_mz = min(min_mz, minimum(s.mz)) + max_mz = max(max_mz, maximum(s.mz)) + end + end + + if !isfinite(min_mz) + return Float64[], Float64[] + end + + # 2. Create bins + mz_bins = range(min_mz, stop=max_mz, length=num_bins) + intensity_sum = zeros(Float64, num_bins) + bin_step = step(mz_bins) + inv_bin_step = 1.0 / bin_step + + # 3. Bin intensities + for s in spectra + for i in eachindex(s.mz) + bin_index = trunc(Int, (s.mz[i] - min_mz) * inv_bin_step + 1.0) + final_index = clamp(bin_index, 1, num_bins) + intensity_sum[final_index] += s.intensity[i] + end + end + + # 4. Average and return + if isempty(spectra) + return collect(mz_bins), intensity_sum + end + average_intensity = intensity_sum ./ length(spectra) + return collect(mz_bins), average_intensity +end + +function get_processed_sum_spectrum(spectra::Vector{MutableSpectrum}; num_bins=2000) + min_mz, max_mz = Inf, -Inf + for s in spectra + if !isempty(s.mz) + min_mz = min(min_mz, minimum(s.mz)) + max_mz = max(max_mz, maximum(s.mz)) + end + end + + if !isfinite(min_mz) + return Float64[], Float64[] + end + + mz_bins = range(min_mz, stop=max_mz, length=num_bins) + intensity_sum = zeros(Float64, num_bins) + bin_step = step(mz_bins) + inv_bin_step = 1.0 / bin_step + + for s in spectra + for i in eachindex(s.mz) + bin_index = trunc(Int, (s.mz[i] - min_mz) * inv_bin_step + 1.0) + final_index = clamp(bin_index, 1, num_bins) + intensity_sum[final_index] += s.intensity[i] + end + end + + return collect(mz_bins), intensity_sum +end + @genietools # == Reactive code == # Reactive code to make the UI interactive @app begin - # == Reactive variables == - # reactive variables exist in both the Julia backend and the browser with two-way synchronization - # @out variables can only be modified by the backend - # @in variables can be modified by both the backend and the browser - # variables must be initialized with constant values, or variables defined outside of the @app block + # == Loading Screen Variables == + @in is_initializing = true + @in initialization_message = "Initializing..." + # Loading animations and readonly / disable elements are all handled by this variable. + @in is_processing = false - ## Interface non Variables - @out btnStartDisable=true - @out btnPlotDisable=false - @out btnSpectraDisable=true - # Loading animations - @in progress=false - @in progressPlot=false - @in progressSpectraPlot=false - # Text field validations - @in triqEnabled=false - @in SpectraEnabled=false - @in MFilterEnabled=false - # Dialogs - @in warning_msg=false - @in CompareDialog=false - - ## Interface Variables + # == SLICE GENERATOR TAB VARIABLES == + # File selection and batch processing @in file_route="" @in file_name="" - @in Nmass=0.0 - @in Tol=0.1 - @in triqProb=0.98 - @in colorLevel=20 - - ## Interface Buttons @in btnSearch=false # To search for files in your device - @in mainProcess=false # To generate images - @in compareBtn=false # To open dialog + @in btnAddBatch = false + @in clear_batch_btn = false + @out batch_file_count = 0 + @in selected_files = String[] + @out full_route="" # Saves the route where imzML and mzML files are located + + # Mass-to-charge parameters + @in Nmass="0.0" # Mass-to-charge ratio(s) of interest + @in Tol=0.1 # Mass-to-charge ratio tolerance + @in colorLevel=20 # Color levels for visualization + + # Processing toggles + @in triqEnabled=false # Threshold Intensity Quantization + @in MFilterEnabled=false # Median Filter + @in maskEnabled=false # Use Mask To Filter Data + @in triqProb=0.98 # TrIQ probability parameter + + # Spectrum selection and coordinates + @in idSpectrum=0 # Spectrum ID for ID-based plots + @in xCoord=0 # X coordinate for coordinate-based plots + @in yCoord=0 # Y coordinate for coordinate-based plots + @in SpectraEnabled=false # Enables xCoord and yCoord inputs when spectral data is loaded + + # Plot generation triggers + @in mainProcess=false # To generate images/slices @in createMeanPlot=false # To generate mean spectrum plot - @in createXYPlot=false # To generate an spectrum plot according to the xy values inputed + @in createXYPlot=false # To generate spectrum plot according to xy values + @in createNSpectrumPlot=false # To generate spectrum plot according to spectrum order + @in createSumPlot=false # To generate sum of all spectrum plots @in image3dPlot=false # To generate 3d plot based on current image @in triq3dPlot=false # To generate 3d plot based on current triq image @in imageCPlot=false # To generate contour plots of current image @in triqCPlot=false # To generate contour plots of current triq image - # Image change buttons - @in imgPlus=false - @in imgMinus=false - @in imgPlusT=false - @in imgMinusT=false - # Image change comparative buttons - @in imgPlusComp=false - @in imgMinusComp=false - @in imgPlusTComp=false - @in imgMinusTComp=false - ## Tabulation variables + # Image navigation controls + @in imgPlus=false # Next image in normal mode + @in imgMinus=false # Previous image in normal mode + @in imgPlusT=false # Next image in TrIQ mode + @in imgMinusT=false # Previous image in TrIQ mode + + # Optical image overlay + @in imgTrans=1.0 # Transparency level for optical overlay + @in btnOptical=false # Load optical image over normal image + @in btnOpticalT=false # Load optical image over TrIQ image + @in opticalOverTriq=false # Toggle optical overlay mode + + # Messages and status + @out msg="" # Main status message + @out msgimg="" # Image status message + @out msgtriq="" # TrIQ status message + + # == CONVERTER TAB VARIABLES == + @in left_tab = "generator" # Active left tab (generator, converter, pre_treatment) + @out mzml_full_route = "" # Path to .mzML file + @out sync_full_route = "" # Path to .txt synchronization file + @in btnSearchMzml = false # Trigger mzML file search + @in btnSearchSync = false # Trigger sync file search + @in convert_process = false # Start conversion process + @out progress_conversion = false # Conversion progress indicator + @out msg_conversion = "" # Conversion status message + @out btnConvertDisable = true # Disable convert button when files not selected + + # == PRE-TREATMENT TAB VARIABLES == + # File selection and batch + @in pre_tab = "stabilization" # Active preprocessing subtab + + # Subset processing + @in enable_subset_processing = false # Enable processing only first N spectra + @in spectra_subset_size = 100 # Number of spectra for subset processing + + # Internal standards management + @in enable_standards = true # Use internal standards for calibration + @in reference_peaks_list = [ + Dict("mz" => 137.0244, "label" => "DHB_fragment"), + Dict("mz" => 155.0349, "label" => "DHB_M+H"), + ] + @in addReferencePeak = false # Add new reference peak + @in remove_peak_trigger = false # Remove reference peak + @in export_standards_btn = false # Export standards to JSON + @in import_standards_btn = false # Import standards from JSON + + # Pipeline step management + @in pipeline_step_order = [ + Dict("name" => "stabilization", "label" => "Stabilization", "enabled" => true), + Dict("name" => "smoothing", "label" => "Smoothing", "enabled" => true), + Dict("name" => "baseline_correction", "label" => "Baseline Correction", "enabled" => true), + Dict("name" => "peak_picking", "label" => "Peak Picking", "enabled" => true), + Dict("name" => "peak_selection", "label" => "Peak Selection", "enabled" => true), + Dict("name" => "calibration", "label" => "Calibration", "enabled" => true), + Dict("name" => "peak_alignment", "label" => "Peak Alignment", "enabled" => true), + Dict("name" => "normalization", "label" => "Normalization", "enabled" => true), + Dict("name" => "peak_binning", "label" => "Peak Binning", "enabled" => true) + ] + @in action_index = -1 # Index for step operations + @in move_step_up_trigger = false # Move step up in pipeline + @in move_step_down_trigger = false # Move step down in pipeline + @in toggle_step_trigger = false # Toggle step enabled/disabled + @out current_pipeline_step = "" # Current running step in full pipeline + + # Preprocessing method parameters + @in stabilization_method="sqrt" + @in smoothing_method="sg" + @in smoothing_window = "" + @in smoothing_order = "" + @in baseline_method="snip" + @in baseline_iterations = "" + @in baseline_window = "" + @in normalization_method="tic" + @in alignment_method="lowess" + @in alignment_span = "" + @in alignment_tolerance = "" + @in alignment_tolerance_unit="mz" + @in alignment_max_shift_ppm = "" + @in alignment_min_matched_peaks = "" + @in peak_picking_method="profile" + @in peak_picking_snr_threshold = "" + @in peak_picking_half_window = "" + @in peak_picking_min_peak_prominence = "" + @in peak_picking_merge_peaks_tolerance = "" + @in peak_picking_min_peak_width_ppm = "" + @in peak_picking_max_peak_width_ppm = "" + @in peak_picking_min_peak_shape_r2 = "" + @in binning_method="adaptive" + @in binning_tolerance = "" + @in binning_tolerance_unit="ppm" + @in binning_frequency_threshold = "" + @in binning_min_peak_per_bin = "" + @in binning_max_bin_width_ppm = "" + @in binning_intensity_weighted_centers=true + @in binning_num_uniform_bins = "" + @in calibration_fit_order = "" + @in calibration_ppm_tolerance = "" + @in peak_selection_min_snr = "" + @in peak_selection_min_fwhm_ppm = "" + @in peak_selection_max_fwhm_ppm = "" + @in peak_selection_min_shape_r2 = "" + @in peak_selection_frequency_threshold = "" + @in peak_selection_correlation_threshold = "" + + # Suggested parameter values + @in suggested_smoothing_window = "" + @in suggested_smoothing_order = "" + @in suggested_baseline_iterations = "" + @in suggested_baseline_window = "" + @in suggested_alignment_span = "" + @in suggested_alignment_tolerance = "" + @in suggested_alignment_max_shift_ppm = "" + @in suggested_alignment_min_matched_peaks = "" + @in suggested_peak_picking_snr_threshold = "" + @in suggested_peak_picking_half_window = "" + @in suggested_peak_picking_min_peak_prominence = "" + @in suggested_peak_picking_merge_peaks_tolerance = "" + @in suggested_peak_picking_min_peak_width_ppm = "" + @in suggested_peak_picking_max_peak_width_ppm = "" + @in suggested_peak_picking_min_peak_shape_r2 = "" + @in suggested_binning_tolerance = "" + @in suggested_binning_frequency_threshold = "" + @in suggested_binning_min_peak_per_bin = "" + @in suggested_binning_max_bin_width_ppm = "" + @in suggested_binning_num_uniform_bins = "" + @in suggested_calibration_fit_order = "" + @in suggested_calibration_ppm_tolerance = "" + @in suggested_peak_selection_min_snr = "" + @in suggested_peak_selection_min_fwhm_ppm = "" + @in suggested_peak_selection_max_fwhm_ppm = "" + @in suggested_peak_selection_min_shape_r2 = "" + @in suggested_peak_selection_frequency_threshold = "" + @in suggested_peak_selection_correlation_threshold = "" + + # Pipeline control triggers + @in run_full_pipeline = false # Trigger full pipeline execution + @in recalculate_suggestions_btn = false # Recalculate parameter suggestions + @in export_params_btn = false # Export parameters to file + @in import_params_btn = false # Import parameters from file + @in save_feature_matrix_btn = false # Save feature matrix results + + # Preprocessing results + @in selected_spectrum_id_for_plot = 1 + @in last_plot_type = "single" + @in last_plot_mode = "lines" + @in feature_matrix_result::Union{Nothing, Matrix{Float64}} = nothing + @in bin_info_result::Union{Nothing, Vector} = nothing + + # == RIGHT PANEL VARIABLES (intDivStyle-right) == + # Tab management @out tabIDs=["tab0","tab1","tab2","tab3","tab4"] @out tabLabels=["Image", "TrIQ", "Spectrum Plot", "Topography Plot","Surface Plot"] @in selectedTab="tab0" - @out CompTabIDs=["tab0","tab1","tab2","tab3","tab4"] - @out CompTabLabels=["Image", "TrIQ", "Spectrum Plot", "Topography Plot","Surface Plot"] - @in CompSelectedTab="tab0" - # Interface Images - @out imgInt="/.bmp" # image Interface - @out imgIntT="/.bmp" # image Interface TrIQ - @out colorbar="/.png" - @out colorbarT="/.png" - # Interface controlling for the comparative view - @out imgIntComp="/.bmp" # image Interface - @out imgIntTComp="/.bmp" # image Interface TrIQ - @out colorbarComp="/.png" - @out colorbarTComp="/.png" + # Compare dialog tabs + @out CompTabIDsLeft=["tab0","tab1","tab2","tab3","tab4"] + @out CompTabLabelsLeft=["Image", "TrIQ", "Spectrum Plot", "Topography Plot","Surface Plot"] + @in CompSelectedTabLeft="tab0" + @out CompTabIDsRight=["tab0","tab1","tab2","tab3","tab4"] + @out CompTabLabelsRight=["Image", "TrIQ", "Spectrum Plot", "Topography Plot","Surface Plot"] + @in CompSelectedTabRight="tab0" + + # Compare dialog controls + @in CompareDialog=false + @in compareBtn=false # Open compare dialog + @in imgPlusCompLeft=false # Next image in compare left panel + @in imgMinusCompLeft=false # Previous image in compare left panel + @in imgPlusTCompLeft=false # Next TrIQ image in compare left panel + @in imgMinusTCompLeft=false # Previous TrIQ image in compare left panel + @in imgPlusCompRight=false # Next image in compare right panel + @in imgMinusCompRight=false # Previous image in compare right panel + @in imgPlusTCompRight=false # Next TrIQ image in compare right panel + @in imgMinusTCompRight=false # Previous TrIQ image in compare right panel + + # Image display variables + @out imgInt="/.bmp" # Normal image interface + @out imgIntT="/.bmp" # TrIQ image interface + @out colorbar="/.png" # Normal colorbar + @out colorbarT="/.png" # TrIQ colorbar + + # Compare dialog images + @out imgIntCompLeft="/.bmp" # Left compare normal image + @out imgIntTCompLeft="/.bmp" # Left compare TrIQ image + @out colorbarCompLeft="/.png" # Left compare normal colorbar + @out colorbarTCompLeft="/.png" # Left compare TrIQ colorbar + @out imgIntCompRight="/.bmp" # Right compare normal image + @out imgIntTCompRight="/.bmp" # Right compare TrIQ image + @out colorbarCompRight="/.png" # Right compare normal colorbar + @out colorbarTCompRight="/.png" # Right compare TrIQ colorbar + @out imgWidth=0 @out imgHeight=0 - # Optical Image Overlay & Transparency - @in imgTrans=1.0 - @in progressOptical=false - @out btnOpticalDisable=true - @in btnOptical=false - @in btnOpticalT=false - @in opticalOverTriq=false - @out imgRoute="" + # Compare dialog messages + @out msgimgCompLeft="" + @out msgtriqCompLeft="" + @out msgimgCompRight="" + @out msgtriqCompRight="" - # Messages to interface variables - @out msg="" - @out msgimg="" - @out msgtriq="" - # Reiteration of the messages under the image to know which spectra is being visualized - @out msgimgComp="" - @out msgtriqComp="" + # == BATCH PROCESSING & REGISTRY VARIABLES == + @private registry_init_done = false + @in refetch_folders = false + @in available_folders = String[] + @in image_available_folders = String[] + @out registry_path = abspath(joinpath(@__DIR__, "public", "registry.json")) - # Saves the route where imzML and mzML files are located - @out full_route="" - @out full_routeMz="" - @out full_routeMz2="" + # Folder selection state + @in selected_folder_main = "" + @in selected_folder_compare_left = "" + @in selected_folder_compare_right = "" - # For the creation of images with a more specific mass charge - @out text_nmass="" + # Progress reporting + @out overall_progress = 0.0 + @out progress_message = "" - # For image search image lists we apply a filter that searches specific type of images into our public folder, then we sort it in a "numerical" order + # Batch summary + @in showBatchSummary = false + @out batch_summary = "" + + # == METADATA VARIABLES == + @in showMetadataDialog = false + @in showMetadataBtn = false + @out metadata_columns = [] + @out metadata_rows = [] + @out btnMetadataDisable = false + @in selected_folder_metadata = "" + + # == DATA MANAGEMENT VARIABLES == + # Centralized MSIData object + @out msi_data::Union{MSIData, Nothing} = nothing + + # Image file management + @out text_nmass="" # For specific mass charge image creation @in msi_bmp=sort(filter(filename -> startswith(filename, "MSI_") && endswith(filename, ".bmp"), readdir("public")),lt=natural) @in col_msi_png=sort(filter(filename -> startswith(filename, "colorbar_MSI_") && endswith(filename, ".png"), readdir("public")),lt=natural) @in triq_bmp=sort(filter(filename -> startswith(filename, "TrIQ_") && endswith(filename, ".bmp"), readdir("public")),lt=natural) @in col_triq_png=sort(filter(filename -> startswith(filename, "colorbar_TrIQ_") && endswith(filename, ".png"), readdir("public")),lt=natural) - - # Set current image for the list to display + + # Current image display @out current_msi="" @out current_col_msi="" @out current_triq="" @out current_col_triq="" - # We reiterate the process to display in the comparative view - @out current_msiComp="" - @out current_col_msiComp="" - @out current_triqComp="" - @out current_col_triqComp="" + @out current_msiCompLeft="" + @out current_col_msiCompLeft="" + @out current_triqCompLeft="" + @out current_col_triqCompLeft="" + @out current_msiCompRight="" + @out current_col_msiCompRight="" + @out current_triqCompRight="" + @out current_col_triqCompRight="" - ## Time measurement variables - @out sTime=time() - @out fTime=time() - @out eTime=time() + # Optical image + @out imgRoute="" - ## Plots - # Local image to plot + # == PLOTTING VARIABLES == + # Image plots layoutImg=PlotlyBase.Layout( + title=PlotlyBase.attr( + text="", + font=PlotlyBase.attr( + family="Roboto, Lato, sans-serif", + size=14, + color="black" + ) + ), xaxis=PlotlyBase.attr( visible=false, - scaleanchor="y" + scaleanchor="y", + range=[0, 0] ), yaxis=PlotlyBase.attr( - visible=false + visible=false, + range=[0, 0] ), margin=attr(l=0,r=0,t=0,b=0,pad=0) ) - traceImg=PlotlyBase.heatmap(x=[], y=[]) + traceImg=PlotlyBase.heatmap(x=Vector{Float64}(), y=Vector{Float64}()) @out plotdataImg=[traceImg] @out plotlayoutImg=layoutImg - # For the image in the comparative view - @out plotdataImgComp=[traceImg] - @out plotlayoutImgComp=layoutImg + @out plotdataImgCompLeft=[traceImg] + @out plotlayoutImgCompLeft=layoutImg + @out plotdataImgCompRight=[traceImg] + @out plotlayoutImgCompRight=layoutImg - # For triq image + # TrIQ image plots @out plotdataImgT=[traceImg] @out plotlayoutImgT=layoutImg - # For the triq image in the comparative view - @out plotdataImgTComp=[traceImg] - @out plotlayoutImgTComp=layoutImg - # Interface Plot Spectrum + @out plotdataImgTCompLeft=[traceImg] + @out plotlayoutImgTCompLeft=layoutImg + @out plotdataImgTCompRight=[traceImg] + @out plotlayoutImgTCompRight=layoutImg + + # Spectrum plots layoutSpectra=PlotlyBase.Layout( - title="Spectrum plot", + title=PlotlyBase.attr( + text="Spectrum plot", + font=PlotlyBase.attr( + family="Roboto, Lato, sans-serif", + size=18, + color="black" + ) + ), + hovermode="closest", xaxis=PlotlyBase.attr( title="m/z", - showgrid=true, - tickformat = ".3g" + showgrid=true ), yaxis=PlotlyBase.attr( title="Intensity", showgrid=true, tickformat = ".3g" ), - margin=attr(l=0,r=0,t=120,b=0,pad=0) + margin=attr(l=0,r=0,t=120,b=0,pad=0), + legend=attr( + x=1.0, + y=1.0, + xanchor="right", + yanchor="top" + ) ) - # Dummy 2D scatter plot - traceSpectra=PlotlyBase.scatter(x=[], y=[], mode="lines") - # Create conection to frontend + traceSpectra=PlotlyBase.scatter(x=Vector{Float64}(), y=Vector{Float64}(), mode="lines", marker=attr(size=1, color="blue", opacity=0.1)) @out plotdata=[traceSpectra] @out plotlayout=layoutSpectra - @in xCoord=0 - @in yCoord=0 - @out xSpectraMz=Float64[] - @out ySpectraMz=Float64[] - # Interactive plot reactions - @in data_click=Dict{String,Any}() - #@in data_selected=Dict{String,Any}() # Selected is for areas, this can work for the masks - # + # Preprocessing spectrum plots + @out plotdata_before = [traceSpectra] + @out plotlayout_before = layoutSpectra + @out plotdata_after = [traceSpectra] + @out plotlayout_after = layoutSpectra - # Interface Plot Surface + # Spectrum data + @out xSpectraMz = Vector{Float64}() + @out ySpectraMz = Vector{Float64}() + + # Contour plots layoutContour=PlotlyBase.Layout( - title="2D Topographic map", + title=PlotlyBase.attr( + text="2D Topographic map", + font=PlotlyBase.attr( + family="Roboto, Lato, sans-serif", + size=18, + color="black" + ) + ), xaxis=PlotlyBase.attr( visible=false, scaleanchor="y" @@ -206,16 +562,20 @@ include("./julia_imzML_visual.jl") ), margin=attr(l=0,r=0,t=100,b=0,pad=0) ) - # Dummy 2D surface plot - traceContour=PlotlyBase.scatter(x=[], y=[], mode="lines") - # Create conection to frontend + traceContour=PlotlyBase.contour(x=Vector{Float64}(), y=Vector{Float64}(), mode="lines") @out plotdataC=[traceContour] @out plotlayoutC=layoutContour - # Interface Plot 3d - # Define the layout for the 3D plot + # 3D surface plots layout3D=PlotlyBase.Layout( - title="3D Surface plot", + title=PlotlyBase.attr( + text="3D Surface plot", + font=PlotlyBase.attr( + family="Roboto, Lato, sans-serif", + size=18, + color="black" + ) + ), scene=attr( xaxis_title="X", yaxis_title="Y", @@ -228,645 +588,2538 @@ include("./julia_imzML_visual.jl") ), margin=attr(l=0,r=0,t=120,b=0,pad=0) ) - - # Dummy 3D surface plot x=1:10 y=1:10 z=[sin(i * j / 10) for i in x, j in y] - trace3D=PlotlyBase.surface(x=[], y=[], z=[], + trace3D=PlotlyBase.surface(x=Vector{Float64}(), y=Vector{Float64}(), z=Matrix{Float64}(undef, 0, 0), contours_z=attr( show=true, usecolormap=true, highlightcolor="limegreen", project_z=true ), colorscale="Viridis") - # Create conection to frontend @out plotdata3d=[trace3D] @out plotlayout3d=layout3D + # Interactive plot reactions + @in data_click=Dict{String,Any}() + + # == TIME MEASUREMENT VARIABLES == + @out sTime=time() + @out fTime=time() + @out eTime=time() + + # == DIALOGS AND MESSAGES == + @in warning_msg=false + # == Reactive handlers == # Reactive handlers watch a variable and execute a block of code when its value changes # The onbutton handler will set the variable to false after the block is executed + # This handler correctly uses pick_file and loads the selected file + # as the active dataset for the UI. @onbutton btnSearch begin - full_route=pick_file(; filterlist="imzML,imzml,mzML,mzml") - msg="" - if full_route != "" - if endswith(full_route, "imzml") - alt_route=replace(full_route, r"\.[^.]*$" => ".imzML") - mv(full_route, alt_route) - full_route=alt_route - # to detect if there's an mzml named wrong - alt_routeMz=replace(full_route, r"\.[^.]*$" => ".mzml") - if isfile(alt_routeMz) - alt_routeMz2=replace(alt_routeMz, r"\.[^.]*$" => ".mzML") - mv(alt_routeMz, alt_routeMz2) - alt_routeMz=alt_routeMz2 - end - end - if endswith(full_route, "mzml") - alt_route=replace(full_route, r"\.[^.]*$" => ".mzML") - mv(full_route, alt_route) - full_route = alt_route - # to detect if there's an imzml named wrong - alt_routeMz=replace(full_route, r"\.[^.]*$" => ".imzml") - if isfile(alt_routeMz) - alt_routeMz2=replace(alt_routeMz, r"\.[^.]*$" => ".imzML") - mv(alt_routeMz, alt_routeMz2) - alt_routeMz=alt_routeMz2 - end + is_processing = true + picked_route = pick_file(; filterlist="imzML,imzml,mzML,mzml") + if isempty(picked_route) + is_processing = false + return + end + + # --- Close previous dataset if one is open --- + if msi_data !== nothing + println("DEBUG: Closing previously loaded dataset before opening new one: $(basename(full_route))") + close(msi_data) + msi_data = nothing + GC.gc() + if Sys.islinux() + ccall(:malloc_trim, Int32, (Int32,), 0) end end - if full_route=="" - msg="No file selected" - warning_msg=true - btnStartDisable=true - btnSpectraDisable=true - SpectraEnabled=false - else - if endswith(full_route, "imzML") # Case if the file loaded is imzML - btnStartDisable=false - btnPlotDisable=false - # Splitting the route with regex from imzml to mzml so the plotting can work - full_routeMz=replace(full_route, r"\.[^.]*$" => ".mzML") - if isfile(full_routeMz) - # Start the mean spectrum creation on loading - progressSpectraPlot=true - btnPlotDisable=true - btnStartDisable=true - msg="Loading mean spectrum plot..." - sTime=time() - plotdata, plotlayout, xSpectraMz, ySpectraMz=meanSpectrumPlot(full_routeMz) - selectedTab="tab2" - progressSpectraPlot=false - btnPlotDisable=false - # We enable coord search and spectra plot creation, also re-enable main process - btnSpectraDisable=false - SpectraEnabled=true - btnStartDisable=false + msg = "Opening file: $(basename(picked_route))..." - fTime=time() - eTime=round(fTime-sTime,digits=3) - msg="Plot loaded in $(eTime) seconds" - else - # If there's no mzML file, we deny access again - btnSpectraDisable=true - SpectraEnabled=false + try + dataset_name = replace(basename(picked_route), r"(\.(imzML|imzml|mzML|mzml))$"i => "") + registry = load_registry(registry_path) + existing_entry = get(registry, dataset_name, nothing) + + # --- Fast Load Path --- + is_same_file = (existing_entry !== nothing && existing_entry["source_path"] == picked_route) + if is_same_file && !isempty(get(existing_entry, "metadata", Dict())) + msg = "Fast loading pre-processed file: $(dataset_name)" + println(msg) + + full_route = existing_entry["source_path"] + metadata_rows = existing_entry["metadata"]["summary"] + + dims_str = first(filter(r -> r["parameter"] == "Image Dimensions", metadata_rows))["value"] + dims = parse.(Int, split(dims_str, " x ")) + imgWidth, imgHeight = dims[1], dims[2] + + msi_data = nothing # Ensure data is not held in memory + log_memory_usage("Fast Load (msi_data cleared)", msi_data) + btnMetadataDisable = false + SpectraEnabled = true + selected_folder_main = dataset_name + + # Update folder lists in UI + all_folders = sort(collect(keys(registry)), lt=natural) + img_folders = filter(folder -> get(get(registry, folder, Dict()), "is_imzML", false), all_folders) + available_folders = deepcopy(all_folders) + image_available_folders = deepcopy(img_folders) + + msg = "Successfully loaded pre-processed dataset: $(dataset_name)" + + end + + + # --- Full Load Path --- + + local local_full_route + if endswith(picked_route, r"imzml"i) + local_full_route = replace(picked_route, r"\.imzml$"i => ".imzML") + if picked_route != local_full_route + mv(picked_route, local_full_route, force=true) end - else # Case if the file loaded is mzML - full_routeMz=full_route - btnSpectraDisable=false - SpectraEnabled=true - if isfile(full_routeMz) - # Start the mean spectrum creation on loading - progressSpectraPlot=true - btnPlotDisable=true - btnStartDisable=true - msg="Loading mean spectrum plot..." - sTime=time() - plotdata, plotlayout, xSpectraMz, ySpectraMz=meanSpectrumPlot(full_routeMz) - selectedTab="tab2" - progressSpectraPlot=false - btnPlotDisable=false + else + local_full_route = picked_route + end + full_route = local_full_route - # We enable coord search and spectra plot creation - btnSpectraDisable=false - SpectraEnabled=true + sTime = time() + loaded_data = OpenMSIData(local_full_route) + is_imzML = loaded_data.source isa ImzMLSource - fTime=time() - eTime=round(fTime-sTime,digits=3) - msg="Plot loaded in $(eTime) seconds" + if existing_entry == nothing + msg = "Performing first-time metadata analysis for: $(basename(picked_route))..." + precompute_analytics(loaded_data) + end + + # Auto-suggest parameters + try + println("Calling main_precalculation to get recommended parameters...") + recommended_params = main_precalculation(loaded_data) + + + for (step_name, params) in recommended_params + for (param_key, value) in params + # Convert value to appropriate type before assignment + processed_value = if value === nothing + nothing + elseif value isa Tuple + @warn "Skipping invalid parameter suggestion (tuple): $value for $param_key" + "" # Set to empty string for safety + elseif value isa Number + value + else + string(value) + end + + if processed_value !== nothing + if step_name == :Smoothing + if param_key == :window + suggested_smoothing_window = string(processed_value) + smoothing_window = string(processed_value) + println(" suggested_smoothing_window set to $(suggested_smoothing_window)") + elseif param_key == :order + suggested_smoothing_order = string(processed_value) + smoothing_order = string(processed_value) + println(" suggested_smoothing_order set to $(suggested_smoothing_order)") + end + elseif step_name == :BaselineCorrection + if param_key == :iterations + suggested_baseline_iterations = string(processed_value) + baseline_iterations = string(processed_value) + println(" suggested_baseline_iterations set to $(suggested_baseline_iterations)") + elseif param_key == :window + suggested_baseline_window = string(processed_value) + baseline_window = string(processed_value) + println(" suggested_baseline_window set to $(suggested_baseline_window)") + end + elseif step_name == :PeakAlignment + if param_key == :span + suggested_alignment_span = string(processed_value) + alignment_span = string(processed_value) + println(" suggested_alignment_span set to $(suggested_alignment_span)") + elseif param_key == :tolerance + suggested_alignment_tolerance = string(processed_value) + alignment_tolerance = string(processed_value) + println(" suggested_alignment_tolerance set to $(suggested_alignment_tolerance)") + elseif param_key == :max_shift_ppm + suggested_alignment_max_shift_ppm = string(processed_value) + alignment_max_shift_ppm = string(processed_value) + println(" suggested_alignment_max_shift_ppm set to $(suggested_alignment_max_shift_ppm)") + elseif param_key == :min_matched_peaks + suggested_alignment_min_matched_peaks = string(processed_value) + alignment_min_matched_peaks = string(processed_value) + println(" suggested_alignment_min_matched_peaks set to $(suggested_alignment_min_matched_peaks)") + end + elseif step_name == :Calibration + if param_key == :fit_order + suggested_calibration_fit_order = string(processed_value) + calibration_fit_order = string(processed_value) + println(" suggested_calibration_fit_order set to $(suggested_calibration_fit_order)") + elseif param_key == :ppm_tolerance + suggested_calibration_ppm_tolerance = string(processed_value) + calibration_ppm_tolerance = string(processed_value) + println(" suggested_calibration_ppm_tolerance set to $(suggested_calibration_ppm_tolerance)") + end + elseif step_name == :PeakPicking + if param_key == :snr_threshold + suggested_peak_picking_snr_threshold = string(processed_value) + peak_picking_snr_threshold = string(processed_value) + println(" suggested_peak_picking_snr_threshold set to $(suggested_peak_picking_snr_threshold)") + elseif param_key == :half_window + suggested_peak_picking_half_window = string(processed_value) + peak_picking_half_window = string(processed_value) + println(" suggested_peak_picking_half_window set to $(suggested_peak_picking_half_window)") + elseif param_key == :min_peak_prominence + suggested_peak_picking_min_peak_prominence = string(processed_value) + peak_picking_min_peak_prominence = string(processed_value) + println(" suggested_peak_picking_min_peak_prominence set to $(suggested_peak_picking_min_peak_prominence)") + elseif param_key == :merge_peaks_tolerance + suggested_peak_picking_merge_peaks_tolerance = string(processed_value) + peak_picking_merge_peaks_tolerance = string(processed_value) + println(" suggested_peak_picking_merge_peaks_tolerance set to $(suggested_peak_picking_merge_peaks_tolerance)") + elseif param_key == :min_peak_width_ppm + suggested_peak_picking_min_peak_width_ppm = string(processed_value) + peak_picking_min_peak_width_ppm = string(processed_value) + println(" suggested_peak_picking_min_peak_width_ppm set to $(suggested_peak_picking_min_peak_width_ppm)") + elseif param_key == :max_peak_width_ppm + suggested_peak_picking_max_peak_width_ppm = string(processed_value) + peak_picking_max_peak_width_ppm = string(processed_value) + println(" suggested_peak_picking_max_peak_width_ppm set to $(suggested_peak_picking_max_peak_width_ppm)") + elseif param_key == :min_peak_shape_r2 + suggested_peak_picking_min_peak_shape_r2 = string(processed_value) + peak_picking_min_peak_shape_r2 = string(processed_value) + println(" suggested_peak_picking_min_peak_shape_r2 set to $(suggested_peak_picking_min_peak_shape_r2)") + end + elseif step_name == :PeakSelection + if param_key == :min_snr + suggested_peak_selection_min_snr = string(processed_value) + peak_selection_min_snr = string(processed_value) + println(" suggested_peak_selection_min_snr set to $(suggested_peak_selection_min_snr)") + elseif param_key == :min_fwhm_ppm + suggested_peak_selection_min_fwhm_ppm = string(processed_value) + peak_selection_min_fwhm_ppm = string(processed_value) + println(" suggested_peak_selection_min_fwhm_ppm set to $(suggested_peak_selection_min_fwhm_ppm)") + elseif param_key == :max_fwhm_ppm + suggested_peak_selection_max_fwhm_ppm = string(processed_value) + peak_selection_max_fwhm_ppm = string(processed_value) + println(" suggested_peak_selection_max_fwhm_ppm set to $(suggested_peak_selection_max_fwhm_ppm)") + elseif param_key == :min_shape_r2 + suggested_peak_selection_min_shape_r2 = string(processed_value) + peak_selection_min_shape_r2 = string(processed_value) + println(" suggested_peak_selection_min_shape_r2 set to $(suggested_peak_selection_min_shape_r2)") + elseif param_key == :frequency_threshold + suggested_peak_selection_frequency_threshold = string(processed_value) + peak_selection_frequency_threshold = string(processed_value) + println(" suggested_peak_selection_frequency_threshold set to $(suggested_peak_selection_frequency_threshold)") + elseif param_key == :correlation_threshold + suggested_peak_selection_correlation_threshold = string(processed_value) + peak_selection_correlation_threshold = string(processed_value) + println(" suggested_peak_selection_correlation_threshold set to $(suggested_peak_selection_correlation_threshold)") + end + elseif step_name == :PeakBinning + if param_key == :tolerance + suggested_binning_tolerance = string(processed_value) + binning_tolerance = string(processed_value) + println(" suggested_binning_tolerance set to $(suggested_binning_tolerance)") + elseif param_key == :frequency_threshold + suggested_binning_frequency_threshold = string(processed_value) + binning_frequency_threshold = string(processed_value) + println(" suggested_binning_frequency_threshold set to $(suggested_binning_frequency_threshold)") + elseif param_key == :min_peak_per_bin + suggested_binning_min_peak_per_bin = string(processed_value) + binning_min_peak_per_bin = string(processed_value) + println(" suggested_binning_min_peak_per_bin set to $(suggested_binning_min_peak_per_bin)") + elseif param_key == :max_bin_width_ppm + suggested_binning_max_bin_width_ppm = string(processed_value) + binning_max_bin_width_ppm = string(processed_value) + println(" suggested_binning_max_bin_width_ppm set to $(suggested_binning_max_bin_width_ppm)") + elseif param_key == :num_uniform_bins + suggested_binning_num_uniform_bins = string(processed_value) + binning_num_uniform_bins = string(processed_value) + println(" suggested_binning_num_uniform_bins set to $(suggested_binning_num_uniform_bins)") + end + end + end + end end - # Splitting the route the same way - full_route=replace(full_route, r"\.[^.]*$" => ".imzML") - if isfile(full_route) - btnStartDisable=false + + # Also set method types for steps + if haskey(recommended_params, :Smoothing) && haskey(recommended_params[:Smoothing], :method) + smoothing_method = string(recommended_params[:Smoothing][:method]) + end + if haskey(recommended_params, :BaselineCorrection) && haskey(recommended_params[:BaselineCorrection], :method) + baseline_method = string(recommended_params[:BaselineCorrection][:method]) + end + if haskey(recommended_params, :Normalization) && haskey(recommended_params[:Normalization], :method) + normalization_method = string(recommended_params[:Normalization][:method]) + end + if haskey(recommended_params, :PeakAlignment) && haskey(recommended_params[:PeakAlignment], :method) + alignment_method = string(recommended_params[:PeakAlignment][:method]) + end + if haskey(recommended_params, :PeakPicking) && haskey(recommended_params[:PeakPicking], :method) + peak_picking_method = string(recommended_params[:PeakPicking][:method]) + end + if haskey(recommended_params, :PeakBinning) && haskey(recommended_params[:PeakBinning], :method) + binning_method = string(recommended_params[:PeakBinning][:method]) + end + if haskey(recommended_params, :PeakAlignment) && haskey(recommended_params[:PeakAlignment], :tolerance_unit) + alignment_tolerance_unit = string(recommended_params[:PeakAlignment][:tolerance_unit]) + end + if haskey(recommended_params, :PeakBinning) && haskey(recommended_params[:PeakBinning], :tolerance_unit) + binning_tolerance_unit = string(recommended_params[:PeakBinning][:tolerance_unit]) + end + + msg = "File loaded and parameters suggested." + catch e + @warn "Could not suggest parameters. Using defaults. Error: $e" + end + + metadata_columns = [ + Dict("name" => "parameter", "label" => "Parameter", "field" => "parameter", "align" => "left"), + Dict("name" => "value", "label" => "Value", "field" => "value", "align" => "left"), + ] + summary_stats = extract_metadata(loaded_data, local_full_route) + metadata_rows = summary_stats["summary"] + btnMetadataDisable = isempty(metadata_rows) + + w, h = loaded_data.image_dims + imgWidth, imgHeight = w > 0 ? (w, h) : (500, 500) + + update_registry(registry_path, dataset_name, local_full_route, summary_stats, is_imzML) + + # Update folder lists in UI + registry = load_registry(registry_path) + all_folders = sort(collect(keys(registry)), lt=natural) + img_folders = filter(folder -> get(get(registry, folder, Dict()), "is_imzML", false), all_folders) + available_folders = deepcopy(all_folders) + image_available_folders = deepcopy(img_folders) + + selected_folder_main = dataset_name + msi_data = loaded_data + + # Determine plot mode from loaded data + df = msi_data.spectrum_stats_df + if df !== nothing && "Mode" in names(df) + profile_count = count(==(MSI_src.PROFILE), df.Mode) + total_count = length(df.Mode) + last_plot_mode = profile_count > total_count / 2 ? "lines" : "stem" + println("DEBUG: Auto-detected plot mode: $(last_plot_mode)") + else + last_plot_mode = "lines" # Default + end + + log_memory_usage("Full Load", msi_data) + + eTime = round(time() - sTime, digits=3) + msg = "Active file loaded in $(eTime) seconds. Dataset '$(dataset_name)' is ready for analysis." + + SpectraEnabled = true + + catch e + msi_data = nothing + msg = "Error loading active file: $e" + warning_msg = true + SpectraEnabled = false + btnMetadataDisable = true + @error "File loading failed" exception=(e, catch_backtrace()) + finally + GC.gc() # Trigger garbage collection + if Sys.islinux() + ccall(:malloc_trim, Int32, (Int32,), 0) # Ensure Julia returns the freed memory to OS + end + is_processing = false + end + end + + @onbutton export_params_btn begin + is_processing = true + params_to_export = Dict( + "pipeline_step_order" => pipeline_step_order, + "enable_standards" => enable_standards, # Export global flag + "stabilization_method" => stabilization_method, + "smoothing_method" => smoothing_method, + "smoothing_window" => smoothing_window, + "smoothing_order" => smoothing_order, + "baseline_method" => baseline_method, + "baseline_iterations" => baseline_iterations, + "baseline_window" => baseline_window, + "normalization_method" => normalization_method, + "alignment_method" => alignment_method, + "alignment_span" => alignment_span, + "alignment_tolerance" => alignment_tolerance, + "alignment_tolerance_unit" => alignment_tolerance_unit, + "alignment_max_shift_ppm" => alignment_max_shift_ppm, + "alignment_min_matched_peaks" => alignment_min_matched_peaks, + "peak_picking_method" => peak_picking_method, + "peak_picking_snr_threshold" => peak_picking_snr_threshold, + "peak_picking_half_window" => peak_picking_half_window, + "peak_picking_min_peak_prominence" => peak_picking_min_peak_prominence, + "peak_picking_merge_peaks_tolerance" => peak_picking_merge_peaks_tolerance, + "peak_picking_min_peak_width_ppm" => peak_picking_min_peak_width_ppm, + "peak_picking_max_peak_width_ppm" => peak_picking_max_peak_width_ppm, + "peak_picking_min_peak_shape_r2" => peak_picking_min_peak_shape_r2, + "binning_method" => binning_method, + "binning_tolerance" => binning_tolerance, + "binning_tolerance_unit" => binning_tolerance_unit, + "binning_frequency_threshold" => binning_frequency_threshold, + "binning_min_peak_per_bin" => binning_min_peak_per_bin, + "binning_max_bin_width_ppm" => binning_max_bin_width_ppm, + "binning_intensity_weighted_centers" => binning_intensity_weighted_centers, + "binning_num_uniform_bins" => binning_num_uniform_bins, + "calibration_fit_order" => calibration_fit_order, + "calibration_ppm_tolerance" => calibration_ppm_tolerance, + "peak_selection_min_snr" => peak_selection_min_snr, + "peak_selection_min_fwhm_ppm" => peak_selection_min_fwhm_ppm, + "peak_selection_max_fwhm_ppm" => peak_selection_max_fwhm_ppm, + "peak_selection_min_shape_r2" => peak_selection_min_shape_r2, + "peak_selection_frequency_threshold" => peak_selection_frequency_threshold, + "peak_selection_correlation_threshold" => peak_selection_correlation_threshold, + "reference_peaks_list" => reference_peaks_list + ) + + # 1. Generate the JSON string + json_string = JSON.json(params_to_export) + + # 2. ESCAPING (Crucial for stability) + # We must escape backslashes (for Windows paths) and single quotes + # so they don't break the JavaScript string literal. + safe_json = replace(json_string, "\\" => "\\\\") + safe_json = replace(safe_json, "'" => "\\'") + + # 3. Create the JavaScript payload + # We inject 'safe_json' into the JS 'encodeURIComponent' + js_script = """ + var element = document.createElement('a'); + element.setAttribute('href', 'data:text/json;charset=utf-8,' + encodeURIComponent('$safe_json')); + element.setAttribute('download', 'preprocessing_params.json'); + element.style.display = 'none'; + document.body.appendChild(element); + element.click(); + document.body.removeChild(element); + """ + + # 4. Execute on the client + run(__model__, js_script) + is_processing = false + msg = "Parameters exported." + end + + @onbutton import_params_btn begin + is_processing = true + picked_file = pick_file(filterlist="json") + if isempty(picked_file) + is_processing = false + return + end + + try + json_string = read(picked_file, String) + params = JSON.parse(json_string) + + # This is a list of all known reactive variables that can be imported. + # This prevents arbitrary variable assignment. + known_params = [ + "stabilization_method", "smoothing_method", "smoothing_window", "smoothing_order", + "baseline_method", "baseline_iterations", "baseline_window", "normalization_method", + "alignment_method", "alignment_span", "alignment_tolerance", "alignment_tolerance_unit", + "alignment_max_shift_ppm", "alignment_min_matched_peaks", "peak_picking_method", + "peak_picking_snr_threshold", "peak_picking_half_window", "peak_picking_min_peak_prominence", + "peak_picking_merge_peaks_tolerance", "peak_picking_min_peak_width_ppm", + "peak_picking_max_peak_width_ppm", "peak_picking_min_peak_shape_r2", "binning_method", + "binning_tolerance", "binning_tolerance_unit", "binning_frequency_threshold", + "binning_min_peak_per_bin", "binning_max_bin_width_ppm", "binning_intensity_weighted_centers", + "binning_num_uniform_bins", "calibration_fit_order", "calibration_ppm_tolerance", + "peak_selection_min_snr", "peak_selection_min_fwhm_ppm", "peak_selection_max_fwhm_ppm", + "peak_selection_min_shape_r2", "peak_selection_frequency_threshold", "peak_selection_correlation_threshold" + ] + + for (key, value) in params + if key == "reference_peaks_list" + reference_peaks_list = value + elseif key == "pipeline_step_order" + pipeline_step_order = value + elseif key == "enable_standards" + enable_standards = value + elseif key in known_params + # Use getfield and setproperty! to update reactive variables by name + if hasfield(typeof(@__MODULE__), Symbol(key)) + getfield(@__MODULE__, Symbol(key))[] = value + end else - btnStartDisable=true - full_route=full_routeMz + @warn "Unknown parameter '$key' found in JSON file. Skipping." end end - xCoord=0 - yCoord=0 + msg = "Parameters imported successfully from $(basename(picked_file))." + catch e + msg = "Failed to import parameters: $e" + warning_msg = true + @error "Parameter import failed" exception=(e, catch_backtrace()) + end + is_processing = false + end + + @onbutton export_standards_btn begin + is_processing = true + json_string = JSON.json(reference_peaks_list) + safe_json = replace(json_string, "\\" => "\\\\") + safe_json = replace(safe_json, "'" => "\\'") + js_script = """ + var element = document.createElement('a'); + element.setAttribute('href', 'data:text/json;charset=utf-8,' + encodeURIComponent('$safe_json')); + element.setAttribute('download', 'internal_standards.json'); + element.style.display = 'none'; + document.body.appendChild(element); + element.click(); + document.body.removeChild(element); + """ + run(__model__, js_script) + is_processing = false + msg = "Internal standards exported." + end + + @onbutton import_standards_btn begin + is_processing = true + picked_file = pick_file(filterlist="json") + if isempty(picked_file) + return + end + + try + json_string = read(picked_file, String) + new_standards = JSON.parse(json_string) + # Basic validation + if new_standards isa Vector && all(p -> p isa Dict && haskey(p, "mz") && haskey(p, "label"), new_standards) + reference_peaks_list = new_standards + msg = "Internal standards imported successfully from $(basename(picked_file))." + else + msg = "Invalid format for internal standards file." + warning_msg = true + end + catch e + msg = "Failed to import internal standards: $e" + warning_msg = true + @error "Standards import failed" exception=(e, catch_backtrace()) + end + is_processing = false + end + + @onbutton run_full_pipeline begin + is_processing = true + current_pipeline_step = "Initializing..." + println("DEBUG: run_full_pipeline started.") + # println("DEBUG: Current pipeline_step_order configuration: $pipeline_step_order") + + try + # --- 1. Initial Checks and Data Loading --- + println("DEBUG: Performing initial checks and data loading...") + if isempty(selected_folder_main) + msg = "No dataset loaded. Please load a file using 'Select an imzMl / mzML file'." + warning_msg = true + println("DEBUG: $msg") + is_processing = false + return + end + + registry = load_registry(registry_path) + entry = get(registry, selected_folder_main, nothing) + if entry === nothing + msg = "Selected dataset '$(selected_folder_main)' not found in registry. Please reload the file." + warning_msg = true + println("DEBUG: $msg") + return + end + target_path = entry["source_path"] + + # Ensure msi_data is for the currently selected file and load if needed + if msi_data === nothing || full_route != target_path + println("DEBUG: Active file path changed or data not in memory. Reloading MSI data: $(basename(target_path))") + if msi_data !== nothing; close(msi_data); end + msg = "Reloading $(basename(target_path)) for analysis..." + full_route = target_path + msi_data = OpenMSIData(target_path) + + # Determine plot mode from loaded data + df = msi_data.spectrum_stats_df + if df !== nothing && "Mode" in names(df) + profile_count = count(==(MSI_src.PROFILE), df.Mode) + total_count = length(df.Mode) + last_plot_mode = profile_count > total_count / 2 ? "lines" : "stem" + println("DEBUG: Auto-detected plot mode for pipeline: $(last_plot_mode)") + else + last_plot_mode = "lines" # Default + end + else + println("DEBUG: Using already loaded MSI data for $(basename(target_path)).") + end + + # Mask path retrieval from registry + local mask_path_for_pipeline::Union{String, Nothing} = nothing + if maskEnabled + println("DEBUG: Masking is ENABLED.") + if get(entry, "has_mask", false) + mask_path_candidate = get(entry, "mask_path", "") + if isfile(mask_path_candidate) + mask_path_for_pipeline = mask_path_candidate + println("DEBUG: Using mask for pipeline: $(mask_path_for_pipeline)") + else + msg = "Mask enabled but file not found: $(mask_path_candidate). Aborting pipeline." + warning_msg = true + @warn msg + println("DEBUG: $msg") + return + end + else + msg = "Mask enabled but no valid mask entry found for: $(selected_folder_main). Aborting pipeline." + warning_msg = true + @warn msg + println("DEBUG: $msg") + return + end + else + println("DEBUG: Masking is DISABLED. No mask will be applied.") + end + + # Apply mask if enabled to get indices to process + spectrum_indices_to_process = collect(1:length(msi_data.spectra_metadata)) + if mask_path_for_pipeline !== nothing + current_pipeline_step = "Applying mask..." + println("DEBUG: Applying mask matrix to filter spectra...") + mask_matrix = load_and_prepare_mask(mask_path_for_pipeline, msi_data.image_dims) + masked_indices_set = get_masked_spectrum_indices(msi_data, mask_matrix) + spectrum_indices_to_process = collect(masked_indices_set) + if isempty(spectrum_indices_to_process) + msg = "No spectra remaining after applying mask. Aborting pipeline." + warning_msg = true + println("DEBUG: $msg") + return + end + println("DEBUG: $(length(spectrum_indices_to_process)) spectra remaining after mask application.") + else + println("DEBUG: No mask applied. Processing all $(length(msi_data.spectra_metadata)) spectra.") + end + + # Apply subset processing if enabled + if enable_subset_processing && spectra_subset_size > 0 + n_total = length(spectrum_indices_to_process) + n_to_process = min(spectra_subset_size, n_total) + spectrum_indices_to_process = spectrum_indices_to_process[1:n_to_process] + println("DEBUG: Subset processing enabled. Processing first $(length(spectrum_indices_to_process)) of $n_total spectra.") + end + + # Initialize spectra data structure + current_pipeline_step = "Loading spectra..." + println("DEBUG: Loading $(length(spectrum_indices_to_process)) spectra into MutableSpectrum objects...") + current_spectra = Vector{MutableSpectrum}(undef, length(spectrum_indices_to_process)) + + Threads.@threads for i in 1:length(spectrum_indices_to_process) + original_idx = spectrum_indices_to_process[i] + mz, intensity = GetSpectrum(msi_data, original_idx) # Fetch mz and intensity for the current spectrum + current_spectra[i] = MutableSpectrum(original_idx, copy(Float64.(mz)), copy(Float64.(intensity)), NamedTuple{(:mz, :intensity, :fwhm, :shape_r2, :snr, :prominence), NTuple{6, Float64}}[]) + end + println("DEBUG: All spectra loaded into temporary structure for processing.") + + + # --- 2. Parameter Assembly with Validation --- + current_pipeline_step = "Configuring parameters..." + println("DEBUG: Configuring parameters and validating enabled steps...") + ref_peaks = Dict{Float64, String}(p["mz"] => p["label"] for p in reference_peaks_list) + + final_params = Dict{Symbol, Dict{Symbol, Any}}() + validation_errors = String[] + + # --- Stabilization --- + println("DEBUG: Checking Stabilization step (name: stabilization)") + if is_step_enabled("stabilization", pipeline_step_order) + println("DEBUG: Stabilization step is ENABLED. Setting method: $(stabilization_method).") + final_params[:Stabilization] = Dict{Symbol, Any}(:method => Symbol(stabilization_method)) + else + println("DEBUG: Stabilization step is DISABLED. Skipping.") + end + + # --- Smoothing --- + println("DEBUG: Checking Smoothing step (name: smoothing)") + if is_step_enabled("smoothing", pipeline_step_order) + println("DEBUG: Smoothing step is ENABLED. Validating parameters.") + window_val = validate_parse(validation_errors, smoothing_window, "Window", Int, "Smoothing") + order_val = validate_parse(validation_errors, smoothing_order, "Order", Int, "Smoothing") + final_params[:Smoothing] = Dict{Symbol, Any}( + :method => Symbol(smoothing_method), + :window => something(window_val, 9), + :order => something(order_val, 2) + ) + if window_val !== nothing && window_val < 1 + push!(validation_errors, "(Smoothing) Window must be positive.") + end + if order_val !== nothing && order_val < 0 + push!(validation_errors, "(Smoothing) Order must be non-negative.") + end + println("DEBUG: Smoothing parameters set: method=$(smoothing_method), window=$(something(window_val, 9)), order=$(something(order_val, 2)).") + else + println("DEBUG: Smoothing step is DISABLED. Skipping parameter validation.") + end + + # --- Baseline Correction --- + println("DEBUG: Checking Baseline Correction step (name: baseline_correction)") + if is_step_enabled("baseline_correction", pipeline_step_order) + println("DEBUG: Baseline Correction step is ENABLED. Validating parameters.") + iterations_val = validate_parse(validation_errors, baseline_iterations, "Iterations", Int, "Baseline Correction") + baseline_window_val = validate_parse(validation_errors, baseline_window, "Window", Int, "Baseline Correction") + final_params[:BaselineCorrection] = Dict{Symbol, Any}( + :method => Symbol(baseline_method), + :iterations => something(iterations_val, 100), + :window => something(baseline_window_val, 20) + ) + if iterations_val !== nothing && iterations_val < 0 + push!(validation_errors, "(Baseline Correction) Iterations must be non-negative.") + end + if baseline_window_val !== nothing && baseline_window_val < 1 + push!(validation_errors, "(Baseline Correction) Window must be positive.") + end + println("DEBUG: Baseline Correction parameters set: method=$(baseline_method), iterations=$(something(iterations_val, 100)), window=$(something(baseline_window_val, 20)).") + else + println("DEBUG: Baseline Correction step is DISABLED. Skipping parameter validation.") + end + + # --- Normalization --- + println("DEBUG: Checking Normalization step (name: normalization)") + if is_step_enabled("normalization", pipeline_step_order) + println("DEBUG: Normalization step is ENABLED. Setting method: $(normalization_method).") + final_params[:Normalization] = Dict{Symbol, Any}(:method => Symbol(normalization_method)) + else + println("DEBUG: Normalization step is DISABLED. Skipping.") + end + + + # --- Peak Picking --- + println("DEBUG: Checking Peak Picking step (name: peak_picking)") + if is_step_enabled("peak_picking", pipeline_step_order) + println("DEBUG: Peak Picking step is ENABLED. Validating parameters.") + snr_threshold_val = validate_parse(validation_errors, peak_picking_snr_threshold, "SNR Threshold", Float64, "Peak Picking") + half_window_val = validate_parse(validation_errors, peak_picking_half_window, "Half Window", Int, "Peak Picking") + min_peak_prominence_val = validate_parse(validation_errors, peak_picking_min_peak_prominence, "Min Prominence", Float64, "Peak Picking") + merge_peaks_tolerance_val = validate_parse(validation_errors, peak_picking_merge_peaks_tolerance, "Merge Tolerance", Float64, "Peak Picking") + final_params[:PeakPicking] = Dict{Symbol, Any}( + :method => Symbol(peak_picking_method), + :snr_threshold => something(snr_threshold_val, 3.0), + :half_window => something(half_window_val, 10), + :min_peak_prominence => something(min_peak_prominence_val, 0.1), + :merge_peaks_tolerance => something(merge_peaks_tolerance_val, 0.002) + ) + if snr_threshold_val !== nothing && snr_threshold_val < 0 + push!(validation_errors, "(Peak Picking) SNR Threshold must be non-negative.") + end + if half_window_val !== nothing && half_window_val < 1 + push!(validation_errors, "(Peak Picking) Half Window must be positive.") + end + if min_peak_prominence_val !== nothing && (min_peak_prominence_val < 0 || min_peak_prominence_val > 1) + push!(validation_errors, "(Peak Picking) Min Prominence must be between 0 and 1.") + end + if merge_peaks_tolerance_val !== nothing && merge_peaks_tolerance_val < 0 + push!(validation_errors, "(Peak Picking) Merge Tolerance must be non-negative.") + end + println("DEBUG: Peak Picking parameters set: method=$(peak_picking_method), snr_threshold=$(something(snr_threshold_val, 3.0)), half_window=$(something(half_window_val, 10))...") + else + println("DEBUG: Peak Picking step is DISABLED. Skipping parameter validation.") + end + + # --- Peak Selection --- + println("DEBUG: Checking Peak Selection step (name: peak_selection)") + if is_step_enabled("peak_selection", pipeline_step_order) + println("DEBUG: Peak Selection step is ENABLED. Validating parameters.") + min_snr_val = validate_parse(validation_errors, peak_selection_min_snr, "Min SNR", Float64, "Peak Selection") + min_fwhm_ppm_val = validate_parse(validation_errors, peak_selection_min_fwhm_ppm, "Min FWHM", Float64, "Peak Selection") + max_fwhm_ppm_val = validate_parse(validation_errors, peak_selection_max_fwhm_ppm, "Max FWHM", Float64, "Peak Selection") + min_shape_r2_val = validate_parse(validation_errors, peak_selection_min_shape_r2, "Min Shape R2", Float64, "Peak Selection") + final_params[:PeakSelection] = Dict{Symbol, Any}( + :min_snr => something(min_snr_val, 0.0), + :min_fwhm_ppm => something(min_fwhm_ppm_val, 0.0), + :max_fwhm_ppm => something(max_fwhm_ppm_val, Inf), + :min_shape_r2 => something(min_shape_r2_val, 0.0) + ) + if min_snr_val !== nothing && min_snr_val < 0 + push!(validation_errors, "(Peak Selection) Min SNR must be non-negative.") + end + if min_fwhm_ppm_val !== nothing && min_fwhm_ppm_val < 0 + push!(validation_errors, "(Peak Selection) Min FWHM must be non-negative.") + end + if max_fwhm_ppm_val !== nothing && max_fwhm_ppm_val < 0 + push!(validation_errors, "(Peak Selection) Max FWHM must be non-negative.") + end + if min_shape_r2_val !== nothing && (min_shape_r2_val < 0 || min_shape_r2_val > 1) + push!(validation_errors, "(Peak Selection) Min Shape R2 must be between 0 and 1.") + end + println("DEBUG: Peak Selection parameters set: min_snr=$(something(min_snr_val, 0.0)), min_fwhm_ppm=$(something(min_fwhm_ppm_val, 0.0))...") + else + println("DEBUG: Peak Selection step is DISABLED. Skipping parameter validation.") + end + + + # --- Calibration --- + println("DEBUG: Checking Calibration step (name: calibration)") + if is_step_enabled("calibration", pipeline_step_order) + println("DEBUG: Calibration step is ENABLED. Validating parameters.") + ppm_tolerance_cal_val = validate_parse(validation_errors, calibration_ppm_tolerance, "PPM Tolerance", Float64, "Calibration") + fit_order_val = validate_parse(validation_errors, calibration_fit_order, "Fit Order", Int, "Calibration") + final_params[:Calibration] = Dict{Symbol, Any}( + :method => :internal_standards, # Fixed method + :ppm_tolerance => something(ppm_tolerance_cal_val, 20.0), + :fit_order => something(fit_order_val, 1) # Default to linear + ) + if ppm_tolerance_cal_val !== nothing && ppm_tolerance_cal_val < 0 + push!(validation_errors, "(Calibration) PPM Tolerance must be non-negative.") + end + if fit_order_val !== nothing && (fit_order_val < 0 || fit_order_val > 2) + push!(validation_errors, "(Calibration) Fit Order must be 0, 1, or 2.") + end + if enable_standards && isempty(ref_peaks) + push!(validation_errors, "(Calibration) Internal Standards are enabled, but no reference peaks are defined.") + end + println("DEBUG: Calibration parameters set: ppm_tolerance=$(something(ppm_tolerance_cal_val, 20.0)), fit_order=$(something(fit_order_val, 1)).") + else + println("DEBUG: Calibration step is DISABLED. Skipping parameter validation.") + end + + + # --- Peak Alignment --- + println("DEBUG: Checking Peak Alignment step (name: peak_alignment)") + if is_step_enabled("peak_alignment", pipeline_step_order) + println("DEBUG: Peak Alignment step is ENABLED. Validating parameters.") + alignment_tolerance_val = validate_parse(validation_errors, alignment_tolerance, "Tolerance", Float64, "Peak Alignment") + final_params[:PeakAlignment] = Dict{Symbol, Any}( + :method => Symbol(alignment_method), + :tolerance => something(alignment_tolerance_val, 0.002), + :tolerance_unit => Symbol(alignment_tolerance_unit) + ) + if alignment_tolerance_val !== nothing && alignment_tolerance_val < 0 + push!(validation_errors, "(Peak Alignment) Tolerance must be non-negative.") + end + println("DEBUG: Peak Alignment parameters set: method=$(alignment_method), tolerance=$(something(alignment_tolerance_val, 0.002)), tolerance_unit=$(alignment_tolerance_unit).") + else + println("DEBUG: Peak Alignment step is DISABLED. Skipping parameter validation.") + end + + + # --- Peak Binning --- + println("DEBUG: Checking Peak Binning step (name: peak_binning)") + if is_step_enabled("peak_binning", pipeline_step_order) + println("DEBUG: Peak Binning step is ENABLED. Validating parameters.") + binning_tolerance_val = validate_parse(validation_errors, binning_tolerance, "Tolerance", Float64, "Peak Binning") + min_peak_per_bin_val = validate_parse(validation_errors, binning_min_peak_per_bin, "Min Peaks Per Bin", Int, "Peak Binning") + final_params[:PeakBinning] = Dict{Symbol, Any}( + :method => Symbol(binning_method), + :tolerance => something(binning_tolerance_val, 20.0), + :tolerance_unit => Symbol(binning_tolerance_unit), + :min_peak_per_bin => something(min_peak_per_bin_val, 3) + ) + if binning_tolerance_val !== nothing && binning_tolerance_val < 0 + push!(validation_errors, "(Peak Binning) Tolerance must be non-negative.") + end + if min_peak_per_bin_val !== nothing && min_peak_per_bin_val < 1 + push!(validation_errors, "(Peak Binning) Min Peaks Per Bin must be positive.") + end + println("DEBUG: Peak Binning parameters set: method=$(binning_method), tolerance=$(something(binning_tolerance_val, 20.0)), min_peak_per_bin=$(something(min_peak_per_bin_val, 3))...") + else + println("DEBUG: Peak Binning step is DISABLED. Skipping parameter validation.") + end + + + if !isempty(validation_errors) + msg = "Pipeline setup errors:\n" * join(validation_errors, "\n") + warning_msg = true + println("DEBUG: Validation errors encountered: $validation_errors") + return + end + + # Build pipeline steps from enabled steps in order + pipeline_stp = [step["name"] for step in pipeline_step_order if step["enabled"]] + println("DEBUG: Final enabled pipeline steps to execute: $pipeline_stp") + + # 3. Execute Pipeline + current_pipeline_step = "Running preprocessing pipeline..." + println("DEBUG: Starting pipeline execution with $(length(pipeline_stp)) enabled steps.") + feature_matrix_result, bin_info_result = execute_full_preprocessing( + current_spectra, + final_params, + pipeline_stp, + ref_peaks, + mask_path_for_pipeline + ) do step + current_pipeline_step = "Processing: $step" + println("DEBUG: Processing step: $step") + end + println("DEBUG: Pipeline execution finished.") + + # 4. Update Results Display + current_pipeline_step = "Updating results..." + subset_label = enable_subset_processing ? " (from subset of $(length(current_spectra)) spectra)" : "" + println("DEBUG: Updating results display after pipeline completion for plot type: $(last_plot_type), mode: $(last_plot_mode)") + + if last_plot_type == "single" + display_spectrum_idx = findfirst(s -> s.id == selected_spectrum_id_for_plot, current_spectra) + if display_spectrum_idx !== nothing + processed_spectrum = current_spectra[display_spectrum_idx] + println("DEBUG: Displaying spectrum $(selected_spectrum_id_for_plot) after processing.") + + # Determine plot mode for this specific spectrum + spectrum_mode_for_plot = "lines" # Default to lines + if msi_data.spectrum_stats_df !== nothing && "Mode" in names(msi_data.spectrum_stats_df) + if selected_spectrum_id_for_plot > 0 && selected_spectrum_id_for_plot <= length(msi_data.spectrum_stats_df.Mode) + mode = msi_data.spectrum_stats_df.Mode[selected_spectrum_id_for_plot] + if mode == MSI_src.CENTROID + spectrum_mode_for_plot = "stem" + end + end + end + + mz_down, int_down = downsample_spectrum(processed_spectrum.mz, processed_spectrum.intensity) + + local after_trace + if spectrum_mode_for_plot == "stem" + after_trace = PlotlyBase.stem( + x=mz_down, + y=int_down, + name="Processed Spectrum", + marker=attr(size=1, color="blue", opacity=0) + ) + else # lines + after_trace = PlotlyBase.scatter( + x=mz_down, + y=int_down, + mode="lines", + name="Processed Spectrum" + ) + end + + traces_after = [after_trace] + + if !isempty(processed_spectrum.peaks) + peak_mzs = [p.mz for p in processed_spectrum.peaks] + peak_intensities = [p.intensity for p in processed_spectrum.peaks] + peak_trace = PlotlyBase.scatter( + x=peak_mzs, + y=peak_intensities, + mode="markers", + name="Picked Peaks", + marker=attr(color="red", size=8) + ) + push!(traces_after, peak_trace) + end + + plotdata_after = traces_after + plotlayout_after = PlotlyBase.Layout( + title=PlotlyBase.attr( + text="After Preprocessing (Spectrum $(selected_spectrum_id_for_plot))$(subset_label)", + font=PlotlyBase.attr( + family="Roboto, Lato, sans-serif", + size=18, + color="black" + ) + ), + hovermode="closest", + xaxis=PlotlyBase.attr( + title="m/z", + showgrid=true + ), + yaxis=PlotlyBase.attr( + title="Intensity", + showgrid=true, + tickformat=".3g" + ), + margin=attr(l=0, r=0, t=120, b=0, pad=0), + legend=attr(x=0.98, y=0.98, xanchor="right", yanchor="top") + ) + else + println("DEBUG: Selected spectrum for display ($(selected_spectrum_id_for_plot)) not found in processed spectra.") + end + elseif last_plot_type == "mean" + mz, intensity = get_processed_mean_spectrum(current_spectra) + mz_down, int_down = downsample_spectrum(mz, intensity) + local trace + if last_plot_mode == "stem" + trace = PlotlyBase.stem( + x=mz_down, + y=int_down, + name="Processed Mean Spectrum", + marker=attr(size=1, color="blue", opacity=0.5), + hoverinfo="x", + hovertemplate="m/z: %{x:.4f}" + ) + else + trace = PlotlyBase.scatter( + x=mz_down, + y=int_down, + mode="lines", + name="Processed Mean Spectrum", + marker=attr(size=1, color="blue", opacity=0.5), + hoverinfo="x", + hovertemplate="m/z: %{x:.4f}" + ) + end + plotdata_after = [trace] + plotlayout_after = PlotlyBase.Layout( + title=PlotlyBase.attr( + text="After Preprocessing (Mean Spectrum)$(subset_label)", + font=PlotlyBase.attr( + family="Roboto, Lato, sans-serif", + size=18, + color="black" + ) + ), + hovermode="closest", + xaxis=PlotlyBase.attr( + title="m/z", + showgrid=true + ), + yaxis=PlotlyBase.attr( + title="Average Intensity", + showgrid=true, + tickformat=".3g" + ), + margin=attr(l=0, r=0, t=120, b=0, pad=0), + legend=attr(x=1.0, y=1.0, xanchor="right", yanchor="top") + ) + elseif last_plot_type == "sum" + mz, intensity = get_processed_sum_spectrum(current_spectra) + mz_down, int_down = downsample_spectrum(mz, intensity) + local trace + if last_plot_mode == "stem" + trace = PlotlyBase.stem( + x=mz_down, + y=int_down, + name="Processed Sum Spectrum", + marker=attr(size=1, color="blue", opacity=0.5), + hoverinfo="x", + hovertemplate="m/z: %{x:.4f}" + ) + else + trace = PlotlyBase.scatter( + x=mz_down, + y=int_down, + mode="lines", + name="Processed Sum Spectrum", + marker=attr(size=1, color="blue", opacity=0.5), + hoverinfo="x", + hovertemplate="m/z: %{x:.4f}" + ) + end + plotdata_after = [trace] + plotlayout_after = PlotlyBase.Layout( + title=PlotlyBase.attr( + text="After Preprocessing (Sum Spectrum)$(subset_label)", + font=PlotlyBase.attr( + family="Roboto, Lato, sans-serif", + size=18, + color="black" + ) + ), + hovermode="closest", + xaxis=PlotlyBase.attr( + title="m/z", + showgrid=true + ), + yaxis=PlotlyBase.attr( + title="Total Intensity", + showgrid=true, + tickformat=".3g" + ), + margin=attr(l=0, r=0, t=120, b=0, pad=0), + legend=attr(x=1.0, y=1.0, xanchor="right", yanchor="top") + ) + end + + # Save feature matrix if binning was performed + if feature_matrix_result !== nothing + output_dir = joinpath("public", selected_folder_main, "preprocessing_results") + mkpath(output_dir) + save_feature_matrix(feature_matrix_result, bin_info_result, output_dir) + msg = "Pipeline completed successfully. Feature matrix saved." + println("DEBUG: Feature matrix saved to $output_dir") + else + msg = "Pipeline completed successfully. No feature matrix generated (binning step not enabled)." + println("DEBUG: $msg") + end + + catch e + msg = "Error during pipeline execution: $e" + warning_msg = true + @error "Pipeline failed" exception=(e, catch_backtrace()) + println("DEBUG: Pipeline caught an exception: $e") + finally + is_processing = false + current_pipeline_step = "" + println("DEBUG: run_full_pipeline finished (finally block).") + GC.gc() # Trigger garbage collection + if Sys.islinux() + ccall(:malloc_trim, Int32, (Int32,), 0) # Ensure Julia returns the freed memory to OS + end + end + end + + @onbutton recalculate_suggestions_btn begin + is_processing = true + if msi_data === nothing + msg = "Please load a file first." + warning_msg = true + return + end + + try + msg = "Recalculating suggestions..." + + ref_peaks = Dict(p["mz"] => p["label"] for p in reference_peaks_list) + recommended_params = main_precalculation(msi_data, reference_peaks=ref_peaks) + + + for (step_name, params) in recommended_params + for (param_key, value) in params + # Convert value to appropriate type before assignment + processed_value = if value === nothing + "" + elseif value isa Tuple + @warn "Skipping invalid parameter suggestion (tuple): $value for $param_key" + "" # Set to empty string for safety + elseif value isa Number + string(value) + else + string(value) + end + + if isempty(processed_value) && !(processed_value isa Number) + continue # Skip if processed_value is an empty string and not a number type + end + + # Map recommended parameters to suggested_* reactive variables + if step_name == :Smoothing + if param_key == :window + suggested_smoothing_window = processed_value + smoothing_window = processed_value + elseif param_key == :order + suggested_smoothing_order = processed_value + smoothing_order = processed_value + end + elseif step_name == :BaselineCorrection + if param_key == :iterations + suggested_baseline_iterations = processed_value + baseline_iterations = processed_value + elseif param_key == :window + suggested_baseline_window = processed_value + baseline_window = processed_value + end + elseif step_name == :PeakAlignment + if param_key == :span + suggested_alignment_span = processed_value + alignment_span = processed_value + elseif param_key == :tolerance + suggested_alignment_tolerance = processed_value + alignment_tolerance = processed_value + elseif param_key == :max_shift_ppm + suggested_alignment_max_shift_ppm = processed_value + alignment_max_shift_ppm = processed_value + elseif param_key == :min_matched_peaks + suggested_alignment_min_matched_peaks = processed_value + alignment_min_matched_peaks = processed_value + end + elseif step_name == :Calibration + if param_key == :fit_order + suggested_calibration_fit_order = processed_value + calibration_fit_order = processed_value + elseif param_key == :ppm_tolerance + suggested_calibration_ppm_tolerance = processed_value + calibration_ppm_tolerance = processed_value + end + elseif step_name == :PeakPicking + if param_key == :snr_threshold + suggested_peak_picking_snr_threshold = processed_value + peak_picking_snr_threshold = processed_value + elseif param_key == :half_window + suggested_peak_picking_half_window = processed_value + peak_picking_half_window = processed_value + elseif param_key == :min_peak_prominence + suggested_peak_picking_min_peak_prominence = processed_value + peak_picking_min_peak_prominence = processed_value + elseif param_key == :merge_peaks_tolerance + suggested_peak_picking_merge_peaks_tolerance = processed_value + peak_picking_merge_peaks_tolerance = processed_value + elseif param_key == :min_peak_width_ppm + suggested_peak_picking_min_peak_width_ppm = processed_value + peak_picking_min_peak_width_ppm = processed_value + elseif param_key == :max_peak_width_ppm + suggested_peak_picking_max_peak_width_ppm = processed_value + peak_picking_max_peak_width_ppm = processed_value + elseif param_key == :min_peak_shape_r2 + suggested_peak_picking_min_peak_shape_r2 = processed_value + peak_picking_min_peak_shape_r2 = processed_value + end + elseif step_name == :PeakSelection + if param_key == :min_snr + suggested_peak_selection_min_snr = processed_value + peak_selection_min_snr = processed_value + elseif param_key == :min_fwhm_ppm + suggested_peak_selection_min_fwhm_ppm = processed_value + peak_selection_min_fwhm_ppm = processed_value + elseif param_key == :max_fwhm_ppm + suggested_peak_selection_max_fwhm_ppm = processed_value + peak_selection_max_fwhm_ppm = processed_value + elseif param_key == :min_shape_r2 + suggested_peak_selection_min_shape_r2 = processed_value + peak_selection_min_shape_r2 = processed_value + elseif param_key == :frequency_threshold + suggested_peak_selection_frequency_threshold = processed_value + peak_selection_frequency_threshold = processed_value + elseif param_key == :correlation_threshold + suggested_peak_selection_correlation_threshold = processed_value + peak_selection_correlation_threshold = processed_value + end + elseif step_name == :PeakBinning + if param_key == :tolerance + suggested_binning_tolerance = processed_value + binning_tolerance = processed_value + elseif param_key == :frequency_threshold + suggested_binning_frequency_threshold = processed_value + binning_frequency_threshold = processed_value + elseif param_key == :min_peak_per_bin + suggested_binning_min_peak_per_bin = processed_value + binning_min_peak_per_bin = processed_value + elseif param_key == :max_bin_width_ppm + suggested_binning_max_bin_width_ppm = processed_value + binning_max_bin_width_ppm = processed_value + elseif param_key == :num_uniform_bins + suggested_binning_num_uniform_bins = processed_value + binning_num_uniform_bins = processed_value + end + end + end + end + + # Also set method types for steps + if haskey(recommended_params, :Smoothing) && haskey(recommended_params[:Smoothing], :method) + smoothing_method = string(recommended_params[:Smoothing][:method]) + end + if haskey(recommended_params, :BaselineCorrection) && haskey(recommended_params[:BaselineCorrection], :method) + baseline_method = string(recommended_params[:BaselineCorrection][:method]) + end + if haskey(recommended_params, :Normalization) && haskey(recommended_params[:Normalization], :method) + normalization_method = string(recommended_params[:Normalization][:method]) + end + if haskey(recommended_params, :PeakAlignment) && haskey(recommended_params[:PeakAlignment], :method) + alignment_method = string(recommended_params[:PeakAlignment][:method]) + end + if haskey(recommended_params, :PeakPicking) && haskey(recommended_params[:PeakPicking], :method) + peak_picking_method = string(recommended_params[:PeakPicking][:method]) + end + if haskey(recommended_params, :PeakBinning) && haskey(recommended_params[:PeakBinning], :method) + binning_method = string(recommended_params[:PeakBinning][:method]) + end + if haskey(recommended_params, :PeakAlignment) && haskey(recommended_params[:PeakAlignment], :tolerance_unit) + alignment_tolerance_unit = string(recommended_params[:PeakAlignment][:tolerance_unit]) + end + if haskey(recommended_params, :PeakBinning) && haskey(recommended_params[:PeakBinning], :tolerance_unit) + binning_tolerance_unit = string(recommended_params[:PeakBinning][:tolerance_unit]) + end + + msg = "Suggestions have been recalculated." + catch e + msg = "Failed to recalculate suggestions: $e" + warning_msg = true + @error "Recalculation failed" exception=(e, catch_backtrace()) + finally + is_processing = false + end + end + + @onbutton addReferencePeak begin + is_processing = true + new_list = deepcopy(reference_peaks_list) + push!(new_list, Dict("mz" => 0.0, "label" => "")) + reference_peaks_list = new_list # Assign new list to trigger reactivity + is_processing = false + end + + @onbutton remove_peak_trigger begin + is_processing = true + if action_index > -1 + julia_index = action_index + 1 + new_list = deepcopy(reference_peaks_list) + if 1 <= julia_index <= length(new_list) + deleteat!(new_list, julia_index) + reference_peaks_list = new_list + end + action_index = -1 # Reset + end + is_processing = false + end + + @onbutton move_step_up_trigger begin + is_processing = true + if action_index > -1 + julia_index = action_index + 1 + if julia_index > 1 + new_order = deepcopy(pipeline_step_order) + temp = new_order[julia_index] + new_order[julia_index] = new_order[julia_index - 1] + new_order[julia_index - 1] = temp + pipeline_step_order = new_order + end + action_index = -1 # Reset + end + is_processing = false + end + + @onbutton move_step_down_trigger begin + is_processing = true + if action_index > -1 + julia_index = action_index + 1 + if julia_index < length(pipeline_step_order) + new_order = deepcopy(pipeline_step_order) + temp = new_order[julia_index] + new_order[julia_index] = new_order[julia_index + 1] + new_order[julia_index + 1] = temp + pipeline_step_order = new_order + end + action_index = -1 # Reset + end + is_processing = false + end + + @onbutton toggle_step_trigger begin + is_processing = true + if action_index > -1 + julia_index = action_index + 1 + if 1 <= julia_index <= length(pipeline_step_order) + new_order = deepcopy(pipeline_step_order) + new_order[julia_index]["enabled"] = !new_order[julia_index]["enabled"] + pipeline_step_order = new_order + end + action_index = -1 # Reset + end + is_processing = false + end + + # This new handler correctly adds the file from full_route to the batch list. + @onbutton btnAddBatch begin + is_processing = true + if isempty(full_route) || full_route == "unknown (manually added)" + msg = "No active file selected to add to batch." + warning_msg = true + return + end + + if !(full_route in selected_files) + push!(selected_files, full_route) + selected_files = deepcopy(selected_files) # Force reactivity + batch_file_count = length(selected_files) + msg = "File added to batch." + else + msg = "File is already in the batch list." + warning_msg = true + end + is_processing = false + end + + @onbutton clear_batch_btn begin + is_processing = true + selected_files = String[] + batch_file_count = 0 + msg = "Batch cleared" + is_processing = false + end + + @onchange selected_files begin + batch_file_count = length(selected_files) + end + + @onchange full_route begin + if !isempty(full_route) && !(full_route in selected_files) + push!(selected_files, full_route) + selected_files = deepcopy(selected_files) # Force reactivity + batch_file_count = length(selected_files) + msg = "File automatically added to batch" + end + end + + @onbutton showMetadataBtn begin + if !isempty(available_folders) + if !isempty(selected_folder_main) + selected_folder_metadata = selected_folder_main + elseif !isempty(available_folders) + selected_folder_metadata = first(available_folders) + end + showMetadataDialog = true + else + msg = "No processed datasets available." + warning_msg = true + end + end + + @onchange selected_folder_metadata begin + if !isempty(selected_folder_metadata) + registry = load_registry(registry_path) + dataset_info = get(registry, selected_folder_metadata, nothing) + + if dataset_info !== nothing && haskey(dataset_info, "metadata") && !isempty(get(dataset_info["metadata"], "summary", [])) + metadata_rows = dataset_info["metadata"]["summary"] + btnMetadataDisable = false + else + metadata_rows = [] + btnMetadataDisable = true + msg = "Metadata not found in registry for $(selected_folder_metadata)." + end + end + end + + @onchange btnSearchMzml, btnSearchSync begin + is_processing = true + if btnSearchMzml + picked_route = pick_file(; filterlist="mzML,mzml") + if !isempty(picked_route) + mzml_full_route = picked_route + end + btnSearchMzml = false # Reset the button + end + + if btnSearchSync + picked_route = pick_file(; filterlist="txt") + if !isempty(picked_route) + sync_full_route = picked_route + end + btnSearchSync = false # Reset the button + end + + # Enable button only if both files are selected + btnConvertDisable = isempty(mzml_full_route) || isempty(sync_full_route) + is_processing = false + end + + @onbutton convert_process begin + is_processing = true + if isempty(mzml_full_route) || isempty(sync_full_route) + msg_conversion = "Please select both an .mzML file and a .txt sync file." + warning_msg = true + return + end + + msg_conversion = "Starting conversion process..." + + try + sTime = time() + target_imzml = replace(mzml_full_route, r"\.(mzml|mzML)$" => ".imzML") + + msg_conversion = "Converting $(basename(mzml_full_route)) to $(basename(target_imzml))... This may take a while." + + success = ImportMzmlFile(mzml_full_route, sync_full_route, target_imzml) + + fTime = time() + eTime = round(fTime - sTime, digits=3) + + if success + msg_conversion = "Conversion successful in $(eTime) seconds. Output file: $(basename(target_imzml))" + else + msg_conversion = "Conversion failed after $(eTime) seconds. Check console for errors." + warning_msg = true + end + + catch e + msg_conversion = "An error occurred during conversion: $e" + warning_msg = true + @error "Conversion failed" exception=(e, catch_backtrace()) + finally + is_processing = false + # Re-enable button if files are still selected + btnConvertDisable = isempty(mzml_full_route) || isempty(sync_full_route) end end - @onbutton mainProcess begin - progress=true # Start progress button animation - btnStartDisable=true # We disable the button to avoid multiple requests - btnPlotDisable=true - btnSpectraDisable=true - text_nmass=replace(string(Nmass), "." => "_") - sTime=time() - if isfile(full_route) && Nmass > 0 && Tol > 0 && Tol <=1 && colorLevel > 1 && colorLevel < 257 - msg="File exists, Nmass=$(Nmass) Tol=$(Tol). Loading file will begin, please be patient." + @onbutton mainProcess @time begin + # --- UI State Update --- + overall_progress = 0.0 + progress_message = "Preparing batch process..." + + # --- CAPTURE CURRENT VALUES HERE --- + current_selected_files = selected_files + current_nmass = Nmass + current_tol = Tol + current_color_level = colorLevel + current_triq_enabled = triqEnabled + current_triq_prob = triqProb + current_mfilter_enabled = MFilterEnabled + current_mask_enabled = maskEnabled + current_registry_path = registry_path + + println("starting main process with $(length(current_selected_files)) files") + total_time_start = time() + try + # --- 1. Parameter Validation --- + if isempty(current_selected_files) + progress_message = "No .imzML files in batch. Please add files first." + warning_msg = true + println(progress_message) + return + end + is_processing = true + + masses = Float64[] try - spectra=LoadImzml(full_route) - msg="File loaded. Creating spectra with the specific mass and tolerance, please be patient." - slice=GetMzSliceJl(spectra,Nmass,Tol) - fig=CairoMakie.Figure(size=(150, 250)) # Container - # Append a query string to force the image to refresh - timestamp=string(time_ns()) - if triqEnabled # If we have TrIQ - if triqProb < 0.8 || triqProb > 1 - msg="Incorrect TrIQ values, please adjust accordingly and try again." - warning_msg=true - else - image_path=joinpath("./public", "TrIQ_$(text_nmass).bmp") - valid_slice=false - while Tol <= 1.0 && !valid_slice - try - slice=GetMzSliceJl(spectra, Nmass, Tol) - sliceTriq=TrIQ(slice, colorLevel, triqProb) - if MFilterEnabled # If the Median filter is ON - sliceTriq=medianFilterjl(sliceTriq) - end - valid_slice=true - catch e - msg="Warning: insufficient tolerance, inputs modified to allow the creation of an image regardless=$Tol: $e" - Tol += 0.1 - end - end - sliceTriq=reverse(sliceTriq, dims=2) - SaveBitmapCl(joinpath("public", "TrIQ_$(text_nmass).bmp"),sliceTriq,ViridisPalette) - # Use timestamp to refresh image interface container - imgIntT="/TrIQ_$(text_nmass).bmp?t=$(timestamp)" - plotdataImgT, plotlayoutImgT, imgWidth, imgHeight=loadImgPlot(imgIntT) - # Get current image - current_triq="TrIQ_$(text_nmass).bmp" - msgtriq="TrIQ image with the Nmass of $(replace(text_nmass, "_" => "."))" - # Create colorbar - bound=julia_mzML_imzML.GetOutlierThres(slice, triqProb) - levels=range(bound[1],stop=bound[2], length=8) - levels=vcat(levels, 2*levels[end]-levels[end-1]) - Colorbar(fig[1, 1], colormap=cgrad(:viridis, colorLevel, categorical=true), limits=(0, bound[2]),ticks=levels,tickformat=log_tick_formatter, label="Intensity", size=25) - save("public/colorbar_TrIQ_$(text_nmass).png", fig) - colorbarT="/colorbar_TrIQ_$(text_nmass).png?t=$(timestamp)" - # Get current colorbar - current_col_triq="colorbar_TrIQ_$(text_nmass).png" - # We update the directory to include the new placed images. - triq_bmp=sort(filter(filename -> startswith(filename, "TrIQ_") && endswith(filename, ".bmp"), readdir("public")),lt=natural) - col_triq_png=sort(filter(filename -> startswith(filename, "colorbar_TrIQ_") && endswith(filename, ".png"), readdir("public")),lt=natural) - fTime=time() - eTime=round(fTime-sTime,digits=3) - msg="The file has been created in $(eTime) seconds successfully inside the 'public' folder of the app" - selectedTab="tab1" - end - else # If we don't use TrIQ - image_path=joinpath("./public", "MSI_$(text_nmass).bmp") - try - sliceQuant=IntQuantCl(slice,Int(colorLevel-1)) - if MFilterEnabled # If the Median filter is ON - sliceQuant=medianFilterjl(sliceQuant) - end - catch e - msg="Warning: $e" - end - sliceQuant=reverse(sliceQuant, dims=2) - SaveBitmapCl(joinpath("public", "MSI_$(text_nmass).bmp"),sliceQuant,ViridisPalette) - # Use timestamp to refresh image interface container - imgInt="/MSI_$(text_nmass).bmp?t=$(timestamp)" - plotdataImg, plotlayoutImg, imgWidth, imgHeight=loadImgPlot(imgInt) - # Get current image - current_msi="MSI_$(text_nmass).bmp" - msgimg="Image with the Nmass of $(replace(text_nmass, "_" => "."))" - # Create colorbar - levels=range(0,maximum(slice),length=8) - Colorbar(fig[1, 1], colormap=cgrad(:viridis, colorLevel, categorical=true), limits=(0, maximum(slice)),ticks=levels,tickformat=log_tick_formatter, label="Intensity", size=25) - save("public/colorbar_MSI_$(text_nmass).png", fig) - colorbar="/colorbar_MSI_$(text_nmass).png?t=$(timestamp)" - # Get current colorbar - current_col_msi="colorbar_MSI_$(text_nmass).png" - # We update the directory to include the new placed images. - msi_bmp=sort(filter(filename -> startswith(filename, "MSI_") && endswith(filename, ".bmp"), readdir("public")),lt=natural) - col_msi_png=sort(filter(filename -> startswith(filename, "colorbar_MSI_") && endswith(filename, ".png"), readdir("public")),lt=natural) - selectedTab="tab0" - fTime=time() - eTime=round(fTime-sTime,digits=3) - msg="The file has been created in $(eTime) seconds successfully inside the 'public' folder of the app" - end + masses = [parse(Float64, strip(m)) for m in split(current_nmass, ',', keepempty=false)] catch e - msg="There was an error loading the ImzML file, please verify the file accordingly and try again. $(e)" - warning_msg=true + progress_message = "Invalid m/z value(s). Please provide a comma-separated list of numbers. Error: $e" + warning_msg = true + return end - else - msg="File does not exist or a parameter is incorrect, please try again." - warning_msg=true - end - GC.gc() # Trigger garbage collection - if Sys.islinux() - ccall(:malloc_trim, Int32, (Int32,), 0) # Ensure julia returns the freed memory to OS - end - btnStartDisable=false - btnPlotDisable=false - btnOpticalDisable=false - progress=false - if isfile(full_routeMz) - # We enable coord search and spectra plot creation - btnSpectraDisable=false - SpectraEnabled=true - end - end - @onbutton createMeanPlot begin - msg="Mean spectrum plot selected" - sTime=time() - if isfile(full_routeMz) # Check if the file exists - progressSpectraPlot=true - btnPlotDisable=true - btnStartDisable=true - msg="Loading plot..." - plotdata, plotlayout, xSpectraMz, ySpectraMz=meanSpectrumPlot(full_routeMz) + if isempty(masses) + progress_message = "No valid m/z values found. Please provide comma-separated positive numbers." + warning_msg = true + return + end + + # --- 2. Batch Processing Loop --- + num_files = length(current_selected_files) + total_steps = num_files + current_step = 0 + errors = Dict("load_errors" => String[], "slice_errors" => String[], "io_errors" => String[]) + newly_created_folders = String[] + files_without_mask = 0 + + for (file_idx, file_path) in enumerate(current_selected_files) + progress_message = "Processing file $(file_idx)/$(num_files): $(basename(file_path))" + overall_progress = current_step / total_steps + + all_params = ( + tolerance = current_tol, + colorL = current_color_level, + triqE = current_triq_enabled, + triqP = current_triq_prob, + medianF = current_mfilter_enabled, + registry = current_registry_path, + fileIdx = file_idx, + nFiles = num_files + ) + + success, error_msg = process_file_safely(file_path, masses, all_params, progress_message, overall_progress, use_mask=current_mask_enabled) + + if !success + push!(errors["load_errors"], error_msg) + else + push!(newly_created_folders, replace(basename(file_path), r"\.imzML$"i => "")) + end + current_step += 1 + end + + # --- 3. Final Report --- + total_time_end = round(time() - total_time_start, digits=3) + + registry = load_registry(current_registry_path) + all_folders = sort(collect(keys(registry)), lt=natural) + img_folders = filter(folder -> get(get(registry, folder, Dict()), "is_imzML", false), all_folders) + available_folders = deepcopy(all_folders) + image_available_folders = deepcopy(img_folders) + + if !isempty(newly_created_folders) + selected_folder_main = first(newly_created_folders) + end + + successful_files = length(newly_created_folders) + total_errors = sum(length, values(errors)) + + if total_errors == 0 + msg = "Successfully processed all $(successful_files) file(s) in $(total_time_end) seconds." + else + msg = "Batch completed in $(total_time_end) seconds with $(total_errors) error(s)." + warning_msg = true + end + + mask_summary = current_mask_enabled ? "\nFiles processed without a mask: $(files_without_mask)" : "" + + batch_summary = """ + Processed $(successful_files)/$(num_files) files successfully. + $(mask_summary) + + Errors by category: + • Load failures: $(length(errors["load_errors"])) + • Slice generation: $(length(errors["slice_errors"])) + • I/O issues: $(length(errors["io_errors"])) + + Detailed errors: + $(join(vcat(values(errors)...), "\n")) + """ + showBatchSummary = true + + # Update UI to display the last generated image + if !isempty(newly_created_folders) + timestamp = string(time_ns()) + folder_path = joinpath("public", selected_folder_main) + + if current_triq_enabled + triq_files = filter(filename -> startswith(filename, "TrIQ_") && endswith(filename, ".bmp"), readdir(folder_path)) + col_triq_files = filter(filename -> startswith(filename, "colorbar_TrIQ_") && endswith(filename, ".png"), readdir(folder_path)) + + if !isempty(triq_files) + latest_triq = triq_files[argmax([mtime(joinpath(folder_path, f)) for f in triq_files])] + current_triq = latest_triq + imgIntT = "/$(selected_folder_main)/$(current_triq)?t=$(timestamp)" + plotdataImgT, plotlayoutImgT, _, _ = loadImgPlot(imgIntT) + text_nmass = replace(current_triq, r"TrIQ_|.bmp" => "") + msgtriq = "TrIQ m/z: $(replace(text_nmass, "_" => "."))" + + if !isempty(col_triq_files) + latest_col_triq = col_triq_files[argmax([mtime(joinpath(folder_path, f)) for f in col_triq_files])] + current_col_triq = latest_col_triq + colorbarT = "/$(selected_folder_main)/$(current_col_triq)?t=$(timestamp)" + else + colorbarT = "" + end + selectedTab = "tab1" + end + else # Not TrIQ enabled, display regular MSI image + msi_files = filter(filename -> startswith(filename, "MSI_") && endswith(filename, ".bmp"), readdir(folder_path)) + col_msi_files = filter(filename -> startswith(filename, "colorbar_MSI_") && endswith(filename, ".png"), readdir(folder_path)) + + if !isempty(msi_files) + latest_msi = msi_files[argmax([mtime(joinpath(folder_path, f)) for f in msi_files])] + current_msi = latest_msi + imgInt = "/$(selected_folder_main)/$(current_msi)?t=$(timestamp)" + plotdataImg, plotlayoutImg, _, _ = loadImgPlot(imgInt) + text_nmass = replace(current_msi, r"MSI_|.bmp" => "") + msgimg = "m/z: $(replace(text_nmass, "_" => "."))" + + if !isempty(col_msi_files) + latest_col_msi = col_msi_files[argmax([mtime(joinpath(folder_path, f)) for f in col_msi_files])] + current_col_msi = latest_col_msi + colorbar = "/$(selected_folder_main)/$(current_col_msi)?t=$(timestamp)" + else + colorbar = "" + end + selectedTab = "tab0" + end + end + end + + catch e + println("Error in main process: $e") + msg = "Batch processing failed: $e" + warning_msg = true + @error "Main process failed" exception=(e, catch_backtrace()) + finally + # --- UI State Reset --- + is_processing = false + SpectraEnabled = true + overall_progress = 0.0 + #println("Done") GC.gc() # Trigger garbage collection if Sys.islinux() - ccall(:malloc_trim, Int32, (Int32,), 0) # Ensure julia returns the freed memory to OS + ccall(:malloc_trim, Int32, (Int32,), 0) # Ensure Julia returns the freed memory to OS end - selectedTab="tab2" - fTime=time() - eTime=round(fTime-sTime,digits=3) - msg="Plot loaded in $(eTime) seconds" - else - msg="there was an error with the mzML, please try again" - warning_msg=true - end - progressSpectraPlot=false - btnPlotDisable=false - if endswith(full_route, "imzML") - btnStartDisable=false - end - if isfile(full_routeMz) - # We enable coord search and spectra plot creation - btnSpectraDisable=false - SpectraEnabled=true end end - @onbutton createXYPlot begin - msg="XY spectrum plot selected" - sTime=time() - if isfile(full_routeMz) # Check if the file exists - progressSpectraPlot=true - btnStartDisable=true - btnPlotDisable=true - btnSpectraDisable=true - msg="Loading plot..." - spectraMz=LoadMzml(full_routeMz) - layoutSpectra=PlotlyBase.Layout( - title="($xCoord, $yCoord) Specific spectrum plot", - xaxis=PlotlyBase.attr( - title="m/z", - showgrid=true - ), - yaxis=PlotlyBase.attr( - title="Intensity", - showgrid=true - ), - autosize=false, - margin=attr(l=0,r=0,t=120,b=0,pad=0) - ) - if xCoord < 1 - xCoord=1 - elseif xCoord > imgWidth - xCoord=imgWidth + @onbutton createMeanPlot @time begin + if isempty(selected_folder_main) + msg = "No dataset selected. Please process a file and select a folder first." + warning_msg = true + return + end + + is_processing = true + + try + sTime = time() + registry = load_registry(registry_path) + entry = registry[selected_folder_main] + target_path = entry["source_path"] + + if target_path == "unknown (manually added)" + msg = "Dataset selected contained no route." + warning_msg = true + return end - if yCoord > -1 - yCoord=-1 - elseif yCoord < -imgHeight - yCoord=-imgHeight + + if msi_data === nothing || full_route != target_path + if msi_data !== nothing + close(msi_data) + end + msg = "Reloading $(basename(target_path)) for analysis..." + full_route = target_path + msi_data = OpenMSIData(target_path) + if haskey(get(entry, "metadata", Dict()), "global_min_mz") && entry["metadata"]["global_min_mz"] !== nothing + raw_min = entry["metadata"]["global_min_mz"] + raw_max = entry["metadata"]["global_max_mz"] + min_val = isa(raw_min, Dict) ? get(raw_min, "value", raw_min) : raw_min + max_val = isa(raw_max, Dict) ? get(raw_max, "value", raw_max) : raw_max + set_global_mz_range!(msi_data, convert(Float64, min_val), convert(Float64, max_val)) + else + precompute_analytics(msi_data) + end end - xSpectraMz=spectraMz[1,abs(xCoord)] - ySpectraMz=spectraMz[2,abs(yCoord)] - traceSpectra=PlotlyBase.scatter(x=xSpectraMz, y=ySpectraMz, mode="lines") - plotdata=[traceSpectra] # We add the data from spectra to the plot - plotlayout=layoutSpectra + + local mask_path_for_plot::Union{String, Nothing} = nothing + if maskEnabled && get(entry, "has_mask", false) + mask_path_for_plot = get(entry, "mask_path", "") + if !isfile(mask_path_for_plot) + @warn "Mask not found for plotting: $(mask_path_for_plot). Plotting without mask." + mask_path_for_plot = nothing + end + end + + plotdata, plotlayout, xSpectraMz, ySpectraMz = meanSpectrumPlot(msi_data, selected_folder_main, mask_path=mask_path_for_plot) + plotdata_before = plotdata + plotlayout_before = plotlayout + last_plot_type = "mean" + selectedTab = "tab2" + fTime = time() + eTime = round(fTime - sTime, digits=3) + msg = "Plot loaded in $(eTime) seconds" + log_memory_usage("Mean Plot Generated", msi_data) + catch e + msg = "Could not generate mean spectrum plot: $e" + warning_msg = true + @error "Mean spectrum plotting failed" exception=(e, catch_backtrace()) + finally + is_processing = false + GC.gc() # Trigger garbage collection + if Sys.islinux() + ccall(:malloc_trim, Int32, (Int32,), 0) # Ensure Julia returns the freed memory to OS + end + end + end + + @onbutton createSumPlot @time begin + if isempty(selected_folder_main) + msg = "No dataset selected. Please process a file and select a folder first." + warning_msg = true + return + end + + is_processing = true + msg = "Loading total spectrum plot for $(selected_folder_main)..." + + try + sTime = time() + registry = load_registry(registry_path) + entry = registry[selected_folder_main] + target_path = entry["source_path"] + + if target_path == "unknown (manually added)" + msg = "Dataset selected contained no route." + warning_msg = true + return + end + + if msi_data === nothing || full_route != target_path + if msi_data !== nothing + close(msi_data) + end + msg = "Reloading $(basename(target_path)) for analysis..." + full_route = target_path + msi_data = OpenMSIData(target_path) + if haskey(get(entry, "metadata", Dict()), "global_min_mz") && entry["metadata"]["global_min_mz"] !== nothing + raw_min = entry["metadata"]["global_min_mz"] + raw_max = entry["metadata"]["global_max_mz"] + min_val = isa(raw_min, Dict) ? get(raw_min, "value", raw_min) : raw_min + max_val = isa(raw_max, Dict) ? get(raw_max, "value", raw_max) : raw_max + set_global_mz_range!(msi_data, convert(Float64, min_val), convert(Float64, max_val)) + else + precompute_analytics(msi_data) + end + end + local mask_path_for_plot::Union{String, Nothing} = nothing + if maskEnabled && get(entry, "has_mask", false) + mask_path_for_plot = get(entry, "mask_path", "") + if !isfile(mask_path_for_plot) + @warn "Mask not found for plotting: $(mask_path_for_plot). Plotting without mask." + mask_path_for_plot = nothing + end + end + + plotdata, plotlayout, xSpectraMz, ySpectraMz = sumSpectrumPlot(msi_data, selected_folder_main, mask_path=mask_path_for_plot) + plotdata_before = plotdata + plotlayout_before = plotlayout + last_plot_type = "sum" + selectedTab = "tab2" + fTime = time() + eTime = round(fTime - sTime, digits=3) + msg = "Total plot loaded in $(eTime) seconds" + log_memory_usage("Sum Plot Generated", msi_data) + catch e + msg = "Could not generate total spectrum plot: $e" + warning_msg = true + @error "Total spectrum plotting failed" exception=(e, catch_backtrace()) + finally + is_processing = false GC.gc() # Trigger garbage collection if Sys.islinux() - ccall(:malloc_trim, Int32, (Int32,), 0) # Ensure julia returns the freed memory to OS + ccall(:malloc_trim, Int32, (Int32,), 0) # Ensure Julia returns the freed memory to OS end - selectedTab="tab2" - fTime=time() - eTime=round(fTime-sTime,digits=3) - msg="Plot loaded in $(eTime) seconds" - else - msg="there was an error with the mzML or the coordenates, please try again" - warning_msg=true - end - progressSpectraPlot=false - btnPlotDisable=false - if endswith(full_route, "imzML") - btnStartDisable=false - end - if isfile(full_routeMz) - # We enable coord search and spectra plot creation - btnSpectraDisable=false - SpectraEnabled=true end end - # Image loaders based on the position of the current image (increment and decrement for both normal and filter) - # And a pre-generated list from all image files from /public folder + @onbutton createXYPlot @time begin + if isempty(selected_folder_main) + msg = "No dataset selected. Please process a file and select a folder first." + warning_msg = true + return + end + + is_processing = true + msg = "Loading plot for $(selected_folder_main)..." + + try + sTime = time() + registry = load_registry(registry_path) + + # Add error handling for registry access + if !haskey(registry, selected_folder_main) + msg = "Dataset '$(selected_folder_main)' not found in registry." + warning_msg = true + return + end + + entry = registry[selected_folder_main] + target_path = entry["source_path"] + + if target_path == "unknown (manually added)" + msg = "Dataset selected contained no route." + warning_msg = true + return + end + + if msi_data === nothing || full_route != target_path + if msi_data !== nothing + close(msi_data) + end + msg = "Reloading $(basename(target_path)) for analysis..." + full_route = target_path + msi_data = OpenMSIData(target_path) + if haskey(get(entry, "metadata", Dict()), "global_min_mz") && entry["metadata"]["global_min_mz"] !== nothing + raw_min = entry["metadata"]["global_min_mz"] + raw_max = entry["metadata"]["global_max_mz"] + min_val = isa(raw_min, Dict) ? get(raw_min, "value", raw_min) : raw_min + max_val = isa(raw_max, Dict) ? get(raw_max, "value", raw_max) : raw_max + set_global_mz_range!(msi_data, convert(Float64, min_val), convert(Float64, max_val)) + else + precompute_analytics(msi_data) + end + end + + local mask_path_for_plot::Union{String, Nothing} = nothing + if maskEnabled && get(entry, "has_mask", false) + mask_path_for_plot = get(entry, "mask_path", "") + if !isfile(mask_path_for_plot) + @warn "Mask not found for plotting: $(mask_path_for_plot). Plotting without mask." + mask_path_for_plot = nothing + end + end + + # Convert to positive coordinates for processing + y_positive = yCoord < 0 ? abs(yCoord) : yCoord + plotdata, plotlayout, xSpectraMz, ySpectraMz, spectrum_id = xySpectrumPlot(msi_data, xCoord, y_positive, imgWidth, imgHeight, selected_folder_main, mask_path=mask_path_for_plot) + plotdata_before = plotdata + plotlayout_before = plotlayout + last_plot_type = "single" + selected_spectrum_id_for_plot = spectrum_id + idSpectrum = spectrum_id # we set the same obtained spectrum id to the UI + + # Update coordinates based on actual plot title + # Extract title text from the Dict safely + actual_title = if plotlayout.title isa Dict && haskey(plotlayout.title, :text) + plotlayout.title[:text] + elseif plotlayout.title isa Dict && haskey(plotlayout.title, "text") + plotlayout.title["text"] + else + string(plotlayout.title) # Fallback + end + + if occursin("Masked Spectrum at", actual_title) + # Extract coordinates from masked spectrum title + coords_match = match(r"Masked Spectrum at \((\d+), (\d+)\)", actual_title) + if coords_match !== nothing + xCoord = parse(Int, coords_match.captures[1]) + yCoord = -parse(Int, coords_match.captures[2]) # Negative for display + end + elseif occursin("Spectrum at", actual_title) + # Extract coordinates from regular spectrum title + coords_match = match(r"Spectrum at \((\d+), (\d+)\)", actual_title) + if coords_match !== nothing + xCoord = parse(Int, coords_match.captures[1]) + yCoord = -parse(Int, coords_match.captures[2]) # Negative for display + end + else + # For non-imaging data or fallback, just clamp the coordinates + xCoord = clamp(xCoord, 1, imgWidth) + yCoord = yCoord < 0 ? yCoord : -clamp(yCoord, 1, imgHeight) + end + + selectedTab = "tab2" + fTime = time() + eTime = round(fTime - sTime, digits=3) + msg = "Plot loaded in $(eTime) seconds" + log_memory_usage("XY Plot Generated", msi_data) + catch e + msg = "Could not retrieve spectrum: $e" + warning_msg = true + @error "Spectrum plotting failed" exception=(e, catch_backtrace()) + finally + is_processing = false + GC.gc() # Trigger garbage collection + if Sys.islinux() + ccall(:malloc_trim, Int32, (Int32,), 0) # Ensure Julia returns the freed memory to OS + end + end + end + + @onbutton createNSpectrumPlot @time begin + if isempty(selected_folder_main) + msg = "No dataset selected. Please process a file and select a folder first." + warning_msg = true + return + end + + is_processing = true + msg = "Loading plot for $(selected_folder_main)..." + + try + sTime = time() + registry = load_registry(registry_path) + + # Add error handling for registry access + if !haskey(registry, selected_folder_main) + msg = "Dataset '$(selected_folder_main)' not found in registry." + warning_msg = true + return + end + + entry = registry[selected_folder_main] + target_path = entry["source_path"] + + if target_path == "unknown (manually added)" + msg = "Dataset selected contained no route." + warning_msg = true + return + end + + if msi_data === nothing || full_route != target_path + if msi_data !== nothing + close(msi_data) + end + msg = "Reloading $(basename(target_path)) for analysis..." + full_route = target_path + msi_data = OpenMSIData(target_path) + if haskey(get(entry, "metadata", Dict()), "global_min_mz") && entry["metadata"]["global_min_mz"] !== nothing + raw_min = entry["metadata"]["global_min_mz"] + raw_max = entry["metadata"]["global_max_mz"] + min_val = isa(raw_min, Dict) ? get(raw_min, "value", raw_min) : raw_min + max_val = isa(raw_max, Dict) ? get(raw_max, "value", raw_max) : raw_max + set_global_mz_range!(msi_data, convert(Float64, min_val), convert(Float64, max_val)) + else + precompute_analytics(msi_data) + end + end + + local mask_path_for_plot::Union{String, Nothing} = nothing + if maskEnabled && get(entry, "has_mask", false) + mask_path_for_plot = get(entry, "mask_path", "") + if !isfile(mask_path_for_plot) + @warn "Mask not found for plotting: $(mask_path_for_plot). Plotting without mask." + mask_path_for_plot = nothing + end + end + + # Call the new nSpectrumPlot function + plotdata, plotlayout, xSpectraMz, ySpectraMz, spectrum_id = nSpectrumPlot(msi_data, idSpectrum, selected_folder_main, mask_path=mask_path_for_plot) + plotdata_before = plotdata + plotlayout_before = plotlayout + last_plot_type = "single" + selected_spectrum_id_for_plot = spectrum_id + + selectedTab = "tab2" + fTime = time() + eTime = round(fTime - sTime, digits=3) + msg = "Plot loaded in $(eTime) seconds" + log_memory_usage("nSpectrum Plot Generated", msi_data) + catch e + msg = "Could not retrieve spectrum: $e" + warning_msg = true + @error "nSpectrum plotting failed" exception=(e, catch_backtrace()) + finally + is_processing = false + GC.gc() # Trigger garbage collection + if Sys.islinux() + ccall(:malloc_trim, Int32, (Int32,), 0) # Ensure Julia returns the freed memory to OS + end + end + end + + # --- Main View Handlers --- @onbutton imgMinus begin - # Append a query string to force the image to refresh - timestamp=string(time_ns()) - # Update the array of images listed in the public folder - msi_bmp=sort(filter(filename -> startswith(filename, "MSI_") && endswith(filename, ".bmp"), readdir("public")),lt=natural) - col_msi_png=sort(filter(filename -> startswith(filename, "colorbar_MSI_") && endswith(filename, ".png"), readdir("public")),lt=natural) + if isempty(selected_folder_main) return end + timestamp=string(time_ns()) + folder_path = joinpath("public", selected_folder_main) + # Check if folder exists to prevent errors + if !isdir(folder_path) return end + + msi_bmp=sort(filter(filename -> startswith(filename, "MSI_") && endswith(filename, ".bmp"), readdir(folder_path)),lt=natural) + col_msi_png=sort(filter(filename -> startswith(filename, "colorbar_MSI_") && endswith(filename, ".png"), readdir(folder_path)),lt=natural) new_msi=decrement_image(current_msi, msi_bmp) new_col_msi=decrement_image(current_col_msi, col_msi_png) - if new_msi!=nothing || new_col_msi!=nothing - current_msi=new_msi - current_col_msi=new_col_msi - imgInt="/$(current_msi)?t=$(timestamp)" - colorbar="/$(current_col_msi)?t=$(timestamp)" - - text_nmass=replace(current_msi, "MSI_" => "") - text_nmass=replace(text_nmass, ".bmp" => "") - msgimg="Image with the Nmass of $(replace(text_nmass, "_" => "."))" - # Process the image in the function - plotdataImg, plotlayoutImg, imgWidth, imgHeight=loadImgPlot(imgInt) - btnOpticalDisable=false - else - traceImg=PlotlyBase.heatmap(x=[], y=[]) - plotdataImg=[traceImg] - msgimg="" + if new_msi !== nothing && new_col_msi !== nothing + current_msi = new_msi + current_col_msi = new_col_msi + imgInt = "/$(selected_folder_main)/$(current_msi)?t=$(timestamp)" + colorbar = "/$(selected_folder_main)/$(current_col_msi)?t=$(timestamp)" + text_nmass = replace(current_msi, r"MSI_|.bmp" => "") + msgimg = "m/z: $(replace(text_nmass, "_" => "."))" + plotdataImg, plotlayoutImg, _, _ = loadImgPlot(imgInt) end end @onbutton imgPlus begin - # Append a query string to force the image to refresh + if isempty(selected_folder_main) return end timestamp=string(time_ns()) - # Update the array of images listed in the public folder - msi_bmp=sort(filter(filename -> startswith(filename, "MSI_") && endswith(filename, ".bmp"), readdir("public")),lt=natural) - col_msi_png=sort(filter(filename -> startswith(filename, "colorbar_MSI_") && endswith(filename, ".png"), readdir("public")),lt=natural) + folder_path = joinpath("public", selected_folder_main) + if !isdir(folder_path) return end + + msi_bmp=sort(filter(filename -> startswith(filename, "MSI_") && endswith(filename, ".bmp"), readdir(folder_path)),lt=natural) + col_msi_png=sort(filter(filename -> startswith(filename, "colorbar_MSI_") && endswith(filename, ".png"), readdir(folder_path)),lt=natural) new_msi=increment_image(current_msi, msi_bmp) new_col_msi=increment_image(current_col_msi, col_msi_png) - if new_msi!=nothing || new_col_msi!=nothing - current_msi=new_msi - current_col_msi=new_col_msi - imgInt="/$(current_msi)?t=$(timestamp)" - colorbar="/$(current_col_msi)?t=$(timestamp)" - - text_nmass=replace(current_msi, "MSI_" => "") - text_nmass=replace(text_nmass, ".bmp" => "") - msgimg="Image with the Nmass of $(replace(text_nmass, "_" => "."))" - # Process the image in the function - plotdataImg, plotlayoutImg, imgWidth, imgHeight=loadImgPlot(imgInt) - btnOpticalDisable=false - else - traceImg=PlotlyBase.heatmap(x=[], y=[]) - plotdataImg=[traceImg] - msgimg="" + if new_msi !== nothing && new_col_msi !== nothing + current_msi = new_msi + current_col_msi = new_col_msi + imgInt = "/$(selected_folder_main)/$(current_msi)?t=$(timestamp)" + colorbar = "/$(selected_folder_main)/$(current_col_msi)?t=$(timestamp)" + text_nmass = replace(current_msi, r"MSI_|.bmp" => "") + msgimg = "m/z: $(replace(text_nmass, "_" => "."))" + plotdataImg, plotlayoutImg, _, _ = loadImgPlot(imgInt) end end @onbutton imgMinusT begin - # Append a query string to force the image to refresh - timestamp=string(time_ns()) - # Update the array of images with TrIQ filter listed in the public folder - triq_bmp=sort(filter(filename -> startswith(filename, "TrIQ_") && endswith(filename, ".bmp"), readdir("public")),lt=natural) - col_triq_png=sort(filter(filename -> startswith(filename, "colorbar_TrIQ_") && endswith(filename, ".png"), readdir("public")),lt=natural) + if isempty(selected_folder_main) return end + timestamp=string(time_ns()) + folder_path = joinpath("public", selected_folder_main) + if !isdir(folder_path) return end + + triq_bmp=sort(filter(filename -> startswith(filename, "TrIQ_") && endswith(filename, ".bmp"), readdir(folder_path)),lt=natural) + col_triq_png=sort(filter(filename -> startswith(filename, "colorbar_TrIQ_") && endswith(filename, ".png"), readdir(folder_path)),lt=natural) new_msi=decrement_image(current_triq, triq_bmp) new_col_msi=decrement_image(current_col_triq, col_triq_png) - if new_msi!=nothing || new_col_msi!=nothing - current_triq=new_msi - current_col_triq=new_col_msi - imgIntT="/$(current_triq)?t=$(timestamp)" - colorbarT="/$(current_col_triq)?t=$(timestamp)" - - text_nmass=replace(current_triq, "TrIQ_" => "") - text_nmass=replace(text_nmass, ".bmp" => "") - msgtriq="TrIQ image with the Nmass of $(replace(text_nmass, "_" => "."))" - # Process the image in the function - plotdataImgT, plotlayoutImgT, imgWidth, imgHeight=loadImgPlot(imgIntT) - btnOpticalDisable=false - else - traceImg=PlotlyBase.heatmap(x=[], y=[]) - plotdataImgT=[traceImg] - msgtriq="" + if new_msi !== nothing && new_col_msi !== nothing + current_triq = new_msi + current_col_triq = new_col_msi + imgIntT = "/$(selected_folder_main)/$(current_triq)?t=$(timestamp)" + colorbarT = "/$(selected_folder_main)/$(current_col_triq)?t=$(timestamp)" + text_nmass = replace(current_triq, r"TrIQ_|.bmp" => "") + msgtriq = "TrIQ m/z: $(replace(text_nmass, "_" => "."))" + plotdataImgT, plotlayoutImgT, _, _ = loadImgPlot(imgIntT) end end @onbutton imgPlusT begin - # Append a query string to force the image to refresh - timestamp=string(time_ns()) - # Update the array of images with TrIQ filter listed in the public folder - triq_bmp=sort(filter(filename -> startswith(filename, "TrIQ_") && endswith(filename, ".bmp"), readdir("public")),lt=natural) - col_triq_png=sort(filter(filename -> startswith(filename, "colorbar_TrIQ_") && endswith(filename, ".png"), readdir("public")),lt=natural) + if isempty(selected_folder_main) return end + timestamp=string(time_ns()) + folder_path = joinpath("public", selected_folder_main) + if !isdir(folder_path) return end + + triq_bmp=sort(filter(filename -> startswith(filename, "TrIQ_") && endswith(filename, ".bmp"), readdir(folder_path)),lt=natural) + col_triq_png=sort(filter(filename -> startswith(filename, "colorbar_TrIQ_") && endswith(filename, ".png"), readdir(folder_path)),lt=natural) new_msi=increment_image(current_triq, triq_bmp) new_col_msi=increment_image(current_col_triq, col_triq_png) - if new_msi!=nothing || new_col_msi!=nothing - current_triq=new_msi - current_col_triq=new_col_msi - imgIntT="/$(current_triq)?t=$(timestamp)" - colorbarT="/$(current_col_triq)?t=$(timestamp)" - - text_nmass=replace(current_triq, "TrIQ_" => "") - text_nmass=replace(text_nmass, ".bmp" => "") - msgtriq="TrIQ image with the Nmass of $(replace(text_nmass, "_" => "."))" - # Process the image in the function - plotdataImgT, plotlayoutImgT, imgWidth, imgHeight=loadImgPlot(imgIntT) - btnOpticalDisable=false - else - traceImg=PlotlyBase.heatmap(x=[], y=[]) - plotdataImgT=[traceImg] - msgtriq="" + if new_msi !== nothing && new_col_msi !== nothing + current_triq = new_msi + current_col_triq = new_col_msi + imgIntT = "/$(selected_folder_main)/$(current_triq)?t=$(timestamp)" + colorbarT = "/$(selected_folder_main)/$(current_col_triq)?t=$(timestamp)" + text_nmass = replace(current_triq, r"TrIQ_|.bmp" => "") + msgtriq = "TrIQ m/z: $(replace(text_nmass, "_" => "."))" + plotdataImgT, plotlayoutImgT, _, _ = loadImgPlot(imgIntT) end end - # Image loaders for the comparative view - @onbutton imgMinusComp begin - # Append a query string to force the image to refresh - timestamp=string(time_ns()) - # Update the array of images listed in the public folder - msi_bmp=sort(filter(filename -> startswith(filename, "MSI_") && endswith(filename, ".bmp"), readdir("public")),lt=natural) - col_msi_png=sort(filter(filename -> startswith(filename, "colorbar_MSI_") && endswith(filename, ".png"), readdir("public")),lt=natural) - - new_msi=decrement_image(current_msiComp, msi_bmp) - new_col_msi=decrement_image(current_col_msiComp, col_msi_png) - if new_msi!=nothing || new_col_msi!=nothing - current_msiComp=new_msi - current_col_msiComp=new_col_msi - imgIntComp="/$(current_msiComp)?t=$(timestamp)" - colorbarComp="/$(current_col_msiComp)?t=$(timestamp)" - - text_nmass=replace(current_msiComp, "MSI_" => "") - text_nmass=replace(text_nmass, ".bmp" => "") - msgimgComp="Image with the Nmass of $(replace(text_nmass, "_" => "."))" - # Process the image in the function - plotdataImgComp, plotlayoutImgComp, _, _=loadImgPlot(imgIntComp) - btnOpticalDisable=false - else - traceImg=PlotlyBase.heatmap(x=[], y=[]) - plotdataImgComp=[traceImg] - msgimgComp="" - end - end - - @onbutton imgPlusComp begin - # Append a query string to force the image to refresh + # --- Compare View Handlers --- + @onbutton imgMinusCompLeft begin + if isempty(selected_folder_compare_left) return end timestamp=string(time_ns()) - # Update the array of images listed in the public folder - msi_bmp=sort(filter(filename -> startswith(filename, "MSI_") && endswith(filename, ".bmp"), readdir("public")),lt=natural) - col_msi_png=sort(filter(filename -> startswith(filename, "colorbar_MSI_") && endswith(filename, ".png"), readdir("public")),lt=natural) + folder_path = joinpath("public", selected_folder_compare_left) + if !isdir(folder_path) return end + + msi_bmp=sort(filter(filename -> startswith(filename, "MSI_") && endswith(filename, ".bmp"), readdir(folder_path)),lt=natural) + col_msi_png=sort(filter(filename -> startswith(filename, "colorbar_MSI_") && endswith(filename, ".png"), readdir(folder_path)),lt=natural) + + new_msi=decrement_image(current_msiCompLeft, msi_bmp) + new_col_msi=decrement_image(current_col_msiCompLeft, col_msi_png) + if new_msi !== nothing && new_col_msi !== nothing + current_msiCompLeft = new_msi + current_col_msiCompLeft = new_col_msi + imgIntCompLeft = "/$(selected_folder_compare_left)/$(current_msiCompLeft)?t=$(timestamp)" + colorbarCompLeft = "/$(selected_folder_compare_left)/$(current_col_msiCompLeft)?t=$(timestamp)" + text_nmass = replace(current_msiCompLeft, r"MSI_|.bmp" => "") + msgimgCompLeft = "m/z: $(replace(text_nmass, "_" => "."))" + plotdataImgCompLeft, plotlayoutImgCompLeft, _, _ = loadImgPlot(imgIntCompLeft) + end + end + + @onbutton imgPlusCompLeft begin + if isempty(selected_folder_compare_left) return end + timestamp=string(time_ns()) + folder_path = joinpath("public", selected_folder_compare_left) + if !isdir(folder_path) return end + + msi_bmp=sort(filter(filename -> startswith(filename, "MSI_") && endswith(filename, ".bmp"), readdir(folder_path)),lt=natural) + col_msi_png=sort(filter(filename -> startswith(filename, "colorbar_MSI_") && endswith(filename, ".png"), readdir(folder_path)),lt=natural) - new_msi=increment_image(current_msiComp, msi_bmp) - new_col_msi=increment_image(current_col_msiComp, col_msi_png) - if new_msi!=nothing || new_col_msi!=nothing - current_msiComp=new_msi - current_col_msiComp=new_col_msi - imgIntComp="/$(current_msiComp)?t=$(timestamp)" - colorbarComp="/$(current_col_msiComp)?t=$(timestamp)" - - text_nmass=replace(current_msiComp, "MSI_" => "") - text_nmass=replace(text_nmass, ".bmp" => "") - msgimgComp="Image with the Nmass of $(replace(text_nmass, "_" => "."))" - # Process the image in the function - plotdataImgComp, plotlayoutImgComp, _, _=loadImgPlot(imgIntComp) - btnOpticalDisable=false - else - traceImg=PlotlyBase.heatmap(x=[], y=[]) - plotdataImgComp=[traceImg] - msgimgComp="" + new_msi=increment_image(current_msiCompLeft, msi_bmp) + new_col_msi=increment_image(current_col_msiCompLeft, col_msi_png) + if new_msi !== nothing && new_col_msi !== nothing + current_msiCompLeft = new_msi + current_col_msiCompLeft = new_col_msi + imgIntCompLeft = "/$(selected_folder_compare_left)/$(current_msiCompLeft)?t=$(timestamp)" + colorbarCompLeft = "/$(selected_folder_compare_left)/$(current_col_msiCompLeft)?t=$(timestamp)" + text_nmass = replace(current_msiCompLeft, r"MSI_|.bmp" => "") + msgimgCompLeft = "m/z: $(replace(text_nmass, "_" => "."))" + plotdataImgCompLeft, plotlayoutImgCompLeft, _, _ = loadImgPlot(imgIntCompLeft) end end - - @onbutton imgMinusTComp begin - # Append a query string to force the image to refresh - timestamp=string(time_ns()) - # Update the array of images with TrIQ filter listed in the public folder - triq_bmp=sort(filter(filename -> startswith(filename, "TrIQ_") && endswith(filename, ".bmp"), readdir("public")),lt=natural) - col_triq_png=sort(filter(filename -> startswith(filename, "colorbar_TrIQ_") && endswith(filename, ".png"), readdir("public")),lt=natural) - - new_msi=decrement_image(current_triqComp, triq_bmp) - new_col_msi=decrement_image(current_col_triqComp, col_triq_png) - if new_msi!=nothing || new_col_msi!=nothing - current_triqComp=new_msi - current_col_triqComp=new_col_msi - imgIntTComp="/$(current_triqComp)?t=$(timestamp)" - colorbarTComp="/$(current_col_triqComp)?t=$(timestamp)" - - text_nmass=replace(current_triqComp, "TrIQ_" => "") - text_nmass=replace(text_nmass, ".bmp" => "") - msgtriqComp="TrIQ image with the Nmass of $(replace(text_nmass, "_" => "."))" - # Process the image in the function - plotdataImgTComp, plotlayoutImgTComp, _, _=loadImgPlot(imgIntTComp) - btnOpticalDisable=false - else - traceImg=PlotlyBase.heatmap(x=[], y=[]) - plotdataImgTComp=[traceImg] - msgtriqComp="" + + @onbutton imgMinusTCompLeft begin + if isempty(selected_folder_compare_left) return end + timestamp=string(time_ns()) + folder_path = joinpath("public", selected_folder_compare_left) + if !isdir(folder_path) return end + + triq_bmp=sort(filter(filename -> startswith(filename, "TrIQ_") && endswith(filename, ".bmp"), readdir(folder_path)),lt=natural) + col_triq_png=sort(filter(filename -> startswith(filename, "colorbar_TrIQ_") && endswith(filename, ".png"), readdir(folder_path)),lt=natural) + + new_msi=decrement_image(current_triqCompLeft, triq_bmp) + new_col_msi=decrement_image(current_col_triqCompLeft, col_triq_png) + if new_msi !== nothing && new_col_msi !== nothing + current_triqCompLeft = new_msi + current_col_triqCompLeft = new_col_msi + imgIntTCompLeft = "/$(selected_folder_compare_left)/$(current_triqCompLeft)?t=$(timestamp)" + colorbarTCompLeft = "/$(selected_folder_compare_left)/$(current_col_triqCompLeft)?t=$(timestamp)" + text_nmass = replace(current_triqCompLeft, r"TrIQ_|.bmp" => "") + msgtriqCompLeft = "TrIQ m/z: $(replace(text_nmass, "_" => "."))" + plotdataImgTCompLeft, plotlayoutImgTCompLeft, _, _ = loadImgPlot(imgIntTCompLeft) end end - - @onbutton imgPlusTComp begin - # Append a query string to force the image to refresh - timestamp=string(time_ns()) - # Update the array of images with TrIQ filter listed in the public folder - triq_bmp=sort(filter(filename -> startswith(filename, "TrIQ_") && endswith(filename, ".bmp"), readdir("public")),lt=natural) - col_triq_png=sort(filter(filename -> startswith(filename, "colorbar_TrIQ_") && endswith(filename, ".png"), readdir("public")),lt=natural) - - new_msi=increment_image(current_triqComp, triq_bmp) - new_col_msi=increment_image(current_col_triqComp, col_triq_png) - if new_msi!=nothing || new_col_msi!=nothing - current_triqComp=new_msi - current_col_triqComp=new_col_msi - imgIntTComp="/$(current_triqComp)?t=$(timestamp)" - colorbarTComp="/$(current_col_triqComp)?t=$(timestamp)" - - text_nmass=replace(current_triqComp, "TrIQ_" => "") - text_nmass=replace(text_nmass, ".bmp" => "") - msgtriqComp="TrIQ image with the Nmass of $(replace(text_nmass, "_" => "."))" - # Process the image in the function - plotdataImgTComp, plotlayoutImgTComp, _, _=loadImgPlot(imgIntTComp) - btnOpticalDisable=false - else - traceImg=PlotlyBase.heatmap(x=[], y=[]) - plotdataImgTComp=[traceImg] - msgtriqComp="" + + @onbutton imgPlusTCompLeft begin + if isempty(selected_folder_compare_left) return end + timestamp=string(time_ns()) + folder_path = joinpath("public", selected_folder_compare_left) + if !isdir(folder_path) return end + + triq_bmp=sort(filter(filename -> startswith(filename, "TrIQ_") && endswith(filename, ".bmp"), readdir(folder_path)),lt=natural) + col_triq_png=sort(filter(filename -> startswith(filename, "colorbar_TrIQ_") && endswith(filename, ".png"), readdir(folder_path)),lt=natural) + + new_msi=increment_image(current_triqCompLeft, triq_bmp) + new_col_msi=increment_image(current_col_triqCompLeft, col_triq_png) + if new_msi !== nothing && new_col_msi !== nothing + current_triqCompLeft = new_msi + current_col_triqCompLeft = new_col_msi + imgIntTCompLeft = "/$(selected_folder_compare_left)/$(current_triqCompLeft)?t=$(timestamp)" + colorbarTCompLeft = "/$(selected_folder_compare_left)/$(current_col_triqCompLeft)?t=$(timestamp)" + text_nmass = replace(current_triqCompLeft, r"TrIQ_|.bmp" => "") + msgtriqCompLeft = "TrIQ m/z: $(replace(text_nmass, "_" => "."))" + plotdataImgTCompLeft, plotlayoutImgTCompLeft, _, _ = loadImgPlot(imgIntTCompLeft) end end + + @onbutton imgMinusCompRight begin + if isempty(selected_folder_compare_right) return end + timestamp=string(time_ns()) + folder_path = joinpath("public", selected_folder_compare_right) + if !isdir(folder_path) return end + + msi_bmp=sort(filter(filename -> startswith(filename, "MSI_") && endswith(filename, ".bmp"), readdir(folder_path)),lt=natural) + col_msi_png=sort(filter(filename -> startswith(filename, "colorbar_MSI_") && endswith(filename, ".png"), readdir(folder_path)),lt=natural) + + new_msi=decrement_image(current_msiCompRight, msi_bmp) + new_col_msi=decrement_image(current_col_msiCompRight, col_msi_png) + if new_msi !== nothing && new_col_msi !== nothing + current_msiCompRight = new_msi + current_col_msiCompRight = new_col_msi + imgIntCompRight = "/$(selected_folder_compare_right)/$(current_msiCompRight)?t=$(timestamp)" + colorbarCompRight = "/$(selected_folder_compare_right)/$(current_col_msiCompRight)?t=$(timestamp)" + text_nmass = replace(current_msiCompRight, r"MSI_|.bmp" => "") + msgimgCompRight = "m/z: $(replace(text_nmass, "_" => "."))" + plotdataImgCompRight, plotlayoutImgCompRight, _, _ = loadImgPlot(imgIntCompRight) + end + end + + @onbutton imgPlusCompRight begin + if isempty(selected_folder_compare_right) return end + timestamp=string(time_ns()) + folder_path = joinpath("public", selected_folder_compare_right) + if !isdir(folder_path) return end + + msi_bmp=sort(filter(filename -> startswith(filename, "MSI_") && endswith(filename, ".bmp"), readdir(folder_path)),lt=natural) + col_msi_png=sort(filter(filename -> startswith(filename, "colorbar_MSI_") && endswith(filename, ".png"), readdir(folder_path)),lt=natural) + + new_msi=increment_image(current_msiCompRight, msi_bmp) + new_col_msi=increment_image(current_col_msiCompRight, col_msi_png) + if new_msi !== nothing && new_col_msi !== nothing + current_msiCompRight = new_msi + current_col_msiCompRight = new_col_msi + imgIntCompRight = "/$(selected_folder_compare_right)/$(current_msiCompRight)?t=$(timestamp)" + colorbarCompRight = "/$(selected_folder_compare_right)/$(current_col_msiCompRight)?t=$(timestamp)" + text_nmass = replace(current_msiCompRight, r"MSI_|.bmp" => "") + msgimgCompRight = "m/z: $(replace(text_nmass, "_" => "."))" + plotdataImgCompRight, plotlayoutImgCompRight, _, _ = loadImgPlot(imgIntCompRight) + end + end + + @onbutton imgMinusTCompRight begin + if isempty(selected_folder_compare_right) return end + timestamp=string(time_ns()) + folder_path = joinpath("public", selected_folder_compare_right) + if !isdir(folder_path) return end + + triq_bmp=sort(filter(filename -> startswith(filename, "TrIQ_") && endswith(filename, ".bmp"), readdir(folder_path)),lt=natural) + col_triq_png=sort(filter(filename -> startswith(filename, "colorbar_TrIQ_") && endswith(filename, ".png"), readdir(folder_path)),lt=natural) + + new_msi=decrement_image(current_triqCompRight, triq_bmp) + new_col_msi=decrement_image(current_col_triqCompRight, col_triq_png) + if new_msi !== nothing && new_col_msi !== nothing + current_triqCompRight = new_msi + current_col_triqCompRight = new_col_msi + imgIntTCompRight = "/$(selected_folder_compare_right)/$(current_triqCompRight)?t=$(timestamp)" + colorbarTCompRight = "/$(selected_folder_compare_right)/$(current_col_triqCompRight)?t=$(timestamp)" + text_nmass = replace(current_triqCompRight, r"TrIQ_|.bmp" => "") + msgtriqCompRight = "TrIQ m/z: $(replace(text_nmass, "_" => "."))" + plotdataImgTCompRight, plotlayoutImgTCompRight, _, _ = loadImgPlot(imgIntTCompRight) + end + end + + @onbutton imgPlusTCompRight begin + if isempty(selected_folder_compare_right) return end + timestamp=string(time_ns()) + folder_path = joinpath("public", selected_folder_compare_right) + if !isdir(folder_path) return end + + triq_bmp=sort(filter(filename -> startswith(filename, "TrIQ_") && endswith(filename, ".bmp"), readdir(folder_path)),lt=natural) + col_triq_png=sort(filter(filename -> startswith(filename, "colorbar_TrIQ_") && endswith(filename, ".png"), readdir(folder_path)),lt=natural) + + new_msi=increment_image(current_triqCompRight, triq_bmp) + new_col_msi=increment_image(current_col_triqCompRight, col_triq_png) + if new_msi !== nothing && new_col_msi !== nothing + current_triqCompRight = new_msi + current_col_triqCompRight = new_col_msi + imgIntTCompRight = "/$(selected_folder_compare_right)/$(current_triqCompRight)?t=$(timestamp)" + colorbarTCompRight = "/$(selected_folder_compare_right)/$(current_col_triqCompRight)?t=$(timestamp)" + text_nmass = replace(current_triqCompRight, r"TrIQ_|.bmp" => "") + msgtriqCompRight = "TrIQ m/z: $(replace(text_nmass, "_" => "."))" + plotdataImgTCompRight, plotlayoutImgTCompRight, _, _ = loadImgPlot(imgIntTCompRight) + end + end + + # This handler will now correctly load the first image from the newly selected folder. + @onchange selected_folder_main begin + # The msi_data object lifecycle is managed by the btnSearch handler. + # This handler is now only for updating the UI images when the folder changes. + + if !isempty(selected_folder_main) + folder_path = joinpath("public", selected_folder_main) + if !isdir(folder_path) + imgInt = "" + colorbar = "" + imgIntT = "" + colorbarT = "" + msgimg = "Folder not found." + msgtriq = "Folder not found." + plotdataImg = [traceImg] + plotlayoutImg = layoutImg + plotdataImgT = [traceImg] + plotlayoutImgT = layoutImg + imgWidth, imgHeight = 0, 0 + return + end + + # Handle normal images + msi_bmp = sort(filter(filename -> startswith(filename, "MSI_") && endswith(filename, ".bmp"), readdir(folder_path)), lt=natural) + col_msi_png = sort(filter(filename -> startswith(filename, "colorbar_MSI_") && endswith(filename, ".png"), readdir(folder_path)), lt=natural) + + if !isempty(msi_bmp) + current_msi = first(msi_bmp) + imgInt = "/$(selected_folder_main)/$(current_msi)" + plotdataImg, plotlayoutImg, w, h = loadImgPlot(imgInt) + imgWidth, imgHeight = w, h + text_nmass = replace(current_msi, r"MSI_|.bmp" => "") + msgimg = "m/z: $(replace(text_nmass, "_" => "."))" + if !isempty(col_msi_png) + current_col_msi = first(col_msi_png) + colorbar = "/$(selected_folder_main)/$(current_col_msi)" + else + colorbar = "" + end + else + imgInt = "" + colorbar = "" + msgimg = "No MSI images found in this dataset." + plotdataImg = [traceImg] + plotlayoutImg = layoutImg + end + + # Handle TrIQ images + triq_bmp = sort(filter(filename -> startswith(filename, "TrIQ_") && endswith(filename, ".bmp"), readdir(folder_path)), lt=natural) + col_triq_png = sort(filter(filename -> startswith(filename, "colorbar_TrIQ_") && endswith(filename, ".png"), readdir(folder_path)), lt=natural) + + if !isempty(triq_bmp) + current_triq = first(triq_bmp) + imgIntT = "/$(selected_folder_main)/$(current_triq)" + plotdataImgT, plotlayoutImgT, w, h = loadImgPlot(imgIntT) + # If no MSI image was loaded, dimensions from TrIQ image are used. + if isempty(msi_bmp) + imgWidth, imgHeight = w, h + end + text_nmass = replace(current_triq, r"TrIQ_|.bmp" => "") + msgtriq = "TrIQ m/z: $(replace(text_nmass, "_" => "."))" + if !isempty(col_triq_png) + current_col_triq = first(col_triq_png) + colorbarT = "/$(selected_folder_main)/$(current_col_triq)" + else + colorbarT = "" + end + else + imgIntT = "" + colorbarT = "" + msgtriq = "No TrIQ images found in this dataset." + plotdataImgT = [traceImg] + plotlayoutImgT = layoutImg + end + + if isempty(msi_bmp) && isempty(triq_bmp) + imgWidth, imgHeight = 0, 0 + end + end + end + + @onchange selected_folder_compare_left begin + if !isempty(selected_folder_compare_left) + timestamp = string(time_ns()) + folder_path = joinpath("public", selected_folder_compare_left) + + if !isdir(folder_path) + imgIntCompLeft, colorbarCompLeft, imgIntTCompLeft, colorbarTCompLeft = "", "", "", "" + msgimgCompLeft, msgtriqCompLeft = "Folder not found.", "Folder not found." + return + end + + # Handle normal images + msi_bmp = sort(filter(f -> startswith(f, "MSI_") && endswith(f, ".bmp"), readdir(folder_path)), lt=natural) + col_msi_png = sort(filter(f -> startswith(f, "colorbar_MSI_") && endswith(f, ".png"), readdir(folder_path)), lt=natural) + + if !isempty(msi_bmp) + current_msiCompLeft = first(msi_bmp) + imgIntCompLeft = "/$(selected_folder_compare_left)/$(current_msiCompLeft)?t=$(timestamp)" + plotdataImgCompLeft, plotlayoutImgCompLeft, _, _ = loadImgPlot(imgIntCompLeft) + text_nmass = replace(current_msiCompLeft, r"MSI_|.bmp" => "") + msgimgCompLeft = "m/z: $(replace(text_nmass, "_" => "."))" + + if !isempty(col_msi_png) + current_col_msiCompLeft = first(col_msi_png) + colorbarCompLeft = "/$(selected_folder_compare_left)/$(current_col_msiCompLeft)?t=$(timestamp)" + else + colorbarCompLeft = "" + end + else + imgIntCompLeft, colorbarCompLeft, msgimgCompLeft = "", "", "No MSI images." + end + + # Handle TrIQ images + triq_bmp = sort(filter(f -> startswith(f, "TrIQ_") && endswith(f, ".bmp"), readdir(folder_path)), lt=natural) + col_triq_png = sort(filter(f -> startswith(f, "colorbar_TrIQ_") && endswith(f, ".png"), readdir(folder_path)), lt=natural) + + if !isempty(triq_bmp) + current_triqCompLeft = first(triq_bmp) + imgIntTCompLeft = "/$(selected_folder_compare_left)/$(current_triqCompLeft)?t=$(timestamp)" + plotdataImgTCompLeft, plotlayoutImgTCompLeft, _, _ = loadImgPlot(imgIntTCompLeft) + text_nmass = replace(current_triqCompLeft, r"TrIQ_|.bmp" => "") + msgtriqCompLeft = "m/z: $(replace(text_nmass, "_" => "."))" + + if !isempty(col_triq_png) + current_col_triqCompLeft = first(col_triq_png) + colorbarTCompLeft = "/$(selected_folder_compare_left)/$(current_col_triqCompLeft)?t=$(timestamp)" + else + colorbarTCompLeft = "" + end + else + imgIntTCompLeft, colorbarTCompLeft, msgtriqCompLeft = "", "", "No TrIQ images." + end + end + end + + @onchange selected_folder_compare_right begin + if !isempty(selected_folder_compare_right) + timestamp = string(time_ns()) + folder_path = joinpath("public", selected_folder_compare_right) + if !isdir(folder_path) + imgIntCompRight, colorbarCompRight, imgIntTCompRight, colorbarTCompRight = "", "", "", "" + msgimgCompRight, msgtriqCompRight = "Folder not found.", "Folder not found." + return + end + + # Handle normal images + msi_bmp = sort(filter(f -> startswith(f, "MSI_") && endswith(f, ".bmp"), readdir(folder_path)), lt=natural) + col_msi_png = sort(filter(f -> startswith(f, "colorbar_MSI_") && endswith(f, ".png"), readdir(folder_path)), lt=natural) + + if !isempty(msi_bmp) + current_msiCompRight = first(msi_bmp) + imgIntCompRight = "/$(selected_folder_compare_right)/$(current_msiCompRight)?t=$(timestamp)" + plotdataImgCompRight, plotlayoutImgCompRight, _, _ = loadImgPlot(imgIntCompRight) + text_nmass = replace(current_msiCompRight, r"MSI_|.bmp" => "") + msgimgCompRight = "m/z: $(replace(text_nmass, "_" => "."))" + + if !isempty(col_msi_png) + current_col_msiCompRight = first(col_msi_png) + colorbarCompRight = "/$(selected_folder_compare_right)/$(current_col_msiCompRight)?t=$(timestamp)" + else + colorbarCompRight = "" + end + else + imgIntCompRight, colorbarCompRight, msgimgCompRight = "", "", "No MSI images." + end + + # Handle TrIQ images + triq_bmp = sort(filter(f -> startswith(f, "TrIQ_") && endswith(f, ".bmp"), readdir(folder_path)), lt=natural) + col_triq_png = sort(filter(f -> startswith(f, "colorbar_TrIQ_") && endswith(f, ".png"), readdir(folder_path)), lt=natural) + + if !isempty(triq_bmp) + current_triqCompRight = first(triq_bmp) + imgIntTCompRight = "/$(selected_folder_compare_right)/$(current_triqCompRight)?t=$(timestamp)" + plotdataImgTCompRight, plotlayoutImgTCompRight, _, _ = loadImgPlot(imgIntTCompRight) + text_nmass = replace(current_triqCompRight, r"TrIQ_|.bmp" => "") + msgtriqCompRight = "TrIQ m/z: $(replace(text_nmass, "_" => "."))" + + if !isempty(col_triq_png) + current_col_triqCompRight = first(col_triq_png) + colorbarTCompRight = "/$(selected_folder_compare_right)/$(current_col_triqCompRight)?t=$(timestamp)" + else + colorbarTCompRight = "" + end + else + imgIntTCompRight, colorbarTCompRight, msgtriqCompRight = "", "", "No TrIQ images." + end + end + end + # 3d plot @onbutton image3dPlot begin - msg="Image 3D plot selected" - cleaned_imgInt=replace(imgInt, r"\?.*" => "") - cleaned_imgInt=lstrip(cleaned_imgInt, '/') - var=joinpath( "./public", cleaned_imgInt ) - sTime=time() + msg = "Image 3D plot selected" + cleaned_imgInt = replace(imgInt, r"\?.*" => "") + cleaned_imgInt = lstrip(cleaned_imgInt, '/') + var = joinpath("./public", cleaned_imgInt) - if isfile(var) - progressPlot=true - btnPlotDisable=true - btnStartDisable=true - btnSpectraDisable=true - try - plotdata3d, plotlayout3d=loadSurfacePlot(imgInt) - GC.gc() # Trigger garbage collection - if Sys.islinux() - ccall(:malloc_trim, Int32, (Int32,), 0) # Ensure julia returns the freed memory to OS - end - selectedTab="tab4" - fTime=time() - eTime=round(fTime-sTime,digits=3) - msg="Plot loaded in $(eTime) seconds" - catch e - msg="Failed to load and process image: $e" - warning_msg=true - end - else - msg="Image could not be 3d plotted" - warning_msg=true + if !isfile(var) + msg = "Image could not be 3d plotted" + warning_msg = true + return end - progressPlot=false - btnPlotDisable=false - btnStartDisable=false - if isfile(full_routeMz) - # We enable coord search and spectra plot creation - btnSpectraDisable=false + is_processing = true + + try + # --- Get Mask Path --- + local mask_path_for_plot::Union{String, Nothing} = nothing + if maskEnabled && !isempty(selected_folder_main) + registry = load_registry(registry_path) + entry = get(registry, selected_folder_main, nothing) + if entry !== nothing && get(entry, "has_mask", false) + mask_path_candidate = get(entry, "mask_path", "") + if isfile(mask_path_candidate) + mask_path_for_plot = mask_path_candidate + else + @warn "Mask enabled but file not found: $(mask_path_candidate). Plotting without mask." + end + end + end + # --- + + sTime = time() + if mask_path_for_plot !== nothing + plotdata3d, plotlayout3d = loadSurfacePlot(imgInt, mask_path_for_plot) + else + plotdata3d, plotlayout3d = loadSurfacePlot(imgInt) + end + + selectedTab = "tab4" + fTime = time() + eTime = round(fTime - sTime, digits=3) + msg = "Plot loaded in $(eTime) seconds" + log_memory_usage("Mean Plot Generated", msi_data) + catch e + msg = "Failed to load and process image: $e" + warning_msg = true + @error "3D plot generation failed" exception=(e, catch_backtrace()) + finally + is_processing = false SpectraEnabled=true + GC.gc() # Trigger garbage collection + if Sys.islinux() + ccall(:malloc_trim, Int32, (Int32,), 0) # Ensure Julia returns the freed memory to OS + end end end - # 3d plot for TrIQ + @onbutton triq3dPlot begin - msg="TrIQ 3D plot selected" - cleaned_imgIntT=replace(imgIntT, r"\?.*" => "") - cleaned_imgIntT=lstrip(cleaned_imgIntT, '/') - var=joinpath( "./public", cleaned_imgIntT ) - sTime=time() + msg = "TrIQ 3D plot selected" + cleaned_imgIntT = replace(imgIntT, r"\?.*" => "") + cleaned_imgIntT = lstrip(cleaned_imgIntT, '/') + var = joinpath("./public", cleaned_imgIntT) - if isfile(var) - progressPlot=true - btnPlotDisable=true - btnStartDisable=true - btnSpectraDisable=true - try - plotdata3d, plotlayout3d=loadSurfacePlot(imgIntT) - GC.gc() # Trigger garbage collection - if Sys.islinux() - ccall(:malloc_trim, Int32, (Int32,), 0) # Ensure julia returns the freed memory to OS - end - selectedTab="tab4" - fTime=time() - eTime=round(fTime-sTime,digits=3) - msg="Plot loaded in $(eTime) seconds" - catch e - msg="Failed to load and process image: $e" - warning_msg=true - end - else - msg="Image could not be 3d plotted" - warning_msg=true + if !isfile(var) + msg = "Image could not be 3d plotted" + warning_msg = true + return end - progressPlot=false - btnPlotDisable=false - btnStartDisable=false - if isfile(full_routeMz) - # We enable coord search and spectra plot creation - btnSpectraDisable=false + + is_processing = true + + try + # --- Get Mask Path --- + local mask_path_for_plot::Union{String, Nothing} = nothing + if maskEnabled && !isempty(selected_folder_main) + registry = load_registry(registry_path) + entry = get(registry, selected_folder_main, nothing) + if entry !== nothing && get(entry, "has_mask", false) + mask_path_candidate = get(entry, "mask_path", "") + if isfile(mask_path_candidate) + mask_path_for_plot = mask_path_candidate + else + @warn "Mask enabled but file not found: $(mask_path_candidate). Plotting without mask." + end + end + end + # --- + + sTime = time() + if mask_path_for_plot !== nothing + plotdata3d, plotlayout3d = loadSurfacePlot(imgIntT, mask_path_for_plot) + else + plotdata3d, plotlayout3d = loadSurfacePlot(imgIntT) + end + + selectedTab = "tab4" + fTime = time() + eTime = round(fTime - sTime, digits=3) + msg = "Plot loaded in $(eTime) seconds" + log_memory_usage("Mean Plot Generated", msi_data) + catch e + msg = "Failed to load and process image: $e" + warning_msg = true + @error "3D TrIQ plot generation failed" exception=(e, catch_backtrace()) + finally + is_processing = false SpectraEnabled=true + GC.gc() # Trigger garbage collection + if Sys.islinux() + ccall(:malloc_trim, Int32, (Int32,), 0) # Ensure Julia returns the freed memory to OS + end end end @@ -876,39 +3129,36 @@ include("./julia_imzML_visual.jl") cleaned_imgInt=replace(imgInt, r"\?.*" => "") cleaned_imgInt=lstrip(cleaned_imgInt, '/') var=joinpath("./public", cleaned_imgInt) - sTime=time() - - if isfile(var) - progressPlot=true - btnPlotDisable=true - btnStartDisable=true - btnSpectraDisable=true - try - img=load(var) - plotdataC,plotlayoutC=loadContourPlot(imgInt) - GC.gc() # Trigger garbage collection - if Sys.islinux() - ccall(:malloc_trim, Int32, (Int32,), 0) # Ensure Julia returns the freed memory to OS - end - selectedTab="tab3" - fTime=time() - eTime=round(fTime-sTime,digits=3) - msg="Plot loaded in $(eTime) seconds" - catch e - msg="Failed to load and process image: $e" - warning_msg=true - end - else + + if !isfile(var) msg="Image could not be 2D plotted" warning_msg=true + return end - progressPlot=false - btnPlotDisable=false - btnStartDisable=false - if isfile(full_routeMz) - # We enable coord search and spectra plot creation - btnSpectraDisable=false + + is_processing = true + + try + sTime=time() + plotdataC,plotlayoutC=loadContourPlot(imgInt) + GC.gc() # Trigger garbage collection + if Sys.islinux() + ccall(:malloc_trim, Int32, (Int32,), 0) # Ensure Julia returns the freed memory to OS + end + selectedTab="tab3" + fTime=time() + eTime=round(fTime-sTime,digits=3) + msg="Plot loaded in $(eTime) seconds" + catch e + msg="Failed to load and process image: $e" + warning_msg=true + finally + is_processing = false SpectraEnabled=true + GC.gc() + if Sys.islinux() + ccall(:malloc_trim, Int32, (Int32,), 0) + end end end # Contour 2d plot for TrIQ @@ -917,39 +3167,36 @@ include("./julia_imzML_visual.jl") cleaned_imgIntT=replace(imgIntT, r"\?.*" => "") cleaned_imgIntT=lstrip(cleaned_imgIntT, '/') var=joinpath("./public", cleaned_imgIntT) - sTime=time() - - if isfile(var) - progressPlot=true - btnPlotDisable=true - btnStartDisable=true - btnSpectraDisable=true - try - img=load(var) - plotdataC,plotlayoutC=loadContourPlot(imgIntT) - GC.gc() # Trigger garbage collection - if Sys.islinux() - ccall(:malloc_trim, Int32, (Int32,), 0) # Ensure Julia returns the freed memory to OS - end - selectedTab="tab3" - fTime=time() - eTime=round(fTime-sTime,digits=3) - msg="Plot loaded in $(eTime) seconds" - catch e - msg="Failed to load and process image: $e" - warning_msg=true - end - else + + if !isfile(var) msg="Image could not be 2D plotted" warning_msg=true + return end - progressPlot=false - btnPlotDisable=false - btnStartDisable=false - if isfile(full_routeMz) - # We enable coord search and spectra plot creation - btnSpectraDisable=false + + is_processing = true + + try + sTime=time() + plotdataC,plotlayoutC=loadContourPlot(imgIntT) + GC.gc() # Trigger garbage collection + if Sys.islinux() + ccall(:malloc_trim, Int32, (Int32,), 0) # Ensure Julia returns the freed memory to OS + end + selectedTab="tab3" + fTime=time() + eTime=round(fTime-sTime,digits=3) + msg="Plot loaded in $(eTime) seconds" + catch e + msg="Failed to load and process image: $e" + warning_msg=true + finally + is_processing = false SpectraEnabled=true + GC.gc() + if Sys.islinux() + ccall(:malloc_trim, Int32, (Int32,), 0) + end end end @@ -960,52 +3207,115 @@ include("./julia_imzML_visual.jl") # To include a visualization in the spectrum plot indicating where is the selected mass @onchange Nmass begin if !isempty(xSpectraMz) - traceSpectra=PlotlyBase.scatter(x=xSpectraMz, y=ySpectraMz, mode="lines",name="Spectra",showlegend=false) - trace2=PlotlyBase.scatter(x=[Nmass, Nmass],y=[0, maximum(ySpectraMz)],mode="lines",line=attr(color="red", width=0.5),name="m/z selected",showlegend=false) - plotdata=[traceSpectra,trace2] # We add the data from spectra and the red line to the plot + df = msi_data.spectrum_stats_df + plot_as_lines = false # Default to stem + if df !== nothing && hasproperty(df, :Mode) && !isempty(df.Mode) + profile_count = count(==(MSI_src.PROFILE), df.Mode) + plot_as_lines = profile_count > length(df.Mode) / 2 + end + + # Downsample for plotting performance + mz_down, int_down = MSI_src.downsample_spectrum(xSpectraMz, ySpectraMz) + + local traceSpectra + if plot_as_lines + # Main spectrum trace + traceSpectra = PlotlyBase.scatter( + x=mz_down, + y=int_down, + marker=attr(size=1, color="blue", opacity=0.5), + name="Spectrum", + hoverinfo="x", + hovertemplate="m/z: %{x:.4f}", + showlegend=false + ) + else + # Main spectrum trace + traceSpectra = PlotlyBase.stem( + x=mz_down, + y=int_down, + marker=attr(size=1, color="blue", opacity=0.5), + name="Spectrum", + hoverinfo="x", + hovertemplate="m/z: %{x:.4f}", + showlegend=false + ) + end + + # Parse all valid masses from the comma-separated string + mass_strs = split(Nmass, ',', keepempty=false) + mass_traces = [traceSpectra] # Start with the main spectrum + + valid_masses = Float64[] + for (idx, mass_str) in enumerate(mass_strs) + try + mass_val = parse(Float64, strip(mass_str)) + if mass_val > 0 # Only add valid positive masses + push!(valid_masses, mass_val) + + # Create a vertical line for this mass (Plotly will auto-assign colors) + mass_trace = PlotlyBase.scatter( + x=[mass_val, mass_val], + y=[0, maximum(ySpectraMz)], + mode="lines", + line=attr(width=1.5, dash="dash"), + name="m/z $(round(mass_val, digits=4))", + showlegend=false, + hoverinfo="x+name", + hovertemplate="%{data.name}" + ) + push!(mass_traces, mass_trace) + end + catch e + # Skip invalid entries, continue with next + continue + end + end + + # Update the plot data + plotdata = mass_traces end end # Event detection for clicking on the images @onchange data_click begin + if selectedTab == "tab1" || selectedTab == "tab0" + # This is for the image heatmaps + cursor_data = get(data_click, "cursor", nothing) + if cursor_data === nothing + return + end + + x_val = get(cursor_data, "x", nothing) + y_val = get(cursor_data, "y", nothing) + + if x_val === nothing || y_val === nothing + return # Do nothing if coordinates are not provided by the event + end + + x = Int32(round(x_val)) + y = Int32(round(y_val)) # y is negative in the UI + + # Update the reactive coordinates, which will trigger the crosshair update + xCoord = clamp(x, 1, imgWidth) + yCoord = clamp(y, -imgHeight, -1) + end + end + + @onchange xCoord, yCoord begin if selectedTab == "tab1" - cursor_data=data_click["cursor"] - xCoord=Int32(round(cursor_data["x"])) - yCoord=Int32(round(cursor_data["y"])) - if xCoord < 1 - xCoord=1 - elseif xCoord > imgWidth - xCoord=imgWidth - end - if yCoord > -1 - yCoord=-1 - elseif yCoord < -imgHeight - yCoord=-imgHeight - end # Get the x and y values from the click of the cursor and make sure they don't exceed image proportions - plotdataImgT=filter(trace -> !(get(trace, :name, "") in ["Line X", "Line Y"]), plotdataImgT) - trace1, trace2=crossLinesPlot(xCoord, yCoord, imgWidth, -imgHeight) - plotdataImgT=append!(plotdataImgT, [trace1, trace2]) + main_trace = plotdataImgT[1] # The heatmap/image trace + trace1, trace2 = crossLinesPlot(xCoord, yCoord, imgWidth, -imgHeight) + plotdataImgT = [main_trace, trace1, trace2] # Fresh array every time elseif selectedTab == "tab0" - cursor_data=data_click["cursor"] - xCoord=Int32(round(cursor_data["x"])) - yCoord=Int32(round(cursor_data["y"])) - if xCoord < 1 - xCoord=1 - elseif xCoord > imgWidth - xCoord=imgWidth - end - if yCoord > -1 - yCoord=-1 - elseif yCoord < -imgHeight - yCoord=-imgHeight - end # Get the x and y values from the click of the cursor and make sure they don't exceed image proportions - plotdataImg=filter(trace -> !(get(trace, :name, "") in ["Line X", "Line Y","Optical"]), plotdataImg) - trace1, trace2=crossLinesPlot(xCoord, yCoord, imgWidth, -imgHeight) - plotdataImg=append!(plotdataImg, [trace1, trace2]) + main_trace = plotdataImg[1] # The heatmap/image trace + trace1, trace2 = crossLinesPlot(xCoord, yCoord, imgWidth, -imgHeight) + plotdataImg = [main_trace, trace1, trace2] end end @onbutton btnOptical begin + is_processing = true imgRoute=pick_file(; filterlist="png,bmp,jpg,jpeg") if imgRoute=="" msg="No optical image selected" @@ -1016,10 +3326,11 @@ include("./julia_imzML_visual.jl") save("./public/css/imgOver.png",img) plotdataImg, plotlayoutImg, imgWidth, imgHeight=loadImgPlot(imgInt,"/css/imgOver.png",imgTrans) end - + is_processing = false end @onbutton btnOpticalT begin + is_processing = true imgRoute=pick_file(; filterlist="png,bmp,jpg,jpeg") if imgRoute=="" msg="No optical image selected" @@ -1031,6 +3342,7 @@ include("./julia_imzML_visual.jl") plotdataImgT, plotlayoutImgT, imgWidth, imgHeight=loadImgPlot(imgIntT,"/css/imgOver.png",imgTrans) opticalOverTriq=true end + is_processing = false end @onchange imgTrans begin @@ -1053,8 +3365,106 @@ include("./julia_imzML_visual.jl") end end + @onbutton refetch_folders begin + is_processing = true + # Re-load registry and update folder lists + registry = load_registry(registry_path) + all_folders = sort(collect(keys(registry)), lt=natural) + img_folders = filter(folder -> get(get(registry, folder, Dict()), "is_imzML", false), all_folders) + + available_folders = deepcopy(all_folders) + image_available_folders = deepcopy(img_folders) + + # For q-selects using image_available_folders + if !isempty(image_available_folders) + first_img_folder = first(image_available_folders) + if isempty(selected_folder_main) + selected_folder_main = first_img_folder + end + if isempty(selected_folder_compare_left) + selected_folder_compare_left = first_img_folder + end + if isempty(selected_folder_compare_right) + selected_folder_compare_right = first_img_folder + end + end + + # For q-selects using available_folders + if !isempty(available_folders) + if isempty(selected_folder_metadata) + selected_folder_metadata = first(available_folders) + end + end + is_processing = false + end + @mounted watchplots() + @onchange isready begin + # is_processing = true + if isready && !registry_init_done + sTime=time() + msg = "Pre-compiling functions at startup..." + warmup_init() + msg = "Pre-compilation finished." + try + msg = "Synchronizing registry with filesystem on backend init..." + reg_path = abspath(joinpath(@__DIR__, "public", "registry.json")) + registry = isfile(reg_path) ? load_registry(reg_path) : Dict{String, Any}() + + public_dirs = isdir("public") ? readdir("public") : [] + ignored_dirs = ["css", "masks"] + + dataset_dirs = filter(d -> isdir(joinpath("public", d)) && !(d in ignored_dirs), public_dirs) + + registry_keys = Set(keys(registry)) + folder_set = Set(dataset_dirs) + + new_folders = setdiff(folder_set, registry_keys) + for folder in new_folders + println("Found new folder: $folder") + registry[folder] = Dict( + "source_path" => "unknown (manually added)", + "processed_date" => "unknown", + "metadata" => Dict(), + "is_imzML" => true # Assume folder contains images if found this way + ) + end + + removed_folders = setdiff(registry_keys, folder_set) + for folder in removed_folders + delete!(registry, folder) + end + + if !isempty(new_folders) || !isempty(removed_folders) + msg = "Registry changed, saving..." + save_registry(reg_path, registry) + end + + all_folders = sort(collect(keys(registry)), lt=natural) + img_folders = filter(folder -> get(get(registry, folder, Dict()), "is_imzML", false), all_folders) + + available_folders = deepcopy(all_folders) + image_available_folders = deepcopy(img_folders) + + println("UI lists updated. All: $(length(available_folders)), Images: $(length(image_available_folders))") + catch e + @warn "Registry synchronization failed: $e" + available_folders = [] + image_available_folders = [] + selected_files = String[] + finally + registry_init_done = true + is_initializing = false # Hide loading screen when initialization is complete + end + end + fTime=time() + eTime=round(fTime-sTime,digits=3) + is_initializing = false # Hide loading screen when initialization is complete (current code is hidden due to incompatibility) + msg = "The app took $(eTime) seconds to get ready." + log_memory_usage("App Ready", msi_data) + end + # is_processing = false GC.gc() # Trigger garbage collection if Sys.islinux() ccall(:malloc_trim, Int32, (Int32,), 0) # Ensure julia returns the freed memory to OS @@ -1063,4 +3473,4 @@ end # == Pages == # Register a new route and the page that will be loaded on access @page("/", "app.jl.html") -end +end \ No newline at end of file diff --git a/app.jl.html b/app.jl.html index 77c2180..736c96c 100644 --- a/app.jl.html +++ b/app.jl.html @@ -1,62 +1,759 @@ -