diff --git a/alpharaw/viz/plot_utils.py b/alpharaw/viz/plot_utils.py index 5b6b8bf..d6282aa 100644 --- a/alpharaw/viz/plot_utils.py +++ b/alpharaw/viz/plot_utils.py @@ -7,14 +7,39 @@ def plot_scatter( - x_values, - y_values, - color, - marker_size, - hovertext, - hovertemplate, - name="", -): + x_values: np.ndarray, + y_values: np.ndarray, + color: str, + marker_size: int, + hovertext: str, + hovertemplate: str, + name: str = "", +) -> go.Scatter: + """ + plotly scatter based on x and y points. + + Parameters + ---------- + x_values : np.ndarray + x values for :class:`go.Scatter` + y_values : np.ndarray + y values for :class:`go.Scatter` + color : str + color name + marker_size : int + marker size of the point (x,y) + hovertext : str + `hovertext` parameter of :class:`go.Scatter` + hovertemplate : str + `hovertemplate` parameter of :class:`go.Scatter` + name : str, optional + `name` parameter of :class:`go.Scatter`, by default '' + + Returns + ------- + go.Scatter + go.Scatter of plotly + """ return go.Scatter( x=x_values, y=y_values, @@ -43,7 +68,34 @@ def plot_line_tims( view_dim: typing.Literal["rt", "im"] = "rt", # or 'im' intensity_scale: float = 1.0, rt_unit: str = "minute", -): +) -> go.Figure: + """ + Plot an XIC line on alphatims `TimsTOF` data + + Parameters + ---------- + tims_data : TimsTOF + The alphatims `TimsTOF` object + tims_raw_indices : np.ndarray + Raw indices on `TimsTOF` object + tims_view_indices : np.array + View indices on `TimsTOF` object + name : str + Display name + legend_group : str + Lines will be grouped by `legend_group` + marker_color : str + Color of the scatter (x, y) + view_dim : "rt", "im", optional + View dimension, "rt" or "im", by default "rt" + rt_unit : str, optional + RT unit, by default "minute" + + Returns + ------- + go.Figure + Line plot + """ x_dimension = alphatims_labels[view_dim] intensities = tims_data.bin_intensities(tims_raw_indices, [x_dimension]) @@ -73,11 +125,42 @@ def plot_line_tims_fast( name: str, legend_group: str, marker_color: str, - view_dim: typing.Literal["rt", "im"] = "rt", # or 'im' + view_dim: typing.Literal["rt", "im"] = "rt", intensity_scale: float = 1.0, rt_unit: str = "minute", add_peak_area=True, -): +) -> go.Figure: + """ + Plot an XIC line on alphatims `TimsTOF` data + + Parameters + ---------- + tims_data : TimsTOF + The alphatims `TimsTOF` object + tims_raw_indices : np.ndarray + Raw indices on `TimsTOF` object + tims_view_indices : np.array + View indices on `TimsTOF` object + name : str + Display name + legend_group : str + Lines will be grouped by `legend_group` + marker_color : str + Color of the scatter (x, y) + view_dim : "rt", "im", optional + View dimension, "rt" or "im", by default "rt" + intensity_scale : float, optional + Intensity scale of mirror plot, by default 1.0 + rt_unit : str, optional + RT unit, by default "minute" + add_peak_area : bool, optional + If add peak area in the hover text, by default True + + Returns + ------- + go.Figure + _description_ + """ x_dimension = alphatims_labels[view_dim] intensities = tims_data.bin_intensities(tims_raw_indices, [x_dimension]) @@ -113,7 +196,35 @@ def plot_line( x_text: str = "RT", other_info: str = "", hovertemplate: str = "%{text}
Intensity: %{y}", -): +) -> go.Scatter: + """ + Plot a line for given x and y points, this is usually for XIC plots. + + Parameters + ---------- + x_values : np.ndarray + x values for :class:`go.Scatter` + y_values : np.ndarray + y values for :class:`go.Scatter` + name : str + Legend name for the plotted line + marker_color : str + Marker color of the point (x,y) + legend_group : str + Different lines can be grouped by the same `legend_group` + x_text : str, optional + Hover text of the x axis, by default "RT" + other_info: str, optional + Other hover information, by default "" + hovertemplate : str, optional + `hovertemplate` parameter of :class:`go.Scatter`, + by default '%{text}
Intensity: %{y}' + + Returns + ------- + go.Scatter + The plotted line + """ return go.Scatter( x=x_values, y=y_values, @@ -136,7 +247,10 @@ def plot_line_df( legend_group: str, marker_color: str, view_dim: str = "rt", # or 'im' -): +) -> go.Figure: + """ + TODO deprecated + """ if view_dim == "rt": tims_sliced_df = tims_sliced_df.groupby("frame_indices", as_index=False).agg( { diff --git a/alpharaw/viz/psm_plot.py b/alpharaw/viz/psm_plot.py index f4b55a3..2bb5820 100644 --- a/alpharaw/viz/psm_plot.py +++ b/alpharaw/viz/psm_plot.py @@ -13,6 +13,24 @@ from .plot_utils import plot_scatter color_map: dict = defaultdict(lambda: "brown") +""" +The colors of different peak annotations. By default: +``` +{ + '-': 'lightgrey', # umnatched peaks + 'a': 'darkskyblue', + 'b': 'blue', + 'c': 'skyblue', + 'x': 'darkred', + 'y': 'red', + 'z': 'deeppink', + 'M': 'purple', # precursor + 'Y': 'orange', + 'B': 'darkgreen', +} +``` +For other annotations, the default color is "brown". +""" color_map.update( { "-": "lightgrey", # umnatched peaks @@ -50,6 +68,55 @@ def plot_multi_psms( query_left_margin: float = 100000.0, query_right_margin: float = 100000.0, ): + """ + Annotate multiple spectra for a peptide in a single plotly go.Figure. + + Parameters + ---------- + spec_masses_list : typing.List[np.ndarray] + The list of peak masses of multiple spectra to be annotated + spec_intens_list : typing.List[np.ndarray] + The list of peak intensities of multiple spectra to be annotated + sequence : str + Peptide sequence + mods : str + Modifications in alphabase format + mod_sites : str + Modification sites in alphabase format + charge : int + Charge state of the precursor + title : str, optional + Plotting title, by default "" + ppm : float, optional + Matching mass tolerance in ppm, by default 20.0 + charged_frag_types : list, optional + Fragment charge states, by default ["b_z1","b_z2","y_z1","y_z2"] + include_fragments : bool, optional + If annotate fragments, by default True + include_precursor_isotopes : bool, optional + If annotate precursor isotopes, by default False + max_isotope : int, optional + Maximal number of isotopes, by default 6 + min_frag_mz : float, optional + Minimal fragment m/z value to annotate, by default 100.0 + plot_unmatched_peaks : bool, optional + If plot unmatched peaks (ion_name='-'), by default True + match_mode : "closest", "highest", optional + Match the closest or highest peak within the matching tolerance, by default "closest" + plot_template : str, optional + Plot template, by default 'plotly_white' + plot_height : int, optional + Plot height, by default 600 + query_left_margin : float, optional + Slice margin to the left mz, by default 100000.0 + query_right_margin : float, optional + Slice martin to the right mz, by default 100000.0 + + Returns + ------- + go.Figure + The annotation plots of multiple spectra + """ plot_df = make_query_df_for_peptide( sequence, mods, @@ -97,6 +164,37 @@ def plot_multi_spectra( plot_template="plotly_white", plot_height=600, ): + """ + Annotate multiple spectra for given queries in a single plotly go.Figure. + + Parameters + ---------- + spec_masses_list : typing.List[np.ndarray] + The list of peak masses of multiple spectra to be annotated + spec_intens_list : typing.List[np.ndarray] + The list of peak intensities of multiple spectra to be annotated + query_masses : np.ndarray + The query m/z values + query_ion_names : typing.List[str] + The query ion names + query_mass_tols : np.ndarray + The query mass tolerance in Da + title : str, optional + The plot title, by default "" + plot_unmatched_peaks : bool, optional + If plot unmatched peaks (ion_name='-'), by default True + match_mode : "closest", "highest", optional + Match the closest or highest peak within the matching tolerance, by default "closest" + plot_template : str, optional + Plot template, by default 'plotly_white' + plot_height : int, optional + Plot height, by default 600 + + Returns + ------- + go.Figure + The annotation plots of multiple spectra + """ plot_dfs = [] for spec_masses, spec_intens in zip(spec_masses_list, spec_intens_list): plot_dfs.append( @@ -138,17 +236,36 @@ def plot_multi_spectra( class PSM_Plot: + """ + The main class for spectrum annotation of a PSM. It contains three plots: + 1. Ladder plot (`FragCoveragePlot`) for fragment coverage of the peptide. + 2. Peak annotation plot (`PeakPlot`) for the spectrum. + 3. Matching mass error plot (`MassErrPlot`) for the matched peaks. + """ + vertical_spacing = 0.05 template = "plotly_white" plot_height = 600 def __init__( self, - peak_plot_rows=4, - mass_err_plot_rows=1, - frag_coverage_plot_rows=1, - frag_coverage=True, + peak_plot_rows: int = 4, + mass_err_plot_rows: int = 1, + frag_coverage_plot_rows: int = 1, + frag_coverage: bool = True, ): + """ + Parameters + ---------- + peak_plot_rows : int, optional + The height (ratio) of peak plot, by default 4 + mass_err_plot_rows : int, optional + The height (ratio) of mass error plot, by default 1 + frag_coverage_plot_rows : int, optional + The height (ratio) of fragment coverage plot, by default 1 + frag_coverage : bool, optional + If plot fragment coverage, by default True + """ specs = [] if frag_coverage: specs.append( @@ -190,7 +307,35 @@ def __init__( self.frag_cov_row = frag_cov_row self.rows = peak_plot_rows + mass_err_plot_rows + frag_coverage_plot_rows - def plot(self, plot_df, sequence, title, plot_unmatched_peaks=False): + def plot( + self, + plot_df: pd.DataFrame, + sequence: str, + title: str, + plot_unmatched_peaks: bool = False, + ) -> go.Figure: + """ + Main entry of `PSM_Plot` for peak annotation. + + Parameters + ---------- + plot_df : pd.DataFrame + The plot_df can be generated by + :func:`alpharaw.viz.df_utils.make_psm_plot_df_for_peptide`, + :func:`alpharaw.viz.df_utils.make_psm_plot_for_frag_dfs`, or + :func:`alpharaw.viz.df_utils.make_psm_plot_df`. + sequence : str + Peptide sequence, for fragment coverage plot + title : str + Plot title + plot_unmatched_peaks : bool, optional + If plot unmatched peaks with ion_name `-`, by default False + + Returns + ------- + go.Figure + Peak annotation plot in plotly go.Figure + """ if "pcc" in plot_df.columns and len(plot_df) > 0: title = f"{title} (R={plot_df.pcc.values[0]:.3f})" self._init_plot(title) diff --git a/alpharaw/viz/xic_plot_tims.py b/alpharaw/viz/xic_plot_tims.py index 4765bf9..03207a3 100644 --- a/alpharaw/viz/xic_plot_tims.py +++ b/alpharaw/viz/xic_plot_tims.py @@ -1,4 +1,5 @@ import typing +import warnings import numpy as np import pandas as pd @@ -11,6 +12,11 @@ from .plot_utils import plot_line_tims_fast +warnings.warn( + "This module will be deprecated or changed in the future releases", + category=DeprecationWarning, +) + class XIC_Plot_Tims: # hovermode = "x" | "y" | "closest" | False | "x unified" | "y unified"