Skip to content

Utilities

slice_d_folder — Extracting a time range from a .d folder

slice_d_folder creates a smaller, self-contained .d folder from an existing one by keeping only a contiguous range of frames. The output is a fully valid Bruker .d folder: both the SQLite metadata (analysis.tdf) and the binary scan data (analysis.tdf_bin) are rebuilt so that downstream tools — including tdfpy's own readers — can open the result directly.

This is useful for:

  • Creating small test datasets from a large acquisition
  • Isolating a chromatographic peak or retention time window for focused analysis
  • Reducing file size before sharing or archiving

What gets filtered

The slicer keeps all frames whose Id falls within [frame_start, frame_end] (inclusive, 1-based) and removes everything else:

Table Behaviour
Frames Rows outside the range are deleted
PasefFrameMsMsInfo Rows referencing deleted frames are deleted
DiaFrameMsMsInfo Rows referencing deleted frames are deleted
PrmFrameMsMsInfo Rows referencing deleted frames are deleted
Precursors Orphaned rows (parent frame deleted) are removed
DiaFrameMsMsWindows Orphaned window groups are removed
analysis.tdf_bin Rebuilt from scratch — only kept frames' blobs are written

The TimsId offsets in the Frames table are updated to point to the correct positions in the new binary file, so the output can be opened immediately with DDA, DIA, PRM, or any Bruker-compatible tool.

Frame IDs vs retention time

frame_start and frame_end are raw frame IDs (the Id column in the Frames table), not retention times. If you need to slice by time, open the .d folder first and look up frame IDs using dda.ms1 or dia.ms1.

Basic usage

from tdfpy import slice_d_folder

out = slice_d_folder(
    source_dir="experiment.d",
    dest_dir="experiment_slice.d",
    frame_start=100,
    frame_end=300,
)
print(out)  # PosixPath('experiment_slice.d')

The destination directory is created automatically. If it already exists it is overwritten.

Slicing by retention time

Open the source file first to map retention time to frame IDs:

from tdfpy import DDA, slice_d_folder

with DDA("experiment.d") as dda:
    # Find frames within a retention time window (seconds)
    rt_min, rt_max = 600.0, 900.0  # 10 – 15 min
    frame_ids = [
        frame.frame_id
        for frame in dda.ms1
        if rt_min <= frame.time <= rt_max
    ]

first_frame = min(frame_ids)
last_frame = max(frame_ids)

slice_d_folder(
    source_dir="experiment.d",
    dest_dir="experiment_10to15min.d",
    frame_start=first_frame,
    frame_end=last_frame,
)

Opening the result

The sliced folder can be opened with any tdfpy reader exactly like the original:

from tdfpy import DDA

with DDA("experiment_slice.d") as dda:
    for frame in dda.ms1:
        peaks = frame.centroid()
        print(frame.frame_id, len(peaks))

tdfpy.slice_d_folder

slice_d_folder(
    source_dir: str | Path,
    dest_dir: str | Path,
    frame_start: int,
    frame_end: int,
) -> Path

Slice a .d folder to contain only frames in [frame_start, frame_end].

Creates a new .d folder at dest_dir with a filtered SQLite database and a rebuilt binary file containing only the kept frames' data.

Parameters:

Name Type Description Default
source_dir str | Path

Path to the source .d folder.

required
dest_dir str | Path

Path for the output .d folder (must not already exist).

required
frame_start int

First frame ID to keep (inclusive, 1-based).

required
frame_end int

Last frame ID to keep (inclusive, 1-based).

required

Returns:

Type Description
Path

The path to the created .d folder.

Raises:

Type Description
FileNotFoundError

If the source .d folder is missing analysis.tdf or analysis.tdf_bin.

FileExistsError

If dest_dir already exists. This function never overwrites or deletes pre-existing data.

ValueError

If frame_start > frame_end, if dest_dir resolves to the source folder or to a location inside it, if no frames fall in the requested range, or if a kept frame has a NULL TimsId.

Notes

If writing fails part-way through, the partially written destination folder is removed before the error propagates, so a failed slice never leaves a corrupt .d folder behind.

Source code in src/tdfpy/slicer.py
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
def slice_d_folder(
    source_dir: str | Path,
    dest_dir: str | Path,
    frame_start: int,
    frame_end: int,
) -> Path:
    """Slice a .d folder to contain only frames in [frame_start, frame_end].

    Creates a new .d folder at ``dest_dir`` with a filtered SQLite database
    and a rebuilt binary file containing only the kept frames' data.

    Parameters
    ----------
    source_dir : str | Path
        Path to the source .d folder.
    dest_dir : str | Path
        Path for the output .d folder (must not already exist).
    frame_start : int
        First frame ID to keep (inclusive, 1-based).
    frame_end : int
        Last frame ID to keep (inclusive, 1-based).

    Returns
    -------
    Path
        The path to the created .d folder.

    Raises
    ------
    FileNotFoundError
        If the source .d folder is missing ``analysis.tdf`` or
        ``analysis.tdf_bin``.
    FileExistsError
        If ``dest_dir`` already exists. This function never overwrites or
        deletes pre-existing data.
    ValueError
        If ``frame_start > frame_end``, if ``dest_dir`` resolves to the source
        folder or to a location inside it, if no frames fall in the requested
        range, or if a kept frame has a NULL ``TimsId``.

    Notes
    -----
    If writing fails part-way through, the partially written destination
    folder is removed before the error propagates, so a failed slice never
    leaves a corrupt .d folder behind.
    """
    source_dir = Path(source_dir)
    dest_dir = Path(dest_dir)

    _validate_inputs(source_dir, dest_dir, frame_start, frame_end)

    logger.info(
        "Slicing .d folder %s%s, frames [%d, %d] (inclusive).",
        source_dir,
        dest_dir,
        frame_start,
        frame_end,
    )

    dest_dir.mkdir(parents=True)
    try:
        frame_ids = _write_slice(source_dir, dest_dir, frame_start, frame_end)
    except BaseException:
        # Never leave a half-written .d folder behind — it would look valid to
        # a reader but contain truncated binary data.
        logger.warning(
            "slice_d_folder: writing %s failed; removing the partial destination.",
            dest_dir,
        )
        shutil.rmtree(dest_dir, ignore_errors=True)
        raise

    logger.info(
        "slice_d_folder: wrote %s (%d frames, binary rebuilt).",
        dest_dir,
        len(frame_ids),
    )
    return dest_dir