Source code for matchms.plotting.spectrum_plots

from typing import Optional, Union
import matplotlib.pyplot as plt
import matplotlib.ticker as mticker
import numpy as np


_annotation_kws = {
    "horizontalalignment": "left",  # if not mirror_intensity else "right",
    "verticalalignment": "center",
    "fontsize": 7,
    "rotation": 90,
    "rotation_mode": "anchor",
    "zorder": 5,
}


[docs]def plot_spectrum(spectrum, annotate_ions: bool = False, mirror_intensity: bool = False, grid: Union[bool, str] = True, ax: plt.Axes = None, peak_color="teal", min_mz: float = None, max_mz: float = None, **plt_kwargs) -> plt.Axes: """ Plot a single MS/MS spectrum. Code is largely taken from package "spectrum_utils". Parameters ---------- spectrum: matchms.Spectrum The spectrum to be plotted. annotate_ions: Flag indicating whether or not to annotate fragment using peak comments (if present in the spectrum). The default is True. mirror_intensity: Flag indicating whether to flip the intensity axis or not. grid: Draw grid lines or not. Either a boolean to enable/disable both major and minor grid lines or 'major'/'minor' to enable major or minor grid lines respectively. ax: Axes instance on which to plot the spectrum. If None the current Axes instance is used. peak_color: Set color of peaks in plot. min_mz: Set lower limit of the plots x-axis to min_mz. Default is None. max_mz: Set upper limit of the plots x-axis to min_mz. Default is None. Returns ------- plt.Axes The matplotlib Axes instance on which the spectrum is plotted. """ # pylint: disable=too-many-locals, too-many-arguments if ax is None: ax = plt.gca() if min_mz is None: min_mz = max(0, np.floor(spectrum.peaks.mz[0] / 100 - 1) * 100) if max_mz is None: max_mz = np.ceil(spectrum.peaks.mz[-1] / 100 + 1) * 100 max_intensity = spectrum.peaks.intensities.max() intensities = spectrum.peaks.intensities / max_intensity def make_stems(): """calculate where the stems of the spectrum peaks are going to be""" x = np.zeros([2, spectrum.peaks.mz.size], dtype="float") y = np.zeros(x.shape) x[:, :] = np.tile(spectrum.peaks.mz, (2, 1)) y[1, :] = intensities return x, y x, y = make_stems() if mirror_intensity is True: y = -y ax.plot(x, y, color=peak_color, linewidth=1.0, marker="", zorder=5, **plt_kwargs) if annotate_ions and isinstance(spectrum.get("peak_comments"), dict): for mz, comment in spectrum.get("peak_comments").items(): idx = (-abs(spectrum.peaks.mz - mz)).argmax() ax.text(mz, intensities[idx], f"m/z: {mz} \n {comment}", _annotation_kws) ax.set_xlim(min_mz, max_mz) ax.yaxis.set_major_formatter(mticker.PercentFormatter(xmax=1.0)) y_max = 1.25 if annotate_ions else 1.10 ax.set_ylim(*(0, y_max) if not mirror_intensity else (-y_max, 0)) ax.xaxis.set_minor_locator(mticker.AutoLocator()) ax.yaxis.set_minor_locator(mticker.AutoLocator()) ax.xaxis.set_minor_locator(mticker.AutoMinorLocator()) ax.yaxis.set_minor_locator(mticker.AutoMinorLocator()) if grid in (True, "both", "major"): ax.grid(visible=True, which="major", color="#9E9E9E", linewidth=0.2) if grid in (True, "both", "minor"): ax.grid(visible=True, which="minor", color="#9E9E9E", linewidth=0.2) ax.set_axisbelow(True) ax.tick_params(axis="both", which="both", labelsize="small") y_ticks = ax.get_yticks() ax.set_yticks(y_ticks[y_ticks <= 1.0]) ax.set_xlabel("m/z", style="italic") ax.set_ylabel("Intensity") title = "Spectrum" if spectrum.get("compound_name") is None else spectrum.get("compound_name") ax.set_title(title) return ax
[docs]def plot_spectra_mirror(spec_top, spec_bottom, ax: Optional[plt.Axes] = None, **spectrum_kws) -> plt.Axes: """Mirror plot two MS/MS spectra. Code is largely taken from package "spectrum_utils". Parameters ---------- spec_top: matchms.Spectrum The spectrum to be plotted on the top. spec_bottom: matchms.Spectrum The spectrum to be plotted on the bottom. ax: Axes instance on which to plot the spectrum. If None the current Axes instance is used. spectrum_kws: Keyword arguments for `plot_spectrum()`. Returns ------- plt.Axes The matplotlib Axes instance on which the spectra are plotted. """ if ax is None: ax = plt.gca() if spectrum_kws is None: spectrum_kws = {} # Top spectrum. plot_spectrum(spec_top, mirror_intensity=False, ax=ax, peak_color="darkblue", **spectrum_kws) y_max = ax.get_ylim()[1] # Mirrored bottom spectrum. plot_spectrum(spec_bottom, mirror_intensity=True, ax=ax, peak_color="teal", **spectrum_kws) y_min = ax.get_ylim()[0] ax.set_ylim(y_min, y_max) ax.axhline(0, color="#9E9E9E", zorder=10) # Update axes so that both spectra fit. min_mz = max( [ 0, np.floor(spec_top.peaks.mz[0] / 100 - 1) * 100, np.floor(spec_bottom.peaks.mz[0] / 100 - 1) * 100, ] ) max_mz = max( [ np.ceil(spec_top.peaks.mz[-1] / 100 + 1) * 100, np.ceil(spec_bottom.peaks.mz[-1] / 100 + 1) * 100, ] ) ax.set_xlim(min_mz, max_mz) ax.yaxis.set_major_locator(mticker.AutoLocator()) ax.yaxis.set_minor_locator(mticker.AutoMinorLocator()) ax.yaxis.set_major_formatter( mticker.FuncFormatter(lambda x, pos: f"{abs(x):.0%}") ) name1 = "Spectrum 1" if spec_top.get("compound_name") is None else spec_top.get("compound_name") name2 = "Spectrum 2" if spec_bottom.get("compound_name") is None else spec_bottom.get("compound_name") x_text = 0.04 * (max_mz - min_mz) ax.text(x_text, y_max, name1, ha="left", va="top", zorder=2, backgroundcolor="white") ax.text(x_text, y_min, name2, ha="left", va="bottom", zorder=2, backgroundcolor="white") ax.set_title("Spectrum comparison") return ax
[docs]def plot_spectra_array(spectrums, n_cols: int = 2, peak_color="darkblue", dpi: int = 200, title: str = None, **spectrum_kws) -> plt.Axes: """Mirror plot two MS/MS spectra. Code is largely taken from package "spectrum_utils". Parameters ---------- spectrums: list of matchms.Spectrum List of spectra to be plotted in a single figure. n_cols: Number of spectra to be plotted per row. Default is 4. spectrum_kws: Keyword arguments for `plot_spectrum()`. """ # pylint: disable=too-many-locals assert isinstance(spectrums, list), "Expected list of Spectrum objects as input." n_spectra = len(spectrums) n_rows = int(np.ceil(n_spectra / n_cols)) fig, axes = plt.subplots(n_rows, n_cols, figsize=(7 * n_cols, 3 * n_rows), dpi=dpi) if spectrum_kws is None: spectrum_kws = {} for i in range(n_rows): for j in range(n_cols): counter = i * n_cols + j if counter >= n_spectra: break plot_spectrum(spectrums[counter], mirror_intensity=False, ax=axes[i, j], peak_color=peak_color, **spectrum_kws) axes[i, j].set_title("") if spectrums[counter].get("compound_name") is None: name = f"Spectrum {i * n_cols + j}" else: name = spectrums[counter].get("compound_name") y_max = axes[i, j].get_ylim()[1] x_min = axes[i, j].get_xlim()[0] axes[i, j].text(x_min, y_max, name, va="bottom", zorder=2) if title is None: fig.suptitle("Spectrum array plot") else: fig.suptitle(title) return fig, axes