Skip to content

Instantly share code, notes, and snippets.

@alisterburt
Last active February 4, 2025 18:03
Show Gist options
  • Save alisterburt/55d73dfa9c7513731fc7e34e00610302 to your computer and use it in GitHub Desktop.
Save alisterburt/55d73dfa9c7513731fc7e34e00610302 to your computer and use it in GitHub Desktop.
works on per-tomogram table files and takes corresponding tomostar file name as input
# /// script
# requires-python = ">=3.11"
# dependencies = [
# "dynamotable",
# "pandas",
# "scipy",
# "starfile",
# "typer",
# ]
# [tool.uv]
# exclude-newer = "2025-01-01T00:00:00Z"
# ///
from pathlib import Path
import dynamotable
import pandas as pd
import starfile
import typer
from scipy.spatial.transform import Rotation as R
def cli(
input_table_file: Path = typer.Option(..., '--input', '-i', help='input table file'),
tomostar_file_name: str = typer.Option(..., '--tomostar', '-ts', help='tomostar file name'),
output_star_file: Path = typer.Option(..., '--output', '-o', help='output star file'),
):
# read table file
df = dynamotable.read(input_table_file)
# extract relevant metadata
positions = df[['x', 'y', 'z']].to_numpy()
shifts = df[['dx', 'dy', 'dz']].to_numpy()
dynamo_euler_angles = df[['tdrot', 'tilt', 'narot']].to_numpy()
# convert dynamo euler angles into rotation matrices in which the
# columns are the particle x/y/z vectors in the tomogram
particle_rotation_matrices = R.from_euler(
angles=dynamo_euler_angles, seq='zxz', degrees=True
).inv().as_matrix()
# construct particle metadata for RELION
positions += shifts
relion_euler_angles = R.from_matrix(particle_rotation_matrices).inv().as_euler(
seq='ZYZ', degrees=True
)
# write out RELION style star file compatible with Warp
star_data = {
'rlnCoordinateX': positions[:, 0],
'rlnCoordinateY': positions[:, 1],
'rlnCoordinateZ': positions[:, 2],
'rlnAngleRot': relion_euler_angles[:, 0],
'rlnAngleTilt': relion_euler_angles[:, 1],
'rlnAnglePsi': relion_euler_angles[:, 2],
'rlnMicrographName': [tomostar_file_name] * len(positions),
}
starfile.write(pd.DataFrame(star_data), output_star_file)
if __name__ == "__main__":
app = typer.Typer(add_completion=False)
app.command(no_args_is_help=True)(cli)
app()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment