bulk and batch processing for multiple imzml and multiple m/z is now available, folder organization for imzml slices in public folder, JSON tracking of processed datasets to save memory time, multiple performance optimizations and UI bug fixes, metadata viewing for all processed files, comparative view between multiple datasets
This commit is contained in:
parent
39fe2bf52c
commit
39c92ba850
3
.gitignore
vendored
3
.gitignore
vendored
@ -1,9 +1,6 @@
|
|||||||
public/*
|
public/*
|
||||||
public/css/imgOver.png
|
public/css/imgOver.png
|
||||||
!public/css/
|
!public/css/
|
||||||
!public/masks/
|
|
||||||
public/masks/*
|
|
||||||
!public/masks/static.txt
|
|
||||||
log/*
|
log/*
|
||||||
R_original_scripts/
|
R_original_scripts/
|
||||||
test/results/
|
test/results/
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
julia_version = "1.11.7"
|
julia_version = "1.11.7"
|
||||||
manifest_format = "2.0"
|
manifest_format = "2.0"
|
||||||
project_hash = "d4aecbadf6a54893101b3b89b57e8ae0ab391000"
|
project_hash = "b3d73d786a430f468e0f2f1b3b05da6a3addc7fe"
|
||||||
|
|
||||||
[[deps.ATK_jll]]
|
[[deps.ATK_jll]]
|
||||||
deps = ["Artifacts", "Glib_jll", "JLLWrappers", "Libdl"]
|
deps = ["Artifacts", "Glib_jll", "JLLWrappers", "Libdl"]
|
||||||
|
|||||||
@ -13,6 +13,7 @@ Dates = "ade2ca70-3891-5945-98fb-dc099432e06a"
|
|||||||
Genie = "c43c736e-a2d1-11e8-161f-af95117fbd1e"
|
Genie = "c43c736e-a2d1-11e8-161f-af95117fbd1e"
|
||||||
GenieFramework = "a59fdf5c-6bf0-4f5d-949c-a137c9e2f353"
|
GenieFramework = "a59fdf5c-6bf0-4f5d-949c-a137c9e2f353"
|
||||||
Images = "916415d5-f1e6-5110-898d-aaa5f9f070e0"
|
Images = "916415d5-f1e6-5110-898d-aaa5f9f070e0"
|
||||||
|
JSON = "682c06a0-de6a-54ab-a142-c8b1cf79cde6"
|
||||||
Libz = "2ec943e9-cfe8-584d-b93d-64dcb6d567b7"
|
Libz = "2ec943e9-cfe8-584d-b93d-64dcb6d567b7"
|
||||||
LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e"
|
LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e"
|
||||||
Mmap = "a63ad114-7e13-5084-954f-fe012c677804"
|
Mmap = "a63ad114-7e13-5084-954f-fe012c677804"
|
||||||
|
|||||||
@ -22,7 +22,7 @@ https://codeberg.org/LabABI/JuliaMSI
|
|||||||
~/Downloads/JuliaMSI-main/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):
|
2. Without entering the Julia environment, launch the project in your terminal with the following command (which works for all operating systems):
|
||||||
```
|
```
|
||||||
julia --threads auto --project=. start_MSI_GUI.jl
|
julia--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.
|
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.
|
||||||
|
|
||||||
|
|||||||
223
app.jl.html
223
app.jl.html
@ -17,19 +17,42 @@
|
|||||||
<q-tab-panel name="generator">
|
<q-tab-panel name="generator">
|
||||||
<div class="text-h6">imzML & mzML Data Processor</div>
|
<div class="text-h6">imzML & mzML Data Processor</div>
|
||||||
<p>Please make sure the ibd and imzML file are located in the same directory and have the same name.
|
<p>Please make sure the ibd and imzML file are located in the same directory and have the same name.
|
||||||
<br>It may take a while to generate the image and the plot, please be patient.
|
<br>It may take a while to generate the slice / spectrum, please be patient.
|
||||||
<br>To generate the contour or surface plots, you have to select the desired image first using the interface.</p>
|
<br>To generate the contour or surface plots, you have to select the desired slice first using the interface.</p>
|
||||||
<q-input standout="custom-standout" class="q-ma-sm cursor-pointer" v-model="full_route" readonly label="Select your imzML or mzML file" v-on:click="btnSearch=true">
|
<div class="row items-center">
|
||||||
<template v-slot:append>
|
<q-input standout="custom-standout" class="q-ma-sm cursor-pointer col"
|
||||||
<q-icon name="search" v:onclick="btnSearch=true" class="cursor-pointer" />
|
v-model="full_route" readonly
|
||||||
</template>
|
:label="batch_file_count > 0 ? batch_file_count + ' file(s) in batch' : 'Select an imzML file'"
|
||||||
</q-input>
|
v-on:click="btnSearch=true">
|
||||||
<!-- Variable Manipulation -->
|
<template v-slot:append>
|
||||||
|
<q-icon name="search" v-on:click="btnSearch=true" class="cursor-pointer" />
|
||||||
|
</template>
|
||||||
|
</q-input>
|
||||||
|
<q-btn class="q-ma-sm" icon="add" v-on:click="btnAddBatch=true" label="Add"></q-btn>
|
||||||
|
<q-btn class="q-ma-sm" icon="clear" v-on:click="clear_batch_btn=true"
|
||||||
|
:disable="batch_file_count === 0" label="Clear"></q-btn>
|
||||||
|
</div>
|
||||||
|
<q-list bordered separator v-if="selected_files.length > 0">
|
||||||
|
<q-item v-for="(file, index) in selected_files" :key="index">
|
||||||
|
<q-item-section>
|
||||||
|
{{ file }}
|
||||||
|
</q-item-section>
|
||||||
|
<q-item-section side>
|
||||||
|
<q-btn flat round icon="delete" size="sm" v-on:click="selected_files.splice(index, 1)"></q-btn>
|
||||||
|
</q-item-section>
|
||||||
|
</q-item>
|
||||||
|
</q-list>
|
||||||
|
|
||||||
|
<!-- Variable Manipulation -->
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="st-col col-4 col-sm q-ma-sm">
|
<div class="st-col col-4 col-sm q-ma-sm">
|
||||||
<q-input standout="custom-standout" id="textNmass" step="0.001" v-model="Nmass"
|
<q-input standout="custom-standout" id="textNmass" v-model="Nmass"
|
||||||
label="Mass-to-charge ratio of interest" type="number"
|
label="Mass-to-charge ratio(s) of interest" type="text"
|
||||||
:rules="[ val => !!val || '* Required', val => val >= 0.0 || 'Need positive mass values']"></q-input>
|
:rules="[
|
||||||
|
val => !!val || '* Required',
|
||||||
|
val => val.split(',').every(m => !isNaN(parseFloat(m.trim())) && parseFloat(m.trim()) > 0) || 'Need comma-separated positive numbers'
|
||||||
|
]">
|
||||||
|
</q-input>
|
||||||
</div>
|
</div>
|
||||||
<div class="st-col col-4 col-sm q-ma-sm">
|
<div class="st-col col-4 col-sm q-ma-sm">
|
||||||
<q-input standout="custom-standout" id="textTol" step="0.005" v-model="Tol"
|
<q-input standout="custom-standout" id="textTol" step="0.005" v-model="Tol"
|
||||||
@ -104,20 +127,24 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<q-btn :loading="progress" class="q-ma-sm btn-style" :disabled="btnStartDisable" icon="play_arrow"
|
<q-btn :loading="progress" class="q-ma-sm btn-style" :disabled="btnStartDisable" icon="play_arrow"
|
||||||
v-on:click="mainProcess=true" padding="lg" label="Generate Slice">
|
v-on:click="mainProcess=true" padding="lg" label="Generate Slice">
|
||||||
<template v-slot:loading>
|
<template v-slot:loading>
|
||||||
<q-spinner-hourglass class="on-left" />
|
<q-spinner-hourglass class="on-left" />
|
||||||
Loading...
|
Loading...
|
||||||
</template>
|
</template>
|
||||||
</q-btn>
|
</q-btn>
|
||||||
<q-btn icon="zoom_out_map" class="q-ma-sm on-right btn-style" v-on:click="compareBtn=true" padding="sm"
|
<q-btn icon="zoom_out_map" class="q-ma-sm on-right btn-style" v-on:click="compareBtn=true" padding="sm"
|
||||||
label="Compare"></q-btn>
|
label="Compare"></q-btn>
|
||||||
<q-btn class="q-ma-sm btn-style" :disable="btnMetadataDisable"
|
<!--<q-btn class="q-ma-sm btn-style" :disable="btnMetadataDisable"
|
||||||
v-on:click="showMetadataBtn=true" label="Show Metadata"></q-btn>
|
v-on:click="showMetadataBtn=true" label="Show Metadata"></q-btn>-->
|
||||||
</div>
|
<q-btn class="q-ma-sm btn-style" v-on:click="showMetadataBtn=true" label="Show Metadata"></q-btn>
|
||||||
<p>{{msg}}</p>
|
<div class="q-pa-md row items-center" v-show="progress">
|
||||||
|
<q-spinner color="primary" size="2em" class="q-mr-sm"></q-spinner>
|
||||||
|
<div class="text-caption">{{ progress_message }}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<p>{{msg}}</p>
|
||||||
<div class="row st-col col-12">
|
<div class="row st-col col-12">
|
||||||
<q-btn-dropdown class="q-ma-sm btn-style" :loading="progressPlot" :disable="btnPlotDisable"
|
<q-btn-dropdown class="q-ma-sm btn-style" :loading="progressPlot" :disable="btnPlotDisable"
|
||||||
label="Generate Plots" icon="play_arrow">
|
label="Generate Plots" icon="play_arrow">
|
||||||
@ -177,13 +204,13 @@
|
|||||||
|
|
||||||
<q-input standout="custom-standout" class="q-ma-sm cursor-pointer" v-model="mzml_full_route" readonly label="Select your .mzML file" v-on:click="btnSearchMzml=true">
|
<q-input standout="custom-standout" class="q-ma-sm cursor-pointer" v-model="mzml_full_route" readonly label="Select your .mzML file" v-on:click="btnSearchMzml=true">
|
||||||
<template v-slot:append>
|
<template v-slot:append>
|
||||||
<q-icon name="search" v:onclick="btnSearchMzml=true" class="cursor-pointer" />
|
<q-icon name="search" v-on:click="btnSearchMzml=true" class="cursor-pointer" />
|
||||||
</template>
|
</template>
|
||||||
</q-input>
|
</q-input>
|
||||||
|
|
||||||
<q-input standout="custom-standout" class="q-ma-sm cursor-pointer" v-model="sync_full_route" readonly label="Select your .txt sync file" v-on:click="btnSearchSync=true">
|
<q-input standout="custom-standout" class="q-ma-sm cursor-pointer" v-model="sync_full_route" readonly label="Select your .txt sync file" v-on:click="btnSearchSync=true">
|
||||||
<template v-slot:append>
|
<template v-slot:append>
|
||||||
<q-icon name="search" v:onclick="btnSearchSync=true" class="cursor-pointer" />
|
<q-icon name="search" v-on:click="btnSearchSync=true" class="cursor-pointer" />
|
||||||
</template>
|
</template>
|
||||||
</q-input>
|
</q-input>
|
||||||
|
|
||||||
@ -205,9 +232,10 @@
|
|||||||
<q-tab-panels v-model="selectedTab">
|
<q-tab-panels v-model="selectedTab">
|
||||||
<q-tab-panel name="tab0">
|
<q-tab-panel name="tab0">
|
||||||
<!-- Content for Tab 0 -->
|
<!-- Content for Tab 0 -->
|
||||||
<!-- Btn image changer -->
|
|
||||||
<h6>Image visualizer</h6>
|
<h6>Image visualizer</h6>
|
||||||
<div>
|
<div class="row items-center">
|
||||||
|
<q-select v-model="selected_folder_main" :options="image_available_folders" label="Select Dataset" class="q-ma-sm" style="min-width: 200px;"></q-select>
|
||||||
|
<q-space></q-space>
|
||||||
<q-btn icon="arrow_back" class="q-my-sm btn-style" v-on:click="imgMinus=true"></q-btn>
|
<q-btn icon="arrow_back" class="q-my-sm btn-style" v-on:click="imgMinus=true"></q-btn>
|
||||||
<q-btn icon="arrow_forward" class="q-my-sm on-right btn-style" v-on:click="imgPlus=true"></q-btn>
|
<q-btn icon="arrow_forward" class="q-my-sm on-right btn-style" v-on:click="imgPlus=true"></q-btn>
|
||||||
</div>
|
</div>
|
||||||
@ -221,14 +249,15 @@
|
|||||||
<q-img id="colorbar-normal" class="q-ma-none q-pa-none" :src="colorbar"></q-img>
|
<q-img id="colorbar-normal" class="q-ma-none q-pa-none" :src="colorbar"></q-img>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<p>{{msgimg}}</p>
|
<p v-html="msgimg"></p>
|
||||||
</q-tab-panel>
|
</q-tab-panel>
|
||||||
|
|
||||||
<q-tab-panel name="tab1">
|
<q-tab-panel name="tab1">
|
||||||
<!-- Content for Tab 1 -->
|
<!-- Content for Tab 1 -->
|
||||||
<!-- Triq Btn image changer -->
|
|
||||||
<h6>TrIQ visualizer</h6>
|
<h6>TrIQ visualizer</h6>
|
||||||
<div>
|
<div class="row items-center">
|
||||||
|
<q-select v-model="selected_folder_main" :options="image_available_folders" label="Select Dataset" class="q-ma-sm" style="min-width: 200px;"></q-select>
|
||||||
|
<q-space></q-space>
|
||||||
<q-btn icon="arrow_back" class="q-my-sm btn-style" v-on:click="imgMinusT=true"></q-btn>
|
<q-btn icon="arrow_back" class="q-my-sm btn-style" v-on:click="imgMinusT=true"></q-btn>
|
||||||
<q-btn icon="arrow_forward" class="q-my-sm on-right btn-style" v-on:click="imgPlusT=true"></q-btn>
|
<q-btn icon="arrow_forward" class="q-my-sm on-right btn-style" v-on:click="imgPlusT=true"></q-btn>
|
||||||
</div>
|
</div>
|
||||||
@ -242,11 +271,38 @@
|
|||||||
<q-img id="colorbar-triq" class="q-ma-none q-pa-none" :src="colorbarT"></q-img>
|
<q-img id="colorbar-triq" class="q-ma-none q-pa-none" :src="colorbarT"></q-img>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<p>{{msgtriq}}</p>
|
<p v-html="msgtriq"></p>
|
||||||
</q-tab-panel>
|
</q-tab-panel>
|
||||||
|
|
||||||
<q-tab-panel name="tab2">
|
<q-tab-panel name="tab2">
|
||||||
<!-- Content for Tab 2 -->
|
<div class="row items-center">
|
||||||
|
<q-select v-model="selected_folder_main" :options="available_folders" label="Select Dataset" class="q-ma-sm" style="min-width: 200px;"></q-select>
|
||||||
|
<q-btn-dropdown class="q-ma-sm btn-style" :loading="progressSpectraPlot" :disable="btnSpectraDisable"
|
||||||
|
label="Generate Spectra" icon="play_arrow">
|
||||||
|
<template v-slot:loading>
|
||||||
|
<q-spinner-hourglass class="on-left" />
|
||||||
|
Loading plot
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<q-list>
|
||||||
|
<q-item clickable v-close-popup v-on:click="createMeanPlot=true">
|
||||||
|
<q-item-section>
|
||||||
|
<q-item-label>Mean spectrum plot</q-item-label>
|
||||||
|
</q-item-section>
|
||||||
|
</q-item>
|
||||||
|
<q-item clickable v-close-popup v-on:click="createSumPlot=true">
|
||||||
|
<q-item-section>
|
||||||
|
<q-item-label>Sum Spectrum plot</q-item-label>
|
||||||
|
</q-item-section>
|
||||||
|
</q-item>
|
||||||
|
<q-item clickable v-close-popup v-on:click="createXYPlot=true">
|
||||||
|
<q-item-section>
|
||||||
|
<q-item-label>Spectrum plot (X,Y)</q-item-label>
|
||||||
|
</q-item-section>
|
||||||
|
</q-item>
|
||||||
|
</q-list>
|
||||||
|
</q-btn-dropdown>
|
||||||
|
</div>
|
||||||
<plotly id="plotSpectra" :data="plotdata" :layout="plotlayout" class="q-pa-none q-ma-none"></plotly>
|
<plotly id="plotSpectra" :data="plotdata" :layout="plotlayout" class="q-pa-none q-ma-none"></plotly>
|
||||||
</q-tab-panel>
|
</q-tab-panel>
|
||||||
|
|
||||||
@ -281,8 +337,8 @@
|
|||||||
|
|
||||||
<q-dialog v-model="CompareDialog" full-width>
|
<q-dialog v-model="CompareDialog" full-width>
|
||||||
<q-card>
|
<q-card>
|
||||||
<q-card-section class="row">
|
<q-card-section class="row items-center">
|
||||||
<div class="text-h6 q-ma-sm">Compare two diferent images or plots</div>
|
<div class="text-h6 q-ma-sm">Compare two different images or plots</div>
|
||||||
<div class="q-mx-sm">
|
<div class="q-mx-sm">
|
||||||
<q-slider color="black" v-model="imgTrans" :min="0.0" :max="1" :step="0.1" :disable="btnOpticalDisable" />
|
<q-slider color="black" v-model="imgTrans" :min="0.0" :max="1" :step="0.1" :disable="btnOpticalDisable" />
|
||||||
<q-badge style="background-color: #009f90;"> Transparency: {{ imgTrans }}</q-badge>
|
<q-badge style="background-color: #009f90;"> Transparency: {{ imgTrans }}</q-badge>
|
||||||
@ -294,46 +350,50 @@
|
|||||||
<q-card-section class="q-pt-none col-12">
|
<q-card-section class="q-pt-none col-12">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-6">
|
<div class="col-6">
|
||||||
<st-tabs id="tabHeaderCompareLeft" :ids="tabIDs" :labels="tabLabels" v-model="selectedTab"></st-tabs>
|
<div class="row items-center">
|
||||||
<q-tab-panels v-model="selectedTab">
|
<q-select v-model="selected_folder_compare_left" :options="image_available_folders" label="Select Left Dataset" class="q-ma-sm" style="min-width: 200px;"></q-select>
|
||||||
|
<q-space></q-space>
|
||||||
|
<st-tabs id="tabHeaderCompareLeft" :ids="CompTabIDsLeft" :labels="CompTabLabelsLeft" v-model="CompSelectedTabLeft"></st-tabs>
|
||||||
|
</div>
|
||||||
|
<q-tab-panels v-model="CompSelectedTabLeft">
|
||||||
<q-tab-panel name="tab0">
|
<q-tab-panel name="tab0">
|
||||||
<!-- Content for Tab 0 -->
|
<!-- Content for Tab 0 -->
|
||||||
<!-- Btn image changer -->
|
<!-- Btn image changer -->
|
||||||
<div>
|
<div>
|
||||||
<q-btn icon="arrow_back" class="q-my-sm btn-style" v-on:click="imgMinus=true"></q-btn>
|
<q-btn icon="arrow_back" class="q-my-sm btn-style" v-on:click="imgMinusCompLeft=true"></q-btn>
|
||||||
<q-btn icon="arrow_forward" class="q-my-sm on-right btn-style" v-on:click="imgPlus=true"></q-btn>
|
<q-btn icon="arrow_forward" class="q-my-sm on-right btn-style" v-on:click="imgPlusCompLeft=true"></q-btn>
|
||||||
</div>
|
</div>
|
||||||
<!-- Image manager -->
|
<!-- Image manager -->
|
||||||
<div id="image-container-compare-left-normal" class="row st-col col-12">
|
<div id="image-container-compare-left-normal" class="row st-col col-12">
|
||||||
<div class="col-10 q-pa-none q-ma-none ">
|
<div class="col-10 q-pa-none q-ma-none ">
|
||||||
<plotly id="plotImgCompareLeft" :data="plotdataImg" :layout="plotlayoutImg" class="q-pa-none q-ma-none">
|
<plotly id="plotImgCompareLeft" :data="plotdataImgCompLeft" :layout="plotlayoutImgCompLeft" class="q-pa-none q-ma-none">
|
||||||
</plotly>
|
</plotly>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-2">
|
<div class="col-2">
|
||||||
<q-img id="colorbarCompareLeft" class="q-ma-none q-pa-none" :src="colorbar"></q-img>
|
<q-img id="colorbarCompareLeft" class="q-ma-none q-pa-none" :src="colorbarCompLeft"></q-img>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<p>{{msgimg}}</p>
|
<p v-html="msgimgCompLeft"></p>
|
||||||
</q-tab-panel>
|
</q-tab-panel>
|
||||||
|
|
||||||
<q-tab-panel name="tab1">
|
<q-tab-panel name="tab1">
|
||||||
<!-- Content for Tab 1 -->
|
<!-- Content for Tab 1 -->
|
||||||
<!-- Triq Btn image changer -->
|
<!-- Triq Btn image changer -->
|
||||||
<div>
|
<div>
|
||||||
<q-btn icon="arrow_back" class="q-my-sm btn-style" v-on:click="imgMinusT=true"></q-btn>
|
<q-btn icon="arrow_back" class="q-my-sm btn-style" v-on:click="imgMinusTCompLeft=true"></q-btn>
|
||||||
<q-btn icon="arrow_forward" class="q-my-sm on-right btn-style" v-on:click="imgPlusT=true"></q-btn>
|
<q-btn icon="arrow_forward" class="q-my-sm on-right btn-style" v-on:click="imgPlusTCompLeft=true"></q-btn>
|
||||||
</div>
|
</div>
|
||||||
<!-- Triq Image manager -->
|
<!-- Triq Image manager -->
|
||||||
<div id="image-container-compare-left-triq" class="row st-col col-12">
|
<div id="image-container-compare-left-triq" class="row st-col col-12">
|
||||||
<div class="col-10 q-pa-none q-ma-none ">
|
<div class="col-10 q-pa-none q-ma-none ">
|
||||||
<plotly id="plotImgTCompareLeft" :data="plotdataImgT" :layout="plotlayoutImgT" class="q-pa-none q-ma-none">
|
<plotly id="plotImgTCompareLeft" :data="plotdataImgTCompLeft" :layout="plotlayoutImgTCompLeft" class="q-pa-none q-ma-none">
|
||||||
</plotly>
|
</plotly>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-2">
|
<div class="col-2">
|
||||||
<q-img id="colorbarTCompareLeft" class="q-ma-none q-pa-none" :src="colorbarT"></q-img>
|
<q-img id="colorbarTCompareLeft" class="q-ma-none q-pa-none" :src="colorbarTCompLeft"></q-img>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<p>{{msgtriq}}</p>
|
<p v-html="msgtriqCompLeft"></p>
|
||||||
</q-tab-panel>
|
</q-tab-panel>
|
||||||
<q-tab-panel name="tab2">
|
<q-tab-panel name="tab2">
|
||||||
<!-- Content for Tab 2 -->
|
<!-- Content for Tab 2 -->
|
||||||
@ -350,51 +410,54 @@
|
|||||||
</q-tab-panels>
|
</q-tab-panels>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-6">
|
<div class="col-6">
|
||||||
<st-tabs id="tabHeaderCompareRight" :ids="CompTabIDs" :labels="CompTabLabels" v-model="CompSelectedTab" outside-arrows
|
<div class="row items-center">
|
||||||
mobile-arrows></st-tabs>
|
<q-select v-model="selected_folder_compare_right" :options="image_available_folders" label="Select Right Dataset" class="q-ma-sm" style="min-width: 200px;"></q-select>
|
||||||
<q-tab-panels v-model="CompSelectedTab">
|
<q-space></q-space>
|
||||||
|
<st-tabs id="tabHeaderCompareRight" :ids="CompTabIDsRight" :labels="CompTabLabelsRight" v-model="CompSelectedTabRight"></st-tabs>
|
||||||
|
</div>
|
||||||
|
<q-tab-panels v-model="CompSelectedTabRight">
|
||||||
<q-tab-panel name="tab0">
|
<q-tab-panel name="tab0">
|
||||||
<!-- Content for Tab 0 -->
|
<!-- Content for Tab 0 -->
|
||||||
<!-- Btn image changer -->
|
<!-- Btn image changer -->
|
||||||
<div>
|
<div>
|
||||||
<q-btn icon="arrow_back" class="q-my-sm btn-style" v-on:click="imgMinusComp=true"></q-btn>
|
<q-btn icon="arrow_back" class="q-my-sm btn-style" v-on:click="imgMinusCompRight=true"></q-btn>
|
||||||
<q-btn icon="arrow_forward" class="q-my-sm on-right btn-style"
|
<q-btn icon="arrow_forward" class="q-my-sm on-right btn-style"
|
||||||
v-on:click="imgPlusComp=true"></q-btn>
|
v-on:click="imgPlusCompRight=true"></q-btn>
|
||||||
</div>
|
</div>
|
||||||
<!-- Image manager -->
|
<!-- Image manager -->
|
||||||
<div id="image-container-compare-right-normal" class="row st-col col-12">
|
<div id="image-container-compare-right-normal" class="row st-col col-12">
|
||||||
<div class="col-10 q-pa-none q-ma-none ">
|
<div class="col-10 q-pa-none q-ma-none ">
|
||||||
<plotly id="plotImgCompareRight" :data="plotdataImgComp" :layout="plotlayoutImgComp"
|
<plotly id="plotImgCompareRight" :data="plotdataImgCompRight" :layout="plotlayoutImgCompRight"
|
||||||
class="q-pa-none q-ma-none">
|
class="q-pa-none q-ma-none">
|
||||||
</plotly>
|
</plotly>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-2 q-pa-none q-ma-none ">
|
<div class="col-2 q-pa-none q-ma-none ">
|
||||||
<q-img id="colorbarComp" class="q-ma-none q-pa-none" :src="colorbarComp"></q-img>
|
<q-img id="colorbarCompRight" class="q-ma-none q-pa-none" :src="colorbarCompRight"></q-img>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<p>{{msgimgComp}}</p>
|
<p v-html="msgimgCompRight"></p>
|
||||||
</q-tab-panel>
|
</q-tab-panel>
|
||||||
|
|
||||||
<q-tab-panel name="tab1">
|
<q-tab-panel name="tab1">
|
||||||
<!-- Content for Tab 1 -->
|
<!-- Content for Tab 1 -->
|
||||||
<!-- Triq Btn image changer -->
|
<!-- Triq Btn image changer -->
|
||||||
<div>
|
<div>
|
||||||
<q-btn icon="arrow_back" class="q-my-sm btn-style" v-on:click="imgMinusTComp=true"></q-btn>
|
<q-btn icon="arrow_back" class="q-my-sm btn-style" v-on:click="imgMinusTCompRight=true"></q-btn>
|
||||||
<q-btn icon="arrow_forward" class="q-my-sm on-right btn-style"
|
<q-btn icon="arrow_forward" class="q-my-sm on-right btn-style"
|
||||||
v-on:click="imgPlusTComp=true"></q-btn>
|
v-on:click="imgPlusTCompRight=true"></q-btn>
|
||||||
</div>
|
</div>
|
||||||
<!-- Triq Image manager -->
|
<!-- Triq Image manager -->
|
||||||
<div id="image-container-compare-right-triq" class="row st-col col-12">
|
<div id="image-container-compare-right-triq" class="row st-col col-12">
|
||||||
<div class="col-10 q-pa-none q-ma-none ">
|
<div class="col-10 q-pa-none q-ma-none ">
|
||||||
<plotly id="plotImgTCompareRight" :data="plotdataImgTComp" :layout="plotlayoutImgTComp"
|
<plotly id="plotImgTCompareRight" :data="plotdataImgTCompRight" :layout="plotlayoutImgTCompRight"
|
||||||
class="q-pa-none q-ma-none">
|
class="q-pa-none q-ma-none">
|
||||||
</plotly>
|
</plotly>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-2 q-pa-none q-ma-none ">
|
<div class="col-2 q-pa-none q-ma-none ">
|
||||||
<q-img id="colorbarTComp" class="q-ma-none q-pa-none" :src="colorbarTComp"></q-img>
|
<q-img id="colorbarTCompRight" class="q-ma-none q-pa-none" :src="colorbarTCompRight"></q-img>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<p>{{msgtriqComp}}</p>
|
<p v-html="msgtriqCompRight"></p>
|
||||||
</q-tab-panel>
|
</q-tab-panel>
|
||||||
<q-tab-panel name="tab2">
|
<q-tab-panel name="tab2">
|
||||||
<!-- Content for Tab 2 -->
|
<!-- Content for Tab 2 -->
|
||||||
@ -419,23 +482,53 @@
|
|||||||
</q-card>
|
</q-card>
|
||||||
</q-dialog>
|
</q-dialog>
|
||||||
|
|
||||||
|
<q-dialog v-model="showBatchSummary">
|
||||||
|
<q-card>
|
||||||
|
<q-card-section>
|
||||||
|
<div class="text-h6">Batch Process Summary</div>
|
||||||
|
</q-card-section>
|
||||||
|
|
||||||
|
<q-card-section class="q-pt-none">
|
||||||
|
<pre>{{ batch_summary }}</pre>
|
||||||
|
</q-card-section>
|
||||||
|
|
||||||
|
<q-card-actions align="right">
|
||||||
|
<q-btn flat label="Ok" style="color:#009f90" v-close-popup />
|
||||||
|
</q-card-actions>
|
||||||
|
</q-card>
|
||||||
|
</q-dialog>
|
||||||
|
|
||||||
<q-dialog v-model="showMetadataDialog" full-width full-height>
|
<q-dialog v-model="showMetadataDialog" full-width full-height>
|
||||||
<q-card>
|
<q-card>
|
||||||
<q-card-section>
|
<q-card-section class="row items-center q-pb-none">
|
||||||
<div class="text-h6">Dataset Summary</div>
|
<div class="text-h6">Dataset Summary</div>
|
||||||
|
<q-space />
|
||||||
|
<q-select
|
||||||
|
v-model="selected_folder_metadata"
|
||||||
|
:options="available_folders"
|
||||||
|
label="Select Dataset"
|
||||||
|
class="q-ma-sm"
|
||||||
|
style="min-width: 250px;"
|
||||||
|
standout="custom-standout"
|
||||||
|
></q-select>
|
||||||
</q-card-section>
|
</q-card-section>
|
||||||
|
|
||||||
<q-card-section class="q-pt-none">
|
<q-card-section class="q-pt-none">
|
||||||
<q-list bordered separator>
|
<q-list bordered separator v-if="metadata_rows.length > 0">
|
||||||
<q-item v-for="row in metadata_rows" :key="row.parameter">
|
<q-item v-for="row in metadata_rows" :key="row.parameter">
|
||||||
<q-item-section>
|
<q-item-section>
|
||||||
<q-item-label>{{ row.parameter }}</q-item-label>
|
<q-item-label class="text-body1">{{ row.parameter }}</q-item-label>
|
||||||
</q-item-section>
|
</q-item-section>
|
||||||
<q-item-section side>
|
<q-item-section side>
|
||||||
<q-item-label caption>{{ row.value }}</q-item-label>
|
<q-item-label caption class="text-body1">{{ row.value }}</q-item-label>
|
||||||
</q-item-section>
|
</q-item-section>
|
||||||
</q-item>
|
</q-item>
|
||||||
</q-list>
|
</q-list>
|
||||||
|
<div v-else class="text-center q-pa-md text-grey-7">
|
||||||
|
<q-icon name="info" size="3em" />
|
||||||
|
<p class="q-mt-md">No metadata found in registry for this dataset.</p>
|
||||||
|
<p class="text-caption">You may need to process the file first.</p>
|
||||||
|
</div>
|
||||||
</q-card-section>
|
</q-card-section>
|
||||||
|
|
||||||
<q-card-actions align="right">
|
<q-card-actions align="right">
|
||||||
|
|||||||
@ -452,10 +452,11 @@ end
|
|||||||
# returns the layout and data for the surface plotly plot
|
# returns the layout and data for the surface plotly plot
|
||||||
# this function loads the spectra data and makes a mean to display
|
# this function loads the spectra data and makes a mean to display
|
||||||
# its values in the spectrum plot
|
# its values in the spectrum plot
|
||||||
function meanSpectrumPlot(data::MSIData)
|
function meanSpectrumPlot(data::MSIData, dataset_name::String="")
|
||||||
|
title_text = isempty(dataset_name) ? "Average Spectrum Plot" : "Average Spectrum for: $dataset_name"
|
||||||
layout = PlotlyBase.Layout(
|
layout = PlotlyBase.Layout(
|
||||||
title=PlotlyBase.attr(
|
title=PlotlyBase.attr(
|
||||||
text="Average Spectrum Plot",
|
text=title_text,
|
||||||
font=PlotlyBase.attr(
|
font=PlotlyBase.attr(
|
||||||
family="Roboto, Lato, sans-serif",
|
family="Roboto, Lato, sans-serif",
|
||||||
size=18,
|
size=18,
|
||||||
@ -480,9 +481,9 @@ function meanSpectrumPlot(data::MSIData)
|
|||||||
|
|
||||||
if isempty(xSpectraMz)
|
if isempty(xSpectraMz)
|
||||||
@warn "Average spectrum is empty."
|
@warn "Average spectrum is empty."
|
||||||
trace = PlotlyBase.stem(x=Float64[], y=Float64[])
|
trace = PlotlyBase.scatter(x=Float64[], y=Float64[])
|
||||||
else
|
else
|
||||||
trace = PlotlyBase.stem(x=xSpectraMz, y=ySpectraMz, marker=attr(size=1, color="blue", opacity=0.5), name="Average", hoverinfo="x",hovertemplate="<b>m/z</b>: %{x:.4f}<extra></extra>")
|
trace = PlotlyBase.scatter(x=xSpectraMz, y=ySpectraMz, marker=attr(size=1, color="blue", opacity=0.5), name="Average", hoverinfo="x",hovertemplate="<b>m/z</b>: %{x:.4f}<extra></extra>")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
@ -491,7 +492,7 @@ function meanSpectrumPlot(data::MSIData)
|
|||||||
return plotdata, plotlayout, xSpectraMz, ySpectraMz
|
return plotdata, plotlayout, xSpectraMz, ySpectraMz
|
||||||
end
|
end
|
||||||
|
|
||||||
function xySpectrumPlot(data::MSIData, xCoord::Int, yCoord::Int, imgWidth::Int, imgHeight::Int)
|
function xySpectrumPlot(data::MSIData, xCoord::Int, yCoord::Int, imgWidth::Int, imgHeight::Int, dataset_name::String="")
|
||||||
local mz::AbstractVector, intensity::AbstractVector
|
local mz::AbstractVector, intensity::AbstractVector
|
||||||
local plot_title::String
|
local plot_title::String
|
||||||
|
|
||||||
@ -502,24 +503,24 @@ function xySpectrumPlot(data::MSIData, xCoord::Int, yCoord::Int, imgWidth::Int,
|
|||||||
x = clamp(xCoord, 1, imgWidth)
|
x = clamp(xCoord, 1, imgWidth)
|
||||||
y = clamp(yCoord, 1, imgHeight)
|
y = clamp(yCoord, 1, imgHeight)
|
||||||
|
|
||||||
# mz, intensity = GetSpectrum(data, Int(x), Int(y))
|
|
||||||
process_spectrum(data, Int(x), Int(y)) do recieved_mz, recieved_intensity
|
process_spectrum(data, Int(x), Int(y)) do recieved_mz, recieved_intensity
|
||||||
mz = recieved_mz
|
mz = recieved_mz
|
||||||
intensity = recieved_intensity
|
intensity = recieved_intensity
|
||||||
end
|
end
|
||||||
plot_title = "Spectrum at ($x, $y)"
|
base_title = "Spectrum at ($x, $y)"
|
||||||
else
|
else
|
||||||
# For non-imaging data, treat xCoord as the spectrum index
|
# For non-imaging data, treat xCoord as the spectrum index
|
||||||
index = clamp(xCoord, 1, length(data.spectra_metadata))
|
index = clamp(xCoord, 1, length(data.spectra_metadata))
|
||||||
|
|
||||||
# mz, intensity = GetSpectrum(data, index)
|
|
||||||
process_spectrum(data, index) do recieved_mz, recieved_intensity
|
process_spectrum(data, index) do recieved_mz, recieved_intensity
|
||||||
mz = recieved_mz
|
mz = recieved_mz
|
||||||
intensity = recieved_intensity
|
intensity = recieved_intensity
|
||||||
end
|
end
|
||||||
plot_title = "Spectrum #$index"
|
base_title = "Spectrum #$index"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
plot_title = isempty(dataset_name) ? base_title : "$base_title for: $dataset_name"
|
||||||
|
|
||||||
layout = PlotlyBase.Layout(
|
layout = PlotlyBase.Layout(
|
||||||
title=PlotlyBase.attr(
|
title=PlotlyBase.attr(
|
||||||
text=plot_title,
|
text=plot_title,
|
||||||
@ -545,7 +546,7 @@ function xySpectrumPlot(data::MSIData, xCoord::Int, yCoord::Int, imgWidth::Int,
|
|||||||
# Downsample for plotting performance
|
# Downsample for plotting performance
|
||||||
mz_down, int_down = MSI_src.downsample_spectrum(mz, intensity)
|
mz_down, int_down = MSI_src.downsample_spectrum(mz, intensity)
|
||||||
|
|
||||||
trace = PlotlyBase.stem(x=mz_down, y=int_down, marker=attr(size=1, color="blue", opacity=0.5), name="Spectrum", hoverinfo="x", hovertemplate="<b>m/z</b>: %{x:.4f}<extra></extra>")
|
trace = PlotlyBase.scatter(x=mz_down, y=int_down, marker=attr(size=1, color="blue", opacity=0.5), name="Spectrum", hoverinfo="x", hovertemplate="<b>m/z</b>: %{x:.4f}<extra></extra>")
|
||||||
|
|
||||||
plotdata = [trace]
|
plotdata = [trace]
|
||||||
plotlayout = layout
|
plotlayout = layout
|
||||||
@ -553,10 +554,11 @@ function xySpectrumPlot(data::MSIData, xCoord::Int, yCoord::Int, imgWidth::Int,
|
|||||||
return plotdata, plotlayout, mz, intensity
|
return plotdata, plotlayout, mz, intensity
|
||||||
end
|
end
|
||||||
|
|
||||||
function sumSpectrumPlot(data::MSIData)
|
function sumSpectrumPlot(data::MSIData, dataset_name::String="")
|
||||||
|
title_text = isempty(dataset_name) ? "Total Spectrum Plot" : "Total Spectrum for: $dataset_name"
|
||||||
layout = PlotlyBase.Layout(
|
layout = PlotlyBase.Layout(
|
||||||
title=PlotlyBase.attr(
|
title=PlotlyBase.attr(
|
||||||
text="Total Spectrum Plot",
|
text=title_text,
|
||||||
font=PlotlyBase.attr(
|
font=PlotlyBase.attr(
|
||||||
family="Roboto, Lato, sans-serif",
|
family="Roboto, Lato, sans-serif",
|
||||||
size=18,
|
size=18,
|
||||||
@ -581,12 +583,47 @@ function sumSpectrumPlot(data::MSIData)
|
|||||||
|
|
||||||
if isempty(xSpectraMz)
|
if isempty(xSpectraMz)
|
||||||
@warn "Total spectrum is empty."
|
@warn "Total spectrum is empty."
|
||||||
trace = PlotlyBase.stem(x=Float64[], y=Float64[])
|
trace = PlotlyBase.scatter(x=Float64[], y=Float64[])
|
||||||
else
|
else
|
||||||
trace = PlotlyBase.stem(x=xSpectraMz, y=ySpectraMz, marker=attr(size=1, color="blue", opacity=0.5), name="Total", hoverinfo="x",hovertemplate="<b>m/z</b>: %{x:.4f}<extra></extra>")
|
trace = PlotlyBase.scatter(x=xSpectraMz, y=ySpectraMz, marker=attr(size=1, color="blue", opacity=0.5), name="Total", hoverinfo="x",hovertemplate="<b>m/z</b>: %{x:.4f}<extra></extra>")
|
||||||
end
|
end
|
||||||
|
|
||||||
plotdata = [trace]
|
plotdata = [trace]
|
||||||
plotlayout = layout
|
plotlayout = layout
|
||||||
return plotdata, plotlayout, xSpectraMz, ySpectraMz
|
return plotdata, plotlayout, xSpectraMz, ySpectraMz
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function warmup_init()
|
||||||
|
@async begin
|
||||||
|
println("Pre-compiling functions at startup...")
|
||||||
|
|
||||||
|
# Create a dummy MSIData object to be used for pre-compilation
|
||||||
|
# dummy_source = ImzMLSource("dummy.ibd", Float32, Float32)
|
||||||
|
# dummy_meta = MSI_src.SpectrumMetadata(0,0,"",MSI_src.UNKNOWN, MSI_src.SpectrumAsset(Float32,false,0,0,:mz), MSI_src.SpectrumAsset(Float32,false,0,0,:intensity))
|
||||||
|
# dummy_msi_data = MSIData(dummy_source, [dummy_meta], (1,1), zeros(Int,1,1), 0)
|
||||||
|
|
||||||
|
# Pre-compile functions from btnSearch
|
||||||
|
# try OpenMSIData("dummy.imzML") catch end
|
||||||
|
# try precompute_analytics(dummy_msi_data) catch end
|
||||||
|
|
||||||
|
# Pre-compile functions from mainProcess
|
||||||
|
# try get_mz_slice(dummy_msi_data, 1.0, 1.0) catch end
|
||||||
|
try TrIQ(zeros(10,10), 256, 0.98) catch end
|
||||||
|
try quantize_intensity(zeros(10,10), 256) catch end
|
||||||
|
|
||||||
|
dummy_bmp_path = joinpath("public", "dummy.bmp")
|
||||||
|
dummy_png_path = joinpath("public", "dummy.png")
|
||||||
|
try
|
||||||
|
save_bitmap(dummy_bmp_path, zeros(UInt8, 10, 10), ViridisPalette)
|
||||||
|
loadImgPlot("/dummy.bmp")
|
||||||
|
generate_colorbar_image(zeros(10,10), 256, dummy_png_path)
|
||||||
|
catch e
|
||||||
|
@warn "Pre-compilation step failed (this is expected if dummy files can't be created/read)"
|
||||||
|
finally
|
||||||
|
rm(dummy_bmp_path, force=true)
|
||||||
|
rm(dummy_png_path, force=true)
|
||||||
|
end
|
||||||
|
|
||||||
|
println("Pre-compilation finished.")
|
||||||
|
end
|
||||||
|
end
|
||||||
@ -82,7 +82,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
#intDivStyle-left .q-tab-panels {
|
#intDivStyle-left .q-tab-panels {
|
||||||
height: 670px; /* Set this to accommodate your tallest content */
|
height: 700px; /* Set this to accommodate your tallest content */
|
||||||
}
|
}
|
||||||
|
|
||||||
#intDivStyle-left .q-tab-panel {
|
#intDivStyle-left .q-tab-panel {
|
||||||
|
|||||||
@ -497,7 +497,7 @@ function ConvertMzmlToImzml(source_file::String, target_ibd_file::String, timing
|
|||||||
open(target_ibd_file, "w") do ibd_stream
|
open(target_ibd_file, "w") do ibd_stream
|
||||||
write(ibd_stream, zeros(UInt8, 16)) # UUID placeholder
|
write(ibd_stream, zeros(UInt8, 16)) # UUID placeholder
|
||||||
end
|
end
|
||||||
return BinaryMetadata[], Tuple{Int, Int}[], (0, 0)
|
return BinaryMetadata[], Tuple{Int, Int}[], (0, 0), UNKNOWN
|
||||||
end
|
end
|
||||||
|
|
||||||
width = maximum(timing_matrix[:, 1])
|
width = maximum(timing_matrix[:, 1])
|
||||||
@ -505,6 +505,11 @@ function ConvertMzmlToImzml(source_file::String, target_ibd_file::String, timing
|
|||||||
|
|
||||||
msi_data = OpenMSIData(source_file)
|
msi_data = OpenMSIData(source_file)
|
||||||
|
|
||||||
|
source_mode = UNKNOWN
|
||||||
|
if !isempty(msi_data.spectra_metadata)
|
||||||
|
source_mode = msi_data.spectra_metadata[1].mode
|
||||||
|
end
|
||||||
|
|
||||||
scan_time_deltas = zeros(Int64, size(scans, 1))
|
scan_time_deltas = zeros(Int64, size(scans, 1))
|
||||||
if size(scans, 1) > 1
|
if size(scans, 1) > 1
|
||||||
for i in 1:(size(scans, 1) - 1)
|
for i in 1:(size(scans, 1) - 1)
|
||||||
@ -553,7 +558,7 @@ function ConvertMzmlToImzml(source_file::String, target_ibd_file::String, timing
|
|||||||
# Write m/z array
|
# Write m/z array
|
||||||
mz_offset = position(ibd_stream)
|
mz_offset = position(ibd_stream)
|
||||||
for val in mz
|
for val in mz
|
||||||
write(ibd_stream, htol(Float64(val)))
|
write(ibd_stream, htol(Float32(val)))
|
||||||
end
|
end
|
||||||
mz_length = position(ibd_stream) - mz_offset
|
mz_length = position(ibd_stream) - mz_offset
|
||||||
|
|
||||||
@ -569,7 +574,7 @@ function ConvertMzmlToImzml(source_file::String, target_ibd_file::String, timing
|
|||||||
end
|
end
|
||||||
|
|
||||||
@info "Found and processed $empty_pixel_count empty pixels out of $(size(timing_matrix, 1)) total."
|
@info "Found and processed $empty_pixel_count empty pixels out of $(size(timing_matrix, 1)) total."
|
||||||
return binary_meta_vec, coords_vec, (width, height)
|
return binary_meta_vec, coords_vec, (width, height), source_mode
|
||||||
end
|
end
|
||||||
|
|
||||||
"""
|
"""
|
||||||
@ -589,7 +594,7 @@ experiment and data format.
|
|||||||
# Returns
|
# Returns
|
||||||
- `true` on success, `false` on failure.
|
- `true` on success, `false` on failure.
|
||||||
"""
|
"""
|
||||||
function ExportImzml(target_file::String, binary_meta::Vector{BinaryMetadata}, coords::Vector{Tuple{Int, Int}}, dims::Tuple{Int, Int})
|
function ExportImzml(target_file::String, binary_meta::Vector{BinaryMetadata}, coords::Vector{Tuple{Int, Int}}, dims::Tuple{Int, Int}, mode::SpectrumMode)
|
||||||
ibd_file = replace(target_file, r"\.imzML$"i => ".ibd")
|
ibd_file = replace(target_file, r"\.imzML$"i => ".ibd")
|
||||||
|
|
||||||
if isempty(binary_meta)
|
if isempty(binary_meta)
|
||||||
@ -604,8 +609,7 @@ function ExportImzml(target_file::String, binary_meta::Vector{BinaryMetadata}, c
|
|||||||
open(target_file, "w") do imzml_stream
|
open(target_file, "w") do imzml_stream
|
||||||
# XML Header
|
# XML Header
|
||||||
write(imzml_stream, """<?xml version="1.0" encoding="ISO-8859-1"?>
|
write(imzml_stream, """<?xml version="1.0" encoding="ISO-8859-1"?>
|
||||||
<indexedmzML xmlns="http://psi.hupo.org/ms/mzml" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://psi.hupo.org/ms/mzml http://psidev.info/files/ms/mzML/xsd/mzML1.1.0_idx.xsd">
|
<mzML xmlns="http://psi.hupo.org/ms/mzml" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://psi.hupo.org/ms/mzml http://psidev.info/files/ms/mzML/xsd/mzML1.1.0.xsd" version="1.1" id="$(splitext(basename(target_file))[1])">
|
||||||
<mzML version="1.1" id="$(splitext(basename(target_file))[1])">
|
|
||||||
""")
|
""")
|
||||||
|
|
||||||
# CV List, File Description, etc. (static parts)
|
# CV List, File Description, etc. (static parts)
|
||||||
@ -627,13 +631,11 @@ function ExportImzml(target_file::String, binary_meta::Vector{BinaryMetadata}, c
|
|||||||
<referenceableParamGroup id="mzArray">
|
<referenceableParamGroup id="mzArray">
|
||||||
<cvParam cvRef="MS" accession="MS:1000576" name="no compression"/>
|
<cvParam cvRef="MS" accession="MS:1000576" name="no compression"/>
|
||||||
<cvParam cvRef="MS" accession="MS:1000514" name="m/z array" unitCvRef="MS" unitAccession="MS:1000040" unitName="m/z"/>
|
<cvParam cvRef="MS" accession="MS:1000514" name="m/z array" unitCvRef="MS" unitAccession="MS:1000040" unitName="m/z"/>
|
||||||
<cvParam cvRef="IMS" accession="IMS:1000101" name="external data" value="true"/>
|
<cvParam cvRef="MS" accession="MS:1000521" name="32-bit float"/>
|
||||||
<cvParam cvRef="MS" accession="MS:1000523" name="64-bit float"/>
|
|
||||||
</referenceableParamGroup>
|
</referenceableParamGroup>
|
||||||
<referenceableParamGroup id="intensityArray">
|
<referenceableParamGroup id="intensityArray">
|
||||||
<cvParam cvRef="MS" accession="MS:1000576" name="no compression"/>
|
<cvParam cvRef="MS" accession="MS:1000576" name="no compression"/>
|
||||||
<cvParam cvRef="MS" accession="MS:1000515" name="intensity array" unitCvRef="MS" unitAccession="MS:1000131" unitName="number of counts"/>
|
<cvParam cvRef="MS" accession="MS:1000515" name="intensity array" unitCvRef="MS" unitAccession="MS:1000131" unitName="number of counts"/>
|
||||||
<cvParam cvRef="IMS" accession="IMS:1000101" name="external data" value="true"/>
|
|
||||||
<cvParam cvRef="MS" accession="MS:1000521" name="32-bit float"/>
|
<cvParam cvRef="MS" accession="MS:1000521" name="32-bit float"/>
|
||||||
</referenceableParamGroup>
|
</referenceableParamGroup>
|
||||||
</referenceableParamGroupList>
|
</referenceableParamGroupList>
|
||||||
@ -699,13 +701,20 @@ function ExportImzml(target_file::String, binary_meta::Vector{BinaryMetadata}, c
|
|||||||
push!(spectrum_offsets, spectrum_start)
|
push!(spectrum_offsets, spectrum_start)
|
||||||
|
|
||||||
# Calculate number of points from byte length
|
# Calculate number of points from byte length
|
||||||
mz_points = meta.mz_length ÷ sizeof(Float64)
|
mz_points = meta.mz_length ÷ sizeof(Float32)
|
||||||
int_points = meta.int_length ÷ sizeof(Float32)
|
int_points = meta.int_length ÷ sizeof(Float32)
|
||||||
|
|
||||||
write(imzml_stream, """ <spectrum id="Scan=$(i)" defaultArrayLength="$(mz_points)" index="$(i-1)">
|
write(imzml_stream, """ <spectrum id="Scan=$(i)" defaultArrayLength="$(mz_points)" index="$(i-1)">
|
||||||
<cvParam cvRef="MS" accession="MS:1000511" name="ms level" value="1"/>
|
<cvParam cvRef="MS" accession="MS:1000511" name="ms level" value="1"/>
|
||||||
<cvParam cvRef="MS" accession="MS:1000128" name="profile spectrum"/>
|
""")
|
||||||
<scanList count="1">
|
if mode == CENTROID
|
||||||
|
write(imzml_stream, """ <cvParam cvRef="MS" accession="MS:1000127" name="centroid spectrum"/>
|
||||||
|
""")
|
||||||
|
else
|
||||||
|
write(imzml_stream, """ <cvParam cvRef="MS" accession="MS:1000128" name="profile spectrum"/>
|
||||||
|
""")
|
||||||
|
end
|
||||||
|
write(imzml_stream, """ <scanList count="1">
|
||||||
<scan instrumentConfigurationRef="instrument1">
|
<scan instrumentConfigurationRef="instrument1">
|
||||||
<cvParam cvRef="IMS" accession="IMS:1000050" name="position x" value="$(x)"/>
|
<cvParam cvRef="IMS" accession="IMS:1000050" name="position x" value="$(x)"/>
|
||||||
<cvParam cvRef="IMS" accession="IMS:1000051" name="position y" value="$(y)"/>
|
<cvParam cvRef="IMS" accession="IMS:1000051" name="position y" value="$(y)"/>
|
||||||
@ -714,16 +723,14 @@ function ExportImzml(target_file::String, binary_meta::Vector{BinaryMetadata}, c
|
|||||||
<binaryDataArrayList count="2">
|
<binaryDataArrayList count="2">
|
||||||
<binaryDataArray encodedLength="0">
|
<binaryDataArray encodedLength="0">
|
||||||
<referenceableParamGroupRef ref="mzArray"/>
|
<referenceableParamGroupRef ref="mzArray"/>
|
||||||
<cvParam cvRef="IMS" accession="IMS:1000102" name="external offset" value="$(meta.mz_offset)"/>
|
|
||||||
<cvParam cvRef="IMS" accession="IMS:1000103" name="external array length" value="$(mz_points)"/>
|
<cvParam cvRef="IMS" accession="IMS:1000103" name="external array length" value="$(mz_points)"/>
|
||||||
<cvParam cvRef="IMS" accession="IMS:1000104" name="external encoded length" value="$(meta.mz_length)"/>
|
<cvParam cvRef="IMS" accession="IMS:1000102" name="external offset" value="$(meta.mz_offset)"/>
|
||||||
<binary/>
|
<binary/>
|
||||||
</binaryDataArray>
|
</binaryDataArray>
|
||||||
<binaryDataArray encodedLength="0">
|
<binaryDataArray encodedLength="0">
|
||||||
<referenceableParamGroupRef ref="intensityArray"/>
|
<referenceableParamGroupRef ref="intensityArray"/>
|
||||||
<cvParam cvRef="IMS" accession="IMS:1000102" name="external offset" value="$(meta.int_offset)"/>
|
|
||||||
<cvParam cvRef="IMS" accession="IMS:1000103" name="external array length" value="$(int_points)"/>
|
<cvParam cvRef="IMS" accession="IMS:1000103" name="external array length" value="$(int_points)"/>
|
||||||
<cvParam cvRef="IMS" accession="IMS:1000104" name="external encoded length" value="$(meta.int_length)"/>
|
<cvParam cvRef="IMS" accession="IMS:1000102" name="external offset" value="$(meta.int_offset)"/>
|
||||||
<binary/>
|
<binary/>
|
||||||
</binaryDataArray>
|
</binaryDataArray>
|
||||||
</binaryDataArrayList>
|
</binaryDataArrayList>
|
||||||
@ -734,19 +741,6 @@ function ExportImzml(target_file::String, binary_meta::Vector{BinaryMetadata}, c
|
|||||||
write(imzml_stream, """ </spectrumList>
|
write(imzml_stream, """ </spectrumList>
|
||||||
</run>
|
</run>
|
||||||
</mzML>
|
</mzML>
|
||||||
""")
|
|
||||||
# Index List
|
|
||||||
index_list_start = position(imzml_stream)
|
|
||||||
write(imzml_stream, """ <indexList count="1">
|
|
||||||
<index name="spectrum">
|
|
||||||
""")
|
|
||||||
for (i, offset) in enumerate(spectrum_offsets)
|
|
||||||
write(imzml_stream, " <offset idRef=\"Scan=$(i)\">$offset</offset>\n")
|
|
||||||
end
|
|
||||||
write(imzml_stream, """ </index>
|
|
||||||
</indexList>
|
|
||||||
<indexListOffset>$index_list_start</indexListOffset>
|
|
||||||
</indexedmzML>
|
|
||||||
""")
|
""")
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -784,13 +778,13 @@ function ImportMzmlFile(source_file::String, sync_file::String, target_file::Str
|
|||||||
|
|
||||||
println("Step 3: Converting spectra and writing .ibd file...")
|
println("Step 3: Converting spectra and writing .ibd file...")
|
||||||
ibd_file = replace(target_file, r"\.imzML$"i => ".ibd")
|
ibd_file = replace(target_file, r"\.imzML$"i => ".ibd")
|
||||||
binary_meta, coords, (width, height) = ConvertMzmlToImzml(source_file, ibd_file, timing_matrix, scans)
|
binary_meta, coords, (width, height), source_mode = ConvertMzmlToImzml(source_file, ibd_file, timing_matrix, scans)
|
||||||
|
|
||||||
# Flip image vertically to match R script output
|
# Flip image vertically to match R script output
|
||||||
flipped_coords = [(x, height - y + 1) for (x, y) in coords]
|
flipped_coords = [(x, height - y + 1) for (x, y) in coords]
|
||||||
|
|
||||||
println("Step 4: Exporting .imzML metadata file...")
|
println("Step 4: Exporting .imzML metadata file...")
|
||||||
success = ExportImzml(target_file, binary_meta, flipped_coords, (width, height))
|
success = ExportImzml(target_file, binary_meta, flipped_coords, (width, height), source_mode)
|
||||||
|
|
||||||
if success
|
if success
|
||||||
println("Conversion successful: $target_file")
|
println("Conversion successful: $target_file")
|
||||||
|
|||||||
78
src/imzML.jl
78
src/imzML.jl
@ -793,6 +793,84 @@ function get_mz_slice(data::MSIData, mass::Real, tolerance::Real)
|
|||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
"""
|
||||||
|
get_multiple_mz_slices(data::MSIData, masses::AbstractVector{<:Real}, tolerance::Real)
|
||||||
|
|
||||||
|
Extracts multiple image slices for a given list of m/z values in a single pass.
|
||||||
|
This is a highly performant function that iterates through the full dataset only once.
|
||||||
|
|
||||||
|
# Returns
|
||||||
|
- A `Dict{Real, Matrix{Float64}}` mapping each mass to its intensity slice matrix.
|
||||||
|
"""
|
||||||
|
function get_multiple_mz_slices(data::MSIData, masses::AbstractVector{<:Real}, tolerance::Real)
|
||||||
|
width, height = data.image_dims
|
||||||
|
|
||||||
|
# 1. Initialize a dictionary to hold the output slice matrices
|
||||||
|
slice_dict = Dict{Real, Matrix{Float64}}()
|
||||||
|
for mass in masses
|
||||||
|
slice_dict[mass] = zeros(Float64, height, width)
|
||||||
|
end
|
||||||
|
|
||||||
|
# 2. Ensure analytics are computed for filtering.
|
||||||
|
if data.spectrum_stats_df === nothing || !hasproperty(data.spectrum_stats_df, :MinMZ)
|
||||||
|
println("Per-spectrum metadata not found. Running one-time analytics computation...")
|
||||||
|
precompute_analytics(data)
|
||||||
|
end
|
||||||
|
|
||||||
|
println("Filtering candidate spectra for $(length(masses)) m/z values...")
|
||||||
|
stats_df = data.spectrum_stats_df
|
||||||
|
candidate_indices = Set{Int}()
|
||||||
|
|
||||||
|
# 3. Find all spectra that could contain *any* of the requested masses.
|
||||||
|
for mass in masses
|
||||||
|
target_min = mass - tolerance
|
||||||
|
target_max = mass + tolerance
|
||||||
|
for i in 1:length(data.spectra_metadata)
|
||||||
|
# If already a candidate, no need to check again
|
||||||
|
if i in candidate_indices
|
||||||
|
continue
|
||||||
|
end
|
||||||
|
spec_min_mz = stats_df.MinMZ[i]
|
||||||
|
spec_max_mz = stats_df.MaxMZ[i]
|
||||||
|
if target_max >= spec_min_mz && target_min <= spec_max_mz
|
||||||
|
push!(candidate_indices, i)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
println("Found $(length(candidate_indices)) total candidate spectra.")
|
||||||
|
|
||||||
|
# 4. Iterate through the data a single time using the optimized iterator.
|
||||||
|
_iterate_spectra_fast(data) do idx, mz_array, intensity_array
|
||||||
|
# Process only the spectra that are candidates
|
||||||
|
if idx in candidate_indices
|
||||||
|
meta = data.spectra_metadata[idx]
|
||||||
|
# For this single spectrum, check all masses of interest
|
||||||
|
for mass in masses
|
||||||
|
# Check if this spectrum's range actually covers the current mass
|
||||||
|
# This is a finer-grained check than the initial filtering
|
||||||
|
if !isempty(mz_array) && (mass + tolerance) >= first(mz_array) && (mass - tolerance) <= last(mz_array)
|
||||||
|
intensity = find_mass(mz_array, intensity_array, mass, tolerance)
|
||||||
|
if intensity > 0.0
|
||||||
|
if 1 <= meta.x <= width && 1 <= meta.y <= height
|
||||||
|
slice_dict[mass][meta.y, meta.x] = intensity
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# 5. Clean up and return
|
||||||
|
for mass in masses
|
||||||
|
replace!(slice_dict[mass], NaN => 0.0)
|
||||||
|
end
|
||||||
|
|
||||||
|
println("Finished generating $(length(masses)) slices in a single pass.")
|
||||||
|
return slice_dict
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
"""
|
"""
|
||||||
plot_slice(msi_data::MSIData, mass::Float64, tolerance::Float64, output_dir::String; stage_name="slice", bins=256)
|
plot_slice(msi_data::MSIData, mass::Float64, tolerance::Float64, output_dir::String; stage_name="slice", bins=256)
|
||||||
|
|
||||||
|
|||||||
32
src/mzML.jl
32
src/mzML.jl
@ -103,9 +103,37 @@ the m/z and intensity array metadata.
|
|||||||
function parse_spectrum_metadata(stream::IO, offset::Int64)
|
function parse_spectrum_metadata(stream::IO, offset::Int64)
|
||||||
seek(stream, offset)
|
seek(stream, offset)
|
||||||
|
|
||||||
id_match = find_tag(stream, r"<spectrum\s+index=\"\d+\"\s+id=\"([^\"]+)" )
|
# Read the whole spectrum block to parse mode
|
||||||
|
spectrum_start_pos = position(stream)
|
||||||
|
line = ""
|
||||||
|
spectrum_buffer = IOBuffer()
|
||||||
|
while !eof(stream)
|
||||||
|
line = readline(stream)
|
||||||
|
write(spectrum_buffer, line)
|
||||||
|
if occursin("</spectrum>", line)
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
spectrum_xml = String(take!(spectrum_buffer))
|
||||||
|
seek(stream, spectrum_start_pos) # Reset for other parsing
|
||||||
|
|
||||||
|
id_match = match(r"<spectrum\s+index=\"\d+\"\s+id=\"([^\"]+)", spectrum_xml)
|
||||||
id = id_match === nothing ? "" : id_match.captures[1]
|
id = id_match === nothing ? "" : id_match.captures[1]
|
||||||
|
|
||||||
|
# Determine mode from the XML block
|
||||||
|
mode = UNKNOWN
|
||||||
|
if occursin("MS:1000127", spectrum_xml)
|
||||||
|
mode = CENTROID
|
||||||
|
elseif occursin("MS:1000128", spectrum_xml)
|
||||||
|
mode = PROFILE
|
||||||
|
end
|
||||||
|
|
||||||
|
# Find where the binary data list starts to parse assets
|
||||||
|
binary_list_match = findfirst("<binaryDataArrayList", spectrum_xml)
|
||||||
|
if binary_list_match !== nothing
|
||||||
|
seek(stream, spectrum_start_pos + binary_list_match.start - 1)
|
||||||
|
end
|
||||||
|
|
||||||
asset1 = get_spectrum_asset_metadata(stream)
|
asset1 = get_spectrum_asset_metadata(stream)
|
||||||
asset2 = get_spectrum_asset_metadata(stream)
|
asset2 = get_spectrum_asset_metadata(stream)
|
||||||
|
|
||||||
@ -118,7 +146,7 @@ function parse_spectrum_metadata(stream::IO, offset::Int64)
|
|||||||
|
|
||||||
# Create the new unified metadata object
|
# Create the new unified metadata object
|
||||||
# For mzML, x and y coordinates are not applicable, so we use 0.
|
# For mzML, x and y coordinates are not applicable, so we use 0.
|
||||||
return SpectrumMetadata(Int32(0), Int32(0), id, UNKNOWN, mz_asset, int_asset)
|
return SpectrumMetadata(Int32(0), Int32(0), id, mode, mz_asset, int_asset)
|
||||||
end
|
end
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user