class ReferenceSpaceCache(Cache): REFERENCE_SPACE_VERSION_KEY = 'REFERENCE_SPACE_VERSION' ANNOTATION_KEY = 'ANNOTATION' TEMPLATE_KEY = 'TEMPLATE' STRUCTURES_KEY = 'STRUCTURES' STRUCTURE_TREE_KEY = 'STRUCTURE_TREE' STRUCTURE_MASK_KEY = 'STRUCTURE_MASK' MANIFEST_VERSION = 1.1 def __init__(self, resolution, reference_space_key, **kwargs): if not 'version' in kwargs: kwargs['version'] = self.MANIFEST_VERSION if not 'base_uri' in kwargs: kwargs['base_uri'] = None super(ReferenceSpaceCache, self).__init__(**kwargs) self.resolution = resolution self.reference_space_key = reference_space_key self.api = ReferenceSpaceApi(base_uri=kwargs['base_uri']) def get_annotation_volume(self, file_name=None): """ Read the annotation volume. Download it first if it doesn't exist. Parameters ---------- file_name: string File name to store the annotation volume. If it already exists, it will be read from this file. If file_name is None, the file_name will be pulled out of the manifest. Default is None. """ file_name = self.get_cache_path( file_name, self.ANNOTATION_KEY, self.reference_space_key, self.resolution) annotation, info = self.api.download_annotation_volume( self.reference_space_key, self.resolution, file_name, strategy='lazy') return annotation, info def get_template_volume(self, file_name=None): """ Read the template volume. Download it first if it doesn't exist. Parameters ---------- file_name: string File name to store the template volume. If it already exists, it will be read from this file. If file_name is None, the file_name will be pulled out of the manifest. Default is None. """ file_name = self.get_cache_path( file_name, self.TEMPLATE_KEY, self.resolution) template, info = self.api.download_template_volume(self.resolution, file_name, strategy='lazy') return template, info def get_structure_tree(self, file_name=None, structure_graph_id=1): """ Read the list of adult mouse structures and return an StructureTree instance. Parameters ---------- file_name: string File name to save/read the structures table. If file_name is None, the file_name will be pulled out of the manifest. If caching is disabled, no file will be saved. Default is None. structure_graph_id: int Build a tree using structure only from the identified structure graph. """ file_name = self.get_cache_path(file_name, self.STRUCTURE_TREE_KEY) return OntologiesApi(self.api.api_url).get_structures_with_sets( strategy='lazy', path=file_name, pre=StructureTree.clean_structures, post=lambda x: StructureTree(StructureTree.clean_structures(x)), structure_graph_ids=structure_graph_id, **Cache.cache_json()) def get_reference_space(self, structure_file_name=None, annotation_file_name=None): """ Build a ReferenceSpace from this cache's annotation volume and structure tree. The ReferenceSpace does operations that relate brain structures to spatial domains. Parameters ---------- structure_file_name: string File name to save/read the structures table. If file_name is None, the file_name will be pulled out of the manifest. If caching is disabled, no file will be saved. Default is None. annotation_file_name: string File name to store the annotation volume. If it already exists, it will be read from this file. If file_name is None, the file_name will be pulled out of the manifest. Default is None. """ return ReferenceSpace(self.get_structure_tree(structure_file_name), self.get_annotation_volume(annotation_file_name)[0], [self.resolution] * 3) def get_structure_mask(self, structure_id, file_name=None, annotation_file_name=None): """ Read a 3D numpy array shaped like the annotation volume that has non-zero values where voxels belong to a particular structure. This will take care of identifying substructures. Notes ----- This method downloads structure masks from the Allen Institute. To make your own locally, see ReferenceSpace.many_structure_masks. Parameters ---------- structure_id: int ID of a structure. file_name: string File name to store the structure mask. If it already exists, it will be read from this file. If file_name is None, the file_name will be pulled out of the manifest. Default is None. annotation_file_name: string File name to store the annotation volume. If it already exists, it will be read from this file. If file_name is None, the file_name will be pulled out of the manifest. Default is None. """ structure_id = ReferenceSpaceCache.validate_structure_id(structure_id) file_name = self.get_cache_path( file_name, self.STRUCTURE_MASK_KEY, self.reference_space_key, self.resolution, structure_id) return self.api.download_structure_mask(structure_id, self.reference_space_key, self.resolution, file_name, strategy='lazy') def add_manifest_paths(self, manifest_builder): """ Construct a manifest for this Cache class and save it in a file. Parameters ---------- file_name: string File location to save the manifest. """ manifest_builder = super(ReferenceSpaceCache, self).add_manifest_paths(manifest_builder) manifest_builder.add_path(self.STRUCTURE_TREE_KEY, 'structures.json', parent_key='BASEDIR', typename='file') manifest_builder.add_path(self.REFERENCE_SPACE_VERSION_KEY, '%s', parent_key='BASEDIR', typename='dir') manifest_builder.add_path(self.ANNOTATION_KEY, 'annotation_%d.nrrd', parent_key=self.REFERENCE_SPACE_VERSION_KEY, typename='file') manifest_builder.add_path(self.TEMPLATE_KEY, 'average_template_%d.nrrd', parent_key='BASEDIR', typename='file') manifest_builder.add_path(self.STRUCTURE_MASK_KEY, 'structure_masks/resolution_%d/structure_%d.nrrd', parent_key=self.REFERENCE_SPACE_VERSION_KEY, typename='file') return manifest_builder @classmethod def validate_structure_id(cls, structure_id): try: structure_id = int(structure_id) except ValueError as e: raise ValueError("Invalid structure_id (%s): could not convert to integer." % str(structure_id)) return structure_id @classmethod def validate_structure_ids(cls, structure_ids): for ii, sid in enumerate(structure_ids): structure_ids[ii] = cls.validate_structure_id(sid) return structure_ids
class ReferenceSpaceCache(Cache): REFERENCE_SPACE_VERSION_KEY = 'REFERENCE_SPACE_VERSION' ANNOTATION_KEY = 'ANNOTATION' TEMPLATE_KEY = 'TEMPLATE' STRUCTURES_KEY = 'STRUCTURES' STRUCTURE_TREE_KEY = 'STRUCTURE_TREE' STRUCTURE_MASK_KEY = 'STRUCTURE_MASK' STRUCTURE_MESH_KEY = 'STRUCTURE_MESH' MANIFEST_VERSION = 1.2 def __init__(self, resolution, reference_space_key, **kwargs): if not 'version' in kwargs: kwargs['version'] = self.MANIFEST_VERSION if not 'base_uri' in kwargs: kwargs['base_uri'] = None super(ReferenceSpaceCache, self).__init__(**kwargs) self.resolution = resolution self.reference_space_key = reference_space_key self.api = ReferenceSpaceApi(base_uri=kwargs['base_uri']) def get_annotation_volume(self, file_name=None): """ Read the annotation volume. Download it first if it doesn't exist. Parameters ---------- file_name: string File name to store the annotation volume. If it already exists, it will be read from this file. If file_name is None, the file_name will be pulled out of the manifest. Default is None. """ file_name = self.get_cache_path( file_name, self.ANNOTATION_KEY, self.reference_space_key, self.resolution) annotation, info = self.api.download_annotation_volume( self.reference_space_key, self.resolution, file_name, strategy='lazy') return annotation, info def get_template_volume(self, file_name=None): """ Read the template volume. Download it first if it doesn't exist. Parameters ---------- file_name: string File name to store the template volume. If it already exists, it will be read from this file. If file_name is None, the file_name will be pulled out of the manifest. Default is None. """ file_name = self.get_cache_path( file_name, self.TEMPLATE_KEY, self.resolution) template, info = self.api.download_template_volume(self.resolution, file_name, strategy='lazy') return template, info def get_structure_tree(self, file_name=None, structure_graph_id=1): """ Read the list of adult mouse structures and return an StructureTree instance. Parameters ---------- file_name: string File name to save/read the structures table. If file_name is None, the file_name will be pulled out of the manifest. If caching is disabled, no file will be saved. Default is None. structure_graph_id: int Build a tree using structure only from the identified structure graph. """ file_name = self.get_cache_path(file_name, self.STRUCTURE_TREE_KEY) return OntologiesApi(self.api.api_url).get_structures_with_sets( strategy='lazy', path=file_name, pre=StructureTree.clean_structures, post=lambda x: StructureTree(StructureTree.clean_structures(x)), structure_graph_ids=structure_graph_id, **Cache.cache_json()) def get_reference_space(self, structure_file_name=None, annotation_file_name=None): """ Build a ReferenceSpace from this cache's annotation volume and structure tree. The ReferenceSpace does operations that relate brain structures to spatial domains. Parameters ---------- structure_file_name: string File name to save/read the structures table. If file_name is None, the file_name will be pulled out of the manifest. If caching is disabled, no file will be saved. Default is None. annotation_file_name: string File name to store the annotation volume. If it already exists, it will be read from this file. If file_name is None, the file_name will be pulled out of the manifest. Default is None. """ return ReferenceSpace(self.get_structure_tree(structure_file_name), self.get_annotation_volume(annotation_file_name)[0], [self.resolution] * 3) def get_structure_mask(self, structure_id, file_name=None, annotation_file_name=None): """ Read a 3D numpy array shaped like the annotation volume that has non-zero values where voxels belong to a particular structure. This will take care of identifying substructures. Notes ----- This method downloads structure masks from the Allen Institute. To make your own locally, see ReferenceSpace.many_structure_masks. Parameters ---------- structure_id: int ID of a structure. file_name: string File name to store the structure mask. If it already exists, it will be read from this file. If file_name is None, the file_name will be pulled out of the manifest. Default is None. annotation_file_name: string File name to store the annotation volume. If it already exists, it will be read from this file. If file_name is None, the file_name will be pulled out of the manifest. Default is None. """ structure_id = ReferenceSpaceCache.validate_structure_id(structure_id) file_name = self.get_cache_path( file_name, self.STRUCTURE_MASK_KEY, self.reference_space_key, self.resolution, structure_id) return self.api.download_structure_mask(structure_id, self.reference_space_key, self.resolution, file_name, strategy='lazy') def get_structure_mesh(self, structure_id, file_name=None): """Obtain a 3D mesh specifying the surface of an annotated structure. Parameters ----------- structure_id: int ID of a structure. file_name: string File name to store the structure mesh. If it already exists, it will be read from this file. If file_name is None, the file_name will be pulled out of the manifest. Default is None. Returns ------- vertices : np.ndarray Dimensions are (nSamples, nCoordinates=3). Locations in the reference space of vertices vertex_normals : np.ndarray Dimensions are (nSample, nElements=3). Vectors normal to vertices. face_vertices : np.ndarray Dimensions are (sample, nVertices=3). References are given in indices (0-indexed here, but 1-indexed in the file) of vertices that make up each face. face_normals : np.ndarray Dimensions are (sample, nNormals=3). References are given in indices (0-indexed here, but 1-indexed in the file) of vertex normals that make up each face. Notes ----- These meshes are meant for 3D visualization and as such have been smoothed. If you are interested in performing quantative analyses, we recommend that you use the structure masks instead. """ structure_id = ReferenceSpaceCache.validate_structure_id(structure_id) file_name = self.get_cache_path( file_name, self.STRUCTURE_MESH_KEY, self.reference_space_key, structure_id) return self.api.download_structure_mesh(structure_id, self.reference_space_key, file_name, strategy='lazy') def add_manifest_paths(self, manifest_builder): """ Construct a manifest for this Cache class and save it in a file. Parameters ---------- file_name: string File location to save the manifest. """ manifest_builder = super(ReferenceSpaceCache, self).add_manifest_paths(manifest_builder) manifest_builder.add_path(self.STRUCTURE_TREE_KEY, 'structures.json', parent_key='BASEDIR', typename='file') manifest_builder.add_path(self.REFERENCE_SPACE_VERSION_KEY, '%s', parent_key='BASEDIR', typename='dir') manifest_builder.add_path(self.ANNOTATION_KEY, 'annotation_%d.nrrd', parent_key=self.REFERENCE_SPACE_VERSION_KEY, typename='file') manifest_builder.add_path(self.TEMPLATE_KEY, 'average_template_%d.nrrd', parent_key='BASEDIR', typename='file') manifest_builder.add_path(self.STRUCTURE_MASK_KEY, 'structure_masks/resolution_%d/structure_%d.nrrd', parent_key=self.REFERENCE_SPACE_VERSION_KEY, typename='file') manifest_builder.add_path(self.STRUCTURE_MESH_KEY, 'structure_meshes/structure_%d.obj', parent_key=self.REFERENCE_SPACE_VERSION_KEY, typename='file') return manifest_builder @classmethod def validate_structure_id(cls, structure_id): try: structure_id = int(structure_id) except ValueError as e: raise ValueError("Invalid structure_id (%s): could not convert to integer." % str(structure_id)) return structure_id @classmethod def validate_structure_ids(cls, structure_ids): for ii, sid in enumerate(structure_ids): structure_ids[ii] = cls.validate_structure_id(sid) return structure_ids
import numpy as np from allensdk.api.queries.reference_space_api import ReferenceSpaceApi from allensdk.config.manifest import Manifest # the annotation download writes a file, so we will need somwhere to put it annotation_dir = 'annotation' Manifest.safe_mkdir(annotation_dir) annotation_path = os.path.join(annotation_dir, 'annotation.nrrd') # this is a string which contains the name of the latest ccf version annotation_version = ReferenceSpaceApi.CCF_VERSION_DEFAULT # download annotations mcapi = ReferenceSpaceApi() mcapi.download_annotation_volume(annotation_version, 50, annotation_path) annotation = nrrd.read(annotation_path) # read nrrd data and header _nrrd = nrrd.read(annotation_path) data = _nrrd[0] header = _nrrd[1] # create header and for RAS orientation space_value = header['space directions'] affine = np.eye(4) * 0.001 * space_value[0, 0] affine[3][3] = 1 # ensure RAS orientation data = np.swapaxes(data, 2, 0) data = np.flip(data, 2)