from .metadata import metadata_loader from .read_and_write import readAtlasVolume, WritePointsToMeshview from .coordinate_extraction import FolderToAtlasSpace from .counting_and_load import labelPoints, PixelCountPerRegion import json import pandas as pd from datetime import datetime class PyNutil: def __init__( self, segmentation_folder=None, alignment_json=None, colour=None, volume_path=None, settings_file=None, ) -> None: self.config, self.metadata_path = metadata_loader.load_config() if settings_file is not None: with open(settings_file, "r") as f: settings = json.load(f) try: segmentation_folder = settings["segmentation_folder"] alignment_json = settings["alignment_json"] colour = settings["colour"] volume_path = settings["volume_path"] except KeyError as exc: raise KeyError( "settings file must contain segmentation_folder, alignment_json, colour, and volume_path" ) from exc # check if any values are None if None in [segmentation_folder, alignment_json, colour, volume_path]: raise ValueError( "segmentation_folder, alignment_json, colour, and volume_path must all be specified and not be None" ) if volume_path not in self.config["annotation_volumes"]: raise ValueError( f"Atlas {volume_path} not found in config file, valid atlases are: \n{' , '.join(list(self.config['annotation_volumes'].keys()))}" ) self.segmentation_folder = segmentation_folder self.alignment_json = alignment_json self.colour = colour self.atlas = volume_path # load the metadata json as well as the path to stored data files def build_quantifier(self): # this could potentially be moved into init atlas_root_path = self.config["annotation_volume_directory"] current_atlas_path = self.config["annotation_volumes"][self.atlas]["volume"] print("loading atlas volume") startTime = datetime.now() self.atlas_volume = readAtlasVolume(atlas_root_path + current_atlas_path) time_taken = datetime.now() - startTime print(f"atlas volume loaded in: {time_taken} ✅") atlas_label_path = self.config["annotation_volumes"][self.atlas]["labels"] print("loading atlas labels") self.atlas_labels = pd.read_csv(atlas_root_path + atlas_label_path) print("atlas labels loaded ✅") def get_coordinates(self, nonLinear=True, method="all"): if not hasattr(self, "atlas_volume"): raise ValueError( "Please run build_quantifier before running get_coordinates" ) if method not in ["per_pixel", "per_object", "all"]: raise ValueError( f"method {method} not recognised, valid methods are: per_pixel, per_object, or all" ) print("extracting coordinates") pixel_points = FolderToAtlasSpace( self.segmentation_folder, self.alignment_json, pixelID=self.colour, nonLinear=nonLinear, method=method, ) self.pixel_points = pixel_points def quantify_coordinates(self): if not hasattr(self, "pixel_points"): raise ValueError( "Please run get_coordinates before running quantify_coordinates" ) print("quantifying coordinates") labeled_points = labelPoints( self.pixel_points, self.atlas_volume, scale_factor=2.5 ) self.label_df = PixelCountPerRegion(labeled_points, self.atlas_labels) self.labeled_points = labeled_points print("quantification complete ✅") def save_analysis(self, output_folder): if not hasattr(self, "pixel_points"): raise ValueError("Please run get_coordinates before running save_analysis") self.label_df.to_csv( output_folder + "/counts.csv", sep=";", na_rep="", index=False ) if not hasattr(self, "label_df"): print("no quantification found so we will only save the coordinates") print( "if you want to save the quantification please run quantify_coordinates" ) else: WritePointsToMeshview( self.pixel_points, self.labeled_points, output_folder + "/pixels_meshview.json", self.atlas_labels, ) print("analysis saved ✅")