Skip to content

cylindra_builtins.relion

This built-in plugin submodule provides functions to work with RELION file formats.

load_molecules(ui, path)

Read monomer coordinates and angles from RELION .star file.

Parameters:

Name Type Description Default
path path - like

The path to the star file.

required
Source code in cylindra_builtins/relion/io.py
25
26
27
28
29
30
31
32
33
34
35
36
37
38
@register_function(name="Load molecules")
def load_molecules(ui: CylindraMainWidget, path: Path.Read[FileFilter.STAR]):
    """
    Read monomer coordinates and angles from RELION .star file.

    Parameters
    ----------
    path : path-like
        The path to the star file.
    """
    path = Path(path)
    moles = _read_star(path, ui.tomogram.scale)
    for i, mole in enumerate(moles):
        add_molecules(ui.parent_viewer, mole, f"{path.name}-{i}", source=None)

load_splines(ui, path)

Read a star file and register all the tubes as splines.

The "rlnHelicalTubeID" column will be used to group the points into splines.

Parameters:

Name Type Description Default
path path - like

The path to the star file.

required
Source code in cylindra_builtins/relion/io.py
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
@register_function(name="Load splines")
def load_splines(ui: CylindraMainWidget, path: Path.Read[FileFilter.STAR]):
    """
    Read a star file and register all the tubes as splines.

    The "rlnHelicalTubeID" column will be used to group the points into splines.

    Parameters
    ----------
    path : path-like
        The path to the star file.
    """
    mole = Molecules.concat(_read_star(path, ui.tomogram.scale))
    if RELION_TUBE_ID not in mole.features.columns:
        warnings.warn(
            f"{RELION_TUBE_ID!r} not found in star file. Use all points as a "
            "single spline.",
            UserWarning,
            stacklevel=2,
        )
        ui.register_path(mole.pos, err_max=1e-8)
    else:
        for _, each in mole.group_by(RELION_TUBE_ID):
            ui.register_path(each.pos, err_max=1e-8)
    return None

save_molecules(ui, save_path, layers, save_features=True)

Save the selected molecules to a RELION .star file.

If multiple layers are selected, the MoleculeGroupID column will be added to the star file to distinguish the layers.

Parameters:

Name Type Description Default
save_path path - like

The path to save the star file.

required
layers sequence of MoleculesLayer

The layers to save.

required
save_features bool

Whether to save the features of the molecules.

True
Source code in cylindra_builtins/relion/io.py
 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
109
110
111
112
113
114
115
116
117
@register_function(name="Save molecules")
def save_molecules(
    ui: CylindraMainWidget,
    save_path: Path.Save[FileFilter.STAR],
    layers: MoleculesLayersType,
    save_features: bool = True,
):
    """
    Save the selected molecules to a RELION .star file.

    If multiple layers are selected, the `MoleculeGroupID` column will be added
    to the star file to distinguish the layers.

    Parameters
    ----------
    save_path : path-like
        The path to save the star file.
    layers : sequence of MoleculesLayer
        The layers to save.
    save_features : bool, default True
        Whether to save the features of the molecules.
    """
    save_path = Path(save_path)
    layers = assert_list_of_layers(layers, ui.parent_viewer)
    mole = Molecules.concat([layer.molecules for layer in layers])
    euler_angle = mole.euler_angle(seq="ZYZ", degrees=True)
    scale = ui.tomogram.scale

    out_dict = {
        POS_COLUMNS[2]: mole.pos[:, 2] / scale,
        POS_COLUMNS[1]: mole.pos[:, 1] / scale,
        POS_COLUMNS[0]: mole.pos[:, 0] / scale,
        ROT_COLUMNS[0]: euler_angle[:, 0],
        ROT_COLUMNS[1]: euler_angle[:, 1],
        ROT_COLUMNS[2]: euler_angle[:, 2],
        OPTICS_GROUP: np.ones(mole.count(), dtype=np.uint32),
    }
    if len(layers) > 1:
        out_dict[MOLE_ID] = np.concatenate(
            [
                np.full(layer.molecules.count(), i, dtype=np.uint32)
                for i, layer in enumerate(layers)
            ]
        )
    if save_features:
        for col in mole.features.columns:
            out_dict[col] = mole.features[col]
    df = pd.DataFrame(out_dict)
    _write_star(df, save_path, scale)
    return None

save_splines(ui, save_path, interval=10.0)

Save the current splines to a RELION .star file.

Parameters:

Name Type Description Default
save_path path - like

The path to save the star file.

required
interval float

Sampling interval along the splines. For example, if interval=10.0 and the length of a spline is 100.0, 11 points will be sampled.

10.0
Source code in cylindra_builtins/relion/io.py
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
@register_function(name="Save splines")
def save_splines(
    ui: CylindraMainWidget,
    save_path: Path.Save[FileFilter.STAR],
    interval: Annotated[float, {"min": 0.01, "max": 1000.0, "label": "Sampling interval (nm)"}] = 10.0,
):  # fmt: skip
    """
    Save the current splines to a RELION .star file.

    Parameters
    ----------
    save_path : path-like
        The path to save the star file.
    interval : float, default 10.0
        Sampling interval along the splines. For example, if interval=10.0 and the
        length of a spline is 100.0, 11 points will be sampled.
    """

    if interval <= 1e-4:
        raise ValueError("Interval must be larger than 1e-4.")
    save_path = Path(save_path)
    data_list: list[pl.DataFrame] = []
    for i, spl in enumerate(ui.splines):
        num = int(spl.length() / interval)
        coords = spl.partition(num) / ui.tomogram.scale
        df = pl.DataFrame(
            {
                POS_COLUMNS[2]: coords[:, 2],
                POS_COLUMNS[1]: coords[:, 1],
                POS_COLUMNS[0]: coords[:, 0],
                ROT_COLUMNS[0]: 0.0,
                ROT_COLUMNS[1]: 0.0,
                ROT_COLUMNS[2]: 0.0,
                RELION_TUBE_ID: i,
                OPTICS_GROUP: np.ones(coords.shape[0], dtype=np.uint32),
            }
        )
        data_list.append(df)
    df = pl.concat(data_list, how="vertical").to_pandas()
    _write_star(df, save_path, ui.tomogram.scale)
    return None