__init__.py 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384
  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 pathlib
  18. import re
  19. import typing
  20. import warnings
  21. import pandas
  22. try:
  23. from freesurfer_volume_reader.version import __version__
  24. except ImportError: # pragma: no cover
  25. __version__ = None
  26. def parse_version_string(
  27. version_string: str,
  28. ) -> typing.Tuple[typing.Union[int, str], ...]:
  29. warnings.warn( # previously used in `__main__.concat_dataframes`
  30. "function `parse_version_string` is deprecated"
  31. )
  32. return tuple(int(p) if p.isdigit() else p for p in version_string.split("."))
  33. def remove_group_names_from_regex(regex_pattern: str) -> str:
  34. return re.sub(r"\?P<.+?>", "", regex_pattern)
  35. class VolumeFile(metaclass=abc.ABCMeta):
  36. FILENAME_REGEX: typing.Pattern[str] = NotImplemented
  37. @abc.abstractmethod
  38. def __init__(self, path: str) -> None:
  39. self._absolute_path = pathlib.Path(path).absolute()
  40. @property
  41. def absolute_path(self) -> str:
  42. return str(self._absolute_path)
  43. @classmethod
  44. def find(
  45. cls, root_dir_path: str, filename_regex: typing.Optional[typing.Pattern] = None
  46. ) -> typing.Iterator["VolumeFile"]:
  47. if filename_regex is None:
  48. filename_regex = cls.FILENAME_REGEX
  49. for dirpath, _, filenames in os.walk(root_dir_path):
  50. for filename in filter(filename_regex.search, filenames):
  51. yield cls(path=os.path.join(dirpath, filename))
  52. class SubfieldVolumeFile(VolumeFile):
  53. @abc.abstractmethod
  54. def read_volumes_mm3(self) -> typing.Dict[str, float]:
  55. raise NotImplementedError()
  56. @abc.abstractmethod
  57. def read_volumes_dataframe(self) -> pandas.DataFrame:
  58. raise NotImplementedError()
  59. def _read_volume_series(self) -> pandas.Series:
  60. subfield_volumes = self.read_volumes_mm3()
  61. return pandas.Series(
  62. data=list(subfield_volumes.values()),
  63. name="volume_mm^3",
  64. index=pandas.Index(data=subfield_volumes.keys(), name="subfield"),
  65. )