diff --git a/assets/default-params.json b/assets/default-params.json index 463a035..2fd55ff 100644 --- a/assets/default-params.json +++ b/assets/default-params.json @@ -40,7 +40,7 @@ "annotate_ms1": false, "annotate_ms2": false, "use_requant": true, - "annotate_gnps_library": true, + "annotate_gnps_library": false, "annoation_rt_window_sec": 60, "annotation_mz_window_ppm": 10, "ms1_annotation_file": "", diff --git "a/pages/0_\360\237\223\201_File_Upload.py" "b/pages/0_\360\237\223\201_File_Upload.py" index f36be66..1788fde 100644 --- "a/pages/0_\360\237\223\201_File_Upload.py" +++ "b/pages/0_\360\237\223\201_File_Upload.py" @@ -43,6 +43,7 @@ if cols[1].button("Copy files to workspace", type="primary", disabled=(local_mzML_dir == "")): copy_local_mzML_files_from_directory(local_mzML_dir) +mzML_dir = Path(st.session_state.workspace, "mzML-files") if any(Path(mzML_dir).iterdir()): v_space(2) # Display all mzML files currently in workspace diff --git "a/pages/2_\360\237\224\215_Extracted_Ion_Chromatograms.py" "b/pages/2_\360\237\224\215_Extracted_Ion_Chromatograms.py" index 4c5ffdb..675d959 100644 --- "a/pages/2_\360\237\224\215_Extracted_Ion_Chromatograms.py" +++ "b/pages/2_\360\237\224\215_Extracted_Ion_Chromatograms.py" @@ -43,7 +43,6 @@ "XIC-input-table.tsv", ) - st.markdown("**Calculate mass and add to table**") c1, c2, c3 = st.columns(3) name = c1.text_input( "compound name (optional)", "") @@ -72,11 +71,10 @@ st.warning("Invalid formula.") with st.form("eic_form"): - st.multiselect("mzML files", [f.stem for f in Path(st.session_state.workspace, "mzML-files").glob("*.mzML")], + st.markdown("**Parameters**") + st.multiselect("**input mzML files**", [f.stem for f in Path(st.session_state.workspace, "mzML-files").glob("*.mzML")], params["eic_selected_mzML"], key="eic_selected_mzML") - # Retention time settings - st.markdown("**Parameters for chromatogram extraction**") c1, c2, c3 = st.columns(3) c1.radio( "time unit for display", ["seconds", "minutes"], index=["seconds", "minutes"].index(params["eic_time_unit"]), key="eic_time_unit", help="Retention time unit for figures and downloadable tables. Rentention time settings have to be specified in seconds." @@ -101,8 +99,10 @@ results_dir = Path(st.session_state.workspace, "extracted-ion-chromatograms") - _, c2, _ = st.columns(3) - submitted = c2.form_submit_button("Extract chromatograms", type="primary") + c1, _, c3 = st.columns(3) + if c1.form_submit_button("Save Parameters"): + save_params(params) + submitted = c3.form_submit_button("Extract chromatograms", type="primary") if submitted: mzML_files = [str(Path(st.session_state.workspace, diff --git "a/pages/3_\360\237\247\252_Untargeted_Metabolomics.py" "b/pages/3_\360\237\247\252_Untargeted_Metabolomics.py" index be0f58d..e68f065 100644 --- "a/pages/3_\360\237\247\252_Untargeted_Metabolomics.py" +++ "b/pages/3_\360\237\247\252_Untargeted_Metabolomics.py" @@ -13,7 +13,7 @@ st.markdown(HELP) with st.form("umetaflow-form"): - st.multiselect("mzML files", [f.stem for f in Path(st.session_state.workspace, "mzML-files").glob("*.mzML")], + st.multiselect("**sample mzML files**", [f.stem for f in Path(st.session_state.workspace, "mzML-files").glob("*.mzML")], params["umetaflow_selected_mzML"], key="umetaflow_selected_mzML") st.markdown("#### 1. Pre-Processing") st.markdown("**Feature Detection**") @@ -56,7 +56,7 @@ c1, c2 = st.columns(2) c1.multiselect( "select blank samples", - st.session_state["umetaflow_selected_mzML"], + [f.stem for f in Path(st.session_state.workspace, "mzML-files").glob("*.mzML")], key="blank_files", help="The selected samples will be used to calculate avarage feature blank intensities and will not be further processed.", ) @@ -224,11 +224,7 @@ with open(path, "wb") as f: f.write(ms1_annotation_file_upload.getbuffer()) params["ms1_annotation_file"] = str(path) - elif params["ms1_annotation_file"]: - c2.info( - f"Currently selected MS1 library: {Path(params['ms1_annotation_file']).name}") else: - c2.warning("No MS1 library selected.") params["ms1_annotation_file"] = "" c1, c2 = st.columns(2) c1.number_input( @@ -259,31 +255,33 @@ with open(path, "wb") as f: f.write(ms2_annotation_file_upload.getbuffer()) params["ms2_annotation_file"] = str(path) - elif params["ms2_annotation_file"]: - c2.info( - f"Currently selected MS2 library: {Path(params['ms2_annotation_file']).name}") else: - c2.warning("No MS2 library selected.") params["ms2_annotation_file"] = "" v_space(1) - _, c2, _ = st.columns(3) - run_button = c2.form_submit_button("Run UmetaFlow", type="primary") + c1, _, c3 = st.columns(3) + if c1.form_submit_button("Save Parameters"): + params = save_params(params) + run_button = c3.form_submit_button("Run UmetaFlow", type="primary") results_dir = Path(st.session_state.workspace, "umetaflow-results") if run_button: save_params(params) - umetaflow_params = load_params() + params = load_params() # Modify paramters to have float values if necessary for key in ("fl_rt_tol", "ad_rt_max_diff", "ma_rt_max", "ffm_noise"): - umetaflow_params[key] = float(umetaflow_params[key]) - mzML_files = [str(Path(st.session_state.workspace, - "mzML-files", f+".mzML")) for f in st.session_state["umetaflow_selected_mzML"]] - if mzML_files: + params[key] = float(params[key]) + + # add blank files to samples which have not been selected as samples + mzML_files = params["umetaflow_selected_mzML"] + mzML_files += [f for f in params["blank_files"] if f not in params["umetaflow_selected_mzML"]] + mzML_files = [str(Path(st.session_state.workspace, "mzML-files", f+".mzML")) for f in mzML_files] + + if len(mzML_files) > len(params["blank_files"]): reset_directory(results_dir) - run_umetaflow(umetaflow_params, mzML_files, results_dir) + run_umetaflow(params, mzML_files, results_dir) else: - st.warning("No mzML files selected!") + st.warning("Check your mzML and blank file selection.") if results_dir.exists(): v_space(1) @@ -432,6 +430,4 @@ "Meta Data", md.T.to_csv(sep="\t", index=False), "MetaData.tsv", - ) - -save_params(params) \ No newline at end of file + ) \ No newline at end of file diff --git a/src/common.py b/src/common.py index f9b9e59..38564ad 100644 --- a/src/common.py +++ b/src/common.py @@ -112,25 +112,12 @@ def page_setup(page: str = "") -> dict[str, Any]: if "windows" in sys.argv: os.chdir("../umetaflow-gui-main") # Define the directory where all workspaces will be stored + workspaces_dir = Path("..", "workspaces-"+REPOSITORY_NAME) if st.session_state.location == "online": - workspaces_dir = Path("workspaces-"+REPOSITORY_NAME) - # Outside of the repository directory for local and docker - # If running in a Docker container, set working directory to the repository directory - if "docker" in sys.argv: - workspaces_dir = Path("..", "workspaces-"+REPOSITORY_NAME) - os.chdir(REPOSITORY_NAME) + st.session_state.workspace = Path(workspaces_dir, str(uuid.uuid1())) else: - workspaces_dir = Path("..", "workspaces-"+REPOSITORY_NAME) - - # If running locally, use the default workspace - if "local" in sys.argv: st.session_state.workspace = Path(workspaces_dir, "default") - # If running online, create a new workspace with a random UUID - else: - st.session_state.workspace = Path( - workspaces_dir, str(uuid.uuid1())) - # Make sure the necessary directories exist st.session_state.workspace.mkdir(parents=True, exist_ok=True) Path(st.session_state.workspace, @@ -140,11 +127,6 @@ def page_setup(page: str = "") -> dict[str, Any]: params = render_sidebar(page) return params - - # Return the loaded parameters - # return params - - def render_sidebar(page: str = "") -> None: """ Renders the sidebar on the Streamlit app, which includes the workspace switcher, diff --git a/src/fileupload.py b/src/fileupload.py index 4f7f585..07c334c 100644 --- a/src/fileupload.py +++ b/src/fileupload.py @@ -7,7 +7,7 @@ # Specify mzML file location in workspace -mzML_dir: Path = Path(st.session_state.workspace, "mzML-files") +mzML_dir = Path(st.session_state.workspace, "mzML-files") @st.cache_data def save_uploaded_mzML(uploaded_files: list[bytes]) -> None: diff --git a/src/umetaflow.py b/src/umetaflow.py index 48b689e..970c046 100644 --- a/src/umetaflow.py +++ b/src/umetaflow.py @@ -272,16 +272,17 @@ def additional_data_for_consensus_df(self): def run_umetaflow(params, mzML_files, results_dir): - umetaflow = UmetaFlow(params, mzML_files, results_dir) + with st.status("Running UmetaFlow", expanded=True) as status: + umetaflow = UmetaFlow(params, mzML_files, results_dir) - with st.spinner("Fetching raw data..."): + st.write("Fetching input mzML files...") umetaflow.fetch_raw_data() - with st.spinner("Detecting features..."): + st.write("Detecting features...") umetaflow.feature_detection() - if params["remove_blanks"] and len(params["blank_files"]) > 0: - with st.spinner("Removing blank features..."): + if params["remove_blanks"] and len(params["blank_files"]) > 0: + st.write("Removing blank features...") umetaflow.remove_blanks() if not any(umetaflow.featureXML_dir.iterdir()): st.warning( @@ -289,90 +290,88 @@ def run_umetaflow(params, mzML_files, results_dir): ) return - if params["use_ad"] and not params["use_requant"]: - with st.spinner("Determining adducts..."): + if params["use_ad"] and not params["use_requant"]: + st.write("Determining adducts...") umetaflow.adduct_detection() - # annotate only when necessary - if ( - params["use_sirius_manual"] or params["annotate_ms2"] or params["use_gnps"] - ) and not params["use_requant"]: - umetaflow.feature_maps_to_df() - with st.spinner("Mapping MS2 data to features..."): + # annotate only when necessary + if ( + params["use_sirius_manual"] or params["annotate_ms2"] or params["use_gnps"] + ) and not params["use_requant"]: + umetaflow.feature_maps_to_df() + st.write("Mapping MS2 data to features...") umetaflow.map_MS2() - if params["use_ma"] and len(list(umetaflow.featureXML_dir.iterdir())) > 1: - with st.spinner("Aligning feature maps..."): + if params["use_ma"] and len(list(umetaflow.featureXML_dir.iterdir())) > 1: + st.write("Aligning feature maps...") umetaflow.align_feature_maps() umetaflow.feature_maps_to_df() - with st.spinner("Aligning mzML files..."): + st.write("Aligning mzML files...") umetaflow.align_peak_maps() umetaflow.peak_maps_to_df() - else: - umetaflow.feature_maps_to_df() - umetaflow.peak_maps_to_df() + else: + umetaflow.feature_maps_to_df() + umetaflow.peak_maps_to_df() - # export only sirius ms files to use in the GUI tool - if params["use_sirius_manual"] and not params["use_requant"]: - with st.spinner("Exporting files for Sirius..."): + # export only sirius ms files to use in the GUI tool + if params["use_sirius_manual"] and not params["use_requant"]: + st.write("Exporting files for Sirius...") umetaflow.sirius() - with st.spinner("Linking features..."): + st.write("Linking features...") umetaflow.link_feature_maps() umetaflow.consensus_df() - if params["use_requant"]: - # for requant run FFMID and Feature Linking and optionally Adduct Decharging and Mapping MS2 data - with st.spinner("Re-quantification..."): + if params["use_requant"]: + # for requant run FFMID and Feature Linking and optionally Adduct Decharging and Mapping MS2 data + st.write("Re-quantification...") umetaflow.requantify() - with st.spinner("Exporting re-quantified feature maps for visualization..."): + st.write("Exporting re-quantified feature maps for visualization...") umetaflow.feature_maps_to_df(requant=True) - # annotate only when necessary - if params["use_sirius_manual"] or params["annotate_ms2"] or params["use_gnps"]: - with st.spinner("Mapping MS2 data to features..."): + # annotate only when necessary + if params["use_sirius_manual"] or params["annotate_ms2"] or params["use_gnps"]: + st.write("Mapping MS2 data to features...") umetaflow.map_MS2() - if params["use_ad"]: - with st.spinner("Determining adducts..."): + if params["use_ad"]: + st.write("Determining adducts...") umetaflow.adduct_detection() - if params["use_sirius_manual"]: - with st.spinner("Exporting files for Sirius..."): + if params["use_sirius_manual"]: + st.write("Exporting files for Sirius...") umetaflow.sirius() - with st.spinner("Linking re-quantified features..."): + st.write("Linking re-quantified features...") umetaflow.link_feature_maps() umetaflow.consensus_df() - # export metadata - umetaflow.export_metadata() + # export metadata + umetaflow.export_metadata() - if params["use_gnps"] or params["annotate_ms2"]: - with st.spinner("Exporting files for GNPS..."): + if params["use_gnps"] or params["annotate_ms2"]: + st.write("Exporting files for GNPS...") umetaflow.gnps() - if params["annotate_ms1"]: - with st.spinner("Annotating features on MS1 level by m/z and RT"): + if params["annotate_ms1"]: + st.write("Annotating features on MS1 level by m/z and RT") umetaflow.annotate_MS1() - if ( - params["annotate_ms2"] and params["ad_ion_mode"] == "positive" - ): # fails with negative mode right now due to wrong charge annotation - with st.spinner( - "Annotating features on MS2 level by fragmentation patterns..." - ): + if ( + params["annotate_ms2"] and params["ad_ion_mode"] == "positive" + ): # fails with negative mode right now due to wrong charge annotation + st.write("Annotating features on MS2 level by fragmentation patterns...") umetaflow.annotate_MS2() - umetaflow.additional_data_for_consensus_df() + umetaflow.additional_data_for_consensus_df() - # Export files - umetaflow.make_zip_archives() + # Export files + umetaflow.make_zip_archives() - st.success("Complete!") + status.update(label="UmetaFlow run complete!", state="complete", expanded=False) METABO = { diff --git a/src/xic.py b/src/xic.py index 807dba1..516b022 100644 --- a/src/xic.py +++ b/src/xic.py @@ -236,7 +236,7 @@ def extract_chromatograms(results_dir, mzML_files, df_input, mz_unit, mz_ppm, mz with open(Path(results_dir, "run-params.txt"), "w") as f: f.write(f"{baseline}\n{time_unit}") # # Re-run to prevent tab jumping back to first tab upon first widget change (streamlit bug) - # st.experimental_rerun() + st.experimental_rerun() @st.cache_resource