masster 0.5.4__tar.gz → 0.5.5__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of masster might be problematic. Click here for more details.
- {masster-0.5.4 → masster-0.5.5}/PKG-INFO +1 -1
- {masster-0.5.4 → masster-0.5.5}/pyproject.toml +1 -1
- {masster-0.5.4 → masster-0.5.5}/src/masster/sample/save.py +5 -0
- {masster-0.5.4 → masster-0.5.5}/src/masster/study/helpers.py +2 -2
- {masster-0.5.4 → masster-0.5.5}/src/masster/study/plot.py +144 -47
- {masster-0.5.4 → masster-0.5.5}/src/masster/study/processing.py +0 -3
- {masster-0.5.4 → masster-0.5.5}/src/masster/wizard/wizard.py +13 -24
- {masster-0.5.4 → masster-0.5.5}/uv.lock +1 -1
- {masster-0.5.4 → masster-0.5.5}/.github/workflows/publish.yml +0 -0
- {masster-0.5.4 → masster-0.5.5}/.github/workflows/security.yml +0 -0
- {masster-0.5.4 → masster-0.5.5}/.github/workflows/test.yml +0 -0
- {masster-0.5.4 → masster-0.5.5}/.gitignore +0 -0
- {masster-0.5.4 → masster-0.5.5}/.pre-commit-config.yaml +0 -0
- {masster-0.5.4 → masster-0.5.5}/LICENSE +0 -0
- {masster-0.5.4 → masster-0.5.5}/Makefile +0 -0
- {masster-0.5.4 → masster-0.5.5}/README.md +0 -0
- {masster-0.5.4 → masster-0.5.5}/TESTING.md +0 -0
- {masster-0.5.4 → masster-0.5.5}/demo/example_batch_process.py +0 -0
- {masster-0.5.4 → masster-0.5.5}/demo/example_sample_process.py +0 -0
- {masster-0.5.4 → masster-0.5.5}/src/masster/__init__.py +0 -0
- {masster-0.5.4 → masster-0.5.5}/src/masster/_version.py +0 -0
- {masster-0.5.4 → masster-0.5.5}/src/masster/chromatogram.py +0 -0
- {masster-0.5.4 → masster-0.5.5}/src/masster/data/dda/20250530_VH_IQX_KW_RP_HSST3_100mm_12min_pos_v4_DDA_OT_C-MiLUT_QC_dil2_01_20250602151849.sample5 +0 -0
- {masster-0.5.4 → masster-0.5.5}/src/masster/data/dda/20250530_VH_IQX_KW_RP_HSST3_100mm_12min_pos_v4_DDA_OT_C-MiLUT_QC_dil3_01_20250602150634.sample5 +0 -0
- {masster-0.5.4 → masster-0.5.5}/src/masster/data/dda/20250530_VH_IQX_KW_RP_HSST3_100mm_12min_pos_v4_MS1_C-MiLUT_C008_v6_r38_01.sample5 +0 -0
- {masster-0.5.4 → masster-0.5.5}/src/masster/data/dda/20250530_VH_IQX_KW_RP_HSST3_100mm_12min_pos_v4_MS1_C-MiLUT_C008_v7_r37_01.sample5 +0 -0
- {masster-0.5.4 → masster-0.5.5}/src/masster/data/dda/20250530_VH_IQX_KW_RP_HSST3_100mm_12min_pos_v4_MS1_C-MiLUT_C017_v5_r99_01.sample5 +0 -0
- {masster-0.5.4 → masster-0.5.5}/src/masster/data/libs/aa.csv +0 -0
- {masster-0.5.4 → masster-0.5.5}/src/masster/data/libs/ccm.csv +0 -0
- {masster-0.5.4 → masster-0.5.5}/src/masster/data/libs/urine.csv +0 -0
- {masster-0.5.4 → masster-0.5.5}/src/masster/data/wiff/2025_01_14_VW_7600_LpMx_DBS_CID_2min_TOP15_030msecMS1_005msecReac_CE35_DBS-ON_3.timeseries.data +0 -0
- {masster-0.5.4 → masster-0.5.5}/src/masster/data/wiff/2025_01_14_VW_7600_LpMx_DBS_CID_2min_TOP15_030msecMS1_005msecReac_CE35_DBS-ON_3.wiff +0 -0
- {masster-0.5.4 → masster-0.5.5}/src/masster/data/wiff/2025_01_14_VW_7600_LpMx_DBS_CID_2min_TOP15_030msecMS1_005msecReac_CE35_DBS-ON_3.wiff.scan +0 -0
- {masster-0.5.4 → masster-0.5.5}/src/masster/data/wiff/2025_01_14_VW_7600_LpMx_DBS_CID_2min_TOP15_030msecMS1_005msecReac_CE35_DBS-ON_3.wiff2 +0 -0
- {masster-0.5.4 → masster-0.5.5}/src/masster/lib/__init__.py +0 -0
- {masster-0.5.4 → masster-0.5.5}/src/masster/lib/lib.py +0 -0
- {masster-0.5.4 → masster-0.5.5}/src/masster/logger.py +0 -0
- {masster-0.5.4 → masster-0.5.5}/src/masster/sample/__init__.py +0 -0
- {masster-0.5.4 → masster-0.5.5}/src/masster/sample/adducts.py +0 -0
- {masster-0.5.4 → masster-0.5.5}/src/masster/sample/defaults/__init__.py +0 -0
- {masster-0.5.4 → masster-0.5.5}/src/masster/sample/defaults/find_adducts_def.py +0 -0
- {masster-0.5.4 → masster-0.5.5}/src/masster/sample/defaults/find_features_def.py +0 -0
- {masster-0.5.4 → masster-0.5.5}/src/masster/sample/defaults/find_ms2_def.py +0 -0
- {masster-0.5.4 → masster-0.5.5}/src/masster/sample/defaults/get_spectrum_def.py +0 -0
- {masster-0.5.4 → masster-0.5.5}/src/masster/sample/defaults/sample_def.py +0 -0
- {masster-0.5.4 → masster-0.5.5}/src/masster/sample/h5.py +0 -0
- {masster-0.5.4 → masster-0.5.5}/src/masster/sample/helpers.py +0 -0
- {masster-0.5.4 → masster-0.5.5}/src/masster/sample/lib.py +0 -0
- {masster-0.5.4 → masster-0.5.5}/src/masster/sample/load.py +0 -0
- {masster-0.5.4 → masster-0.5.5}/src/masster/sample/parameters.py +0 -0
- {masster-0.5.4 → masster-0.5.5}/src/masster/sample/plot.py +0 -0
- {masster-0.5.4 → masster-0.5.5}/src/masster/sample/processing.py +0 -0
- {masster-0.5.4 → masster-0.5.5}/src/masster/sample/quant.py +0 -0
- {masster-0.5.4 → masster-0.5.5}/src/masster/sample/sample.py +0 -0
- {masster-0.5.4 → masster-0.5.5}/src/masster/sample/sample5_schema.json +0 -0
- {masster-0.5.4 → masster-0.5.5}/src/masster/sample/sciex.py +0 -0
- {masster-0.5.4 → masster-0.5.5}/src/masster/spectrum.py +0 -0
- {masster-0.5.4 → masster-0.5.5}/src/masster/study/__init__.py +0 -0
- {masster-0.5.4 → masster-0.5.5}/src/masster/study/analysis.py +0 -0
- {masster-0.5.4 → masster-0.5.5}/src/masster/study/defaults/__init__.py +0 -0
- {masster-0.5.4 → masster-0.5.5}/src/masster/study/defaults/align_def.py +0 -0
- {masster-0.5.4 → masster-0.5.5}/src/masster/study/defaults/export_def.py +0 -0
- {masster-0.5.4 → masster-0.5.5}/src/masster/study/defaults/fill_def.py +0 -0
- {masster-0.5.4 → masster-0.5.5}/src/masster/study/defaults/find_consensus_def.py +0 -0
- {masster-0.5.4 → masster-0.5.5}/src/masster/study/defaults/find_ms2_def.py +0 -0
- {masster-0.5.4 → masster-0.5.5}/src/masster/study/defaults/identify_def.py +0 -0
- {masster-0.5.4 → masster-0.5.5}/src/masster/study/defaults/integrate_chrom_def.py +0 -0
- {masster-0.5.4 → masster-0.5.5}/src/masster/study/defaults/integrate_def.py +0 -0
- {masster-0.5.4 → masster-0.5.5}/src/masster/study/defaults/merge_def.py +0 -0
- {masster-0.5.4 → masster-0.5.5}/src/masster/study/defaults/study_def.py +0 -0
- {masster-0.5.4 → masster-0.5.5}/src/masster/study/export.py +0 -0
- {masster-0.5.4 → masster-0.5.5}/src/masster/study/h5.py +0 -0
- {masster-0.5.4 → masster-0.5.5}/src/masster/study/id.py +0 -0
- {masster-0.5.4 → masster-0.5.5}/src/masster/study/load.py +0 -0
- {masster-0.5.4 → masster-0.5.5}/src/masster/study/merge.py +0 -0
- {masster-0.5.4 → masster-0.5.5}/src/masster/study/parameters.py +0 -0
- {masster-0.5.4 → masster-0.5.5}/src/masster/study/save.py +0 -0
- {masster-0.5.4 → masster-0.5.5}/src/masster/study/study.py +0 -0
- {masster-0.5.4 → masster-0.5.5}/src/masster/study/study5_schema.json +0 -0
- {masster-0.5.4 → masster-0.5.5}/src/masster/wizard/README.md +0 -0
- {masster-0.5.4 → masster-0.5.5}/src/masster/wizard/__init__.py +0 -0
- {masster-0.5.4 → masster-0.5.5}/src/masster/wizard/example.py +0 -0
- {masster-0.5.4 → masster-0.5.5}/tests/conftest.py +0 -0
- {masster-0.5.4 → masster-0.5.5}/tests/test_chromatogram.py +0 -0
- {masster-0.5.4 → masster-0.5.5}/tests/test_defaults.py +0 -0
- {masster-0.5.4 → masster-0.5.5}/tests/test_imports.py +0 -0
- {masster-0.5.4 → masster-0.5.5}/tests/test_integration.py +0 -0
- {masster-0.5.4 → masster-0.5.5}/tests/test_logger.py +0 -0
- {masster-0.5.4 → masster-0.5.5}/tests/test_parameters.py +0 -0
- {masster-0.5.4 → masster-0.5.5}/tests/test_sample.py +0 -0
- {masster-0.5.4 → masster-0.5.5}/tests/test_spectrum.py +0 -0
- {masster-0.5.4 → masster-0.5.5}/tests/test_study.py +0 -0
- {masster-0.5.4 → masster-0.5.5}/tests/test_version.py +0 -0
- {masster-0.5.4 → masster-0.5.5}/tox.ini +0 -0
|
@@ -411,6 +411,11 @@ def export_mgf(
|
|
|
411
411
|
rt_str = f"{rt:.2f}"
|
|
412
412
|
mz_str = f"{mz:.4f}"
|
|
413
413
|
|
|
414
|
+
# Initialize charge for this feature
|
|
415
|
+
charge = preferred_charge
|
|
416
|
+
if row["charge"] is not None and row["charge"] != 0:
|
|
417
|
+
charge = row["charge"]
|
|
418
|
+
|
|
414
419
|
# Skip features without MS2 data (unless include_all_ms1 is True, but we already handled MS1 above)
|
|
415
420
|
if row["ms2_scans"] is None:
|
|
416
421
|
skip = skip + 1
|
|
@@ -500,7 +500,7 @@ def align_reset(self):
|
|
|
500
500
|
# TODO I don't get this param
|
|
501
501
|
def get_consensus(self, quant="chrom_area"):
|
|
502
502
|
if self.consensus_df is None:
|
|
503
|
-
self.logger.error("No consensus
|
|
503
|
+
self.logger.error("No consensus found.")
|
|
504
504
|
return None
|
|
505
505
|
|
|
506
506
|
# Convert Polars DataFrame to pandas for this operation since the result is used for export
|
|
@@ -613,7 +613,7 @@ def get_gaps_matrix(self, uids=None, samples=None):
|
|
|
613
613
|
import polars as pl
|
|
614
614
|
|
|
615
615
|
if self.consensus_df is None or self.consensus_df.is_empty():
|
|
616
|
-
self.logger.error("No consensus
|
|
616
|
+
self.logger.error("No consensus found.")
|
|
617
617
|
return None
|
|
618
618
|
|
|
619
619
|
if self.consensus_mapping_df is None or self.consensus_mapping_df.is_empty():
|
|
@@ -564,6 +564,10 @@ def plot_consensus_2d(
|
|
|
564
564
|
Parameters:
|
|
565
565
|
filename (str, optional): Path to save the plot
|
|
566
566
|
colorby (str): Column name to use for color mapping (default: "number_samples")
|
|
567
|
+
Automatically detects if column contains categorical (string) or
|
|
568
|
+
numeric data and applies appropriate color mapping:
|
|
569
|
+
- Categorical: Uses factor_cmap with distinct colors and legend
|
|
570
|
+
- Numeric: Uses LinearColorMapper with continuous colorbar
|
|
567
571
|
sizeby (str): Column name to use for size mapping (default: "inty_mean")
|
|
568
572
|
markersize (int): Base marker size (default: 6)
|
|
569
573
|
scaling (str): Controls whether points scale with zoom. Options:
|
|
@@ -645,12 +649,13 @@ def plot_consensus_2d(
|
|
|
645
649
|
from bokeh.models import HoverTool
|
|
646
650
|
from bokeh.models import LinearColorMapper
|
|
647
651
|
from bokeh.io.export import export_png
|
|
652
|
+
from bokeh.transform import factor_cmap
|
|
648
653
|
|
|
649
654
|
try:
|
|
650
655
|
from bokeh.models import ColorBar # type: ignore[attr-defined]
|
|
651
656
|
except ImportError:
|
|
652
657
|
from bokeh.models.annotations import ColorBar
|
|
653
|
-
from bokeh.palettes import viridis
|
|
658
|
+
from bokeh.palettes import viridis, Category20
|
|
654
659
|
|
|
655
660
|
# Import cmap for colormap handling
|
|
656
661
|
from cmap import Colormap
|
|
@@ -695,61 +700,144 @@ def plot_consensus_2d(
|
|
|
695
700
|
self.logger.warning(f"Could not interpret colormap '{cmap}': {e}, falling back to viridis")
|
|
696
701
|
palette = viridis(256)
|
|
697
702
|
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
703
|
+
# Check if colorby column contains categorical data (string/object)
|
|
704
|
+
colorby_values = data[colorby].to_list()
|
|
705
|
+
is_categorical = (
|
|
706
|
+
data_pd[colorby].dtype in ["object", "string", "category"] or
|
|
707
|
+
isinstance(colorby_values[0], str) if colorby_values else False
|
|
702
708
|
)
|
|
709
|
+
|
|
710
|
+
if is_categorical:
|
|
711
|
+
# Handle categorical coloring
|
|
712
|
+
# Use natural order of unique values - don't sort to preserve correct legend mapping
|
|
713
|
+
# Sorting would break the correspondence between legend labels and point colors
|
|
714
|
+
unique_values = [v for v in data_pd[colorby].unique() if v is not None]
|
|
715
|
+
|
|
716
|
+
if len(unique_values) <= 20:
|
|
717
|
+
palette = Category20[min(20, max(3, len(unique_values)))]
|
|
718
|
+
else:
|
|
719
|
+
# For many categories, use a subset of the viridis palette
|
|
720
|
+
palette = viridis(min(256, len(unique_values)))
|
|
721
|
+
|
|
722
|
+
color_mapper = factor_cmap(colorby, palette, unique_values)
|
|
723
|
+
else:
|
|
724
|
+
# Handle numeric coloring with LinearColorMapper
|
|
725
|
+
color_mapper = LinearColorMapper(
|
|
726
|
+
palette=palette,
|
|
727
|
+
low=data[colorby].min(),
|
|
728
|
+
high=data[colorby].max(),
|
|
729
|
+
)
|
|
703
730
|
# scatter plot rt vs mz
|
|
704
731
|
p = bp.figure(
|
|
705
732
|
width=width,
|
|
706
733
|
height=height,
|
|
707
|
-
title="Consensus
|
|
734
|
+
title=f"Consensus features, colored by {colorby}",
|
|
708
735
|
)
|
|
709
|
-
p.xaxis.axis_label = "
|
|
710
|
-
p.yaxis.axis_label = "m/z"
|
|
736
|
+
p.xaxis.axis_label = "RT [s]"
|
|
737
|
+
p.yaxis.axis_label = "m/z [Th]"
|
|
711
738
|
scatter_renderer: Any = None
|
|
712
|
-
if
|
|
713
|
-
#
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
739
|
+
if is_categorical:
|
|
740
|
+
# For categorical data, create separate renderers for each category
|
|
741
|
+
# This enables proper legend interactivity where each category can be toggled independently
|
|
742
|
+
unique_values = [v for v in data_pd[colorby].unique() if v is not None]
|
|
743
|
+
|
|
744
|
+
if len(unique_values) <= 20:
|
|
745
|
+
palette = Category20[min(20, max(3, len(unique_values)))]
|
|
746
|
+
else:
|
|
747
|
+
palette = viridis(min(256, len(unique_values)))
|
|
748
|
+
|
|
749
|
+
# Create a separate renderer for each category
|
|
750
|
+
for i, category in enumerate(unique_values):
|
|
751
|
+
# Filter data for this category
|
|
752
|
+
category_data = data.filter(pl.col(colorby) == category)
|
|
753
|
+
category_data_pd = category_data.to_pandas()
|
|
754
|
+
category_source = bp.ColumnDataSource(category_data_pd)
|
|
755
|
+
|
|
756
|
+
color = palette[i % len(palette)]
|
|
757
|
+
|
|
758
|
+
if scaling.lower() in ["dyn", "dynamic"]:
|
|
759
|
+
# Calculate appropriate radius for dynamic scaling
|
|
760
|
+
rt_range = data["rt"].max() - data["rt"].min()
|
|
761
|
+
mz_range = data["mz"].max() - data["mz"].min()
|
|
762
|
+
dynamic_radius = min(rt_range, mz_range) * 0.0005 * markersize
|
|
763
|
+
|
|
764
|
+
renderer = p.circle(
|
|
765
|
+
x="rt",
|
|
766
|
+
y="mz",
|
|
767
|
+
radius=dynamic_radius,
|
|
768
|
+
fill_color=color,
|
|
769
|
+
line_color=None,
|
|
770
|
+
alpha=alpha,
|
|
771
|
+
source=category_source,
|
|
772
|
+
legend_label=str(category),
|
|
773
|
+
)
|
|
774
|
+
else:
|
|
775
|
+
renderer = p.scatter(
|
|
776
|
+
x="rt",
|
|
777
|
+
y="mz",
|
|
778
|
+
size="markersize",
|
|
779
|
+
fill_color=color,
|
|
780
|
+
line_color=None,
|
|
781
|
+
alpha=alpha,
|
|
782
|
+
source=category_source,
|
|
783
|
+
legend_label=str(category),
|
|
784
|
+
)
|
|
785
|
+
|
|
786
|
+
# No single scatter_renderer for categorical data
|
|
787
|
+
scatter_renderer = None
|
|
718
788
|
|
|
719
|
-
scatter_renderer = p.circle(
|
|
720
|
-
x="rt",
|
|
721
|
-
y="mz",
|
|
722
|
-
radius=dynamic_radius,
|
|
723
|
-
fill_color={"field": colorby, "transform": color_mapper},
|
|
724
|
-
line_color=None,
|
|
725
|
-
alpha=alpha,
|
|
726
|
-
source=source,
|
|
727
|
-
)
|
|
728
789
|
else:
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
790
|
+
# Handle numeric coloring - single renderer with color mapping
|
|
791
|
+
if scaling.lower() in ["dyn", "dynamic"]:
|
|
792
|
+
# Calculate appropriate radius for dynamic scaling
|
|
793
|
+
rt_range = data["rt"].max() - data["rt"].min()
|
|
794
|
+
mz_range = data["mz"].max() - data["mz"].min()
|
|
795
|
+
dynamic_radius = min(rt_range, mz_range) * 0.0005 * markersize
|
|
796
|
+
|
|
797
|
+
scatter_renderer = p.circle(
|
|
798
|
+
x="rt",
|
|
799
|
+
y="mz",
|
|
800
|
+
radius=dynamic_radius,
|
|
801
|
+
fill_color={"field": colorby, "transform": color_mapper},
|
|
802
|
+
line_color=None,
|
|
803
|
+
alpha=alpha,
|
|
804
|
+
source=source,
|
|
805
|
+
)
|
|
806
|
+
else:
|
|
807
|
+
scatter_renderer = p.scatter(
|
|
808
|
+
x="rt",
|
|
809
|
+
y="mz",
|
|
810
|
+
size="markersize",
|
|
811
|
+
fill_color={"field": colorby, "transform": color_mapper},
|
|
812
|
+
line_color=None,
|
|
813
|
+
alpha=alpha,
|
|
814
|
+
source=source,
|
|
815
|
+
)
|
|
738
816
|
# add hover tool
|
|
739
|
-
# Start with base tooltips
|
|
817
|
+
# Start with base tooltips - rt and mz moved to top, removed consensus_id and iso_mean
|
|
740
818
|
tooltips = [
|
|
819
|
+
("rt", "@rt"),
|
|
820
|
+
("mz", "@mz"),
|
|
741
821
|
("consensus_uid", "@consensus_uid"),
|
|
742
|
-
("consensus_id", "@consensus_id"),
|
|
743
822
|
("number_samples", "@number_samples"),
|
|
744
823
|
("number_ms2", "@number_ms2"),
|
|
745
|
-
("rt", "@rt"),
|
|
746
|
-
("mz", "@mz"),
|
|
747
824
|
("inty_mean", "@inty_mean"),
|
|
748
|
-
("iso_mean", "@iso_mean"),
|
|
749
825
|
("coherence_mean", "@chrom_coherence_mean"),
|
|
750
826
|
("prominence_scaled_mean", "@chrom_prominence_scaled_mean"),
|
|
751
827
|
]
|
|
752
828
|
|
|
829
|
+
# Add adduct_top if it exists in data
|
|
830
|
+
if "adduct_top" in data.columns:
|
|
831
|
+
tooltips.append(("adduct_top", "@adduct_top"))
|
|
832
|
+
|
|
833
|
+
# Add id_top_name if it exists in data
|
|
834
|
+
if "id_top_name" in data.columns:
|
|
835
|
+
tooltips.append(("id_top_name", "@id_top_name"))
|
|
836
|
+
|
|
837
|
+
# Add id_top_adduct if it exists in data
|
|
838
|
+
if "id_top_adduct" in data.columns:
|
|
839
|
+
tooltips.append(("id_top_adduct", "@id_top_adduct"))
|
|
840
|
+
|
|
753
841
|
# Add id_top_* columns if they exist and have non-null values
|
|
754
842
|
id_top_columns = ["id_top_name", "id_top_class", "id_top_adduct", "id_top_score"]
|
|
755
843
|
for col in id_top_columns:
|
|
@@ -764,19 +852,28 @@ def plot_consensus_2d(
|
|
|
764
852
|
|
|
765
853
|
hover = HoverTool(
|
|
766
854
|
tooltips=tooltips,
|
|
767
|
-
renderers=[scatter_renderer],
|
|
768
855
|
)
|
|
856
|
+
# For categorical data, hover will work on all renderers automatically
|
|
857
|
+
# For numeric data, specify the single renderer
|
|
858
|
+
if not is_categorical and scatter_renderer:
|
|
859
|
+
hover.renderers = [scatter_renderer]
|
|
860
|
+
|
|
769
861
|
p.add_tools(hover)
|
|
770
862
|
|
|
771
|
-
# add colorbar
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
863
|
+
# add colorbar only for numeric data (LinearColorMapper)
|
|
864
|
+
if not is_categorical:
|
|
865
|
+
color_bar = ColorBar(
|
|
866
|
+
color_mapper=color_mapper,
|
|
867
|
+
label_standoff=12,
|
|
868
|
+
location=(0, 0),
|
|
869
|
+
title=colorby,
|
|
870
|
+
ticker=BasicTicker(desired_num_ticks=8),
|
|
871
|
+
)
|
|
872
|
+
p.add_layout(color_bar, "right")
|
|
873
|
+
else:
|
|
874
|
+
# For categorical data, configure the legend that was automatically created
|
|
875
|
+
p.legend.location = "top_right"
|
|
876
|
+
p.legend.click_policy = "hide"
|
|
780
877
|
|
|
781
878
|
if filename is not None:
|
|
782
879
|
# Convert relative paths to absolute paths using study folder as base
|
|
@@ -341,9 +341,6 @@ def _integrate_chrom_impl(self, **kwargs):
|
|
|
341
341
|
uids = params.get("uids")
|
|
342
342
|
rt_tol = params.get("rt_tol")
|
|
343
343
|
|
|
344
|
-
if self.consensus_map is None:
|
|
345
|
-
self.logger.error("No consensus map found.")
|
|
346
|
-
return
|
|
347
344
|
if uids is None:
|
|
348
345
|
# get all consensus_id from consensus_df
|
|
349
346
|
ids = self.consensus_df["consensus_uid"].to_list()
|
|
@@ -455,6 +455,9 @@ class Wizard:
|
|
|
455
455
|
params_lines.append(' # === Processing Parameters ===')
|
|
456
456
|
params_lines.append(f' "adducts": {params_dict.get("adducts", [])!r}, # Adduct specifications for feature detection and annotation')
|
|
457
457
|
params_lines.append(f' "detector_type": {params_dict.get("detector_type", "unknown")!r}, # MS detector type ("orbitrap", "tof", "unknown")')
|
|
458
|
+
params_lines.append(f' "noise": {params_dict.get("noise", 50.0)}, # Noise threshold for feature detection')
|
|
459
|
+
params_lines.append(f' "chrom_fwhm": {params_dict.get("chrom_fwhm", 0.5)}, # Chromatographic peak full width at half maximum (seconds)')
|
|
460
|
+
params_lines.append(f' "chrom_peak_snr": {params_dict.get("chrom_peak_snr", 5.0)}, # Minimum signal-to-noise ratio for chromatographic peaks')
|
|
458
461
|
params_lines.append('')
|
|
459
462
|
|
|
460
463
|
# Alignment & Merging
|
|
@@ -643,6 +646,7 @@ class Wizard:
|
|
|
643
646
|
' # Step 4: Add sample5 files to study',
|
|
644
647
|
' print("\\nStep 4/7: Adding samples to study...")',
|
|
645
648
|
' study.add(str(Path(PARAMS[\'folder\']) / "*.sample5"))',
|
|
649
|
+
' study.features_filter(study.features_select(chrom_coherence=0.1, chrom_prominence_scaled=1))',
|
|
646
650
|
' ',
|
|
647
651
|
' # Step 5: Core processing',
|
|
648
652
|
' print("\\nStep 5/7: Processing...")',
|
|
@@ -651,29 +655,14 @@ class Wizard:
|
|
|
651
655
|
' rt_tol=PARAMS[\'rt_tol\']',
|
|
652
656
|
' )',
|
|
653
657
|
' ',
|
|
654
|
-
'
|
|
655
|
-
'
|
|
656
|
-
'
|
|
657
|
-
'
|
|
658
|
-
'
|
|
659
|
-
'
|
|
660
|
-
' method="qt_chunked",',
|
|
661
|
-
' dechunking="hierarchical",',
|
|
662
|
-
' min_samples=PARAMS[\'min_samples_per_feature\'],',
|
|
663
|
-
' threads=PARAMS[\'num_cores\'],',
|
|
664
|
-
' rt_tol=PARAMS[\'rt_tol\'],',
|
|
665
|
-
' mz_tol=PARAMS[\'mz_tol\']',
|
|
666
|
-
' )',
|
|
667
|
-
' else:',
|
|
668
|
-
' print(f" Using standard merge method for {num_samples} samples")',
|
|
669
|
-
' study.merge(',
|
|
670
|
-
' min_samples=PARAMS[\'min_samples_per_feature\'],',
|
|
671
|
-
' threads=PARAMS[\'num_cores\'],',
|
|
672
|
-
' rt_tol=PARAMS[\'rt_tol\'],',
|
|
673
|
-
' mz_tol=PARAMS[\'mz_tol\']',
|
|
674
|
-
' )',
|
|
658
|
+
' study.merge(',
|
|
659
|
+
' method="qt",',
|
|
660
|
+
' min_samples=PARAMS[\'min_samples_per_feature\'],',
|
|
661
|
+
' threads=PARAMS[\'num_cores\'],',
|
|
662
|
+
' rt_tol=PARAMS[\'rt_tol\'],'
|
|
663
|
+
' )',
|
|
675
664
|
' study.find_iso()',
|
|
676
|
-
' study.fill(
|
|
665
|
+
' study.fill()',
|
|
677
666
|
' study.integrate()',
|
|
678
667
|
' ',
|
|
679
668
|
' # Step 6/7: Saving results',
|
|
@@ -689,8 +678,8 @@ class Wizard:
|
|
|
689
678
|
' study.plot_consensus_2d(filename="consensus.png")',
|
|
690
679
|
' study.plot_alignment(filename="alignment.html")',
|
|
691
680
|
' study.plot_alignment(filename="alignment.png")',
|
|
692
|
-
' study.
|
|
693
|
-
' study.
|
|
681
|
+
' study.plot_samples_pca(filename="pca.html")',
|
|
682
|
+
' study.plot_samples_pca(filename="pca.png")',
|
|
694
683
|
' study.plot_bpc(filename="bpc.html")',
|
|
695
684
|
' study.plot_bpc(filename="bpc.png")',
|
|
696
685
|
' study.plot_rt_correction(filename="rt_correction.html")',
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|