Images are now plots, now you can select the pixel of the plot to create a spectra according to those coordenates, gave more clearness to the code by creating functions for some processes

This commit is contained in:
Pixelguy14 2025-01-26 13:48:18 -06:00
parent b660d7defb
commit 7667bc26e9
5 changed files with 401 additions and 277 deletions

View File

@ -9,12 +9,12 @@ A Graphical User Interface for MSI in Julia: https://github.com/CINVESTAV-LABI/j
unzip the file in your desired location<br> unzip the file in your desired location<br>
## Load User Interface ## Load User Interface
1. Set working directory to Julia_msi_GUI (this repository) in your terminal using: 1. Set working directory to Julia_msi_GUI (this repository) in your terminal using:<br>
linux: Linux:
``` ```
cd PathToRepository/Julia_msi_GUI-main cd PathToRepository/Julia_msi_GUI-main
``` ```
windows/mac: Windows/Mac:
``` ```
cd PathToRepository\Julia_msi_GUI-main cd PathToRepository\Julia_msi_GUI-main
``` ```
@ -24,7 +24,7 @@ A Graphical User Interface for MSI in Julia: https://github.com/CINVESTAV-LABI/j
``` ```
3. After the script has finished loading, it should open a page (http://127.0.0.1:1481/) in your browser with the web app running. 3. After the script has finished loading, it should open a page (http://127.0.0.1:1481/) in your browser with the web app running.
Additional notes: Additional notes:<br>
After the first boot initializes the packages in your computer, subsequent uses of the app should not take longer to load. After the first boot initializes the packages in your computer, subsequent uses of the app should not take longer to load.<br>
Recomended system requirements: 4 core processor, 8 GB ram Recomended system requirements: 4 core processor, 8 GB ram<br>
Minimum system requirements: 2 core processor, 8 GB ram (long loading times) Minimum system requirements: 2 core processor, 8 GB ram (long loading times)<br>

641
app.jl
View File

@ -15,18 +15,18 @@ using NativeFileDialog # Opens the file explorer depending on the OS
using StipplePlotly using StipplePlotly
@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) rgb_ViridisPalette=reinterpret(ColorTypes.RGB24, ViridisPalette)
# ==Search functions == # == Search functions ==
function increment_image(current_image, image_list) function increment_image(current_image, image_list)
if isempty(image_list) if isempty(image_list)
return nothing return nothing
end end
current_index=findfirst(isequal(current_image), image_list) current_index=findfirst(isequal(current_image), image_list)
if current_index ==nothing || current_index ==length(image_list) || current_image ==="" if current_index==nothing || current_index==length(image_list) || current_image ===""
return image_list[length(image_list)] # Return the current image if it's the last one or not found return image_list[length(image_list)] # Return the current image if it's the last one or not found
else else
return image_list[current_index + 1] # Move to the next image return image_list[current_index + 1] # Move to the next image
@ -38,17 +38,215 @@ function decrement_image(current_image, image_list)
return nothing return nothing
end end
current_index=findfirst(isequal(current_image), image_list) current_index=findfirst(isequal(current_image), image_list)
if current_index ==nothing || current_index ==1 || current_image ==="" if current_index==nothing || current_index==1 || current_image===""
return image_list[1] # Return the current image if it's the first one or not found return image_list[1] # Return the current image if it's the first one or not found
else else
return image_list[current_index - 1] # Move to the previous image return image_list[current_index - 1] # Move to the previous image
end end
end end
# ==Reactive code == ## Plot Image functions
# loadImgPlot recieves the local directory of the image as a string,
# returns the layout and data for the heatmap plotly plot
# this function loads the image into a plot
function loadImgPlot(interfaceImg::String)
# Load the image
cleaned_img=replace(interfaceImg, r"\?.*" => "")
cleaned_img=lstrip(cleaned_img, '/')
var=joinpath("./public", cleaned_img)
img=load(var)
# Convert to grayscale
img_gray=Gray.(img)
img_array=Array(img_gray)
#println(typeof(img_array))
elevation=Float32.(Array(img_gray))
#println(typeof(elevation))
# Get the X, Y coordinates of the image
height, width = size(img_array)
#println("height: $(height), width: $(width)")
X = collect(1:width)
Y = collect(1:height)
# Create the layout
layout = PlotlyBase.Layout(
xaxis = PlotlyBase.attr(
visible = false,
scaleanchor = "y"
),
yaxis = PlotlyBase.attr(
visible = false
)
)
# Create the trace for the image
trace = PlotlyBase.heatmap(
z = elevation,
x = X,
y = -Y,
name="",
showlegend=false,
colorscale = "Viridis",
showscale = true,
colorbar = attr(
title = attr(
text = "Intensity",
font = attr(
size = 14,
color = "black"
),
side = "right"
),
ticks = "outside",
ticklen = 2,
tickwidth = 0.5,
nticks = 5,
tickformat = ".2g"
)
)
plotdata = [trace]
plotlayout = layout
return plotdata, plotlayout, width, height
end
# loadContourPlot recieves the local directory of the image as a string,
# returns the layout and data for the contour plotly plot
# this function loads the image and applies a gaussian filter
# to smoothen it and loads it into a plot
function loadContourPlot(interfaceImg::String)
# Load the image
cleaned_img=replace(interfaceImg, r"\?.*" => "")
cleaned_img=lstrip(cleaned_img, '/')
var=joinpath("./public", cleaned_img)
img=load(var)
img_gray=Gray.(img)
img_array=Array(img_gray)
elevation=Float32.(Array(img_gray)) ./ 255.0 # Normalize between 0 and 1
# Smooth the image
sigma=3.0
kernel=Kernel.gaussian(sigma)
elevation_smoothed=imfilter(elevation, kernel)
# Create the X, Y meshgrid coordinates
x=1:size(elevation_smoothed, 2)
y=1:size(elevation_smoothed, 1)
X=repeat(reshape(x, 1, length(x)), length(y), 1)
Y=repeat(reshape(y, length(y), 1), 1, length(x))
layout=PlotlyBase.Layout(
title="2D Topographic Map",
xaxis=PlotlyBase.attr(
title="X",
scaleanchor="y"
),
yaxis=PlotlyBase.attr(
title="Y"
),
)
trace=PlotlyBase.contour(
z=elevation_smoothed,
x=X[1, :], # Use the first row
y=-Y[:, 1], # Use the first column
contours_coloring="Viridis",
colorscale="Viridis",
colorbar = attr(
tickformat = ".2g"
)
)
plotdata = [trace]
plotlayout = layout
return plotdata, plotlayout
end
# loadSurfacePlot recieves the local directory of the image as a string,
# returns the layout and data for the surface plotly plot
# this function loads the image and applies a gaussian filter
# to smoothen it and loads it into a 3D plot
function loadSurfacePlot(interfaceImg::String)
# Load the image
cleaned_img=replace(interfaceImg, r"\?.*" => "")
cleaned_img=lstrip(cleaned_img, '/')
var=joinpath("./public", cleaned_img)
img=load(var)
#println("Image type:", typeof(img))
img_gray=Gray.(img) # Convert to grayscale
#println("Grayscale image type:", typeof(img_gray))
img_array=Array(img_gray)
elevation=Float32.(Array(img_gray)) ./ 255.0 # Normalize between 0 and 1
#println("Elevation size:", size(elevation))
# Smooth the image
sigma=3.0
kernel=Kernel.gaussian(sigma)
#println(size(kernel))
elevation_smoothed=imfilter(elevation, kernel)
#println("Smoothed elevation size:", size(elevation_smoothed))
# Transpose the elevation_smoothed array
# Create the X, Y meshgrid coordinates
x=1:size(elevation_smoothed, 2)
y=1:size(elevation_smoothed, 1)
X=repeat(reshape(x, 1, length(x)), length(y), 1)
#println("Size of X:", size(X))
Y=repeat(reshape(y, length(y), 1), 1, length(x))
#println("Size of Y:", size(Y))
# Calculate the number of ticks and aspect ratio for the 3d plot
x_nticks=min(20, length(x))
y_nticks=min(20, length(y))
z_nticks=5
aspect_ratio=attr(x=1, y=length(y) / length(x), z=0.5)
# Define the layout for the 3D plot
layout3D=PlotlyBase.Layout(
title="3D Surface Plot",
scene=attr(
xaxis_nticks=x_nticks,
yaxis_nticks=y_nticks,
zaxis_nticks=z_nticks,
camera=attr(eye=attr(x=0, y=-1, z=0.5)),
aspectratio=aspect_ratio
)
)
if size(elevation_smoothed, 1) < size(elevation_smoothed, 2)
# Transpose the elevation_smoothed array if Y axis is longer than X axis to fix chopping
elevation_smoothed=transpose(elevation_smoothed)
Y=-Y
end
trace3D=PlotlyBase.surface(
x=X[1, :],
y=Y[:, 1],
z=elevation_smoothed,
contours_z=attr(
show=true,
usecolormap=true,
highlightcolor="limegreen",
project_z=true
),
colorscale="Viridis",
colorbar = attr(
tickformat = ".2g"
)
)
plotdata = [trace3D]
plotlayout = layout3D
return plotdata, plotlayout
end
function crossLinesPlot(x, y, maxwidth, maxheight)
# Define the coordinates for the two lines
l1_x = [0, maxwidth]
l1_y = [y, y]
l2_x = [x, x]
l2_y = [0, maxheight]
# Create the line traces
trace1 = PlotlyBase.scatter(x = l1_x, y = l1_y, mode = "lines",line=attr(color="red", width=0.5),name="Line X",showlegend=false)
trace2 = PlotlyBase.scatter(x = l2_x, y = l2_y, mode = "lines",line=attr(color="red", width=0.5),name="Line Y",showlegend=false)
return trace1, trace2
end
# == Reactive code ==
# 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
# @out variables can only be modified by the backend # @out variables can only be modified by the backend
# @in variables can be modified by both the backend and the browser # @in variables can be modified by both the backend and the browser
@ -107,8 +305,8 @@ end
@out imgIntT="/.bmp" # image Interface TrIQ @out imgIntT="/.bmp" # image Interface TrIQ
@out colorbar="/.png" @out colorbar="/.png"
@out colorbarT="/.png" @out colorbarT="/.png"
@out img_width=0 @out imgWidth=0
@out img_height=0 @out imgHeight=0
# Messages to interface variables # Messages to interface variables
@out msg="" @out msg=""
@ -141,6 +339,22 @@ end
@out eTime=time() @out eTime=time()
## Plots ## Plots
# Local image to plot
layoutImg = PlotlyBase.Layout(
xaxis = PlotlyBase.attr(
visible = false,
scaleanchor = "y"
),
yaxis = PlotlyBase.attr(
visible = false
)
)
traceImg=PlotlyBase.heatmap(x=[], y=[])
@out plotdataImg = [traceImg]
@out plotlayoutImg = layoutImg
# For triq image
@out plotdataImgT = [traceImg]
@out plotlayoutImgT = layoutImg
# Interface Plot Spectrum # Interface Plot Spectrum
layoutSpectra=PlotlyBase.Layout( layoutSpectra=PlotlyBase.Layout(
title="SUM Spectrum plot", title="SUM Spectrum plot",
@ -216,7 +430,7 @@ end
@out plotdata3d=[trace3D] @out plotdata3d=[trace3D]
@out plotlayout3d=layout3D @out plotlayout3d=layout3D
# ==Reactive handlers == # == Reactive handlers ==
# Reactive handlers watch a variable and execute a block of code when its value changes # 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 # The onbutton handler will set the variable to false after the block is executed
@ -238,6 +452,8 @@ end
btnSpectraDisable=false btnSpectraDisable=false
SpectraEnabled=true SpectraEnabled=true
end end
xCoord=0
yCoord=0
end end
end end
@ -271,11 +487,12 @@ end
img=reverse(permutedims(img, (2, 1)), dims=1) img=reverse(permutedims(img, (2, 1)), dims=1)
end end
flipped_img=reverse(img, dims=1) flipped_img=reverse(img, dims=1)
img_width=size(flipped_img, 2) imgWidth=size(flipped_img, 2)
img_height=size(flipped_img, 1) imgHeight=size(flipped_img, 1)
save(image_path, flipped_img) save(image_path, flipped_img)
# Use timestamp to refresh image interface container # Use timestamp to refresh image interface container
imgIntT="/TrIQ_$(text_nmass).bmp?t=$(timestamp)" imgIntT="/TrIQ_$(text_nmass).bmp?t=$(timestamp)"
plotdataImgT, plotlayoutImgT, imgWidth, imgHeight = loadImgPlot(imgIntT)
# Get current image # Get current image
current_triq="TrIQ_$(text_nmass).bmp" current_triq="TrIQ_$(text_nmass).bmp"
msgtriq="TrIQ image with the Nmass of $(replace(text_nmass, "_" => "."))" msgtriq="TrIQ image with the Nmass of $(replace(text_nmass, "_" => "."))"
@ -305,11 +522,12 @@ end
img=reverse(permutedims(img, (2, 1)), dims=1) img=reverse(permutedims(img, (2, 1)), dims=1)
end end
flipped_img=reverse(img, dims=1) flipped_img=reverse(img, dims=1)
img_width=size(flipped_img, 2) imgWidth=size(flipped_img, 2)
img_height=size(flipped_img, 1) imgHeight=size(flipped_img, 1)
save(image_path, flipped_img) save(image_path, flipped_img)
# Use timestamp to refresh image interface container # Use timestamp to refresh image interface container
imgInt="/MSI_$(text_nmass).bmp?t=$(timestamp)" imgInt="/MSI_$(text_nmass).bmp?t=$(timestamp)"
plotdataImg, plotlayoutImg, imgWidth, imgHeight = loadImgPlot(imgInt)
# Get current image # Get current image
current_msi="MSI_$(text_nmass).bmp" current_msi="MSI_$(text_nmass).bmp"
msgimg="Image with the Nmass of $(replace(text_nmass, "_" => "."))" msgimg="Image with the Nmass of $(replace(text_nmass, "_" => "."))"
@ -466,15 +684,22 @@ end
new_msi=decrement_image(current_msi, msi_bmp) new_msi=decrement_image(current_msi, msi_bmp)
new_col_msi=decrement_image(current_col_msi, col_msi_png) new_col_msi=decrement_image(current_col_msi, col_msi_png)
if new_msi!=nothing || new_col_msi!=nothing
current_msi=new_msi current_msi=new_msi
current_col_msi=new_col_msi current_col_msi=new_col_msi
imgInt="/$(current_msi)?t=$(timestamp)" imgInt="/$(current_msi)?t=$(timestamp)"
colorbar="/$(current_col_msi)?t=$(timestamp)" colorbar="/$(current_col_msi)?t=$(timestamp)"
text_nmass=replace(current_msi, "MSI_" => "") text_nmass=replace(current_msi, "MSI_" => "")
text_nmass=replace(text_nmass, ".bmp" => "") text_nmass=replace(text_nmass, ".bmp" => "")
msgimg="Image with the Nmass of $(replace(text_nmass, "_" => "."))" msgimg="Image with the Nmass of $(replace(text_nmass, "_" => "."))"
# Process the image in the function
plotdataImg, plotlayoutImg, imgWidth, imgHeight = loadImgPlot(imgInt)
else
traceImg=PlotlyBase.heatmap(x=[], y=[])
plotdataImg = [traceImg]
msgimg = ""
end
end end
@onbutton imgPlus begin @onbutton imgPlus begin
# Append a query string to force the image to refresh # Append a query string to force the image to refresh
@ -485,53 +710,75 @@ end
new_msi=increment_image(current_msi, msi_bmp) new_msi=increment_image(current_msi, msi_bmp)
new_col_msi=increment_image(current_col_msi, col_msi_png) 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)"
current_msi=new_msi text_nmass=replace(current_msi, "MSI_" => "")
current_col_msi=new_col_msi text_nmass=replace(text_nmass, ".bmp" => "")
imgInt="/$(current_msi)?t=$(timestamp)" msgimg="Image with the Nmass of $(replace(text_nmass, "_" => "."))"
colorbar="/$(current_col_msi)?t=$(timestamp)" # Process the image in the function
plotdataImg, plotlayoutImg, imgWidth, imgHeight = loadImgPlot(imgInt)
text_nmass=replace(current_msi, "MSI_" => "") else
text_nmass=replace(text_nmass, ".bmp" => "") traceImg=PlotlyBase.heatmap(x=[], y=[])
msgimg="Image with the Nmass of $(replace(text_nmass, "_" => "."))" plotdataImg = [traceImg]
msgimg = ""
end
end end
@onbutton imgMinusT begin @onbutton imgMinusT begin
# Append a query string to force the image to refresh # Append a query string to force the image to refresh
timestamp=string(time_ns()) timestamp=string(time_ns())
new_msi=decrement_image(current_triq, triq_bmp)
new_col_msi=decrement_image(current_col_triq, col_triq_png)
# Update the array of images with TrIQ filter listed in the public folder # 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) 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) col_triq_png=sort(filter(filename -> startswith(filename, "colorbar_TrIQ_") && endswith(filename, ".png"), readdir("public")),lt=natural)
current_triq=new_msi new_msi=decrement_image(current_triq, triq_bmp)
current_col_triq=new_col_msi new_col_msi=decrement_image(current_col_triq, col_triq_png)
imgIntT="/$(current_triq)?t=$(timestamp)" if new_msi!=nothing || new_col_msi!=nothing
colorbarT="/$(current_col_triq)?t=$(timestamp)" 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(current_triq, "TrIQ_" => "")
text_nmass=replace(text_nmass, ".bmp" => "") text_nmass=replace(text_nmass, ".bmp" => "")
msgtriq="TrIQ image with the Nmass of $(replace(text_nmass, "_" => "."))" msgtriq="TrIQ image with the Nmass of $(replace(text_nmass, "_" => "."))"
# Process the image in the function
plotdataImgT, plotlayoutImgT, imgWidth, imgHeight = loadImgPlot(imgIntT)
else
traceImg=PlotlyBase.heatmap(x=[], y=[])
plotdataImgT = [traceImg]
msgtriq = ""
end
end end
@onbutton imgPlusT begin @onbutton imgPlusT begin
# Append a query string to force the image to refresh # Append a query string to force the image to refresh
timestamp=string(time_ns()) timestamp=string(time_ns())
new_msi=increment_image(current_triq, triq_bmp)
new_col_msi=increment_image(current_col_triq, col_triq_png)
# Update the array of images with TrIQ filter listed in the public folder # 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) 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) col_triq_png=sort(filter(filename -> startswith(filename, "colorbar_TrIQ_") && endswith(filename, ".png"), readdir("public")),lt=natural)
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_" => "") new_msi=increment_image(current_triq, triq_bmp)
text_nmass=replace(text_nmass, ".bmp" => "") new_col_msi=increment_image(current_col_triq, col_triq_png)
msgtriq="TrIQ image with the Nmass of $(replace(text_nmass, "_" => "."))" 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)
else
traceImg=PlotlyBase.heatmap(x=[], y=[])
plotdataImgT = [traceImg]
msgtriq = ""
end
end end
# 3d plot # 3d plot
@ -548,59 +795,7 @@ end
btnStartDisable=true btnStartDisable=true
btnSpectraDisable=true btnSpectraDisable=true
try try
img=load(var) plotdata3d, plotlayout3d = loadSurfacePlot(imgInt)
#println("Image type:", typeof(img))
img_gray=Gray.(img) # Convert to grayscale
#println("Grayscale image type:", typeof(img_gray))
img_array=Array(img_gray)
elevation=Float32.(Array(img_gray)) ./ 255.0 # Normalize between 0 and 1
#println("Elevation size:", size(elevation))
# Smooth the image
sigma=3.0
kernel=Kernel.gaussian(sigma)
#println(size(kernel))
elevation_smoothed=imfilter(elevation, kernel)
#println("Smoothed elevation size:", size(elevation_smoothed))
# Transpose the elevation_smoothed array
# Create the X, Y meshgrid coordinates
x=1:size(elevation_smoothed, 2)
y=1:size(elevation_smoothed, 1)
X=repeat(reshape(x, 1, length(x)), length(y), 1)
#println("Size of X:", size(X))
Y=repeat(reshape(y, length(y), 1), 1, length(x))
#println("Size of Y:", size(Y))
# Calculate the number of ticks and aspect ratio for the 3d plot
x_nticks=min(20, length(x))
y_nticks=min(20, length(y))
z_nticks=5
aspect_ratio=attr(x=1, y=length(y) / length(x), z=0.5)
# Define the layout for the 3D plot
layout3D=PlotlyBase.Layout(
title="3D Surface Plot",
scene=attr(
xaxis_nticks=x_nticks,
yaxis_nticks=y_nticks,
zaxis_nticks=z_nticks,
camera=attr(eye=attr(x=0, y=-1, z=0.5)),
aspectratio=aspect_ratio
)
)
if size(elevation_smoothed, 1) < size(elevation_smoothed, 2)
# Transpose the elevation_smoothed array if Y axis is longer than X axis to fix chopping
elevation_smoothed=transpose(elevation_smoothed)
Y=-Y
end
trace3D=PlotlyBase.surface(x=X[1, :], y=Y[:, 1], z=elevation_smoothed,
contours_z=attr(
show=true,
usecolormap=true,
highlightcolor="limegreen",
project_z=true
), colorscale="Viridis")
plotdata3d=[trace3D] # We add the data from the image to the plot
plotlayout3d=layout3D # we update the style of the plot to fit the image.
GC.gc() # Trigger garbage collection GC.gc() # Trigger garbage collection
if Sys.islinux() 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
@ -641,53 +836,7 @@ end
btnStartDisable=true btnStartDisable=true
btnSpectraDisable=true btnSpectraDisable=true
try try
img=load(var) plotdata3d, plotlayout3d = loadSurfacePlot(imgIntT)
img_gray=Gray.(img) # Convert to grayscale
img_array=Array(img_gray)
elevation=Float32.(Array(img_gray)) ./ 255.0 # Normalize between 0 and 1
# Smooth the image
sigma=3.0
kernel=Kernel.gaussian(sigma)
elevation_smoothed=imfilter(elevation, kernel)
# Create the X, Y meshgrid coordinates
x=1:size(elevation_smoothed, 2)
y=1:size(elevation_smoothed, 1)
X=repeat(reshape(x, 1, length(x)), length(y), 1)
Y=repeat(reshape(y, length(y), 1), 1, length(x))
# Calculate the number of ticks and aspect ratio for the 3d plot
x_nticks=min(20, length(x))
y_nticks=min(20, length(y))
z_nticks=5
aspect_ratio=attr(x=1, y=length(y) / length(x), z=0.5)
# Define the layout for the 3D plot
layout3D=PlotlyBase.Layout(
title="3D Surface Plot",
scene=attr(
xaxis_nticks=x_nticks,
yaxis_nticks=y_nticks,
zaxis_nticks=z_nticks,
camera=attr(eye=attr(x=0, y=-1, z=0.5)),
aspectratio=aspect_ratio
)
)
if size(elevation_smoothed, 1) < size(elevation_smoothed, 2)
# Transpose the elevation_smoothed array if Y axis is longer than X axis to fix chopping
elevation_smoothed=transpose(elevation_smoothed)
Y=-Y
end
trace3D=PlotlyBase.surface(x=X[1, :], y=Y[:, 1], z=elevation_smoothed,
contours_z=attr(
show=true,
usecolormap=true,
highlightcolor="limegreen",
project_z=true
), colorscale="Viridis")
plotdata3d=[trace3D] # We add the data from the image to the plot
plotlayout3d=layout3D # we update the style of the plot to fit the image.
GC.gc() # Trigger garbage collection GC.gc() # Trigger garbage collection
if Sys.islinux() 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
@ -730,41 +879,7 @@ end
btnSpectraDisable=true btnSpectraDisable=true
try try
img=load(var) img=load(var)
# Convert to grayscale plotdataC,plotlayoutC=loadContourPlot(imgInt)
img_gray=Gray.(img)
img_array=Array(img_gray)
elevation=Float32.(Array(img_gray)) ./ 255.0 # Normalize between 0 and 1
# Smooth the image
sigma=3.0
kernel=Kernel.gaussian(sigma)
elevation_smoothed=imfilter(elevation, kernel)
# Create the X, Y meshgrid coordinates
x=1:size(elevation_smoothed, 2)
y=1:size(elevation_smoothed, 1)
X=repeat(reshape(x, 1, length(x)), length(y), 1)
Y=repeat(reshape(y, length(y), 1), 1, length(x))
layoutContour=PlotlyBase.Layout(
title="2D Topographic Map",
xaxis=PlotlyBase.attr(
title="X",
scaleanchor="y"
),
yaxis=PlotlyBase.attr(
title="Y"
),
)
traceContour=PlotlyBase.contour(
z=elevation_smoothed,
x=X[1, :], # Use the first row
y=-Y[:, 1], # Use the first column
contours_coloring="Viridis",
colorscale="Viridis"
)
plotdataC=[traceContour]
plotlayoutC=layoutContour
GC.gc() # Trigger garbage collection GC.gc() # Trigger garbage collection
if Sys.islinux() 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
@ -806,41 +921,7 @@ end
btnSpectraDisable=true btnSpectraDisable=true
try try
img=load(var) img=load(var)
# Convert to grayscale plotdataC,plotlayoutC=loadContourPlot(imgIntT)
img_gray=Gray.(img)
img_array=Array(img_gray)
elevation=Float32.(Array(img_gray)) ./ 255.0 # Normalize between 0 and 1
# Smooth the image
sigma=3.0
kernel=Kernel.gaussian(sigma)
elevation_smoothed=imfilter(elevation, kernel)
# Create the X, Y meshgrid coordinates
x=1:size(elevation_smoothed, 2)
y=1:size(elevation_smoothed, 1)
X=repeat(reshape(x, 1, length(x)), length(y), 1)
Y=repeat(reshape(y, length(y), 1), 1, length(x))
layoutContour=PlotlyBase.Layout(
title="2D Topographic Map",
xaxis=PlotlyBase.attr(
title="X",
scaleanchor="y"
),
yaxis=PlotlyBase.attr(
title="Y"
),
)
traceContour=PlotlyBase.contour(
z=elevation_smoothed,
x=X[1, :], # Use the first row
y=-Y[:, 1], # Use the first column
contours_coloring="Viridis",
colorscale="Viridis"
)
plotdataC=[traceContour]
plotlayoutC=layoutContour
GC.gc() # Trigger garbage collection GC.gc() # Trigger garbage collection
if Sys.islinux() 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
@ -877,50 +958,90 @@ end
# Event detection for clicking on the spectrum plot # Event detection for clicking on the spectrum plot
@onchange data_click begin @onchange data_click begin
if !isempty(xSpectraMz) if selectedTab == "tab2"
#println("Clicked data on sum spectrum plot : ", data_click) if !isempty(xSpectraMz)
spectracoords=reshape(plotdata, 1, length(plotdata)) #println("Clicked data on sum spectrum plot : ", data_click)
#println("Spectra: $(ndims(spectracoords))") spectracoords=reshape(plotdata, 1, length(plotdata))
# Extract x and y values from data_click #println("Spectra: $(ndims(spectracoords))")
cursor_data=data_click["cursor"] # Extract x and y values from data_click
x_value = cursor_data["x"] cursor_data=data_click["cursor"]
y_value = cursor_data["y"] # Get the x and y values from the click of the cursor x_value = cursor_data["x"]
closest_distance = Inf y_value = cursor_data["y"] # Get the x and y values from the click of the cursor
closest_distance = Inf
for val in spectracoords
# Find the index where x is within a range
start_idx = findfirst(x -> x >= x_value - 10, val[:x])
end_idx = findlast(x -> x <= x_value + 10, val[:x])
# Ensure the index are valid and within range for val in spectracoords
if start_idx !== nothing && end_idx !== nothing # Find the index where x is within a range
for i in start_idx:end_idx start_idx = findfirst(x -> x >= x_value - 10, val[:x])
spectra_x = val[:x][i] end_idx = findlast(x -> x <= x_value + 10, val[:x])
spectra_y = val[:y][i]
distance = sqrt((spectra_x - x_value)^2 + (spectra_y - y_value)^2) # Calculate distance # Ensure the index are valid and within range
if distance < closest_distance if start_idx !== nothing && end_idx !== nothing
closest_distance = distance for i in start_idx:end_idx
Nmass = round(spectra_x, digits=2) spectra_x = val[:x][i]
spectra_y = val[:y][i]
distance = sqrt((spectra_x - x_value)^2 + (spectra_y - y_value)^2) # Calculate distance
if distance < closest_distance
closest_distance = distance
Nmass = round(spectra_x, digits=2)
end
end end
end end
end end
layoutSpectra=PlotlyBase.Layout(
title="SUM Spectrum plot",
xaxis=PlotlyBase.attr(
title="<i>m/z</i>",
showgrid=true
),
yaxis=PlotlyBase.attr(
title="Intensity",
showgrid=true
),
autosize=false
)
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="<i>m/z</i> selected",showlegend=false)
plotdata=[traceSpectra,trace2] # We add the data from spectra and the red line to the plot
plotlayout=layoutSpectra
end end
layoutSpectra=PlotlyBase.Layout( elseif selectedTab == "tab1"
title="SUM Spectrum plot", #println("you have clicked the triq image")
xaxis=PlotlyBase.attr( cursor_data=data_click["cursor"]
title="<i>m/z</i>", xCoord = Int32(round(cursor_data["x"]))
showgrid=true if xCoord < 0
), xCoord = 0
yaxis=PlotlyBase.attr( elseif xCoord > imgWidth
title="Intensity", xCoord = imgWidth
showgrid=true end
), yCoord = Int32(round(cursor_data["y"]))
autosize=false if yCoord > 0
) yCoord = 0
traceSpectra=PlotlyBase.scatter(x=xSpectraMz, y=ySpectraMz, mode="lines",name="Spectra",showlegend=false) elseif yCoord < -imgHeight
trace2=PlotlyBase.scatter(x=[Nmass, Nmass],y=[0, maximum(ySpectraMz)],mode="lines",line=attr(color="red", width=0.5),name="<i>m/z</i> selected",showlegend=false) yCoord = -imgHeight
plotdata=[traceSpectra,trace2] # We add the data from spectra and the red line to the plot end # Get the x and y values from the click of the cursor and make sure they don't exceed image proportions
plotlayout=layoutSpectra #plotdataImgT, plotlayoutImgT, imgWidth, imgHeight = loadImgPlot(imgIntT)
plotdataImgT = filter(trace -> !(get(trace, :name, "") in ["Line X", "Line Y"]), plotdataImgT)
trace1, trace2 = crossLinesPlot(xCoord, yCoord, imgWidth, -imgHeight)
plotdataImgT=append!(plotdataImgT, [trace1, trace2])
elseif selectedTab == "tab0"
#println("you have clicked the normal image")
cursor_data=data_click["cursor"]
xCoord = Int32(round(cursor_data["x"]))
if xCoord < 0
xCoord = 0
elseif xCoord > imgWidth
xCoord = imgWidth
end
yCoord = Int32(round(cursor_data["y"]))
if yCoord > 0
yCoord = 0
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, plotlayoutImg, imgWidth, imgHeight = loadImgPlot(imgInt)
plotdataImg = filter(trace -> !(get(trace, :name, "") in ["Line X", "Line Y"]), plotdataImg)
trace1, trace2 = crossLinesPlot(xCoord, yCoord, imgWidth, -imgHeight)
plotdataImg=append!(plotdataImg, [trace1, trace2])
end end
end end
@ -934,12 +1055,12 @@ end
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 end
end end
# ==Pages == # == Pages ==
# Register a new route and the page that will be loaded on access # Register a new route and the page that will be loaded on access
@page("/", "app.jl.html") @page("/", "app.jl.html")
end 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

View File

@ -160,7 +160,8 @@
<!-- Image manager --> <!-- Image manager -->
<div id="image-container" class="row st-col col-12"> <div id="image-container" class="row st-col col-12">
<div class="col-10"> <div class="col-10">
<q-img id="imgInt" class="q-ma-none q-pa-none" :src="imgInt" width="80%"></q-img> <plotly id="plotStyle" :data="plotdataImg" :layout="plotlayoutImg" class="q-pa-none q-ma-none sync_data" @click="data_click"></plotly>
<!--<q-img id="imgInt" class="q-ma-none q-pa-none" :src="imgInt" width="80%"></q-img>-->
</div> </div>
<div class="col-2"> <div class="col-2">
<q-img id="colorbar" class="q-ma-none q-pa-none" :src="colorbar"></q-img> <q-img id="colorbar" class="q-ma-none q-pa-none" :src="colorbar"></q-img>
@ -180,7 +181,8 @@
<!-- Triq Image manager --> <!-- Triq Image manager -->
<div id="image-container" class="row st-col col-12"> <div id="image-container" class="row st-col col-12">
<div class="col-10"> <div class="col-10">
<q-img id="imgInt" class="q-ma-none q-pa-none" :src="imgIntT" width="80%"></q-img> <plotly id="plotStyle" :data="plotdataImgT" :layout="plotlayoutImgT" class="q-pa-none q-ma-none sync_data" @click="data_click"></plotly>
<!--<q-img id="imgInt" class="q-ma-none q-pa-none" :src="imgIntT" width="80%"></q-img>-->
</div> </div>
<div class="col-2"> <div class="col-2">
<q-img id="colorbar" class="q-ma-none q-pa-none" :src="colorbarT"></q-img> <q-img id="colorbar" class="q-ma-none q-pa-none" :src="colorbarT"></q-img>
@ -192,8 +194,7 @@
<q-tab-panel name="tab2"> <q-tab-panel name="tab2">
<!-- Content for Tab 2 --> <!-- Content for Tab 2 -->
<!--<plotly id="plotStyle" :data="plotdata" :layout="plotlayout" class="q-pa-none q-ma-none"></plotly>--> <!--<plotly id="plotStyle" :data="plotdata" :layout="plotlayout" class="q-pa-none q-ma-none"></plotly>-->
<plotly id="plotStyle" :data="plotdata" :layout="plotlayout" @click="data_click" <plotly id="plotStyle" :data="plotdata" :layout="plotlayout" class="q-pa-none q-ma-none sync_data" @click="data_click"></plotly>
class="q-pa-none q-ma-none sync_data"></plotly>
</q-tab-panel> </q-tab-panel>
<q-tab-panel name="tab3"> <q-tab-panel name="tab3">
@ -246,7 +247,7 @@
<!-- Image manager --> <!-- Image manager -->
<div id="image-container" class="row st-col col-12"> <div id="image-container" class="row st-col col-12">
<div class="st-col col-10"> <div class="st-col col-10">
<q-img id="imgInt" class="q-ma-none q-pa-none" :src="imgInt" width="80%"></q-img> <plotly id="plotStyle" :data="plotdataImg" :layout="plotlayoutImg" class="q-pa-none q-ma-none"></plotly>
</div> </div>
<div class="st-col col-2"> <div class="st-col col-2">
<q-img id="colorbar" class="q-ma-none q-pa-none" :src="colorbar"></q-img> <q-img id="colorbar" class="q-ma-none q-pa-none" :src="colorbar"></q-img>
@ -265,7 +266,7 @@
<!-- Triq Image manager --> <!-- Triq Image manager -->
<div id="image-container" class="row st-col col-12"> <div id="image-container" class="row st-col col-12">
<div class="col-10"> <div class="col-10">
<q-img id="imgInt" class="q-ma-none q-pa-none" :src="imgIntT" width="80%"></q-img> <plotly id="plotStyle" :data="plotdataImgT" :layout="plotlayoutImgT" class="q-pa-none q-ma-none"></plotly>
</div> </div>
<div class="col-2"> <div class="col-2">
<q-img id="colorbar" class="q-ma-none q-pa-none" :src="colorbarT"></q-img> <q-img id="colorbar" class="q-ma-none q-pa-none" :src="colorbarT"></q-img>
@ -301,7 +302,7 @@
<!-- Image manager --> <!-- Image manager -->
<div id="image-container" class="row st-col col-12"> <div id="image-container" class="row st-col col-12">
<div class="st-col col-10"> <div class="st-col col-10">
<q-img id="imgInt" class="q-ma-none q-pa-none" :src="imgInt" width="80%"></q-img> <plotly id="plotStyle" :data="plotdataImg" :layout="plotlayoutImg" class="q-pa-none q-ma-none"></plotly>
</div> </div>
<div class="st-col col-2"> <div class="st-col col-2">
<q-img id="colorbar" class="q-ma-none q-pa-none" :src="colorbar"></q-img> <q-img id="colorbar" class="q-ma-none q-pa-none" :src="colorbar"></q-img>
@ -320,7 +321,7 @@
<!-- Triq Image manager --> <!-- Triq Image manager -->
<div id="image-container" class="row st-col col-12"> <div id="image-container" class="row st-col col-12">
<div class="col-10"> <div class="col-10">
<q-img id="imgInt" class="q-ma-none q-pa-none" :src="imgIntT" width="80%"></q-img> <plotly id="plotStyle" :data="plotdataImgT" :layout="plotlayoutImgT" class="q-pa-none q-ma-none"></plotly>
</div> </div>
<div class="col-2"> <div class="col-2">
<q-img id="colorbar" class="q-ma-none q-pa-none" :src="colorbarT"></q-img> <q-img id="colorbar" class="q-ma-none q-pa-none" :src="colorbarT"></q-img>

View File

@ -1,9 +1,8 @@
PENDING PENDING
Rmsi & julia coherence with image creation and colorbar Rmsi & julia coherence with image creation and colorbar
colorbar revamp colorbar revamp CURRENTLY ONGOING
Create function that makes the imzML from mzML files ? Create function that makes the imzML from mzML files ?
Possibility to add multiple imzML to process at once ? Possibility to add multiple imzML to process at once ?
Per pixel of image plot creation for spectra
Add comparison image (rotate, transform, translate, transparency) CURRENTLY ONGOING Add comparison image (rotate, transform, translate, transparency) CURRENTLY ONGOING
DONE DONE
@ -25,3 +24,4 @@ DONE
Comparative for two views Comparative for two views
Even faster initial boot and subsectuential boot Even faster initial boot and subsectuential boot
Multiple spectra plot types Multiple spectra plot types
Plot creation for spectra Per pixel of image

View File

@ -37,6 +37,8 @@ Genie.loadapp()
@async run(`xdg-open $url`) # For Linux @async run(`xdg-open $url`) # For Linux
elseif Sys.iswindows() elseif Sys.iswindows()
@async run(`start $url`) # For Windows @async run(`start $url`) # For Windows
@async run(`explorer $url`)
@async run(`Start-Process $url`) # For Windows
end end
end end