From 6c326082f03e8d2ad1bb4d6cb26367e878138806 Mon Sep 17 00:00:00 2001 From: Lauraschwarz <104347948+Lauraschwarz@users.noreply.github.com> Date: Tue, 22 Oct 2024 20:36:22 +0100 Subject: [PATCH] Add example to convert file formats and changing keypoints (#304) * first draft of example to convert file formats and changing keypoints * second draft to convert and modify pose track files. I split the function into three separate operations. * formatted the code and gotrid of spelling mistakes for the docs * changed outline of code, new functions now handle ds not fpaths and added additional example function to run on fpath * Apply suggestions from code review added Niko's suggestions, implementing comments Co-authored-by: Niko Sirmpilatze * pre-commit changes * corrected import error * pre-commit changes again * get rid of extra underlines * finishing touches * added default thumbnail for examples without plots --------- Co-authored-by: Niko Sirmpilatze --- docs/source/_static/data_icon.png | Bin 0 -> 41099 bytes docs/source/conf.py | 1 + examples/convert_file_formats.py | 231 ++++++++++++++++++++++++++++++ 3 files changed, 232 insertions(+) create mode 100644 docs/source/_static/data_icon.png create mode 100644 examples/convert_file_formats.py diff --git a/docs/source/_static/data_icon.png b/docs/source/_static/data_icon.png new file mode 100644 index 0000000000000000000000000000000000000000..835121ffa412d4e1099eb7da7be593afef9efc43 GIT binary patch literal 41099 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 aVnd$)#a7%Eg&~3$2x(+_zS{8G-G2a_X4>fh literal 0 HcmV?d00001 diff --git a/docs/source/conf.py b/docs/source/conf.py index fda3e86f..42ac0668 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -109,6 +109,7 @@ "dependencies": ["environment.yml"], }, "reference_url": {"movement": None}, + "default_thumb_file": "source/_static/data_icon.png", # default thumbnail image "remove_config_comments": True, # do not render config params set as # sphinx_gallery_config [= value] } diff --git a/examples/convert_file_formats.py b/examples/convert_file_formats.py new file mode 100644 index 00000000..7ee1da6e --- /dev/null +++ b/examples/convert_file_formats.py @@ -0,0 +1,231 @@ +"""Convert pose tracks between file formats +=========================================== + +Load pose tracks from one file format, modify them, +and save them to another file format. +""" + +# %% +# Motivation +# ---------- +# When working with pose estimation data, it's often useful to convert +# between file formats. For example, you may need to +# use some downstream analysis tool that requires a specific file +# format, or expects the keypoints to be named in a certain way. +# +# In the following example, we will load a dataset from a +# SLEAP file, modify the keypoints (rename, delete, reorder), +# and save the modified dataset as a DeepLabCut file. +# +# We'll first walk through each step separately, and then +# combine them into a single function that can be applied +# to multiple files at once. + +# %% +# Imports +# ------- +import tempfile +from pathlib import Path + +from movement import sample_data +from movement.io import load_poses, save_poses + +# %% +# Load the dataset +# ---------------- +# We'll start with the path to a file output by one of +# our :ref:`supported pose estimation frameworks`. +# For example, the path could be something like: + +# uncomment and edit the following line to point to your own local file +# file_path = "/path/to/my/data.h5" + +# %% +# For the sake of this example, we will use the path to one of +# the sample datasets provided with ``movement``. + +file_path = sample_data.fetch_dataset_paths( + "SLEAP_single-mouse_EPM.analysis.h5" +)["poses"] +print(file_path) + +# %% +# Now let's load this file into a +# :ref:`movement poses dataset`, +# which we can then modify to our liking. + +ds = load_poses.from_sleap_file(file_path, fps=30) +print(ds, "\n") +print("Individuals:", ds.coords["individuals"].values) +print("Keypoints:", ds.coords["keypoints"].values) + + +# %% +# .. note:: +# If you're running this code in a Jupyter notebook, +# you can just type ``ds`` (instead of printing it) +# to explore the dataset interactively. + +# %% +# Rename keypoints +# ---------------- +# We start with a dictionary that maps old keypoint names to new ones. +# Next, we define a function that takes that dictionary and a dataset +# as inputs, and returns a modified dataset. Notice that under the hood +# this function calls :meth:`xarray.Dataset.assign_coords`. + +rename_dict = { + "snout": "nose", + "left_ear": "earL", + "right_ear": "earR", + "centre": "middle", + "tail_base": "tailbase", + "tail_end": "tailend", +} + + +def rename_keypoints(ds, rename_dict): + # get the current names of the keypoints + keypoint_names = ds.coords["keypoints"].values + + # rename the keypoints + if not rename_dict: + print("No keypoints to rename. Skipping renaming step.") + else: + new_keypoints = [rename_dict.get(kp, str(kp)) for kp in keypoint_names] + # Assign the modified values back to the Dataset + ds = ds.assign_coords(keypoints=new_keypoints) + return ds + + +# %% +# Let's apply the function to our dataset and see the results. +ds_renamed = rename_keypoints(ds, rename_dict) +print("Keypoints in modified dataset:", ds_renamed.coords["keypoints"].values) + + +# %% +# Delete keypoints +# ----------------- +# Let's create a list of keypoints to delete. +# In this case, we choose to get rid of the ``tailend`` keypoint, +# which is often hard to reliably track. +# We delete it using :meth:`xarray.Dataset.drop_sel`, +# wrapped in an appropriately named function. + +keypoints_to_delete = ["tailend"] + + +def delete_keypoints(ds, delete_keypoints): + if not delete_keypoints: + print("No keypoints to delete. Skipping deleting step.") + else: + # Delete the specified keypoints and their corresponding data + ds = ds.drop_sel(keypoints=delete_keypoints) + return ds + + +ds_deleted = delete_keypoints(ds_renamed, keypoints_to_delete) +print("Keypoints in modified dataset:", ds_deleted.coords["keypoints"].values) + + +# %% +# Reorder keypoints +# ------------------ +# We start with a list of keypoints in the desired order +# (in this case, we'll just swap the order of the left and right ears). +# We then use :meth:`xarray.Dataset.reindex`, wrapped in yet another function. + +ordered_keypoints = ["nose", "earR", "earL", "middle", "tailbase"] + + +def reorder_keypoints(ds, ordered_keypoints): + if not ordered_keypoints: + print("No keypoints to reorder. Skipping reordering step.") + else: + ds = ds.reindex(keypoints=ordered_keypoints) + return ds + + +ds_reordered = reorder_keypoints(ds_deleted, ordered_keypoints) +print( + "Keypoints in modified dataset:", ds_reordered.coords["keypoints"].values +) + +# %% +# Save the modified dataset +# --------------------------- +# Now that we have modified the dataset to our liking, +# let's save it to a .csv file in the DeepLabCut format. +# In this case, we save the file to a temporary +# directory, and we use the same file name +# as the original, but ending in ``_dlc.csv``. +# You will need to specify a different ``target_dir`` and edit +# the ``dest_path`` variable to your liking. + +target_dir = tempfile.mkdtemp() +dest_path = Path(target_dir) / f"{file_path.stem}_dlc.csv" + +save_poses.to_dlc_file(ds_reordered, dest_path, split_individuals=False) +print(f"Saved modified dataset to {dest_path}.") + +# %% +# .. note:: +# The ``split_individuals`` argument allows you to save +# a dataset with multiple individuals as separate files, +# with the individual ID appended to each file name. +# In this case, we set it to ``False`` because we only have +# one individual in the dataset, and we don't need its name +# appended to the file name. + + +# %% +# One function to rule them all +# ----------------------------- +# Since we know how to rename, delete, and reorder keypoints, +# let's put it all together in a single function +# and see how we could apply it to multiple files at once, +# as we might do in a real-world scenario. +# +# The following function will convert all files in a folder +# (that end with a specified suffix) from SLEAP to DeepLabCut format. +# Each file will be loaded, modified according to the +# ``rename_dict``, ``keypoints_to_delete``, and ``ordered_keypoints`` +# we've defined above, and saved to the target directory. + + +data_dir = "/path/to/your/data/" +target_dir = "/path/to/your/target/data/" + + +def convert_all(data_dir, target_dir, suffix=".slp"): + source_folder = Path(data_dir) + file_paths = list(source_folder.rglob(f"*{suffix}")) + + for file_path in file_paths: + file_path = Path(file_path) + + # this determines the file names for the modified files + dest_path = Path(target_dir) / f"{file_path.stem}_dlc.csv" + + if dest_path.exists(): + print(f"Skipping {file_path} as {dest_path} already exists.") + continue + + if file_path.exists(): + print(f"Processing: {file_path}") + # load the data from SLEAP file + ds = load_poses.from_sleap_file(file_path) + # modify the data + ds_renamed = rename_keypoints(ds, rename_dict) + ds_deleted = delete_keypoints(ds_renamed, keypoints_to_delete) + ds_reordered = reorder_keypoints(ds_deleted, ordered_keypoints) + # save modified data to a DeepLabCut file + save_poses.to_dlc_file( + ds_reordered, dest_path, split_individuals=False + ) + else: + raise ValueError( + f"File '{file_path}' does not exist. " + f"Please check the file path and try again." + )