def test_init_annotation_order(): num_peaks = 150 mz = np.random.uniform(100, 1400, num_peaks) intensity = np.random.lognormal(0, 1, num_peaks) annotation = [spectrum.FragmentAnnotation('y', i, 1, this_mz) for i, this_mz in enumerate(mz)] spec = spectrum.MsmsSpectrum('test_spectrum', 500, 2, mz, intensity, annotation) for this_mz, this_annotation in zip(spec.mz, spec.annotation): assert this_mz == pytest.approx(this_annotation.calc_mz)
def test_mz_annotation_len(): num_peaks = 150 mz = np.random.uniform(100, 1400, num_peaks) intensity = np.random.lognormal(0, 1, num_peaks) annotation = [ spectrum.FragmentAnnotation(None, this_mz, str(this_mz)) for this_mz in mz[:100] ] with pytest.raises(ValueError): spectrum.MsmsSpectrum('test_spectrum', 500, 2, mz, intensity, annotation)
def test_filter_intensity_keep_all(): num_peaks = 150 mz = np.random.uniform(100, 1400, num_peaks) intensity = np.random.lognormal(0, 1, num_peaks) annotation = [spectrum.FragmentAnnotation('y', i, 1, this_mz) for i, this_mz in enumerate(mz)] spec = spectrum.MsmsSpectrum('test_spectrum', 500, 2, mz, intensity, annotation) spec.filter_intensity() assert len(spec.mz) == num_peaks assert len(spec.intensity) == num_peaks assert len(spec.annotation) == num_peaks
def test_set_mz_range_none(): num_peaks = 150 mz = np.random.uniform(100, 1400, num_peaks) intensity = np.random.lognormal(0, 1, num_peaks) annotation = [spectrum.FragmentAnnotation('y', i, 1, this_mz) for i, this_mz in enumerate(mz)] spec = spectrum.MsmsSpectrum('test_spectrum', 500, 2, mz, intensity, annotation) spec.set_mz_range(None, None) assert len(spec.mz) == num_peaks assert len(spec.intensity) == num_peaks assert len(spec.annotation) == num_peaks
def test_annotate_mz_fragments_most_intense(): fragment_tol_mass = 1 fragment_tol_mode = 'Da' mz, intensity = np.asarray([200, 200.5, 201.5]), np.asarray([10, 20, 30]) spec = spectrum.MsmsSpectrum('test_spectrum', 100, 1, mz, intensity) fragment_mz = 200.15 charge = 1 spec.annotate_mz_fragment(fragment_mz, charge, fragment_tol_mass, fragment_tol_mode, 'most_intense', 'hello') assert spec.annotation[0] is None assert spec.annotation[1] == spectrum.FragmentAnnotation( charge, fragment_mz, 'hello') assert spec.annotation[2] is None
def test_filter_intensity_max_num_peaks(): num_peaks = 150 mz = np.random.uniform(100, 1400, num_peaks) intensity = np.random.lognormal(0, 1, num_peaks) max_intensity = intensity.max() annotation = [spectrum.FragmentAnnotation('y', i, 1, this_mz) for i, this_mz in enumerate(mz)] spec = spectrum.MsmsSpectrum('test_spectrum', 500, 2, mz, intensity, annotation) max_num_peaks = 50 spec.filter_intensity(max_num_peaks=max_num_peaks) assert len(spec.mz) == max_num_peaks assert len(spec.intensity) == max_num_peaks assert len(spec.annotation) == max_num_peaks assert spec.intensity.max() == pytest.approx(max_intensity)
def test_set_mz_range_truncate_right(): num_peaks = 150 mz = np.random.uniform(100, 1400, num_peaks) intensity = np.random.lognormal(0, 1, num_peaks) annotation = [spectrum.FragmentAnnotation('y', i, 1, this_mz) for i, this_mz in enumerate(mz)] spec = spectrum.MsmsSpectrum('test_spectrum', 500, 2, mz, intensity, annotation) min_mz, max_mz = 0, 1200 assert spec.mz.max() > max_mz spec.set_mz_range(min_mz, max_mz) assert len(spec.mz) < num_peaks assert len(spec.intensity) < num_peaks assert len(spec.annotation) < num_peaks assert spec.mz.max() <= max_mz
def test_round_merge_len(): num_peaks = 10 mz = np.arange(1, num_peaks + 1) + np.random.uniform(-0.2, 0.2, num_peaks) mz[4] = mz[3] + 0.0002 mz[5] = mz[3] + 0.0005 mz[7] = mz[8] - 0.00037 intensity = np.random.exponential(1, num_peaks) annotation = [spectrum.FragmentAnnotation('y', i, 1, this_mz) for i, this_mz in enumerate(mz)] spec = spectrum.MsmsSpectrum('test_spectrum', 500, 2, mz, intensity, annotation) spec.round(1) assert len(spec.mz) == len(mz) - 3 assert len(spec.mz) == len(spec.intensity) assert len(spec.mz) == len(spec.annotation)
def test_round_no_merge(): num_peaks = 150 mz = np.arange(1, num_peaks + 1) + np.random.uniform(-0.49, 0.5, num_peaks) intensity = np.random.exponential(1, num_peaks) annotation = [spectrum.FragmentAnnotation('y', i, 1, this_mz) for i, this_mz in enumerate(mz)] spec = spectrum.MsmsSpectrum('test_spectrum', 500, 2, mz.copy(), intensity.copy(), annotation.copy()) decimals = 0 spec.round(decimals) assert len(spec.mz) == num_peaks assert len(spec.intensity) == num_peaks assert len(spec.annotation) == num_peaks np.testing.assert_allclose(spec.mz, np.around(mz, decimals)) np.testing.assert_allclose(spec.intensity, intensity)
def test_remove_precursor_peak_none(): num_peaks = 150 mz = np.random.uniform(100, 1400, num_peaks) fragment_tol_mass = np.random.uniform(0, 0.5) fragment_tol_mode = 'Da' precursor_mz = mz[np.random.randint(0, num_peaks)] + fragment_tol_mass * 2 intensity = np.random.lognormal(0, 1, num_peaks) annotation = [spectrum.FragmentAnnotation('y', i, 1, this_mz) for i, this_mz in enumerate(mz)] spec = spectrum.MsmsSpectrum('test_spectrum', precursor_mz, 2, mz, intensity, annotation) spec.remove_precursor_peak(fragment_tol_mass, fragment_tol_mode) assert len(spec.mz) == num_peaks assert len(spec.intensity) == num_peaks assert len(spec.annotation) == num_peaks assert np.abs(precursor_mz - spec.mz).all() > fragment_tol_mass
def test_filter_intensity_remove_low_intensity(): num_peaks = 150 mz = np.random.uniform(100, 1400, num_peaks) intensity = np.random.lognormal(0, 1, num_peaks) max_intensity = intensity.max() annotation = [spectrum.FragmentAnnotation('y', i, 1, this_mz) for i, this_mz in enumerate(mz)] spec = spectrum.MsmsSpectrum('test_spectrum', 500, 2, mz, intensity, annotation) min_intensity = 0.05 assert spec.intensity.min() < min_intensity * spec.intensity.max() spec.filter_intensity(min_intensity=min_intensity) assert len(spec.mz) < num_peaks assert len(spec.intensity) < num_peaks assert len(spec.annotation) < num_peaks assert spec.intensity.max() == pytest.approx(max_intensity) assert spec.intensity.min() >= min_intensity * max_intensity
def test_annotate_peaks_most_intense(): fragment_tol_mass = 0.02 fragment_tol_mode = 'Da' peptide = 'YLYEIAR' fragment_mz = np.asarray([fragment.calc_mz for fragment in spectrum._get_theoretical_peptide_fragments( peptide)]) mz = np.asarray([fragment_mz[0] - 0.01, fragment_mz[0] + 0.01]) intensity = np.asarray([10, 20]) charge = 2 spec = spectrum.MsmsSpectrum( 'test_spectrum', mass.calculate_mass(sequence=peptide, charge=charge), charge, mz, intensity, peptide=peptide) spec.annotate_peaks(fragment_tol_mass, fragment_tol_mode, peak_assignment='most_intense') assert spec.annotation[0] is None assert spec.annotation[1] == spectrum.FragmentAnnotation('b', 1, 1, fragment_mz[0])
def test_remove_precursor_peak_isotope(): num_peaks = 150 mz = np.random.uniform(100, 1400, num_peaks) fragment_tol_mass = np.random.uniform(0, 0.5) fragment_tol_mode = 'Da' precursor_mz = mz[np.random.randint(0, num_peaks)] + fragment_tol_mass / 2 precursor_charge = 3 mz[-1] = precursor_mz + 1 / precursor_charge mz[-2] = precursor_mz + 2 / precursor_charge intensity = np.random.lognormal(0, 1, num_peaks) annotation = [spectrum.FragmentAnnotation('y', i, 1, this_mz) for i, this_mz in enumerate(mz)] spec = spectrum.MsmsSpectrum('test_spectrum', precursor_mz, precursor_charge, mz, intensity, annotation) spec.remove_precursor_peak(fragment_tol_mass, fragment_tol_mode, 2) assert np.abs(precursor_mz - spec.mz).all() > fragment_tol_mass assert len(spec.mz) <= num_peaks - 3 assert len(spec.intensity) <= num_peaks - 3 assert len(spec.annotation) <= num_peaks - 3
def test_round_merge_annotation(): num_peaks = 10 mz = np.arange(1, num_peaks + 1) + np.random.uniform(-0.2, 0.2, num_peaks) mz[4] = mz[3] + 0.0002 mz[5] = mz[3] + 0.0005 mz[7] = mz[8] - 0.00037 intensity = np.arange(1, 11) annotation = [None, None, None, spectrum.FragmentAnnotation('b', 4, 1, mz[3]), None, spectrum.FragmentAnnotation('b', 6, 1, mz[5]), spectrum.FragmentAnnotation('b', 7, 1, mz[6]), None, None, spectrum.FragmentAnnotation('b', 10, 1, mz[9])] spec = spectrum.MsmsSpectrum('test_spectrum', 500, 2, mz.copy(), intensity, annotation.copy()) spec.round(1, 'max') np.testing.assert_array_equal(spec.annotation, [ None, None, None, spectrum.FragmentAnnotation('b', 6, 1, mz[5]), spectrum.FragmentAnnotation('b', 7, 1, mz[6]), None, spectrum.FragmentAnnotation('b', 10, 1, mz[9])])
def generate_mirror_figure( spectrum_top: sus.MsmsSpectrum, spectrum_bottom: sus.MsmsSpectrum, extension: str, **kwargs: Any, ) -> io.BytesIO: """ Generate a mirror plot of two spectra. Parameters ---------- spectrum_top : sus.MsmsSpectrum The spectrum to be plotted at the top of the mirror plot. spectrum_bottom : sus.MsmsSpectrum The spectrum to be plotted at the bottom of the mirror plot. extension : str Image format. kwargs : Any Plotting settings. Returns ------- io.BytesIO Bytes buffer containing the mirror plot. """ usi1 = spectrum_top.identifier usi2 = spectrum_bottom.identifier fig, ax = plt.subplots(figsize=(kwargs["width"], kwargs["height"])) # Determine cosine similarity and matching peaks. if kwargs["cosine"]: # Assign the matching peak annotations. sim_score, peak_matches = similarity.cosine( spectrum_top, spectrum_bottom, kwargs["fragment_mz_tolerance"], kwargs["cosine"] == "shifted", ) peak_matches = zip(*peak_matches) else: sim_score = 0 # Make sure that top and bottom spectra are colored.. peak_matches = [ np.arange(len(spectrum_top.annotation)), np.arange(len(spectrum_bottom.annotation)), ] if spectrum_top.peptide is None: # Initialize the annotations as unmatched. for annotation in spectrum_top.annotation: if annotation is not None: annotation.ion_type = "unmatched" for annotation in spectrum_bottom.annotation: if annotation is not None: annotation.ion_type = "unmatched" for peak_idx, spectrum, label in zip(peak_matches, [spectrum_top, spectrum_bottom], ["top", "bottom"]): for i in peak_idx: if spectrum.annotation[i] is None: spectrum.annotation[i] = sus.FragmentAnnotation( 0, spectrum.mz[i], "") spectrum.annotation[i].ion_type = label # Colors for mirror plot peaks (subject to change). sup.colors["top"] = "#212121" sup.colors["bottom"] = "#388E3C" sup.colors["unmatched"] = "darkgray" sup.colors[None] = "darkgray" sup.mirror( spectrum_top, spectrum_bottom, { "annotate_ions": kwargs["annotate_peaks"], "annot_kws": { "rotation": kwargs["annotation_rotation"], "clip_on": True, }, "grid": kwargs["grid"], }, ax=ax, ) else: sup.mirror( spectrum_top, spectrum_bottom, { "annot_kws": { "rotation": kwargs["annotation_rotation"], "clip_on": True, }, "grid": kwargs["grid"], }, ax=ax, ) ax.set_xlim(kwargs["mz_min"], kwargs["mz_max"]) ax.set_ylim(-kwargs["max_intensity"] / 100, kwargs["max_intensity"] / 100) if not kwargs["grid"]: ax.spines["right"].set_visible(False) ax.spines["top"].set_visible(False) ax.yaxis.set_ticks_position("left") ax.xaxis.set_ticks_position("bottom") text_y = 1.2 if kwargs["cosine"] else 1.15 for usi, spec, loc in zip([usi1, usi2], [spectrum_top, spectrum_bottom], ["Top", "Bottom"]): title = ax.text( 0.5, text_y, f"{loc}: {usi}", horizontalalignment="center", verticalalignment="bottom", fontsize="x-large", fontweight="bold", transform=ax.transAxes, ) title.set_url(f"{USI_SERVER}mirror/?usi1={usi1}&usi2={usi2}") text_y -= 0.04 subtitle = (f"Precursor $m$/$z$: " f'{spec.precursor_mz:.{kwargs["annotate_precision"]}f} ' if spec.precursor_mz > 0 else "") subtitle += f"Charge: {spec.precursor_charge}" subtitle = ax.text( 0.5, text_y, subtitle, horizontalalignment="center", verticalalignment="bottom", fontsize="large", transform=ax.transAxes, ) subtitle.set_url(f"{USI_SERVER}mirror/?usi1={usi1}&usi2={usi2}") text_y -= 0.06 if kwargs["cosine"]: subtitle_score = f"Cosine similarity = {sim_score:.4f}" ax.text( 0.5, text_y, subtitle_score, horizontalalignment="center", verticalalignment="bottom", fontsize="x-large", fontweight="bold", transform=ax.transAxes, ) buf = io.BytesIO() plt.savefig(buf, bbox_inches="tight", format=extension) buf.seek(0) fig.clear() plt.close(fig) gc.collect() return buf
def _generate_mirror_figure(usi1: str, usi2: str, extension: str, **kwargs) \ -> io.BytesIO: fig, ax = plt.subplots(figsize=(kwargs['width'], kwargs['height'])) annotate_peaks = kwargs['annotate_peaks'] kwargs['annotate_peaks'] = annotate_peaks[0] spectrum_top = _prepare_spectrum(usi1, **kwargs) kwargs['annotate_peaks'] = annotate_peaks[1] spectrum_bottom = _prepare_spectrum(usi2, **kwargs) fragment_mz_tolerance = kwargs['fragment_mz_tolerance'] if kwargs['cosine']: # Initialize the annotations as unmatched. if spectrum_top.annotation is None: spectrum_top.annotation = np.full_like(spectrum_top.mz, None, object) if spectrum_bottom.annotation is None: spectrum_bottom.annotation = np.full_like(spectrum_bottom.mz, None, object) for annotation in spectrum_top.annotation: if annotation is not None: annotation.ion_type = 'unmatched' for annotation in spectrum_bottom.annotation: if annotation is not None: annotation.ion_type = 'unmatched' # Assign the matching peak annotations. similarity, peak_matches = cosine(spectrum_top, spectrum_bottom, fragment_mz_tolerance, kwargs['cosine'] == 'shifted') for top_i, bottom_i in peak_matches: if spectrum_top.annotation[top_i] is None: spectrum_top.annotation[top_i] = sus.FragmentAnnotation( 0, spectrum_top.mz[top_i], '') spectrum_top.annotation[top_i].ion_type = 'top' if spectrum_bottom.annotation[bottom_i] is None: spectrum_bottom.annotation[bottom_i] = sus.FragmentAnnotation( 0, spectrum_bottom.mz[bottom_i], '') spectrum_bottom.annotation[bottom_i].ion_type = 'bottom' else: similarity = 0 # Colors for mirror plot peaks, subject to change. sup.colors['top'] = '#212121' sup.colors['bottom'] = '#388E3C' sup.colors['unmatched'] = 'darkgray' sup.mirror(spectrum_top, spectrum_bottom, { 'annotate_ions': kwargs['annotate_peaks'], 'annot_kws': { 'rotation': kwargs['annotation_rotation'], 'clip_on': True }, 'grid': kwargs['grid'] }, ax=ax) ax.set_xlim(kwargs['mz_min'], kwargs['mz_max']) ax.set_ylim(-kwargs['max_intensity'], kwargs['max_intensity']) if not kwargs['grid']: ax.spines['right'].set_visible(False) ax.spines['top'].set_visible(False) ax.yaxis.set_ticks_position('left') ax.xaxis.set_ticks_position('bottom') text_y = 1.2 if kwargs['cosine'] else 1.15 for usi, spec, loc in zip([usi1, usi2], [spectrum_top, spectrum_bottom], ['Top', 'Bottom']): title = ax.text(0.5, text_y, f'{loc}: {usi}', horizontalalignment='center', verticalalignment='bottom', fontsize='x-large', fontweight='bold', transform=ax.transAxes) title.set_url(f'{USI_SERVER}mirror/?usi1={usi1}&usi2={usi2}') text_y -= 0.04 subtitle = (f'Precursor $m$/$z$: ' f'{spec.precursor_mz:.{kwargs["annotate_precision"]}f} ' if spec.precursor_mz > 0 else '') subtitle += f'Charge: {spec.precursor_charge}' subtitle = ax.text(0.5, text_y, subtitle, horizontalalignment='center', verticalalignment='bottom', fontsize='large', transform=ax.transAxes) subtitle.set_url(f'{USI_SERVER}mirror/?usi1={usi1}&usi2={usi2}') text_y -= 0.06 if kwargs['cosine']: subtitle_score = f'Cosine similarity = {similarity:.4f}' ax.text(0.5, text_y, subtitle_score, horizontalalignment='center', verticalalignment='bottom', fontsize='x-large', fontweight='bold', transform=ax.transAxes) buf = io.BytesIO() plt.savefig(buf, bbox_inches='tight', format=extension) buf.seek(0) fig.clear() plt.close(fig) gc.collect() return buf