Migrating to 5.0¶
tdfpy 5.0 cleans up the public API in one release. None of the renamed names keep an alias, and everything deprecated in 4.x is gone. The table below lists every rename; the sections after it cover changes of type or behaviour.
Renamed¶
| 4.x | 5.0 |
|---|---|
Frame.time, PrmTarget.time |
.rt |
PrmTarget.one_over_k0 |
PrmTarget.ook0 |
Frame.mz_calibration |
Frame.mz_calibration_id |
Frame.tims_calibration |
Frame.tims_calibration_id |
Frame.property_group |
Frame.property_group_id |
Precursor.parent_frame |
Precursor.parent_frame_id |
PasefFrameMsmsInfo.precursor |
PasefFrameMsmsInfo.precursor_id |
DiaWindowGroup.window_group, DiaWindow.window_group |
.window_group_id |
Frame.peaks, DiaWindow.peaks, PrmTransition.peaks (property) |
.scan_peaks() (method) |
Precursor.peaks, PasefFrameMsmsInfo.peaks (property) |
.merged_peaks() (method) |
Precursor.pasef_peaks (property) |
Precursor.pasef_merged_peaks() (method) |
FrameMetadata.time |
FrameMetadata.rt |
FrameMetadata.mz_calibration, tims_calibration, property_group |
*_id |
DiaWindowLookup.query(window_group_index=...), .query_range(window_group_index=...) |
window_group= (an id or a DiaWindowGroup) |
MetaData.one_over_k0_acq_range, _lower, _upper |
MetaData.ook0_acq_range, _lower, _upper |
TimsData.indexToMz, mzToIndex |
index_to_mz, mz_to_index |
TimsData.scanNumToOneOverK0, oneOverK0ToScanNum |
scan_num_to_ook0, ook0_to_scan_num |
TimsData.scanNumToVoltage, voltageToScanNum |
scan_num_to_voltage, voltage_to_scan_num |
TimsData.readScans |
TimsData.read_scans |
tdfpy.timsdata.oneOverK0ToCCSforMz |
tdfpy.ook0_to_ccs |
mz_tolerance_type= (merge_peaks, get_mobility_collapsed_spectrum, MergePeaksCentroider, PrecursorLookup.query, PrmTargetLookup.query) |
mz_tolerance_unit= (same values, "da" / "ppm") |
im_tolerance_type= (merge_peaks, MergePeaksCentroider) |
im_tolerance_unit= (same values, "relative" / "absolute") |
tdfpy.timsdata.ccsToOneOverK0forMz, ccsToOneOverK0ToCCSforMz |
tdfpy.ccs_to_ook0 |
tdfpy.calibration.one_over_k0_to_ccs, ccs_to_one_over_k0 |
ook0_to_ccs, ccs_to_ook0 |
TimsCalibration.scan_to_one_over_k0, one_over_k0_to_scan |
scan_to_ook0, ook0_to_scan |
MCP tool query_dia_windows(window_group=...) |
window_group_id= |
MCP tools query_frames, query_precursors, query_dia_windows, query_prm_targets, query_prm_transitions: rt= |
rt_range= |
MCP query_precursors / query_prm_targets: mz= |
precursor_mz_range= |
MCP query_dia_windows / query_prm_transitions: mz= |
isolation_mz_range= (matched on the isolation center) |
ion_mobility_type= (get_raw_peaks, get_centroided_spectrum, convert, element raw_peaks() / centroid(), iter_window_spectra, plot_centroiding) |
mobility_type= (same values) |
MCP processing.ion_mobility_type |
processing.mobility_type ("ook0" / "voltage") |
MCP query_frames rows: Id, Time, Polarity "+", SummedIntensities, MaxIntensity, MzCalibration, TimsCalibration, PropertyGroup, ... under rows |
frame_id, rt, polarity "positive", total_ion_current, base_peak_intensity, mz_calibration_id, tims_calibration_id, property_group_id, ... (the Frame names) under items |
MCP convert_coordinates frame.polarity, export metadata frames[].polarity: "+" / "-" |
"positive" / "negative" |
MCP server_info units.retention_time |
units.rt |
PasefFrameMsmsInfo.mz_range, DiaWindow.mz_range, PrmTransition.mz_range, Precursor.mz_range |
.isolation_mz_range |
.mz_begin, .mz_end (isolation windows) |
removed: lo, hi = w.isolation_mz_range |
PrmTarget.monoisotopic_mz |
PrmTarget.precursor_mz |
Frame.summed_intensities |
Frame.total_ion_current |
Frame.max_intensity |
Frame.base_peak_intensity |
PrecursorLookup.query_range(mz_range=...), PrmTargetLookup.query_range(mz_range=...) |
precursor_mz_range= |
PrecursorLookup.query(mz=...), PrmTargetLookup.query(mz=...) |
precursor_mz= |
Polarity.POSITIVE, Polarity.NEGATIVE |
"positive", "negative" |
These names match mzmlpy, so code can read both formats with one vocabulary.
Every spectral accessor is now a method, so each call visibly decodes the frame:
| method | returns | cost |
|---|---|---|
scan_peaks() |
a list of (N_i, 2) [m/z, intensity] arrays, one per scan |
decode only |
raw_peaks() |
one (N, 3) [m/z, intensity, 1/K0] array |
decode only |
centroid() |
one (N, 3) array |
decode + 2D centroiding |
merged_peaks() (Precursor, PasefFrameMsmsInfo) |
one (N, 2) array, mobility collapsed |
decode + greedy m/z merge; the slowest, call once |
PasefFrameMsmsInfo now has scan_peaks(), raw_peaks() and centroid() too.
Added¶
ms_levelon frames (1 or 2, frommsms_type) and onPasefFrameMsmsInfo,DiaWindowandPrmTransition(always 2). Those window classes carrymsms_typeas a class constant.Precursor.precursor_mz:monoisotopic_mzwhen known, otherwiselargest_peak_mz.PrecursorLookupmatches on it.reader.ms1.query_range(rt_range=(lo, hi))andreader.ms1.query(rt=, rt_tolerance=).tdfpy.iter_precursor_spectra(dda.precursors)yields(precursor, peaks)withpeaks == precursor.merged_peaks(), decoding each PASEF frame once. Use it instead of looping overmerged_peaks()when you need many precursors.
Removed¶
plot_centroiding(mz_tolerance=, mz_tolerance_type=, im_tolerance=, im_tolerance_type=, min_peaks=, max_peaks=), deprecated in 4.1. Passcentroid=MergePeaksCentroider(...).tdfpy.centroiding.batch_iterator,calculate_nmass,get_tdf_dfandPeak. They were unused helpers, not part of the documented API.DIAMs1Frame.dia_windowsandPRMMs1Frame.prm_transitions. They were always empty. UseDIA.windowsandPRM.transitions.
Changed types and behaviour¶
- Errors. Every tdfpy error subclasses
TdfpyError, which subclassesValueError. A missing id or key raisesTdfpyKeyError(also aKeyError); spectral access after the reader closes raisesReaderClosedError(also aRuntimeError).UnsupportedTdfErrorandUnsupportedCalibrationErrorstill subclassNotImplementedError. SQLite errors fromPandasTdf,convert_table_to_dfandslice_d_folderare raised asTdfpyError(wasRuntimeErroror a rawsqlite3.Error). Handlers for the old built-in types keep working, exceptexcept RuntimeErroraroundconvert_table_to_df. get_acquisition_typereturnsAcquisitionType, aStrEnum, soget_acquisition_type(p) == "DDA"still holds.Frame.msms_typeis aMsMsType(anIntEnum), not a plainint.MsMsType,PolarityandToleranceUnitare exported fromtdfpy.PolarityisLiteral["positive", "negative"](was aStrEnumwith the same values). Everypolarityfield isPolarity | None: aPolaritycolumn value other than+/-givesNoneand one warning per file, andPrecursor.polarityisNonewith a warning when its PASEF frames disagree. Compare with strings:frame.polarity == "positive".FrameMetadata.polarityis still the raw"+"/"-".- Lookup keywords. A
(low, high)tuple is always*_rangeand goes toquery_range; a point isrt=/precursor_mz=/ook0=plus a*_toleranceand goes toquery, as in mzmlpy 0.10.query(mz=...)is nowquery(precursor_mz=...)and the range isprecursor_mz_range=;mz_tolerance_typeis nowmz_tolerance_unit(see the table). - MS1 centroids.
MergePeaksCentroidernow sorts on the integer TOF index before converting to m/z, andmerge_peaksorders its input by m/z, then descending 1/K0 (TOF, then scan), then intensity, and seeds equal-intensity peaks in that order with a stable sort, so the result does not depend on input order even when many points share one m/z. About 1.2-1.4% of centroids on dense MS1 frames differ from 4.x (1.43% diaPASEF, 1.16% DDA, 15-min runs); summed intensity moves by under 0.02%.merged_peaks()is unchanged. - Elements are frozen, slotted and keyword-only. Assigning to a field raises
FrozenInstanceError; constructing one needs keyword arguments.PrmTargetequality and hashing ignoretransitions. - Lookups.
dia.windows[group_id]andprm.transitions[target_id]return a tuple (was a list).DIA.window_groupsis a tuple (was a generator). Every lookup hasids(), supportsid in lookup, andget(id, default). The arguments ofquery()andquery_range()are keyword-only. MetaDataandCalibrationare read-onlyMappings of key to value. Thedfpandas Series field is replaced bytable, a plain mapping. Usedict(metadata)orpd.Series(metadata)if you need a copy.plot_centroidingtakes every argument afterframe_idby keyword, includingmobility_type.- Mobility ranges are
(low, high).ook0_range,ccs_rangeandvoltage_range(and their*_begin/*_end) onPasefFrameMsmsInfo,Precursor,DiaWindowandPrmTransitionused to follow scan order, which is high-to-low 1/K0. They now matchisolation_mz_range,ook0_acq_rangeandquery_range(ook0_range=). Code that swapped them by hand must stop. - Wrong reader for the file.
DDAon a DIA run (or any other mismatch) raisesAcquisitionTypeError. Check first withtdfpy.get_acquisition_type(path). - Closed readers. After the
withblock,reader.timsdata,metadata,calibrationandpandas_tdfraiseReaderClosedError, like the spectral accessors. Read what you need inside the block. AcquisitionType.UNKNOWNis"unknown"(was"Unknown").TimsDatatakes its options by keyword:TimsData(path, use_recalibrated_state=True).FrameMetadatais exported fromtdfpyand its fields followFrame(rt,*_id).TimsData.read_scansandread_frame_arraysraiseTdfpyErrorfor a non-integer bound or a range outside0 <= scan_begin <= scan_end <= num_scans.read_scanspadded with empty arrays andread_frame_arraysclamped; an empty range (begin == end) is valid and reads nothing.- Window accessors (
scan_peaks,raw_peaks,centroid,merged_peaks) raiseTdfpyErrorwhen a window's scan range does not fit its frame, instead of clamping.
Downstream code¶
# 4.x
frame.time, target.one_over_k0, metadata.one_over_k0_acq_range
td.scanNumToOneOverK0(frame_id, scans)
from tdfpy.timsdata import oneOverK0ToCCSforMz
ms2 = precursor.peaks
lo, hi = window.mz_begin, window.mz_end
dda.precursors.query_range(mz_range=(500, 600))
frame.summed_intensities, target.monoisotopic_mz
frame.polarity == Polarity.POSITIVE
# 5.0
frame.rt, target.ook0, metadata.ook0_acq_range
td.scan_num_to_ook0(frame_id, scans)
from tdfpy import ook0_to_ccs
ms2 = precursor.merged_peaks()
lo, hi = window.isolation_mz_range
dda.precursors.query_range(precursor_mz_range=(500, 600))
frame.total_ion_current, target.precursor_mz
frame.polarity == "positive"