Skip to content

Commit

Permalink
[pre-commit.ci] auto fixes from pre-commit.com hooks
Browse files Browse the repository at this point in the history
for more information, see https://pre-commit.ci
  • Loading branch information
pre-commit-ci[bot] committed Jan 9, 2025
1 parent 99e2ea3 commit 0477608
Showing 1 changed file with 119 additions and 61 deletions.
180 changes: 119 additions & 61 deletions brainglobe_atlasapi/atlas_generation/atlas_scripts/kim_devccf_mouse.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
import argparse
import json
import time
from pathlib import Path
import pooch

import numpy as np
import pandas as pd
import pooch
from brainglobe_utils.IO.image import load_nii
from rich.progress import track

Expand All @@ -15,7 +14,6 @@
create_region_mesh,
)
from brainglobe_atlasapi.atlas_generation.wrapup import wrapup_atlas_from_data

from brainglobe_atlasapi.config import DEFAULT_WORKDIR
from brainglobe_atlasapi.structure_tree_util import get_structures_tree

Expand All @@ -29,101 +27,127 @@
PACKAGER = "Carlo Castoldi <castoldi[at]ipmc.cnrs.fr>"
ATLAS_FILE_URL = "https://doi.org/10.6084/m9.figshare.26377171.v1"

TIMEPOINTS = (
"E11.5",
"E13.5",
"E15.5",
"E18.5",
"P04",
"P14",
"P56"
)
TIMEPOINTS = ("E11.5", "E13.5", "E15.5", "E18.5", "P04", "P14", "P56")
MODALITIES = (
"LSFM", # Light Sheet Fluorescence Microscopy
"LSFM", # Light Sheet Fluorescence Microscopy
"MRI-adc", # MRI Apparent Diffusion Coefficient
"MRI-dwi", # MRI Difusion Weighted Imaging
"MRI-fa", # MRI Fractional Anisotropy
"MRI-fa", # MRI Fractional Anisotropy
"MRI-MTR", # MRI Magnetization Transfer Ratio
"MRI-T2" # MRI T2-weighted
"MRI-T2", # MRI T2-weighted
)


def pooch_init(download_dir_path: Path, timepoints: list[str]) -> pooch.Pooch:
utils.check_internet_connection()

empty_registry = {a+".zip": None for a in [*timepoints, "DevCCFv1_OntologyStructure.xlsx"]}
empty_registry = {
a + ".zip": None
for a in [*timepoints, "DevCCFv1_OntologyStructure.xlsx"]
}
p = pooch.create(
path=download_dir_path,
base_url="doi:10.6084/m9.figshare.26377171.v1/",
registry=empty_registry
registry=empty_registry,
)
p.load_registry(
Path(__file__).parent.parent / "hashes" / (ATLAS_NAME + ".txt")
)
p.load_registry(Path(__file__).parent.parent/"hashes"/(ATLAS_NAME+".txt"))
return p


def fetch_animal(pooch_: pooch.Pooch, age: str, modality: str):
assert age in TIMEPOINTS, f"Unknown age timepoint: '{age}'"
archive = age+".zip"
archive = age + ".zip"
if modality == "LSFM":
resolution_um = 20
elif modality in MODALITIES:
match age:
case "E11.5":
resolution_um = 31.5
raise RuntimeError("Can't generate an atlas at embryonic stage with MRI reference images.")
raise RuntimeError(
"Can't generate an atlas at embryonic stage with MRI reference images."
)
case "E13.5":
resolution_um = 34
raise RuntimeError("Can't generate an atlas at embryonic stage with MRI reference images.")
raise RuntimeError(
"Can't generate an atlas at embryonic stage with MRI reference images."
)
case "E15.5":
resolution_um = 37.5
raise RuntimeError("Can't generate an atlas at embryonic stage with MRI reference images.")
raise RuntimeError(
"Can't generate an atlas at embryonic stage with MRI reference images."
)
case "E18.5":
resolution_um = 40
raise RuntimeError("Can't generate an atlas at embryonic stage with MRI reference images.")
raise RuntimeError(
"Can't generate an atlas at embryonic stage with MRI reference images."
)
case _:
resolution_um = 50
else:
raise RuntimeError(f"Unknown reference image modality: {modality}")
members = [
f"{age}/{age.replace('.','-')}_DevCCF_Annotations_{resolution_um}um.nii.gz",
f"{age}/{age.replace('.','-')}_{modality}_{resolution_um}um.nii.gz"
f"{age}/{age.replace('.','-')}_{modality}_{resolution_um}um.nii.gz",
]
annotations_path, reference_path = pooch_.fetch(archive,
progressbar=True,
processor=pooch.Unzip(extract_dir=".", members=members)
)
annotations_path, reference_path = pooch_.fetch(
archive,
progressbar=True,
processor=pooch.Unzip(extract_dir=".", members=members),
)
annotations = load_nii(annotations_path, as_array=True)
reference = load_nii(reference_path, as_array=True)
return annotations, reference, resolution_um


def fetch_ontology(pooch_: pooch.Pooch):
devccfv1_path = pooch_.fetch("DevCCFv1_OntologyStructure.xlsx", progressbar=True)
devccfv1_path = pooch_.fetch(
"DevCCFv1_OntologyStructure.xlsx", progressbar=True
)
xl = pd.ExcelFile(devccfv1_path)
# xl.sheet_names # it has two excel sheets
# 'DevCCFv1_Ontology', 'README'
# 'DevCCFv1_Ontology', 'README'
df = xl.parse("DevCCFv1_Ontology", header=1)
df = df[["Acronym", "ID16", "Name", "Structure ID Path16", "R", "G", "B"]]
df.rename(columns={
"Acronym": "acronym",
"ID16": "id",
"Name": "name",
"Structure ID Path16": "structure_id_path",
"R": "r",
"G": "g",
"B": "b"
}, inplace=True)
df.rename(
columns={
"Acronym": "acronym",
"ID16": "id",
"Name": "name",
"Structure ID Path16": "structure_id_path",
"R": "r",
"G": "g",
"B": "b",
},
inplace=True,
)
structures = list(df.to_dict(orient="index").values())
for structure in structures:
if structure["acronym"] == "mouse":
structure["acronym"] = "root"
structure_path = structure["structure_id_path"]
structure["structure_id_path"] = [int(id) for id in structure_path.strip("/").split("/")]
structure["rgb_triplet"] = [structure["r"], structure["g"], structure["b"]]
structure["structure_id_path"] = [
int(id) for id in structure_path.strip("/").split("/")
]
structure["rgb_triplet"] = [
structure["r"],
structure["g"],
structure["b"],
]
del structure["r"]
del structure["g"]
del structure["b"]
return structures

def create_meshes(output_path: str|Path,
structures, annotation_volume, root_id, decimate_fraction):

def create_meshes(
output_path: str | Path,
structures,
annotation_volume,
root_id,
decimate_fraction,
):
if not isinstance(output_path, Path):
output_path = Path(output_path)
output_path.mkdir(exist_ok=True)
Expand All @@ -150,7 +174,7 @@ def create_meshes(output_path: str|Path,
# total=5,
description="Creating meshes",
):
output_file = output_path/f"{node.identifier}.obj"
output_file = output_path / f"{node.identifier}.obj"
if output_file.exists():
# print(f"mesh already existing: {output_file.exists()} - {output_file}")
continue
Expand All @@ -175,6 +199,7 @@ def create_meshes(output_path: str|Path,
)
return output_path


def create_mesh_dict(structures, meshes_dir_path):
meshes_dict = dict()
structures_with_mesh = []
Expand All @@ -197,21 +222,25 @@ def create_mesh_dict(structures, meshes_dir_path):
)
return meshes_dict, structures_with_mesh


class HideChoicesRawTextHelpFormatter(argparse.RawTextHelpFormatter):
def _get_help_string(self, action):
help_text = action.help
if action.choices:
help_text = help_text.split('(choices')[0].strip()
help_text = help_text.split("(choices")[0].strip()
return help_text

def _format_action_invocation(self, action):
if action.option_strings:
return ', '.join(action.option_strings)
return ", ".join(action.option_strings)
if action.metavar:
return action.metavar
return super()._format_action_invocation(action)

arg_parser = argparse.ArgumentParser(formatter_class=HideChoicesRawTextHelpFormatter)

arg_parser = argparse.ArgumentParser(
formatter_class=HideChoicesRawTextHelpFormatter
)
timepoints_help = """the age timepoint at which the atlas will be generated.
Options are:
- E11.5 ⅂
Expand All @@ -221,7 +250,7 @@ def _format_action_invocation(self, action):
- P04 ⅂
- P14 |- Postnatal day
- P56 ⅃
By default, it generates an atlas for each timepoint.
"""
modalities_help = """the acquisition modalities with which the reference image was captured.
Expand All @@ -236,44 +265,73 @@ def _format_action_invocation(self, action):
By default, LSFM
"""
decimate_fraction_help = "fraction of the original number of meshes' vertices to be kept. Must be a number > 0 and <= 1.\nBy default, 0.2"


def decimate_fraction_type(arg):
try:
f = float(arg)
if 0 < f <= 1:
return f
except ValueError:
pass
raise argparse.ArgumentTypeError(f"invalid value: '{arg}' (must be a number > 0 and <= 1)")
arg_parser.add_argument("-t", "--timepoints", default=TIMEPOINTS, type=str, nargs="+", choices=TIMEPOINTS, help=timepoints_help)
arg_parser.add_argument("-m", "--modality", default="LSFM", type=str, choices=MODALITIES, help=modalities_help)
arg_parser.add_argument("-d", "--decimate-fraction", default=0.2, type=decimate_fraction_type, help=decimate_fraction_help)
raise argparse.ArgumentTypeError(
f"invalid value: '{arg}' (must be a number > 0 and <= 1)"
)


arg_parser.add_argument(
"-t",
"--timepoints",
default=TIMEPOINTS,
type=str,
nargs="+",
choices=TIMEPOINTS,
help=timepoints_help,
)
arg_parser.add_argument(
"-m",
"--modality",
default="LSFM",
type=str,
choices=MODALITIES,
help=modalities_help,
)
arg_parser.add_argument(
"-d",
"--decimate-fraction",
default=0.2,
type=decimate_fraction_type,
help=decimate_fraction_help,
)

if __name__ == "__main__":
params = vars(arg_parser.parse_args())
timepoints = params["timepoints"]
modality = params["modality"]
decimate_fraction = params["decimate_fraction"]
atlas_name = f"{ATLAS_NAME}_{modality}"
bg_root_dir = DEFAULT_WORKDIR/atlas_name
download_dir_path = bg_root_dir/"downloads"
bg_root_dir = DEFAULT_WORKDIR / atlas_name
download_dir_path = bg_root_dir / "downloads"
download_dir_path.mkdir(exist_ok=True, parents=True)
pooch_ = pooch_init(download_dir_path, timepoints)
structures = fetch_ontology(pooch_)

for age in timepoints:
atlas_name = f"{atlas_name}_{age.replace('.', '-')}"
annotation_volume, reference_volume, resolution_um = fetch_animal(pooch_, age, modality)
atlas_dir = bg_root_dir/atlas_name
annotation_volume, reference_volume, resolution_um = fetch_animal(
pooch_, age, modality
)
atlas_dir = bg_root_dir / atlas_name
atlas_dir.mkdir(exist_ok=True)
print(f"Saving atlas data at {atlas_dir}")
# Create meshes:
meshes_dir_path = atlas_dir/"meshes"
meshes_dir_path = atlas_dir / "meshes"
create_meshes(
meshes_dir_path,
structures,
annotation_volume,
ROOT_ID,
decimate_fraction
decimate_fraction,
)
meshes_dict, structures_with_mesh = create_mesh_dict(
structures, meshes_dir_path
Expand All @@ -286,7 +344,7 @@ def decimate_fraction_type(arg):
citation=CITATION,
atlas_link=ATLAS_LINK,
species=SPECIES,
resolution=(resolution_um,)*3,
resolution=(resolution_um,) * 3,
orientation=ORIENTATION,
root_id=ROOT_ID,
reference_stack=reference_volume,
Expand All @@ -295,9 +353,9 @@ def decimate_fraction_type(arg):
meshes_dict=meshes_dict,
working_dir=atlas_dir,
atlas_packager=PACKAGER,
hemispheres_stack=None, # it is symmetric
hemispheres_stack=None, # it is symmetric
cleanup_files=False,
compress=True,
scale_meshes=True,
)
print("Done. Atlas generated at: ", output_filename)
print("Done. Atlas generated at: ", output_filename)

0 comments on commit 0477608

Please sign in to comment.