mobiusklein / ms_deisotope

A library for deisotoping and charge state deconvolution of complex mass spectra
https://mobiusklein.github.io/ms_deisotope
Apache License 2.0
33 stars 14 forks source link

Exporting deconvoluted peak lists from a standalone MS2 scan #13

Closed JeffEdge closed 5 years ago

JeffEdge commented 5 years ago

Thank you for this fantastic library. Briefly what works:

What I have issues with is exporting a mzML file of the deconvoluted data. While my knowledge of mzML is limited I tried the following to address the fact that I have no MS1 scan and no precursor list (the graphical output seems to work so I focused on the writer part)

with open("Output_deconvoluted.mzML", 'wb') as fh:
    writer = MzMLSerializer(fh, n_spectra=len(reader))  # is len(reader) correct here?
    writer.copy_metadata_from(reader)
    writer.save_scan_bunch2(bunch)
    writer.close()

Where save_scan_bunch2() is a method where I edited "precursor" out:

    def save_scan_bunch2(self, bunch, **kwargs):
        if bunch is not None:
            self.save_scan2(bunch, deconvoluted=True)
        if self.indexer is not None:
            self.indexer.add_scan_bunch2(bunch)

In save_scan2(), I just commented out the bloc staring with if scan.precursor_information:

Now my problems really start: The edited add_scan_bunch() so that add_scan_bunch2() looks like

    def add_scan_bunch2(self, bunch):
        if bunch is not None:
            package = {
 #                "scan_time": bunch.precursor.scan_time,
 #                "product_scan_ids": [
 #                    product.id for product in bunch.products
 #                ],
                "msms_peaks": [
                    p.index.neutral_mass for p in bunch.deconvoluted_peak_set
                    if p.chosen_for_msms
                ] if bunch.deconvoluted_peak_set is not None else [],
            }
            if bunch.has_ion_mobility():
                package['drift_time'] = bunch.drift_time
 #            self.ms1_ids[bunch.id] = MS1Record(**package)
 #        for product in bunch.products:
 #            self.msn_ids[product.id] = MSnRecord(**self._package_precursor_information(product))

All this yields a mzML file which displays using openMS as centroided deisotope peaks ( nothing else), see file at the end.

First I believe I might have an indexation problem but I am not sure. Could it be that the issue stems from the binaryDataArrayList breaking the data into 5 parts.

Ultimately what I would like is export a charge deconvoluted spectrum (everything converted to MH+ ions, no higher charge states) and if possible a list of the isotope distributions extracted (ideally MH+) also. Perhaps it would be possible to create a new method to export an extracted isotope distribution and find a way to append them in a single mzML file?

Any help would be very much appreciated! Many thanks, With my best wishes, Jeff

If it is any help I can provide a MS2 single scan data file. The output written out is below.

<?xml version='1.0' encoding='utf-8'?>
<indexedmzML xmlns="http://psi.hupo.org/ms/mzml" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://psi.hupo.org/ms/mzml http://psidev.info/files/ms/mzML/xsd/mzML1.1.2_idx.xsd">
  <mzML xmlns="http://psi.hupo.org/ms/mzml" version="1.1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://psi.hupo.org/ms/mzml http://psidev.info/files/ms/mzML/xsd/mzML1.1.0.xsd">
    <cvList count="2">
      <cv URI="https://raw.githubusercontent.com/HUPO-PSI/psi-ms-CV/master/psi-ms.obo" fullName="PSI-MS" id="PSI-MS" version="4.1.28"/>
      <cv URI="http://ontologies.berkeleybop.org/uo.obo" fullName="UNIT-ONTOLOGY" id="UO" version="releases/2019-03-29"/>
    </cvList>
    <fileDescription>
      <fileContent>
        <cvParam accession="MS:1000580" cvRef="PSI-MS" name="MSn spectrum" value=""/>
      </fileContent>
      <sourceFileList count="1">
        <sourceFile location="D:/test" name="20190116_EMR1_22h02_Com0-300_part.mzML" id="sf_ru_0">
          <cvParam accession="MS:1000569" cvRef="PSI-MS" name="SHA-1" value="178307a241cda7a75aa85fb1ea77fc9f6a20af13"/>
          <cvParam accession="MS:1000777" cvRef="PSI-MS" name="spectrum identifier nativeID format" value=""/>
          <cvParam accession="MS:1000584" cvRef="PSI-MS" name="mzML format" value=""/>
        </sourceFile>
      </sourceFileList>
    </fileDescription>
    <sampleList count="1">
      <sample name="sample_1" id="sample_1">
        <userParam name="SampleRun-UUID" value="8e4141e0-202a-475d-8461-cffd8674c822"/>
      </sample>
    </sampleList>
    <softwareList count="7">
      <software version="2.3-170371/2.3.0.1765" id="so_in_0">
        <cvParam accession="MS:1000532" cvRef="PSI-MS" name="Xcalibur" value=""/>
      </software>
      <software version="" id="so_default">
        <cvParam accession="MS:1000799" cvRef="PSI-MS" name="custom unreleased software tool" value=""/>
      </software>
      <software version="3.0.19011" id="so_dp_sp_0_pm_0">
        <cvParam accession="MS:1000615" cvRef="PSI-MS" name="ProteoWizard software" value=""/>
      </software>
      <software version="2.4.0-HEAD-2019-02-07" id="so_dp_sp_0_pm_1">
        <cvParam accession="MS:1000753" cvRef="PSI-MS" name="BaselineFilter" value=""/>
      </software>
      <software version="2.4.0-HEAD-2019-02-07" id="so_dp_sp_0_pm_2">
        <cvParam accession="MS:1000799" cvRef="PSI-MS" name="custom unreleased software tool" value=""/>
      </software>
      <software version="2.4.0-HEAD-2019-02-07" id="so_dp_sp_0_pm_3">
        <cvParam accession="MS:1000799" cvRef="PSI-MS" name="custom unreleased software tool" value=""/>
      </software>
      <software version="0.0.9" id="ms_deisotope_1">
        <cvParam accession="MS:1002990" cvRef="PSI-MS" name="ms_deisotope" value=""/>
      </software>
    </softwareList>
    <instrumentConfigurationList count="1">
      <instrumentConfiguration id="ic_0">
        <componentList count="4">
          <source order="1">
            <cvParam accession="MS:1000485" cvRef="PSI-MS" name="nanospray inlet" value=""/>
            <cvParam accession="MS:1000398" cvRef="PSI-MS" name="nanoelectrospray" value=""/>
          </source>
          <analyzer order="2">
            <cvParam accession="MS:1000014" cvRef="PSI-MS" name="accuracy" unitAccession="MS:1000040" unitCvRef="PSI-MS" unitName="m/z" value=""/>
            <cvParam accession="MS:1000022" cvRef="PSI-MS" name="TOF Total Path Length" unitAccession="UO:0000008" unitCvRef="UO" unitName="meter" value=""/>
            <cvParam accession="MS:1000024" cvRef="PSI-MS" name="final MS exponent" value=""/>
            <cvParam accession="MS:1000025" cvRef="PSI-MS" name="magnetic field strength" unitAccession="UO:0000228" unitCvRef="UO" unitName="tesla" value=""/>
            <cvParam accession="MS:1000081" cvRef="PSI-MS" name="quadrupole" value=""/>
          </analyzer>
          <analyzer order="3">
            <cvParam accession="MS:1000014" cvRef="PSI-MS" name="accuracy" unitAccession="MS:1000040" unitCvRef="PSI-MS" unitName="m/z" value=""/>
            <cvParam accession="MS:1000022" cvRef="PSI-MS" name="TOF Total Path Length" unitAccession="UO:0000008" unitCvRef="UO" unitName="meter" value=""/>
            <cvParam accession="MS:1000024" cvRef="PSI-MS" name="final MS exponent" value=""/>
            <cvParam accession="MS:1000025" cvRef="PSI-MS" name="magnetic field strength" unitAccession="UO:0000228" unitCvRef="UO" unitName="tesla" value=""/>
            <cvParam accession="MS:1000484" cvRef="PSI-MS" name="orbitrap" value=""/>
          </analyzer>
          <detector order="4">
            <cvParam accession="MS:1000028" cvRef="PSI-MS" name="detector resolution" value=""/>
            <cvParam accession="MS:1000029" cvRef="PSI-MS" name="sampling frequency" unitAccession="UO:0000106" unitCvRef="UO" unitName="hertz" value=""/>
            <cvParam accession="MS:1000624" cvRef="PSI-MS" name="inductive detector" value=""/>
          </detector>
        </componentList>
      </instrumentConfiguration>
    </instrumentConfigurationList>
    <dataProcessingList count="1">
      <dataProcessing id="dp_sp_0">
        <processingMethod order="0" softwareRef="so_dp_sp_0_pm_0">
          <cvParam accession="MS:1000544" cvRef="PSI-MS" name="Conversion to mzML" value=""/>
        </processingMethod>
        <processingMethod order="0" softwareRef="so_dp_sp_0_pm_1">
          <cvParam accession="MS:1000593" cvRef="PSI-MS" name="baseline reduction" value=""/>
          <cvParam accession="MS:1000747" cvRef="PSI-MS" name="completion time" value="2019-07-19+16:13"/>
          <userParam name="parameter: in" value="C:/Users/Greis002/AppData/Local/Temp/TOPPView_20190719_161335_BMS-2YZBKY1_4624_1_in"/>
          <userParam name="parameter: out" value="C:/Users/Greis002/AppData/Local/Temp/TOPPView_20190719_161335_BMS-2YZBKY1_4624_1_out"/>
          <userParam name="parameter: struc_elem_length" value="3.0"/>
          <userParam name="parameter: struc_elem_unit" value="Thomson"/>
          <userParam name="parameter: method" value="tophat"/>
          <userParam name="parameter: log" value=""/>
          <userParam name="parameter: debug" value="0.0"/>
          <userParam name="parameter: threads" value="1.0"/>
          <userParam name="parameter: no_progress" value="true"/>
          <userParam name="parameter: force" value="false"/>
          <userParam name="parameter: test" value="false"/>
        </processingMethod>
        <processingMethod order="0" softwareRef="so_dp_sp_0_pm_2">
          <cvParam accession="MS:1001486" cvRef="PSI-MS" name="data filtering" value=""/>
          <cvParam accession="MS:1000747" cvRef="PSI-MS" name="completion time" value="2019-07-19+16:16"/>
        </processingMethod>
        <processingMethod order="0" softwareRef="so_dp_sp_0_pm_3">
          <cvParam accession="MS:1001486" cvRef="PSI-MS" name="data filtering" value=""/>
          <cvParam accession="MS:1000747" cvRef="PSI-MS" name="completion time" value="2019-07-19+19:26"/>
        </processingMethod>
      </dataProcessing>
    </dataProcessingList>
    <run defaultInstrumentConfigurationRef="ic_0" sampleRef="sample_1" id="RUN_1">
      <spectrumList count="1" defaultDataProcessingRef="dp_sp_0">
        <spectrum index="0" defaultArrayLength="23" id="controllerType=0 controllerNumber=1 scan=1">
          <cvParam accession="MS:1000511" cvRef="PSI-MS" name="ms level" value="2"/>
          <cvParam accession="MS:1000580" cvRef="PSI-MS" name="MSn spectrum" value=""/>
          <cvParam accession="MS:1000504" cvRef="PSI-MS" name="base peak m/z" unitAccession="MS:1000040" unitCvRef="PSI-MS" unitName="m/z" value="2024.3660346586512"/>
          <cvParam accession="MS:1000505" cvRef="PSI-MS" name="base peak intensity" unitAccession="MS:1000131" unitCvRef="PSI-MS" unitName="number of detector counts" value="12599.448654174805"/>
          <cvParam accession="MS:1000285" cvRef="PSI-MS" name="total ion current" value="79548.09947953442"/>
          <cvParam accession="MS:1000528" cvRef="PSI-MS" name="lowest observed m/z" unitAccession="MS:1000040" unitCvRef="PSI-MS" unitName="m/z" value="1998.7206726276697"/>
          <cvParam accession="MS:1000527" cvRef="PSI-MS" name="highest observed m/z" unitAccession="MS:1000040" unitCvRef="PSI-MS" unitName="m/z" value="2096.0621316761285"/>
          <cvParam accession="MS:1000130" cvRef="PSI-MS" name="positive scan" value=""/>
          <cvParam accession="MS:1000127" cvRef="PSI-MS" name="centroid spectrum" value=""/>
          <scanList count="1">
            <cvParam accession="MS:1000795" cvRef="PSI-MS" name="no combination" value=""/>
            <scan instrumentConfigurationRef="ic_0">
              <cvParam accession="MS:1000927" cvRef="PSI-MS" name="ion injection time" unitAccession="UO:0000028" unitCvRef="UO" unitName="millisecond" value="0"/>
              <cvParam accession="MS:1000927" cvRef="PSI-MS" name="ion injection time" unitAccession="UO:0000028" unitCvRef="UO" unitName="millisecond" value="249.999999254942"/>
              <cvParam accession="MS:1000016" cvRef="PSI-MS" name="scan start time" unitAccession="UO:0000031" unitCvRef="UO" unitName="minute" value="0.043343780000000005"/>
              <userParam name="[Thermo Trailer Extra]Monoisotopic M/Z:" value="0.0"/>
              <scanWindowList count="1">
                <scanWindow>
                  <cvParam accession="MS:1000501" cvRef="PSI-MS" name="scan window lower limit" unitAccession="MS:1000040" unitCvRef="PSI-MS" unitName="m/z" value="297.016078153813"/>
                  <cvParam accession="MS:1000500" cvRef="PSI-MS" name="scan window upper limit" unitAccession="MS:1000040" unitCvRef="PSI-MS" unitName="m/z" value="20202.6853922973"/>
                </scanWindow>
              </scanWindowList>
            </scan>
          </scanList>
          <binaryDataArrayList count="5">
            <binaryDataArray encodedLength="260">
              <cvParam accession="MS:1000514" cvRef="PSI-MS" name="m/z array" unitAccession="MS:1000040" unitCvRef="PSI-MS" unitName="m/z" value=""/>
              <cvParam accession="MS:1000574" cvRef="PSI-MS" name="zlib compression" value=""/>
              <cvParam accession="MS:1000523" cvRef="PSI-MS" name="64-bit float" value=""/>
              <binary>
                eJwBuABH/y64e2RoQ59AfFj/GxKEn0APF53UdZGfQLkMHhsRlJ9AabDZpw/En0Co5SD8G+SfQDnx87TW5J9A4IfUvBM8oECwohMfG1igQNF/gsJ7WKBAMWHMT7xCn0AQfy7HHI6fQPxFr5m1G6BAOzS5zhZRoEBgfCo7mHGfQMjHCajYAqBA1L73xqMJoEB6xPiL1hSgQMYmdJjdMKBAcCDK0Xahn0AJGrnPH2CgQNtbAfjhOp9AzFsS3vPan0BWKljD
              </binary>
            </binaryDataArray>
            <binaryDataArray encodedLength="140">
              <cvParam accession="MS:1000515" cvRef="PSI-MS" name="intensity array" unitAccession="MS:1000131" unitCvRef="PSI-MS" unitName="number of detector counts" value=""/>
              <cvParam accession="MS:1000574" cvRef="PSI-MS" name="zlib compression" value=""/>
              <cvParam accession="MS:1000521" cvRef="PSI-MS" name="32-bit float" value=""/>
              <binary>
                eJwBXACj//yAhUTheKFEhJMXRFrvokQMsT9FsaLTRJFNgUQ2I5JERxZ2RFrfWETRQnBExlKxRNOSdkQTiypE8R2tRW8B30SkPwBGOAgMRcleNkbL3URGwhO+RaCpIUahanZFXB0m/Q==
              </binary>
            </binaryDataArray>
            <binaryDataArray encodedLength="36">
              <cvParam accession="MS:1000516" cvRef="PSI-MS" name="charge array" value=""/>
              <cvParam accession="MS:1000574" cvRef="PSI-MS" name="zlib compression" value=""/>
              <cvParam accession="MS:1000519" cvRef="PSI-MS" name="32-bit integer" value=""/>
              <binary>
                eJxjZGBgYCQCMwExMxJmxYLZoJgdigEI7ABJ
              </binary>
            </binaryDataArray>
            <binaryDataArray encodedLength="140">
              <cvParam accession="MS:1000786" cvRef="PSI-MS" name="non-standard data array" value=""/>
              <cvParam accession="MS:1000574" cvRef="PSI-MS" name="zlib compression" value=""/>
              <cvParam accession="MS:1000521" cvRef="PSI-MS" name="32-bit float" value=""/>
              <userParam name="deconvolution score array" value=""/>
              <binary>
                eJwBXACj/2T82kEPjKpBMWSyQUAftUFgs4lCFDHZQQk0u0ElUrtBf/HVQbeI7UHjwcJB0ngPQrsqp0Eiy8FB5IPjQWuBSUJvtSJD66kXQlr3O0MSW5BDUvjhQiReWEPbMPlBmi8qDw==
              </binary>
            </binaryDataArray>
            <binaryDataArray arrayLength="448" encodedLength="2056">
              <cvParam accession="MS:1000786" cvRef="PSI-MS" name="non-standard data array" value=""/>
              <cvParam accession="MS:1000574" cvRef="PSI-MS" name="zlib compression" value=""/>
              <cvParam accession="MS:1000521" cvRef="PSI-MS" name="32-bit float" value=""/>
              <userParam name="isotopic envelopes array" value=""/>
              <binary>
                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
              </binary>
            </binaryDataArray>
          </binaryDataArrayList>
        </spectrum>
      </spectrumList>
      <chromatogramList count="2" defaultDataProcessingRef="dp_sp_0">
        <chromatogram index="0" defaultArrayLength="1" id="TIC">
          <cvParam accession="MS:1000235" cvRef="PSI-MS" name="total ion current chromatogram" value=""/>
          <binaryDataArrayList count="2">
            <binaryDataArray encodedLength="16">
              <cvParam accession="MS:1000595" cvRef="PSI-MS" name="time array" unitAccession="UO:0000031" unitCvRef="UO" unitName="minute" value=""/>
              <cvParam accession="MS:1000574" cvRef="PSI-MS" name="zlib compression" value=""/>
              <cvParam accession="MS:1000521" cvRef="PSI-MS" name="32-bit float" value=""/>
              <binary>
                eJyz7zS0BQADOgE3
              </binary>
            </binaryDataArray>
            <binaryDataArray encodedLength="16">
              <cvParam accession="MS:1000515" cvRef="PSI-MS" name="intensity array" unitAccession="MS:1000131" unitCvRef="PSI-MS" unitName="number of detector counts" value=""/>
              <cvParam accession="MS:1000574" cvRef="PSI-MS" name="zlib compression" value=""/>
              <cvParam accession="MS:1000521" cvRef="PSI-MS" name="32-bit float" value=""/>
              <binary>
                eJzjjZvtDgACzwFO
              </binary>
            </binaryDataArray>
          </binaryDataArrayList>
        </chromatogram>
        <chromatogram index="1" defaultArrayLength="1" id="BPC">
          <cvParam accession="MS:1000628" cvRef="PSI-MS" name="basepeak chromatogram" value=""/>
          <binaryDataArrayList count="2">
            <binaryDataArray encodedLength="16">
              <cvParam accession="MS:1000595" cvRef="PSI-MS" name="time array" unitAccession="UO:0000031" unitCvRef="UO" unitName="minute" value=""/>
              <cvParam accession="MS:1000574" cvRef="PSI-MS" name="zlib compression" value=""/>
              <cvParam accession="MS:1000521" cvRef="PSI-MS" name="32-bit float" value=""/>
              <binary>
                eJyz7zS0BQADOgE3
              </binary>
            </binaryDataArray>
            <binaryDataArray encodedLength="16">
              <cvParam accession="MS:1000515" cvRef="PSI-MS" name="intensity array" unitAccession="MS:1000131" unitCvRef="PSI-MS" unitName="number of detector counts" value=""/>
              <cvParam accession="MS:1000574" cvRef="PSI-MS" name="zlib compression" value=""/>
              <cvParam accession="MS:1000521" cvRef="PSI-MS" name="32-bit float" value=""/>
              <binary>
                eJw7fdfFDQAGlQIz
              </binary>
            </binaryDataArray>
          </binaryDataArrayList>
        </chromatogram>
      </chromatogramList>
    </run>
  </mzML>
  <indexList count="2">
    <index name="spectrum">
      <offset idRef="controllerType=0 controllerNumber=1 scan=1">7327</offset>
    </index>
    <index name="chromatogram">
      <offset idRef="TIC">15195</offset>
      <offset idRef="BPC">16489</offset>
    </index>
  </indexList>
  <indexListOffset>17812</indexListOffset>
  <fileChecksum>2960f08c3755eea9876157ad8d8e1ad5d7501322</fileChecksum>
</indexedmzML>
mobiusklein commented 5 years ago

Thank you for your interest in my work. I'm glad it's (partially) helping you.

Saving Spectra

If I'm following your post correctly, you started with an input MS data file of some sort (another mzML file?) with only MS2 spectra, and attempting to export the processed spectra did not work as expected because the save_scan_bunch method expected a precursor?

This sounds like a combination of things weren't aligned. The mzML format supports MS2-only files and the readers and writers in ms_deisotope should too.

When you iterated over your input file, were you getting Scan or ScanBunch instances? A Scan is a single scan/spectrum, while a ScanBunch is a collection of an MS1 scan (which may be None) and zero or more MSn scans. Since you have a snippet invoking bunch.deconvolute, and only Scan objects have a deconvolute method, I assume bunch is a Scan. MzMLSerializer.save_scan_bunch assumes its input is a ScanBunch. To save a single Scan, you should call MzMLSerializer.save_scan, or you can use the MzMLSerializer.save method, which does type checking to figure out which method to use. In the docs, I show an example using save.

I probably need to document the iteration modes better, since it sounds like you've read some examples where iteration yields ScanBunch instances, but that didn't match what you had.

The mzML snippet you posted appears to be missing the <precursorList> element. Is it present in your input file? I can't tell if this is because you've changed the scan saving code, or because it is missing. if you can share the file, I might be able to better understand what's happening.

What Is Saved

When you save a deconvoluted scan with ms_deisotope's MzMLSerializer, your <spectrum> elements contain the following <binaryDataArray>s:

  1. m/z array - The monoisotopic m/z of each deconvoluted peak, given by their neutral mass and charge state
  2. intensity array - The sum of the intensity of all isotopic peaks underlying each deconvoluted peak
  3. charge array - The charge state of the ion forming the isotopic pattern underlying each deconvoluted peak
  4. deconvolution score array - Non-standard. The score of the theoretical isotopic pattern fit underlying each deconvoluted peak
  5. isotopic envelope array - Non-standard. The isotopic peaks of each deconvoluted peak. This array is a bit tricky to decode. All of the previous arrays map a single value to each peak, where this array maps a variable number of values to each peak. Every two values in this array correspond to the m/z and intensity of an isotopic peak, and distinct isotopic patterns are delimited by a pair of 0 entries. See the following function from ms_deisotope.output.text_utils for the implementation:
    def decode_envelopes(array):
    envelope_list = []
    current_envelope = []
    i = 0
    n = len(array)
    while i < n:
        a = array[i]
        b = array[i + 1]
        i += 2
        if a == 0 and b == 0:
            if current_envelope is not None:
                if current_envelope:
                    envelope_list.append(Envelope(current_envelope))
                current_envelope = []
        else:
            current_envelope.append(EnvelopePair(a, b))
    envelope_list.append(Envelope(current_envelope))
    return envelope_list

    This lets me reconstruct DeconvolutedPeak instances, preserving their envelope attributes which is where the experimental isotopic patterns get stored. This hopefully takes care of encoding the isotopic patterns for you as well. Note, they are at whatever charge state the matching deconvoluted peak was fit at.

You said you'd prefer for the m/z stored to be de-charged, so transformed as if z = 1. I don't have a method for doing that directly, but while I figure out if there is a better way, you could just do the following to achieve the desired effect:

import ms_deisotope

for peak in scan.deconvoluted_peak_set:
    peak.mz = ms_deisotope.mass_charge_ratio(peak.neutral_mass, 1)
    peak.charge = 1
scan.deconvoluted_peak_set.reindex()
JeffEdge commented 5 years ago

Saving Spectra

-> Yes, I start with a mzML data file with only one MS2 spectrum, and indeed attempting to export the processed spectra did not work as expected presumably because the save_scan_bunch method expected a precursor.

“When you iterated over your input file, were you getting Scan or ScanBunch instances? A Scan is a single scan/spectrum, while a ScanBunch is a collection of an MS1 scan (which may be None) and zero or more MSn scans. Since you have a snippet invoking bunch.deconvolute, and only Scan objects have a deconvolute method, I assume bunch is a Scan.”

-> Yes, sorry for naming my scan so: I cleaned this up and now use MzMLSerializer.save_scan.

“The mzML snippet you posted appears to be missing the element. Is it present in your input file?”

-> Yes, it is present and reads as follows (the file is attached):

“I can't tell if this is because you've changed the scan saving code, or because it is missing. if you can share the file, I might be able to better understand what's happening.”

-> I join the file. I also went back to “originals”.

Using """ output to file """ with open("Output_deconvoluted_b.mzML", 'wb') as fh: writer = MzMLSerializer(fh, n_spectra=len(reader)) writer.copy_metadata_from(reader) writer.save_scan(scan) writer.close()

I get: c:...\ms-deisotope\psims\psims\document.py:734: AmbiguousTermWarning: Multiple unit options are possible for parameter 'accuracy' but none were specified self.write_params(xml_file) Traceback (most recent call last): File "C:/…/ms-deisotope/test04b.py", line 75, in writer.save_scan(scan) File "C:...\ms-deisotope\ms_deisotope\output\mzml.py", line 828, in save_scan if scan.precursor_information: File "C:...\ms-deisotope\ms_deisotope\data_source\scan\scan.py", line 351, in precursor_information self._data) File "C:...\ms-deisotope\ms_deisotope\data_source\mzml.py", line 127, in _precursor_information pinfo_dict = self._get_selected_ion(scan) File "C:...\ms-deisotope\ms_deisotope\data_source\mzml.py", line 108, in _get_selected_ion pinfo_dict = scan["precursorList"]['precursor'][0]["selectedIonList"]['selectedIon'][0]

KeyError: 'selectedIonList'

The (graphic) output of your library is really great and I am tremendously enjoying myself using it as it can enhance our workflow a lot. Thanks a lot for the feedback,

mobiusklein commented 5 years ago

Thank you for the response. Unfortunately, Github strips attachments from emails. I'll get a file request link set up later today.

So your mzML file does not list a <selectedIonList> element, just an isolation window and an activation. It makes sense, given that your isolation window is immense, but the way I wrote things. I'll have to go about breaking this up downstream.

In the mean time, you can create a fake precursor:

import ms_deisotope
from ms_deisotope.data_source import PrecursorInformation, ChargeNotProvided

def make_fake_precursor(scan):
    source = scan.source
    isolation_window = scan.isolation_window
    pinfo = PrecursorInformation(
        isolation_window.target, 0, ChargeNotProvided, source=source, product_scan_id=scan.id)
    scan.precursor_information = pinfo
    return scan
mobiusklein commented 5 years ago

Please upload the problematic mzML file here: https://www.dropbox.com/request/b36TB6MmPnb7lHcJhaQv

mobiusklein commented 5 years ago

I've received your file. I'll get to work fixing the problem. I assumed that all precursors would have selected ions, but this is not true. I treated precursor_information as if it were synonymous with selected ion, so I'll have to decouple that idea, which may mean changing psims too. Shouldn't take more than a day or two to make all the required changes.

Did the fake precursor workaround get you past the problem?

JeffEdge commented 5 years ago

Nice, yes, this works: I do not get error messages. Thanks a lot for the changes this will be really helpful!

mobiusklein commented 5 years ago

I've pushed commits to ms_deisotope and psims that should have fixed the problem. I was able to read the file back in using both ms_deisotope and pyopenms, though I think I need to upgrade pyopenms to be able to read arrays other than m/z and intensity.

JeffEdge commented 5 years ago

Using the updated modules, Error is:

Windows fatal exception: access violation

Current thread 0x00000100 (most recent call first):
  File "C:\...\ms-deisotope\ms_deisotope\deconvolution\exhaustive.py", line 904 in deconvolute
  File "C:\...\ms-deisotope\ms_deisotope\deconvolution\api.py", line 139 in deconvolute_peaks
  File "C:\...\ms-deisotope\ms_deisotope\data_source\scan\scan.py", line 664 in deconvolute
  File "C:/.../ms-deisotope/test04c.py", line 70 in <module>

am I doing something wrong?

In the meantime I'll continue using def make_fake_precursor(scan): to move forward with your def decode_envelopes(array):

If you find a way to generate a deconvoluted spectrum as mzML format (MH+) I would be delighted! Thank you

mobiusklein commented 5 years ago

That error message looks like a segfault is happening in the C-extensions related to solution graph construction and traversal in populate_graph. Unfortunately, that function is large and complex, so I can't immediately tell where in there the error is occurring.

Are you using the same mzML file you sent me? Did you change any of the parameters, or adjust the scan's peak_set attribute in any way? If the file is different, I will probably need to see it to debug the problem, I think the file upload link is still good.

By MH+, do you mean you want all charge states to be converted to 1+, but not merged? Do you want the envelopes array to be left as-is, or also have its charge adjusted?

JeffEdge commented 5 years ago

Yes, I am using exactly the same input file, no parameter changed. I just commented out the "def make_fake_precursor(scan):" part in my script, that "solved" the issue with the previous version.

Leaving it in generates the same error.

By MH+ I mean all charge states to be converted to 1+ with their envelopes charge adjusted (converted to 1+) and the envelopes merged into a single mzML file. The goal would be to have a mzML file corresponding to a spectrum with all the ions being 1+. Basically the information that the signal is split in envelopes would be lost.

In other words a single mzml file with only MH+ ions, the spectrum described only by the two lines: m/z array - The monoisotopic m/z of each deconvoluted peak, given by their neutral mass and charge state intensity array - The sum of the intensity of all isotopic peaks underlying each deconvoluted peak

mobiusklein commented 5 years ago

Okay. Sounds like there might actually be a linking/loading issue then. Could you please completely uninstall ms_deisotope (pip uninstall ms_deisotope until it can't find it) and re-install it from source?

I'll add a convenience function to transform a DeconvolutedPeak with charge state z and neutral mass m into a DeconvolutedPeak with charge state 1 and neutral mass m, updating derived attributes, and a separate function to create a new PeakSet which contains only isotopic peaks matched from DeconvolutedPeakSet.

JeffEdge commented 5 years ago

Sorry the last two lines should read m/z array - all the isotopic m/z of each charge deconvoluted peak, given by m/z corresponding to the charge state =1 intensity array - The intensities corresponding to each isotopic peaks underlying each charge deconvoluted distribution

JeffEdge commented 5 years ago

After completely removing ms-deisotope, psims, and ms-peak-picker and reinstalling all three from source (see package list below), it works if I use def make_fake_precursor(scan): ...

If I omit this part I get the follwing error:

Traceback (most recent call last):
  File ".\test04c.py", line 88, in <module>
    writer.save_scan(scan)
  File "c:\...\ms_deisotope\ms_deisotope\output\mzml.py", line 828, in save_scan
    if scan.precursor_information:
  File "c:\...\ms_deisotope\ms_deisotope\data_source\scan\scan.py", line 351, in precursor_information
    self._data)
  File "c:\...\ms_deisotope\ms_deisotope\data_source\mzml.py", line 127, in _precursor_information
    pinfo_dict = self._get_selected_ion(scan)
  File "c:\...\ms_deisotope\ms_deisotope\data_source\mzml.py", line 108, in _get_selected_ion
    pinfo_dict = scan["precursorList"]['precursor'][0]["selectedIonList"]['selectedIon'][0]
KeyError: 'selectedIonList'

The package list used is:

Package                     Version   Location
--------------------------- --------- ----------------------------------------------------------------
attrs                       19.1.0
brain-isotopic-distribution 1.5.2
certifi                     2019.6.16
chardet                     3.0.4
comtypes                    1.1.7
cycler                      0.10.0
Cython                      0.29.12
decorator                   4.4.0
dill                        0.3.0
idna                        2.8
ipython-genutils            0.2.0
jsonschema                  3.0.1
jupyter-core                4.5.0
kiwisolver                  1.1.0
lxml                        4.3.4
matplotlib                  3.1.1
ms-deisotope                0.0.9     c:\...\ms_deisotope
ms-peak-picker              0.1.25    c:\...\ms_peak_picker
nbformat                    4.4.0
numpy                       1.16.4
pip                         19.2.1
plotly                      4.0.0
psims                       0.1.28    c:\...\psims
pymzml                      2.2.5
pynumpress                  0.0.5
pyparsing                   2.4.0
pyrsistent                  0.15.3
pyteomics                   4.1.2
python-dateutil             2.8.0
python-idzip                0.3.5
pythonnet                   2.4.0
pytz                        2019.1
regex                       2019.6.8
requests                    2.22.0
retrying                    1.3.3
scipy                       1.3.0
setuptools                  41.0.1
six                         1.12.0
SQLAlchemy                  1.3.6
traitlets                   4.3.2
urllib3                     1.25.3

Hopes this helps?

mobiusklein commented 5 years ago

That does help, thank you. This means the bug is in a totally different part of the code and doesn't need to be recompiled every time I make a change. I should be able to get to this some time tonight.

JeffEdge commented 5 years ago

Thank you, much appreciated!

mobiusklein commented 5 years ago

It looks like the error you're encountering was fixed in b4a3312. Do you still have the problem if you pull in the latest commits from master?

JeffEdge commented 5 years ago

It is improving but I still get errors (not using the fake approach) ms-deisotope 0.0.9 c:...\ms_deisotope

c:\...\ms_deisotope\ms_deisotope\data_source\mzml.py:116: UserWarning: No selected ions were found for precursor
  warnings.warn("No selected ions were found for precursor")
Traceback (most recent call last):
  File ".\test04c.py", line 88, in <module>
    writer.save_scan(scan)
  File "c:\...\ms_deisotope\ms_deisotope\output\mzml.py", line 861, in save_scan
    encoding=self.data_encoding)
  File "c:\...\psims\psims\mzml\writer.py", line 548, in write_spectrum
    intensity_unit=intensity_unit)
  File "c:\....\psims\psims\mzml\writer.py", line 510, in spectrum
    precursor_information, intensity_unit=intensity_unit)
  File "c:\...\psims\psims\mzml\writer.py", line 657, in _prepare_precursor_list
    intensity_unit=intensity_unit, **precursors)])
TypeError: _prepare_precursor_information() missing 1 required positional argument: 'intensity'
mobiusklein commented 5 years ago

Did you update psims? I made the selectedIon-related parameters optional in psims/b6e34a1bad

JeffEdge commented 5 years ago

After updating psims it works! thank you!

Just for info, warnings are: c:...\psims\psims\document.py:735: AmbiguousTermWarning: Multiple unit options are possible for parameter 'accuracy' but none were specified self.write_params(xml_file) c:...\ms_deisotope\ms_deisotope\data_source\mzml.py:116: UserWarning: No selected ions were found for precursor warnings.warn("No selected ions were found for precursor")

mobiusklein commented 5 years ago

Thank you for debugging that with me.

The warning about accuracy refers to the <cvParam /> with the name "accuracy" in your instrumentConfiguration, which I don't think belongs there. Also, all of your detectors have a TOF path length parameter, which doesn't make sense for an Orbitrap instrument. I think one of your upstream tools added those, and when ms_deisotope copies them into the new mzML file, psims complains that it isn't complete.

To achieve your requested isotopic pattern-reduced centroided scan, the following snippet should do:

import ms_deisotope
from ms_deisotope.output import MzMLSerializer
from ms_peak_picker import simple_peak, PeakSet
...
scan = get_scan()
duplicate = scan.copy()
scan.pick_peaks().deconvolute(...)
isotopic_peaks = []
for peak in scan.deconvoluted_peak_set:
    for point in peak.envelope:
        mass = ms_deisotope.neutral_mass(point.mz, peak.charge)
        mz = ms_deisotope.mass_charge_ratio(mass, 1)
        isotopic_peaks.append(simple_peak(mz, point.intensity)
isotopic_peaks = PeakSet(isotopic_peaks)
isotopic_peaks.reindex()
duplicate.peak_set = isotopic_peaks
...
writer = MzMLSerializer(...)
with writer:
    ...
    writer.save(duplicate, deconvoluted=False)

The deconvoluted=False parameter of writer.save tells the MzMLSerializer that it should look at the peak_set and not the deconvoluted_peak_set attribute when getting the peak list to write.

JeffEdge commented 5 years ago

Thank you for the snippet. A few questions: The is no need to update the modules as the last commit was 3 days ago. Correct? If I use:

import ms_deisotope
from ms_deisotope.test.common import datafile
from ms_deisotope.output.mzml import MzMLSerializer
from ms_peak_picker import simple_peak, PeakSet
from ms_deisotope.data_source import PrecursorInformation, ChargeNotProvided

reader = ms_deisotope.MSFileLoader(datafile("../../../../20190116_EMR1_22h02_Com0-300_part3.mzML"))
scan = next(reader)

#scan = get_scan() # I have not found a method called get_scan (there is one by index though)
duplicate = scan.copy()
scan.pick_peaks().deconvolute(averagine=ms_deisotope.peptide, scorer=ms_deisotope.PenalizedMSDeconVFitter(20., 2.0),
        truncate_after=0.9, ignore_below=0.0, charge_range=(1, 13))
isotopic_peaks = []
for peak in scan.deconvoluted_peak_set:
    for point in peak.envelope:
        mass = ms_deisotope.neutral_mass(point.mz, peak.charge)
        mz = ms_deisotope.mass_charge_ratio(mass, 1)
        isotopic_peaks.append(simple_peak(mz, point.intensity))
isotopic_peaks = PeakSet(isotopic_peaks)
isotopic_peaks.reindex()
duplicate.peak_set = isotopic_peaks

""" output to file """
with open("Output_deconvoluted_b.mzML", 'wb') as fh:
    writer = MzMLSerializer(fh, n_spectra=len(reader))
    writer.copy_metadata_from(reader)
    with writer:
        writer.save(duplicate, deconvoluted=False)
    writer.close()

I get:```

Traceback (most recent call last): File ".\test06b.py", line 34, in writer.save(duplicate, deconvoluted=False) File "c:...\ms_deisotope\ms_deisotope\output\common.py", line 67, in save self.save_scan(bunch, **kwargs) File "c:...\ms_deisotope\ms_deisotope\output\mzml.py", line 856, in save_scan other_arrays=self._prepare_extra_arrays(scan), File "c:...\ms_deisotope\ms_deisotope\output\mzml.py", line 757, in _prepare_extra_arrays peak.score for peak in scan.deconvoluted_peak_set TypeError: 'NoneType' object is not iterable


An suggestion about get_scan? and 'NoneType' object is not iterable ?
Do I need to update? is there an import missing?
Thank you!
mobiusklein commented 5 years ago

Sorry. I apparently missed a code path controlled by the deconvoluted flag. To make it work for you right now, when instantiating MzMLSerializer, pass it deconvoluted=False. This will make it skip building those extra arrays.

The deconvoluted flag on the object controls other facets of how it would construct a <dataProcessing> element, but this snippet doesn't call the relevant functions to add that anyway. The keyword argument on save was supposed to make it possible to decouple the two parts.

JeffEdge commented 5 years ago

Fantastic the file in output contains what I am looking for. I can work with that! There is still an issue with close though:

Traceback (most recent call last):
  File ".\test06b.py", line 35, in <module>
    writer.close()
  File "c:\...\ms_deisotope\ms_deisotope\output\mzml.py", line 1004, in close
    self.complete()
  File "c:\...\ms_deisotope\ms_deisotope\output\mzml.py", line 974, in complete
    self._spectrum_list_tag.__exit__(None, None, None)
  File "c:\...\psims\psims\mzml\writer.py", line 72, in __exit__
    self.writer.flush()
  File "c:\...\psims\psims\xml.py", line 911, in flush
    self.writer.flush()
  File "src\lxml\serializer.pxi", line 1242, in lxml.etree._IncrementalFileWriter.flush
AssertionError

This is not critical but if you have time to give it a look that would help making the code more complex :-)

mobiusklein commented 5 years ago

I must have read your earlier post in a hurry because I missed half of it.

get_scan was meant to be "do whatever it is you do to get the Scan object you want", so that I didn't have to type out opening an imaginary file and getting a particular scan.

I saw you calling datafile. That's not necessary. datafile is a convenience function for testing that automatically resolves the path to that file in ms_deistope/test/test_data/ given a file name. It has no practical use in real code.

You have a double-close in your mzML writing code. The MzMLSerializer class, like other file writers, can be used as a context manager that will close the file on __exit__. You shouldn't call close if you used with.

JeffEdge commented 5 years ago

Thank you I will try that! It may take a week though as I am abroad.


From: Joshua Klein notifications@github.com Sent: Saturday, 27 July 2019 00:46:37 To: mobiusklein/ms_deisotope ms_deisotope@noreply.github.com Cc: Greisch, J. (Jean-Francois) j.greisch@uu.nl; Author author@noreply.github.com Subject: Re: [mobiusklein/ms_deisotope] Exporting deconvoluted peak lists from a standalone MS2 scan (#13)

I must have read your earlier post in a hurry because I missed half of it.

get_scan was meant to be "do whatever it is you do to get the Scan object you want", so that I didn't have to type out opening an imaginary file and getting a particular scan.

I saw you calling datafile. That's not necessary. datafile is a convenience function for testing that automatically resolves the path to that file in ms_deistope/test/test_data/ given a file name. It has no practical use in real code.

You have a double-close in your mzML writing code. The MzMLSerializer class, like other file writers, can be used as a context manager that will close the file on exit. You shouldn't call close if you used with.

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHubhttps://github.com/mobiusklein/ms_deisotope/issues/13?email_source=notifications&email_token=AMVVYNPQQNA4JJACBEJVYI3QBN5E3A5CNFSM4IFW2YA2YY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOD254CJA#issuecomment-515621156, or mute the threadhttps://github.com/notifications/unsubscribe-auth/AMVVYNLYPMVQIY7D6JEJDWDQBN5E3ANCNFSM4IFW2YAQ.

mobiusklein commented 5 years ago

Understood. Thank you for your patience during the debugging process.

mobiusklein commented 5 years ago

Just checking in to see if this issue was resolved. Please let me know if you ran into any other issues or if we were able to solve your problem.

JeffEdge commented 5 years ago

I am in the final stages of checking ☺ I will get back to you by the end of the week.

mobiusklein commented 5 years ago

Great. Thank you. Hopefully it works.

JeffEdge commented 5 years ago

As far as I can judge, it works perfect! Thank you very much!

mobiusklein commented 5 years ago

Is this in the deconvolution result or after the extra step to remove the charge state? An example would be helpful.

On Mon, Aug 26, 2019 at 12:30 PM JeffEdge notifications@github.com wrote:

Closed #13 https://github.com/mobiusklein/ms_deisotope/issues/13.

— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/mobiusklein/ms_deisotope/issues/13?email_source=notifications&email_token=AAK4E6NEXRT2KAHCAGBLWCLQGQAI5A5CNFSM4IFW2YA2YY3PNVWWK3TUL52HS4DFWZEXG43VMVCXMZLOORHG65DJMZUWGYLUNFXW5KTDN5WW2ZLOORPWSZGOTIEEJOQ#event-2584233146, or mute the thread https://github.com/notifications/unsubscribe-auth/AAK4E6JWWCUIPQP5VXN432DQGQAI5ANCNFSM4IFW2YAQ .

JeffEdge commented 5 years ago

Sorry, I removed the comment as I now believe it to be related to noise or a misidentified charge state. Usually I perform a baseline subtraction. In a few cases this leaves me with a small area where the deconvolution identifies two overlapping isotopic distributions. Although I had this for several spectra, I now believe it to be an artefact (possibly related to a higher charge state) Should I be wrong and occurrences appear for intense peaks I will open a new call. My solution for this is currently to exclude overlapping distributions in the output but I am not sure this is the best way to proceed. Thank you.

From: Joshua Klein notifications@github.com Sent: Tuesday, August 27, 2019 12:15 AM To: mobiusklein/ms_deisotope ms_deisotope@noreply.github.com Cc: Greisch, J. (Jean-Francois) j.greisch@uu.nl; State change state_change@noreply.github.com Subject: Re: [mobiusklein/ms_deisotope] Exporting deconvoluted peak lists from a standalone MS2 scan (#13)

Is this in the deconvolution result or after the extra step to remove the charge state? An example would be helpful.

On Mon, Aug 26, 2019 at 12:30 PM JeffEdge notifications@github.com<mailto:notifications@github.com> wrote:

Closed #13 https://github.com/mobiusklein/ms_deisotope/issues/13.

— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/mobiusklein/ms_deisotope/issues/13?email_source=notifications&email_token=AAK4E6NEXRT2KAHCAGBLWCLQGQAI5A5CNFSM4IFW2YA2YY3PNVWWK3TUL52HS4DFWZEXG43VMVCXMZLOORHG65DJMZUWGYLUNFXW5KTDN5WW2ZLOORPWSZGOTIEEJOQ#event-2584233146, or mute the thread https://github.com/notifications/unsubscribe-auth/AAK4E6JWWCUIPQP5VXN432DQGQAI5ANCNFSM4IFW2YAQ .

— You are receiving this because you modified the open/close state. Reply to this email directly, view it on GitHubhttps://github.com/mobiusklein/ms_deisotope/issues/13?email_source=notifications&email_token=AMVVYNOOGEDT2BIDTBIZML3QGRIVJA5CNFSM4IFW2YA2YY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOD5F3CHQ#issuecomment-525054238, or mute the threadhttps://github.com/notifications/unsubscribe-auth/AMVVYNME75UGLVVEO4RUVM3QGRIVJANCNFSM4IFW2YAQ.