Source code for spectrum_utils.iplot

import functools
import operator
from typing import Callable, Dict, Optional

try:
    import altair
    import pandas as pd
except ImportError:
    raise ImportError(
        "Missing dependencies for interactive plotting. Install using `pip "
        "install spectrum_utils[iplot]`, manually install Altair and Pandas, or"
        " use the default Matplotlib (`spectrum_utils.plot`) plotting backend."
    )

from spectrum_utils.plot import annotate_ion_type, colors
from spectrum_utils.spectrum import MsmsSpectrum


[docs]def spectrum( spec: MsmsSpectrum, *_, color_ions: bool = True, annot_fmt: Optional[Callable] = functools.partial( annotate_ion_type, ion_types="by" ), annot_kws: Optional[Dict] = None, mirror_intensity: bool = False, grid: bool = True, ) -> altair.LayerChart: """ Plot an MS/MS spectrum. Parameters ---------- spec : MsmsSpectrum The spectrum to be plotted. color_ions : bool, optional Flag indicating whether or not to color annotated fragment ions. The default is True. annot_fmt : Optional[Callable] Function to format the peak annotations. See `FragmentAnnotation` for supported elements. By default, only canonical b and y peptide fragments are annotated. If `None`, no peaks are annotated. annot_kws : Optional[Dict], optional Keyword arguments for `altair.Chart.mark_text` to customize peak annotations. mirror_intensity : bool, optional Flag indicating whether to flip the intensity axis or not. grid : bool, optional Draw grid lines or not. Returns ------- altair.LayerChart The Altair chart instance with the plotted spectrum. """ intensity = spec.intensity / spec.intensity.max() if mirror_intensity: intensity *= -1 if spec.annotation is not None: annotations = list(map(operator.itemgetter(0), spec.annotation)) peak_labels = map(annot_fmt, annotations) peak_colors = [ colors.get(a.ion_type[0] if color_ions else None) for a in annotations ] mz_delta = [ None if a.mz_delta is None else "".join(map(str, a.mz_delta)) for a in annotations ] spec_df = pd.DataFrame( { "mz": spec.mz, "intensity": intensity, "fragment": peak_labels, "mz_delta": mz_delta, "color": peak_colors, } ) else: spec_df = pd.DataFrame( { "mz": spec.mz, "intensity": intensity, "color": [colors[None]] * len(spec.mz), } ) x_axis = altair.X( "mz", axis=altair.Axis(title="m/z", titleFontStyle="italic", grid=grid), scale=altair.Scale(nice=True, padding=5), ) y_axis = altair.Y( "intensity", axis=altair.Axis(title="Intensity", format="%", grid=grid), scale=altair.Scale(nice=True), ) color = altair.Color("color", scale=None, legend=None) tooltip_not_annotated = [ altair.Tooltip("mz", format=".4f", title="m/z"), altair.Tooltip("intensity", format=".1%", title="Intensity"), ] tooltip_annotated = [ altair.Tooltip("mz", format=".4f", title="m/z"), altair.Tooltip("intensity", format=".1%", title="Intensity"), altair.Tooltip("fragment", title="Fragment"), altair.Tooltip("mz_delta", title="m/z deviation"), ] # Unannotated peaks. mask_unannotated = spec_df["fragment"] == "" spec_plot = ( altair.Chart(spec_df[mask_unannotated]) .mark_rule(size=2) .encode(x=x_axis, y=y_axis, color=color, tooltip=tooltip_not_annotated) ) # Annotated peaks. annotation_kws = { "align": "left" if not mirror_intensity else "right", "angle": 270, "baseline": "middle", } if annot_kws is not None: annotation_kws.update(annot_kws) spec_plot += ( altair.Chart(spec_df[~mask_unannotated]) .mark_rule(size=2) .encode(x=x_axis, y=y_axis, color=color, tooltip=tooltip_annotated) ) spec_plot += ( altair.Chart(spec_df[~mask_unannotated]) .mark_text(dx=-5 if mirror_intensity else 5, **annotation_kws) .encode( x=x_axis, y=y_axis, text="fragment", color=color, tooltip=tooltip_annotated, ) ) return spec_plot
[docs]def mirror( spec_top: MsmsSpectrum, spec_bottom: MsmsSpectrum, spectrum_kws: Optional[Dict] = None, *_, ) -> altair.LayerChart: """ Mirror plot two MS/MS spectra. Parameters ---------- spec_top : MsmsSpectrum The spectrum to be plotted on the top. spec_bottom : MsmsSpectrum The spectrum to be plotted on the bottom. spectrum_kws : Optional[Dict], optional Keyword arguments for `iplot.spectrum`. *_ Ignored, for consistency with the `plot.mirror` API. Returns ------- altair.LayerChart The Altair chart instance with the plotted spectrum. """ if spectrum_kws is None: spectrum_kws = {} # Top spectrum. spec_plot = spectrum(spec_top, mirror_intensity=False, **spectrum_kws) # Mirrored bottom spectrum. spec_plot += spectrum(spec_bottom, mirror_intensity=True, **spectrum_kws) spec_plot += ( altair.Chart(pd.DataFrame({"sep": [0]})) .mark_rule(size=3) .encode(y="sep", color=altair.value("lightGray")) ) return spec_plot