Showcase: isocor Python package

[1]:
import isocor

The correction of a measurement vector starts by instantiating a metabolite-specific corrector object and calling its .correct() method.

Instantiation of a corrector

We recommend that you use MetaboliteCorrectorFactory to choose the best correction strategy depending on your resolution:

[2]:
corrector = isocor.mscorrectors.MetaboliteCorrectorFactory("C3PO", tracer="13C")
corrector_HR = isocor.mscorrectors.MetaboliteCorrectorFactory("C3PO", tracer="13C", resolution=1e4, mz_of_resolution=400, charge=1)
[3]:
corrector
[3]:
<isocor.mscorrectors.LowResMetaboliteCorrector at 0x7f2eb49e0670>
[4]:
corrector_HR
[4]:
<isocor.mscorrectors.HighResMetaboliteCorrector at 0x7f2eb49e0640>

Watch out for default parameters!

You should pay attention to the default parameters of MetaboliteCorrectorFactory, such as the mass and natural abundance stored for each isotope, the formula used to interpret the resolution, etc.

[5]:
corrector.data_isotopes
[5]:
{'C': {'abundance': [0.9893, 0.0107],
  'mass': [Decimal('12.0'), Decimal('13.003354835')]},
 'H': {'abundance': [0.999885, 0.000115],
  'mass': [Decimal('1.0078250322'), Decimal('2.0141017781')]},
 'N': {'abundance': [0.99636, 0.00364],
  'mass': [Decimal('14.003074004'), Decimal('15.000108899')]},
 'P': {'abundance': [1.0], 'mass': [Decimal('30.973761998')]},
 'O': {'abundance': [0.99757, 0.00038, 0.00205],
  'mass': [Decimal('15.99491462'),
   Decimal('16.999131757'),
   Decimal('17.999159613')]},
 'S': {'abundance': [0.9499, 0.0075, 0.0425, 0.0, 0.0001],
  'mass': [Decimal('31.972071174'),
   Decimal('32.971458910'),
   Decimal('33.9678670'),
   Decimal('35.0'),
   Decimal('35.967081')]},
 'Si': {'abundance': [0.92223, 0.04685, 0.03092],
  'mass': [Decimal('27.976926535'),
   Decimal('28.976494665'),
   Decimal('29.9737701')]}}
[6]:
corrector.tracer_purity  # perfect purity: [0% of 12C, 100% of 13C]
[6]:
[0.0, 1.0]

Direct instantiation

If you don’t want to use the factory or want to create your own corrector, you can use LowResMetaboliteCorrector and HighResMetaboliteCorrector directly for respectively low and high resolution data.

But keep in mind that we do not use the same algorithm at low and high resolution.

[7]:
corrector_LR  = isocor.mscorrectors.LowResMetaboliteCorrector(formula="C3PO", tracer="13C",
                                                              derivative_formula=None,
                                                              tracer_purity=[0.0, 1.0],
                                                              data_isotopes=isocor.mscorrectors.LowResMetaboliteCorrector.DEFAULT_ISODATA,
                                                              correct_NA_tracer= False)
corrector_LR
[7]:
<isocor.mscorrectors.LowResMetaboliteCorrector at 0x7f2eb49e0fa0>

Correction of a measurement vector

The correction is performed on a vector of measurements through the .correct() method:

[8]:
corrected_area, iso_fraction, res, m_enr = corrector.correct([0., 4000., 200., 0.])
corrected_area
[8]:
array([1.30186754e-05, 4.00972659e+03, 1.98956608e+02, 0.00000000e+00])

In addition of the corrected area, .correct() returns:

  • isotopologue_fraction, that is the abundance of each tracer isotopologue (corrected area normalized to 1)

  • residuum

  • mean enrichment

One corrector can safely be re-used for other measurements vectors (given that it is the same metabolite/derivative/parameters), for instance in another sample:

[9]:
corrector.correct([0., 4000, 2000, 1000])
[9]:
(array([1.16470462e-11, 4.00974368e+03, 2.00334442e+03, 9.93432796e+02]),
 [1.6623152066774086e-15,
  0.5722874070659756,
  0.2859257045808499,
  0.14178688835317282],
 [-1.6598205588440532e-15,
  1.9489172180848461e-16,
  -8.120488408686859e-16,
  7.633259104165648e-16],
 0.523166493762398)

Empty vectors will give:

[10]:
corrector.correct([0., 0., 0., 0.])
[10]:
(array([0., 0., 0., 0.]), [nan, nan, nan, nan], [nan, nan, nan, nan], nan)

IsoCor check the inputs you provide and warn you if you did something unexpected:

[11]:
try:
    corrector.correct([0., 0., 0.])  # our corrector was defined for a C3, so we expect 4 "peaks" (n+1)
except Exception as e:
    print(e.__class__, e)
<class 'ValueError'> The length of the measured isotopic cluster (3) is different than the required number of measurements: 4 (i.e. N + 1, where N is the number of atoms that could be traced)

Readable attributes

Everything is accessible from the corrector.

[12]:
corrector.formula
[12]:
Counter({'C': 3, 'P': 1, 'O': 1})

The correction matrix is always available (computed on-the-fly at first access):

[13]:
corrector.correction_matrix
[13]:
array([[9.9757e-01, 0.0000e+00, 0.0000e+00, 0.0000e+00],
       [3.8000e-04, 9.9757e-01, 0.0000e+00, 0.0000e+00],
       [2.0500e-03, 3.8000e-04, 9.9757e-01, 0.0000e+00],
       [0.0000e+00, 2.0500e-03, 3.8000e-04, 9.9757e-01]])
[14]:
corrector_HR.correction_matrix
[14]:
array([[9.9757e-01, 0.0000e+00, 0.0000e+00, 0.0000e+00],
       [3.8000e-04, 9.9757e-01, 0.0000e+00, 0.0000e+00],
       [0.0000e+00, 3.8000e-04, 9.9757e-01, 0.0000e+00],
       [0.0000e+00, 0.0000e+00, 3.8000e-04, 9.9757e-01]])

Of course, other attributes and parameters are available too:

[15]:
corrector.molecular_weight
[15]:
Decimal('82.968676618')
[16]:
corrector.correct_NA_tracer
[16]:
False

The correction matrix is unique to a corrector object. You should never have to set or reset the correction matrix yourself.

If you need a new correction matrix, you should re-instanciate a new corrector object. IsoCor forbids you to change directly the correction matrix:

[17]:
try:
    corrector.correction_matrix = [45]
except Exception as e:
    print(e.__class__, e)
<class 'AttributeError'> can't set attribute

In the same vein, you should never change parameters of the corrector at runtime. IsoCor might even forbid you to do so:

[18]:
try:
    corrector.formula = {'H': 2, 'O': 1}
except Exception as e:
    print(e.__class__, e)
<class 'AttributeError'> can't set attribute

As a rule of thumbs, always instantiate a new corrector if anything else than the measurement vector changed in your analysis.

Catch the logs

You can use logging to catch the logs. By default, logs go to the stderr (that is printed in Jupyter notebooks):

[19]:
import logging

logging.basicConfig(format='%(asctime)s - %(levelname)s - %(message)s', datefmt='%H:%M', level=logging.DEBUG)
[20]:
# Let's do something silly
isocor.MetaboliteCorrectorFactory("C3PO", '13C', resolution=0.1, mz_of_resolution= 400, charge=1)
15:46 - DEBUG - MetaboliteCorrectorFactory chose to use a HighResMetaboliteCorrector for C3PO.
15:46 - WARNING - Improper usage of HighResMetaboliteCorrector by MetaboliteCorrectorFactory. Falling back to LowResMetaboliteCorrector. Reason: The correction limit is expected to be sufficent to distinguish peaks with a delta-mass of 1 amu (627.2625176486116>0.5).
15:46 - DEBUG - New LowResMetaboliteCorrector, C3PO||13C: [('_data_isotopes', {'C': {'abundance': [0.9893, 0.0107], 'mass': [Decimal('12.0'), Decimal('13.003354835')]}, 'H': {'abundance': [0.999885, 0.000115], 'mass': [Decimal('1.0078250322'), Decimal('2.0141017781')]}, 'N': {'abundance': [0.99636, 0.00364], 'mass': [Decimal('14.003074004'), Decimal('15.000108899')]}, 'P': {'abundance': [1.0], 'mass': [Decimal('30.973761998')]}, 'O': {'abundance': [0.99757, 0.00038, 0.00205], 'mass': [Decimal('15.99491462'), Decimal('16.999131757'), Decimal('17.999159613')]}, 'S': {'abundance': [0.9499, 0.0075, 0.0425, 0.0, 0.0001], 'mass': [Decimal('31.972071174'), Decimal('32.971458910'), Decimal('33.9678670'), Decimal('35.0'), Decimal('35.967081')]}, 'Si': {'abundance': [0.92223, 0.04685, 0.03092], 'mass': [Decimal('27.976926535'), Decimal('28.976494665'), Decimal('29.9737701')]}}), ('_molecular_weight', None), ('_tracer_purity', [0.0, 1.0]), ('_correct_NA_tracer', False), ('_formula', Counter({'C': 3, 'P': 1, 'O': 1})), ('_inchi', ''), ('_isotopic_inchi', None), ('_derivative_formula', None), ('_correction_formula', None), ('_mzshift_tracer', None), ('_str_formula', 'C3PO'), ('_str_derivative_formula', ''), ('_str_tracer_code', '13C'), ('_charge', None), ('_tracer_el', 'C'), ('_idx_tracer', 1), ('label', 'C3PO||13C'), ('_correction_matrix', None)].
15:46 - DEBUG - C3PO||13C additionally uses: []
[20]:
<isocor.mscorrectors.LowResMetaboliteCorrector at 0x7f2eb49e0bb0>
[21]:
# it is forbidden to half-define a isocorrector
try:
    isocor.MetaboliteCorrectorFactory("C3PO", '13C', mz_of_resolution= 400, charge=1)
except Exception as e:
    print(e.__class__, e)
15:46 - ERROR - MetaboliteCorrectorFactory was unable to select a correction strategy. Please check your inputs.
<class 'ValueError'> MetaboliteCorrectorFactory was unable to select a correction strategy. Please check your inputs.