Skip to content

Commit

Permalink
fix FLASHViewer to match merging with FLASHTaggerViewer
Browse files Browse the repository at this point in the history
  • Loading branch information
JeeH-K committed May 7, 2024
1 parent 0ef23f1 commit 5c86414
Show file tree
Hide file tree
Showing 20 changed files with 3,745 additions and 53 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ This app is based on [OpenMS streamlit template project](https://github.com/Open

run locally:

`streamlit run FLASHViewer.py local`
`streamlit run app.py local`

### Working with submodules

Expand Down
37 changes: 21 additions & 16 deletions app.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,39 +19,38 @@
"""

import sys

import streamlit as st

from src.captcha_ import captcha_control
from src.common import page_setup, save_params

from st_pages import Page, show_pages

params = page_setup(page="main")



def flashdeconvPages():
show_pages([
Page("app.py", "FLASHViewer", "🏠"),
Page("pages/FLASHDeconvWorkflow.py", "Workflow", "⚙️"),
Page("pages/FLASHDeconvDownload.py", "Download", "⬇️"),
#Page("pages/FileUpload.py", "File Upload", "📁"),
#Page("pages/SequenceInput.py", "Sequence Input", "🧵"),
#Page("pages/LayoutManager.py", "Layout Manager", "️"),
#Page("pages/FLASHDeconvViewer.py", "Viewer", "👀"),
Page("pages/FileUpload.py", "File Upload", "📁"),
Page("pages/SequenceInput.py", "Sequence Input", "🧵"),
Page("pages/LayoutManager.py", "Layout Manager", "📝️"),
Page("pages/FLASHDeconvViewer.py", "Viewer", "👀"),
])


def flashtagPages():
show_pages([
Page("app.py", "FLASHViewer", "🏠"),
Page("pages/FLASHTaggerWorkflow.py", "Workflow", "⚙️"),
Page("pages/FLASHTaggerViewer.py", "Viewer", "👀"),
])


def flashquantPages():
show_pages([
Page("pages/FLASHViewer.py", "FLASHViewer", "🏠"),
Page("app.py", "FLASHViewer", "🏠"),
Page("pages/FileUpload_FLASHQuant.py", "File Upload", "📁"),
Page("pages/FLASHQuantViewer.py", "Viewer", "👀"),
])
Expand All @@ -66,8 +65,14 @@ def flashquantPages():

def onToolChange():
if 'changed_tool_name' in st.session_state:
st.session_state['tool_index'] = 0 if st.session_state.changed_tool_name == 'FLASHDeconv' else 1

match st.session_state.changed_tool_name:
case 'FLASHDeconv':
st.session_state['tool_index'] = 0
case 'FLASHTagger':
st.session_state['tool_index'] = 1
case 'FLASHQuant':
st.session_state['tool_index'] = 2
st.rerun() # reload the page to sync the change


def main():
Expand All @@ -85,28 +90,28 @@ def main():

st.info("""
**💡 How to run FLASHViewer**
1. Go to the **⚙️ Workflow** page through the sidebar and run your analysis.
1. Go to the **⚙️ Workflow** page through the sidebar and run your analysis.\
OR, go to the **📁 File Upload** page through the sidebar and upload FLASHDeconv output files (\*_annotated.mzML & \*_deconv.mzML)
2. Click the **👀 Viewer** page on the sidebar to view the results in detail.
**\***For FLASHDeconv only download of results is supported.
**\***Download of results is supported.only for FLASHDeconv
""")

# when entered into other page, key is resetting (emptied) - thus set the value with index
# st.selectbox("Choose a tool", ['FLASHTagViewer', 'FLASHDeconv', 'FLASHQuant'], index=st.session_state.tool_index,
st.selectbox("Choose a tool", ['FLASHDeconv', 'FLASHTagger'], index=st.session_state.tool_index,
st.selectbox("Choose a tool", ['FLASHDeconv', 'FLASHTagger', 'FLASHQuant'], index=st.session_state.tool_index,
on_change=onToolChange(), key='changed_tool_name')
page_names_to_funcs[st.session_state.changed_tool_name]()

save_params(params)


# Check if the script is run in local mode (e.g., "streamlit run app.py local")
if "local" in sys.argv:
# In local mode, run the main function without applying captcha
main()

# If not in local mode, assume it's hosted/online mode
else:

show_pages([
Page("app.py", "FLASHViewer", "🏠"),
])
Expand All @@ -118,4 +123,4 @@ def main():

else:
# Run the main function
main()
main()
3,669 changes: 3,669 additions & 0 deletions dist/assets/index-05a624fb.js

Large diffs are not rendered by default.

5 changes: 5 additions & 0 deletions dist/assets/index-912b5bda.css

Large diffs are not rendered by default.

Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file added dist/favicon.ico
Binary file not shown.
15 changes: 15 additions & 0 deletions dist/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" href="./favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>openms-streamlit-vue-component</title>
<script type="module" crossorigin src="./assets/index-05a624fb.js"></script>
<link rel="stylesheet" href="./assets/index-912b5bda.css">
</head>
<body>
<div id="app"></div>

</body>
</html>
2 changes: 1 addition & 1 deletion pages/FLASHDeconvViewer.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ def sendDataToJS(selected_data, layout_info_per_exp, grid_key='flash_viewer_grid
per_scan_contents['3d'] = True
component_arguments = Plotly3Dplot(title="Precursor Signals")
elif comp_name == 'sequence_view':
data_to_send['sequence_data'] = getFragmentDataFromSeq(st.session_state.input_sequence)
data_to_send['sequence_data'] = {0: getFragmentDataFromSeq(st.session_state.input_sequence)}
component_arguments = SequenceView()
elif comp_name == 'internal_fragment_map':
data_to_send['internal_fragment_data'] = getInternalFragmentDataFromSeq(st.session_state.input_sequence)
Expand Down
6 changes: 4 additions & 2 deletions pages/FileUploadTagger.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
from pathlib import Path
import os, shutil
import numpy as np
from src.masstable import parseFLASHDeconvOutput
from src.masstable import parseFLASHDeconvOutput, parseFLASHTaggerOutput
from src.common import page_setup, v_space, save_params, reset_directory


Expand Down Expand Up @@ -135,9 +135,11 @@ def parsingWithProgressBar(infiles_deconv, infiles_anno, infiles_tag, infiles_pr
exp_name = anno_f[0: anno_f.rfind('_')]

with st.spinner('Parsing the experiment %s...'%exp_name):
spec_df, anno_df, tolerance, massoffset, chargemass, tag_df, protein_df = parseFLASHDeconvOutput(
spec_df, anno_df, tolerance, massoffset, chargemass, = parseFLASHDeconvOutput(
Path(st.session_state["workspace"], "anno-mzMLs", anno_f),
Path(st.session_state["workspace"], "deconv-mzMLs", deconv_f),
)
tag_df, protein_df = parseFLASHTaggerOutput(
Path(st.session_state["workspace"], "tags-tsv", tag_f),
Path(st.session_state["workspace"], "proteins-tsv", protein_f)
# Path(st.session_state["workspace"], "db-fasta", db_f)
Expand Down
4 changes: 4 additions & 0 deletions pages/LayoutManager.py
Original file line number Diff line number Diff line change
Expand Up @@ -255,6 +255,10 @@ def setSequenceView():
### TIPs (TODO: Add image)
st.info("""
**💡 Tips**
- If nothing is set, the default layout will be used in the **👀 Viewer** page
- Don't forget to click "save" on the bottom-right corner to save your setting
""")

save_params(params)
4 changes: 2 additions & 2 deletions pages/FLASHViewer.py → pages/TODO_pages/FLASHViewer.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,6 @@

# to convert between FLASHDeconv and FLASHQuant
from st_pages import Page, show_pages
from pathlib import Path



def flashdeconvPages():
Expand All @@ -17,13 +15,15 @@ def flashdeconvPages():
Page("pages/FLASHDeconvViewer.py", "Viewer", "👀"),
])


def flashtagPages():
show_pages([
Page("pages/FLASHViewer.py", "FlashViewer", "🏠"),
Page("pages/5_TOPP-Workflow.py", "Workflow", "⚙️"),
Page("pages/FLASHTagViewer.py", "Viewer", "👀"),
])


def flashquantPages():
show_pages([
Page("pages/FLASHViewer.py", "FLASHViewer", "🏠"),
Expand Down
3 changes: 0 additions & 3 deletions requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,8 @@
# note that it is much more restricted in terms of installing third-parties / etc.
# preferably use the batteries included or simple docker file for local hosting
streamlit==1.29.0
streamlit-plotly-events==0.0.6
streamlit-aggrid==0.3.4.post3
pandas==2.1.2
numpy==1.25.2
plotly==5.18.0
pyopenms==3.1.0
captcha==0.5.0
st_pages==0.4.5
2 changes: 1 addition & 1 deletion src/captcha_.py
Original file line number Diff line number Diff line change
Expand Up @@ -196,7 +196,7 @@ def captcha_control():
# control if the captcha is correct
if "controllo" not in st.session_state or st.session_state["controllo"] is False:
# remove all pages from the sidebar
show_pages([Page("FLASHViewer.py", "FLASHViewer", "🏠")])
show_pages([Page("app.py", "FLASHViewer", "🏠")])

st.title("Make sure you are not a robot🤖")

Expand Down
7 changes: 3 additions & 4 deletions src/components.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,6 @@
_RELEASE = False




def flash_viewer_grid_component(components, data, component_key='flash_viewer_grid'):

if not _RELEASE:
Expand All @@ -21,7 +19,6 @@ def flash_viewer_grid_component(components, data, component_key='flash_viewer_gr
build_dir = os.path.join(parent_dir, '..', "js-component", "dist")
_component_func = st_components.declare_component("flash_viewer_grid", path=build_dir)


out_components = []
for row in components:
out_components.append(list(map(lambda component: {"componentArgs": component.componentArgs.__dict__}, row)))
Expand Down Expand Up @@ -73,14 +70,14 @@ def __init__(self, table_type):
elif table_type == 'TagTable':
self.title = 'Tag Table'
self.componentName = "TabulatorTagTable"



class PlotlyLineplot:
def __init__(self, title):
self.title = title
self.componentName = "PlotlyLineplot"


class PlotlyLineplotTagger:
def __init__(self, title):
self.title = title
Expand All @@ -97,10 +94,12 @@ class SequenceView:
def __init__(self):
self.componentName = 'SequenceView'


class SequenceViewTagger:
def __init__(self):
self.componentName = 'SequenceViewTagger'


class InternalFragmentMap:
def __init__(self):
self.componentName = 'InternalFragmentMap'
Expand Down
31 changes: 12 additions & 19 deletions src/masstable.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,27 +2,15 @@
import pandas as pd
import numpy as np
from pathlib import Path
import pandas as pd
from pyopenms import MSExperiment, MzMLFile, SpectrumLookup, Constants

def parseFLASHDeconvOutput(annotated, deconvolved, tags=None, proteins=None):

if tags is not None:
tag_df = pd.read_csv(tags, sep='\t')

# db = get_sequences(FastaFile.read(db), ProteinSequence)
protein_df = pd.read_csv(proteins, sep='\t')
else:
tag_df = None
protein_df = None


@st.cache_data
def parseFLASHDeconvOutput(annotated, deconvolved):
annotated_exp = MSExperiment()
deconvolved_exp = MSExperiment()
MzMLFile().load(str(Path(annotated)), annotated_exp)
MzMLFile().load(str(Path(deconvolved)), deconvolved_exp)
#MzMLFile().load(annotated, annotated_exp)
#MzMLFile().load(deconvolved, deconvolved_exp)
tolerance = .0
massoffset = .0
chargemass = .0
Expand Down Expand Up @@ -162,7 +150,6 @@ def parseFLASHDeconvOutput(annotated, deconvolved, tags=None, proteins=None):
else:
massPeak.append(round(parsed_peak[0]/massPeak[1]))
npeaks.append(massPeak)


# if len(sigindicesset) != len(speaks):
# print("*")
Expand All @@ -175,25 +162,31 @@ def parseFLASHDeconvOutput(annotated, deconvolved, tags=None, proteins=None):
specnpeaks.append(npeaks)
signalPeaks.append(specspeaks)
noisyPeaks.append(specnpeaks)

msLevels.append(spec.getMSLevel())

df['SignalPeaks'] = signalPeaks
df['NoisyPeaks'] = noisyPeaks
df['CombinedPeaks'] = noisyPeaks
df['MSLevel'] = msLevels
df['Scan'] = scans
return df, annotateddf, tolerance, massoffset, chargemass, tag_df, protein_df

#@st.cache_data
return df, annotateddf, tolerance, massoffset, chargemass


def parseFLASHTaggerOutput(tags, proteins):
# db = get_sequences(FastaFile.read(db), ProteinSequence)
return pd.read_csv(tags, sep='\t'), pd.read_csv(proteins, sep='\t')


@st.cache_data
def getSpectraTableDF(deconv_df: pd.DataFrame):
out_df = deconv_df[['Scan', 'MSLevel', 'RT', 'PrecursorMass']].copy()
out_df['#Masses'] = [len(ele) for ele in deconv_df['MinCharges']]
out_df.reset_index(inplace=True)
return out_df


#@st.cache_data
@st.cache_data
def getMSSignalDF(anno_df: pd.DataFrame):
ints = np.concatenate([anno_df.loc[index, "intarray"] for index in anno_df.index])
mzs = np.concatenate([anno_df.loc[index, "mzarray"] for index in anno_df.index])
Expand Down
9 changes: 6 additions & 3 deletions src/sequence.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,18 +77,21 @@ def setFixedModification(protein):


#@st.cache_data
def getFragmentDataFromSeq(sequence, coverage, maxCoverage):
def getFragmentDataFromSeq(sequence, coverage=None, maxCoverage=None):
protein = AASequence.fromString(sequence)
protein, fixed_mods = setFixedModification(protein) # handling fixed modifications

# calculating proteoform mass from sequence
protein_mass = protein.getMonoWeight()

out_object = {'sequence': list(sequence),
'coverage' : list(coverage),
'maxCoverage' : maxCoverage,
'theoretical_mass': protein_mass,
'fixed_modifications': fixed_mods}
if coverage:
out_object['coverage'] = list(coverage)
if maxCoverage:
out_object['maxCoverage'] = maxCoverage

# per ion type, calculate the possible fragment masses and save them in dictionary
for ion_type in ['ax', 'by', 'cz']:
# calculate fragment ion masses
Expand Down

0 comments on commit 5c86414

Please sign in to comment.