__init__.py 2.4 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980
  1. """
  2. Read hippocampal subfield volumes computed by Freesurfer and/or ASHS
  3. https://sites.google.com/site/hipposubfields/home
  4. https://surfer.nmr.mgh.harvard.edu/fswiki/HippocampalSubfields
  5. >>> from freesurfer_volume_reader import ashs, freesurfer
  6. >>>
  7. >>> for volume_file in itertools.chain(
  8. >>> ashs.HippocampalSubfieldsVolumeFile.find('/my/ashs/subjects'),
  9. >>> freesurfer.HippocampalSubfieldsVolumeFile.find('/my/freesurfer/subjects')):
  10. >>> print(volume_file.absolute_path)
  11. >>> print(volume_file.subject, volume_file.hemisphere)
  12. >>> print(volume_file.read_volumes_mm3())
  13. >>> print(volume_file.read_volumes_dataframe())
  14. """
  15. import abc
  16. import os
  17. import re
  18. import typing
  19. import pandas
  20. try:
  21. from freesurfer_volume_reader.version import __version__
  22. except ImportError: # pragma: no cover
  23. __version__ = None
  24. def parse_version_string(
  25. version_string: str,
  26. ) -> typing.Tuple[typing.Union[int, str], ...]:
  27. return tuple(int(p) if p.isdigit() else p for p in version_string.split("."))
  28. def remove_group_names_from_regex(regex_pattern: str) -> str:
  29. return re.sub(r"\?P<.+?>", "", regex_pattern)
  30. class VolumeFile(metaclass=abc.ABCMeta):
  31. FILENAME_REGEX: typing.Pattern[str] = NotImplemented
  32. @abc.abstractmethod
  33. def __init__(self, path: str) -> None:
  34. pass
  35. @property
  36. @abc.abstractmethod
  37. def absolute_path(self):
  38. raise NotImplementedError()
  39. @classmethod
  40. def find(
  41. cls, root_dir_path: str, filename_regex: typing.Optional[typing.Pattern] = None
  42. ) -> typing.Iterator["VolumeFile"]:
  43. if filename_regex is None:
  44. filename_regex = cls.FILENAME_REGEX
  45. for dirpath, _, filenames in os.walk(root_dir_path):
  46. for filename in filter(filename_regex.search, filenames):
  47. yield cls(path=os.path.join(dirpath, filename))
  48. class SubfieldVolumeFile(VolumeFile):
  49. @abc.abstractmethod
  50. def read_volumes_mm3(self) -> typing.Dict[str, float]:
  51. raise NotImplementedError()
  52. @abc.abstractmethod
  53. def read_volumes_dataframe(self) -> pandas.DataFrame:
  54. raise NotImplementedError()
  55. def _read_volume_series(self) -> pandas.Series:
  56. subfield_volumes = self.read_volumes_mm3()
  57. return pandas.Series(
  58. data=list(subfield_volumes.values()),
  59. name="volume_mm^3",
  60. index=pandas.Index(data=subfield_volumes.keys(), name="subfield"),
  61. )