Added Colorbar for each slice of scan

improved UI, better response, better bug report, minor fixes
This commit is contained in:
José Julián Sierra Álvarez 2024-09-18 21:15:18 -06:00 committed by GitHub
parent 2aaa53ee42
commit 1caf0a76c3
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 114 additions and 93 deletions

View File

@ -1,18 +1,22 @@
# Julia_imzML_GUI<br /> # Julia_msi_GUI<br />
A Graphical User Interface created with Julia Genie Builder made for this repository: https://github.com/CINVESTAV-LABI/julia_mzML_imzML that generates images with the imzML and ibd files.<br /> A Graphical User Interface created with <i>Julia Genie Builder</i> made for to assist in the use of this repository: https://github.com/CINVESTAV-LABI/julia_mzML_imzML which generates images with the mzMl, imzML and ibd files.<br />
For this to work you must insert the next lines as they are depicted in your Julia terminal for the first time only: <br /> For the correct implementation and use of this repository one must insert the next lines just as they are depicted in your <b>Julia</b> terminal to install the dependencies needed, this part is only needed once. <br />
``` ```
julia julia
] ]
add Pkg Libz ; add https://github.com/CINVESTAV-LABI/julia_mzML_imzML ; add PlotlyBase ; add Statistics add Pkg Libz ; add https://github.com/CINVESTAV-LABI/julia_mzML_imzML ; add PlotlyBase ; add Statistics ; add CairoMakie ; add Colors ; add
```
Then open a terminal on the directory "JuliaIMZML_GUI" and put the next code: <br />
```
julia
]
activate .
add Genie add Genie
##(press backspace) ```
Then open a <b>Julia</b> terminal on the directory <i>"Julia_msi_GUI"</i> and put the next code, this is needed every time you want to run the GUI: <br />
```
]
```
to enter Pkg mode.
```
activate .
```
Press backspace key to exit Pkg mode.
```
using Genie ; Genie.loadapp() ; up() using Genie ; Genie.loadapp() ; up()
``` ```
And finally open the port that gets generated to access to the GUI<br /> And finally open the port that gets generated to access to the GUI<br />

136
app.jl
View File

@ -1,20 +1,22 @@
module App module App
# == Packages == # == Packages ==
# set up Genie development environment. using GenieFramework # set up Genie development environment.
using GenieFramework
using Pkg using Pkg
using Libz using Libz
using PlotlyBase using PlotlyBase
using CairoMakie
using Colors
using julia_mzML_imzML using julia_mzML_imzML
using Statistics using Statistics
@genietools @genietools
# == Code import == # == Code import ==
# add your data analysis code here or in the lib folder. Code in lib/ will be # add your data analysis code here or in the lib folder. Code in lib/ will be
# automatically loaded # automatically loaded
rgb_ViridisPalette =reinterpret(ColorTypes.RGB24, ViridisPalette)
# == Reactive code == # == Reactive code ==
# add reactive code to make the UI interactive # reactive code to make the UI interactive
@app begin @app begin
# == Reactive variables == # == Reactive variables ==
# reactive variables exist in both the Julia backend and the browser with two-way synchronization # reactive variables exist in both the Julia backend and the browser with two-way synchronization
@ -42,14 +44,16 @@ using Statistics
@in ImgPlusT = false @in ImgPlusT = false
@in ImgMinusT = false @in ImgMinusT = false
@out testT = "/.bmp" @out testT = "/.bmp"
@in msg = "" @out msg = ""
@in msgimg = "" @out msgimg = ""
@in msgtriq = "" @out msgtriq = ""
@out full_route = "" @out full_route = ""
@out full_routeMz = "" @out full_routeMz = ""
@out full_routeMz2 = "" @out full_routeMz2 = ""
@out colorbar = "/.png"
@out colorbarT = "/.png"
layoutSpectra = PlotlyBase.Layout( layoutSpectra = PlotlyBase.Layout(
title = "Spectra Plot", title = "SUM Spectrum plot",
xaxis = PlotlyBase.attr( xaxis = PlotlyBase.attr(
title = "<i>m/z</i>", title = "<i>m/z</i>",
showgrid = true showgrid = true
@ -63,41 +67,45 @@ using Statistics
) )
traceSpectra = PlotlyBase.scatter(x=[], y=[], mode="lines") traceSpectra = PlotlyBase.scatter(x=[], y=[], mode="lines")
@out plotdata = [traceSpectra] @out plotdata = [traceSpectra]
@out plotlayout = layoutSpectra @out plotlayout = layoutSpectra
# == Reactive handlers == # == Reactive handlers ==
# reactive handlers watch a variable and execute a block of code when # reactive handlers watch a variable and execute a block of code when
# its value changes # its value changes
@onchange triqEnabled begin @onchange triqEnabled begin
if !triqEnabled if !triqEnabled
triqProb = 0.0 #triqProb = 0.0
triqColor = 0 #triqColor = 0
end end
end end
@onchange file_name begin @onchange file_name begin
msg = ""
if contains(file_name,".imzML") if contains(file_name,".imzML")
warning_fr = "" warning_fr = ""
full_route = joinpath( file_route, file_name ) full_route = joinpath( file_route, file_name )
if isfile(full_route) # check if the file exists if isfile(full_route) # check if the file exists
full_routeMz = split( full_route, "." )[1] * ".mzML" # Splitting the route from imzml to mzml so the plotting can work full_routeMz = split( full_route, "." )[1] * ".mzML" # Splitting the route from imzml to mzml so the plotting can work
if isfile(full_routeMz) && (full_routeMz2 == "" || full_routeMz2 != full_routeMz) # check if there is an mzML file around if isfile(full_routeMz) && (full_routeMz2 == "" || full_routeMz2 != full_routeMz) # check if there is an mzML file around
Disab_btn = true Disab_btn = true
warning_fr = "Loading plot..." warning_fr = "Loading plot..."
spectraMz = LoadMzml(full_routeMz) spectraMz = LoadMzml(full_routeMz)
# dims = size(spectraMz) # dims = size(spectraMz)
# scansMax = dims[2] # we get the total of scansMax # scansMax = dims[2] # we get the total of scansMax
# traceSpectra = PlotlyBase.scatter(x = spectraMz[1, 1], y = spectraMz[2, 1], mode="lines") # traceSpectra = PlotlyBase.scatter(x = spectraMz[1, 1], y = spectraMz[2, 1], mode="lines")
traceSpectra = PlotlyBase.scatter(x = mean(spectraMz[1,:]), y = mean(spectraMz[2,:]), mode="lines") traceSpectra = PlotlyBase.scatter(x = mean(spectraMz[1,:]), y = mean(spectraMz[2,:]), mode="lines")
plotdata = [traceSpectra] # we add the data of spectra to the plot plotdata = [traceSpectra] # we add the data of spectra to the plot
spectraMz = nothing # Important for memory cleaning spectraMz = nothing # Important for memory cleaning
GC.gc() # Trigger garbage collection GC.gc() # Trigger garbage collection
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
warning_fr = "Plot loaded." warning_fr = "Plot loaded."
Disab_btn = false Disab_btn = false
full_routeMz2 = full_routeMz # to avoid creating the plot if its the same file read as before full_routeMz2 = full_routeMz # to avoid creating the plot if its the same file read as before
end end
else
warning_fr = "is not an imzML file"
end end
else else
full_route = "/"
warning_fr = "is not an imzML file" warning_fr = "is not an imzML file"
end end
end end
@ -106,39 +114,45 @@ using Statistics
indeximgTriq = floor(Int, Nmass) indeximgTriq = floor(Int, Nmass)
lastimg = floor(Int, Nmass) lastimg = floor(Int, Nmass)
lastimgTriq = floor(Int, Nmass) lastimgTriq = floor(Int, Nmass)
end end
# the onbutton handler will set the variable to false after the block is executed # The onbutton handler will set the variable to false after the block is executed
@onbutton Main_Process begin @onbutton Main_Process begin
Disab_btn = true #We disable the button to avoid multiple requests Disab_btn = true # We disable the button to avoid multiple requests
indeximg = floor(Int, Nmass) indeximg = floor(Int, Nmass)
full_route = joinpath(file_route, file_name) full_route = joinpath(file_route, file_name)
if isfile(full_route) && Nmass > 0 && Tol > 0 && Tol <= 1 if isfile(full_route) && Nmass > 0 && Tol > 0 && Tol <= 1
msg = "File exists, Nmass=$(Nmass) Tol=$(Tol). Please do not press the start button until confirmation" msg = "File exists, Nmass=$(Nmass) Tol=$(Tol). Loading file will begin, please be patient."
spectra = LoadImzml(full_route) try
msg = "File loaded. Please do not press the start button until confirmation" spectra = LoadImzml(full_route)
slice = GetSlice(spectra, Nmass, Tol) msg = "File loaded. Creating Spectra with the specific mass and tolerance, please be patient."
if triqProb != 0 # if we have TrIQ slice = GetSlice(spectra, Nmass, Tol)
if triqColor < 1 || triqColor > 256 fig = CairoMakie.Figure(size = (100, 200)) #container
triqColor = 1 if triqEnabled # if we have TrIQ
if triqColor < 1 || triqColor > 256 ||triqProb < 0 || triqProb > 1
msg = "Incorrect TrIQ values, please adjust accordingly and try again."
else
SaveBitmap(joinpath("public", "TrIQ_$(floor(Int, Nmass)).bmp"),TrIQ(slice, Int(triqColor), triqProb),ViridisPalette)
testT = "/TrIQ_$(floor(Int, Nmass)).bmp" # we define the starting value of the images
msgtriq = "TrIQ image with the Nmass of $(floor(Int, Nmass))"
Colorbar(fig[1, 1], colormap = rgb_ViridisPalette, limits = (0, maximum(TrIQ(slice, Int(triqColor), triqProb))))
save("public/colorbar_TrIQ_$(floor(Int, Nmass)).png", fig)
msg = "The file has been created successfully inside the 'public' folder of the app."
colorbarT = "/colorbar_TrIQ_$(floor(Int, Nmass)).png"
end
else # if we don't use TrIQ
SaveBitmap(joinpath("public", "$(floor(Int, Nmass)).bmp"),IntQuant(slice),ViridisPalette)
test = "/$(floor(Int, Nmass)).bmp" # we define the starting value of the images
msgimg = "image with the Nmass of $(floor(Int, Nmass))"
Colorbar(fig[1, 1], colormap = rgb_ViridisPalette, limits = (0, maximum(slice)))
save("public/colorbar_$(floor(Int, Nmass)).png", fig)
msg = "The file has been created successfully inside the 'public' folder of the app."
colorbar = "/colorbar_$(floor(Int, Nmass)).png"
end end
if triqProb < 0 || triqProb > 1 catch e
triqProb = 0.1 msg = "There was an error loading the ImzML file, please verify the file accordingly and try again. $(e)"
end
SaveBitmap(joinpath("public", "TrIQ_$(floor(Int, Nmass)).bmp"),
TrIQ(slice, Int(triqColor), triqProb),
ViridisPalette)
testT = "/TrIQ_$(floor(Int, Nmass)).bmp" # we define the starting value of the images
msgtriq = "TrIQ image with the Nmass of $(floor(Int, Nmass))"
else # if we don't
SaveBitmap(joinpath("public", "$(floor(Int, Nmass)).bmp"),
IntQuant(slice),
ViridisPalette)
test = "/$(floor(Int, Nmass)).bmp" # we define the starting value of the images
msgimg = "image with the Nmass of $(floor(Int, Nmass))"
end end
msg = "The file has been created inside the 'public' folder of the app"
else else
msg = "File does not exist or a parameter was not well inputted" msg = "File does not exist or a parameter is incorrect, please try again."
end end
spectra = nothing # Important for memory cleaning spectra = nothing # Important for memory cleaning
slice = nothing slice = nothing
@ -155,10 +169,9 @@ using Statistics
indeximg = lastimg indeximg = lastimg
end end
test = "/$(indeximg).bmp" test = "/$(indeximg).bmp"
colorbar = "/colorbar_$(indeximg).png"
msgimg = "image with the Nmass of $(indeximg)" msgimg = "image with the Nmass of $(indeximg)"
lastimg = indeximg lastimg = indeximg
GC.gc() # Trigger garbage collection
ccall(:malloc_trim, Int32, (Int32,), 0) # Ensure julia returns the freed memory to OS
end end
@onbutton ImgPlus begin @onbutton ImgPlus begin
indeximg+=1 indeximg+=1
@ -169,10 +182,9 @@ using Statistics
indeximg = lastimg indeximg = lastimg
end end
test = "/$(indeximg).bmp" test = "/$(indeximg).bmp"
colorbar = "/colorbar_$(indeximg).png"
msgimg = "image with the Nmass of $(indeximg)" msgimg = "image with the Nmass of $(indeximg)"
lastimg = indeximg lastimg = indeximg
GC.gc() # Trigger garbage collection
ccall(:malloc_trim, Int32, (Int32,), 0) # Ensure julia returns the freed memory to OS
end end
@onbutton ImgMinusT begin @onbutton ImgMinusT begin
@ -184,10 +196,9 @@ using Statistics
indeximgTriq = lastimgTriq indeximgTriq = lastimgTriq
end end
testT = "/TrIQ_$(indeximgTriq).bmp" testT = "/TrIQ_$(indeximgTriq).bmp"
colorbarT = "/colorbar_TrIQ_$(indeximgTriq).png"
msgtriq = "TrIQ image with the Nmass of $(indeximgTriq)" msgtriq = "TrIQ image with the Nmass of $(indeximgTriq)"
lastimgTriq = indeximgTriq lastimgTriq = indeximgTriq
GC.gc() # Trigger garbage collection
ccall(:malloc_trim, Int32, (Int32,), 0) # Ensure julia returns the freed memory to OS
end end
@onbutton ImgPlusT begin @onbutton ImgPlusT begin
indeximgTriq+=1 indeximgTriq+=1
@ -198,10 +209,9 @@ using Statistics
indeximgTriq = lastimgTriq indeximgTriq = lastimgTriq
end end
testT = "/TrIQ_$(indeximgTriq).bmp" testT = "/TrIQ_$(indeximgTriq).bmp"
colorbarT = "/colorbar_TrIQ_$(indeximgTriq).png"
msgtriq = "TrIQ image with the Nmass of $(indeximgTriq)" msgtriq = "TrIQ image with the Nmass of $(indeximgTriq)"
lastimgTriq = indeximgTriq lastimgTriq = indeximgTriq
GC.gc() # Trigger garbage collection
ccall(:malloc_trim, Int32, (Int32,), 0) # Ensure julia returns the freed memory to OS
end end
GC.gc() # Trigger garbage collection GC.gc() # Trigger garbage collection
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
@ -213,7 +223,7 @@ end
# == Advanced features == # == Advanced features ==
#= #=
- The @private macro defines a reactive variable that is not sent to the browser. - The @private macro defines a reactive variable that is not sent to the browser.
This is useful for storing data that is unique to each user session but is not needed This is useful for storing data that is unique to each user session but is not needed
in the UI. in the UI.
@private table = DataFrame(a = 1:10, b = 10:19, c = 20:29) @private table = DataFrame(a = 1:10, b = 10:19, c = 20:29)

View File

@ -1,13 +1,15 @@
<header> <header id="ikbk"><!--<img src="/css/biotech_100dp_1B1F3B.png" alt="Bioteck Icon" id="i65e">-->
<h4>Julia mzML imzML GUI&nbsp;</h4> <img src="/css/LABI_logo.jpeg" alt="Labi Logo Icon" id="i65e">
<h6>Please make sure the ibd, the mzML and the imzML files are located in the same directory and have the same name</h6> <div>
<h6>It may take a while to generate the image and the plot, please be patient</h6> <h4>Julia mzML imzML analysis GUI&nbsp;</h4>
<h6>Please make sure the ibd, the mzML and the imzML files are located in the same directory and have the same name.</h6>
<h6>It may take a while to generate the image and the plot, please be patient.</h6>
</div>
</header> </header>
<div class="row"> <div class="row">
<div class="st-col col-12 col-sm st-module"> <div class="st-col col-12 col-sm st-module" id="i0xj8">
<div class="row"> <div class="row">
<div class="st-col col-12 col-sm st-module"> <div class="st-col col-12 col-sm st-module" id="idbha">
<!--Left DIV--> <!--Left DIV-->
<!--<q-file v-model="file_route" filled="" label="Select your imzML file" accept=".imzML"></q-file>--> <!--<q-file v-model="file_route" filled="" label="Select your imzML file" accept=".imzML"></q-file>-->
<q-input id="ijii1" v-model="file_route" :dense="true" label="Insert the route to your imzML file"></q-input> <q-input id="ijii1" v-model="file_route" :dense="true" label="Insert the route to your imzML file"></q-input>
@ -15,12 +17,12 @@
<p id="i7brk">full route: {{full_route}} {{warning_fr}}</p> <p id="i7brk">full route: {{full_route}} {{warning_fr}}</p>
<div class="row"> <div class="row">
<div class="st-col col-12 col-sm"> <div class="st-col col-12 col-sm">
<q-input id="icc9d" v-model="Nmass" :dense="true" label="Mass Value" type="number" :rules="[ <q-input id="icc9d" v-model="Nmass" :dense="true" label="Mass-to-charge ratio of interest" type="number" :rules="[
val => val >= 0 || 'Need positive mass values', val => val >= 0 || 'Need positive mass values',
]"></q-input> ]"></q-input>
</div> </div>
<div class="st-col col-12 col-sm"> <div class="st-col col-12 col-sm">
<q-input id="iqt3l" step="0.01" v-model="Tol" :dense="true" label="Tolerance" type="number" :rules="[ <q-input id="iqt3l" step="0.01" v-model="Tol" :dense="true" label="Mass-to-charge ratio Tolerance" type="number" :rules="[
val => !!val || '* Required', val => !!val || '* Required',
val => val >= 0 &amp;&amp; val <= 1 || 'Needs to be in range between 0 and 1', val => val >= 0 &amp;&amp; val <= 1 || 'Needs to be in range between 0 and 1',
]"></q-input> ]"></q-input>
@ -38,7 +40,7 @@
]" :readonly="!triqEnabled"></q-input> ]" :readonly="!triqEnabled"></q-input>
</div> </div>
<div class="st-col col-12 col-sm-4"> <div class="st-col col-12 col-sm-4">
<q-input id="i28wb-2" step="1" v-model="triqColor" :dense="true" label="TrIQ Color" type="number" :rules="[ <q-input id="i28wb-2" step="1" v-model="triqColor" :dense="true" label="TrIQ Color Levels" type="number" :rules="[
val => val >= 0 &amp;&amp; val <= 256 || 'Needs to be in range between 1 and 256', val => val >= 0 &amp;&amp; val <= 256 || 'Needs to be in range between 1 and 256',
]" :readonly="!triqEnabled"></q-input> ]" :readonly="!triqEnabled"></q-input>
</div> </div>
@ -46,29 +48,34 @@
<q-btn id="isfqg" :disabled="Disab_btn" color="primary" icon="play_arrow" v-on:click="Main_Process = true" label="Start"></q-btn> <q-btn id="isfqg" :disabled="Disab_btn" color="primary" icon="play_arrow" v-on:click="Main_Process = true" label="Start"></q-btn>
<p>{{msg}}</p> <p>{{msg}}</p>
</div> </div>
</div> </div><!-- <plotly :data="plotdata" :layout="plotlayout"> </plotly>-->
<!-- <plotly :data="plotdata" :layout="plotlayout"> </plotly>-->
</div> </div>
<div class="st-col col-12 col-sm st-module"> <div class="st-col col-12 col-sm st-module" id="i8pdn">
<div class="row"> <div class="row">
<div class="st-col col-12 col-sm st-module"> <div class="st-col col-12 col-sm st-module" id="ihxlc">
<!--Right DIV--> <!--Right DIV-->
<h6>Image Visualizer</h6><br> <h6>Image Visualizer</h6><br>
<p></p> <p></p>
<q-btn id="ijhjl-2" color="primary" icon="arrow_back" label="Previous" v-on:click="ImgMinus = true"></q-btn> <q-btn id="ijhjl-2" color="primary" icon="arrow_back" label="Previous" v-on:click="ImgMinus = true"></q-btn>
<q-btn id="i3zt1" color="primary" icon="arrow_forward" label="Next" v-on:click="ImgPlus = true"></q-btn> <q-btn id="i3zt1" color="primary" icon="arrow_forward" label="Next" v-on:click="ImgPlus = true"></q-btn>
<q-img id="i6e3p" :src="test"></q-img> <div id="image-container" class="row col-12">
<div class="col-10"><q-img id="i6e3p" :src="test"></q-img></div>
<div class="col-2"><q-img id="colorbar" :src="colorbar"></q-img></div>
</div>
<p>{{msgimg}}</p> <p>{{msgimg}}</p>
<q-btn id="ijhjl-2-2" color="primary" icon="arrow_back" label="Previous" v-on:click="ImgMinusT = true"></q-btn> <q-btn id="ijhjl-2-2" color="primary" icon="arrow_back" label="Previous" v-on:click="ImgMinusT = true"></q-btn>
<q-btn id="i3zt1-2" color="primary" icon="arrow_forward" label="Next" v-on:click="ImgPlusT = true"></q-btn> <q-btn id="i3zt1-2" color="primary" icon="arrow_forward" label="Next" v-on:click="ImgPlusT = true"></q-btn>
<q-img id="i6e3p-2" :src="testT"></q-img> <div id="image-container" class="row col-12">
<div class="col-10"><q-img id="i6e3p-2" :src="testT"></q-img></div>
<div class="col-2"><q-img id="colorbar-2" :src="colorbarT"></q-img></div>
</div>
<p>{{msgtriq}}</p> <p>{{msgtriq}}</p>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
<div class="row"> <div class="row">
<div class="st-col col-12 col-sm st-module"> <div class="st-col col-12 col-sm st-module">
<plotly :data="plotdata" :layout="plotlayout"> </plotly> <plotly id="iiglk" :data="plotdata" :layout="plotlayout"></plotly>
</div> </div>
</div> </div>