__init__.py 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109
  1. """
  2. Python Library to Read FreeSurfer's cortical parcellation anatomical statistics
  3. ([lh]h.aparc(.*)?.stats)
  4. Freesurfer
  5. https://surfer.nmr.mgh.harvard.edu/
  6. >>> stats = CorticalParcellationStats.read('tests/subjects/fabian/stats/lh.aparc.DKTatlas.stats')
  7. >>> stats.creation_time.isoformat()
  8. '2019-05-09T21:05:54+00:00'
  9. >>> stats.cvs_version
  10. 'Id: mris_anatomical_stats.c,v 1.79 2016/03/14 15:15:34 greve Exp'
  11. >>> stats.cmdline[:64]
  12. 'mris_anatomical_stats -th3 -mgz -cortex ../label/lh.cortex.label'
  13. """
  14. import datetime
  15. import re
  16. import typing
  17. import pandas
  18. from freesurfer_stats.version import __version__
  19. class CorticalParcellationStats:
  20. _HEMISPHERE_PREFIX_TO_SIDE = {'lh': 'left', 'rh': 'right'}
  21. def __init__(self):
  22. self.creation_time = None # type: typing.Optional[datetime.datetime]
  23. self.generating_program = None # type: typing.Optional[str]
  24. self.cvs_version = None # type: typing.Optional[str]
  25. self.mrisurf_ccvs_version = None # type: typing.Optional[str]
  26. self.cmdline = None # type: typing.Optional[str]
  27. self.sysname = None # type: typing.Optional[str]
  28. self.hostname = None # type: typing.Optional[str]
  29. self.machine = None # type: typing.Optional[str]
  30. self.user = None # type: typing.Optional[str]
  31. self.subjects_dir = None # type: typing.Optional[str]
  32. self.anatomy_type = None # type: typing.Optional[str]
  33. self.subject_name = None # type: typing.Optional[str]
  34. self.hemisphere = None # type: typing.Optional[str]
  35. self.annotation_file = None # type: typing.Optional[str]
  36. self.annotation_file_timestamp \
  37. = None # type: typing.Optional[datetime.datetime]
  38. def _read_headers(self, stream: typing.TextIO) -> None:
  39. creation_time_str = stream.readline()[len('# CreationTime '):].rstrip()
  40. self.creation_time = datetime.datetime.strptime(
  41. creation_time_str, '%Y/%m/%d-%H:%M:%S-%Z')
  42. if self.creation_time.tzinfo is None:
  43. assert creation_time_str.endswith('-GMT')
  44. self.creation_time = self.creation_time.replace(
  45. tzinfo=datetime.timezone.utc)
  46. while True:
  47. line = stream.readline().rstrip()
  48. if line == '#':
  49. continue
  50. elif line.startswith('# Measure'):
  51. break
  52. prefix, attr_name, attr_value = line.split(' ', maxsplit=2)
  53. assert prefix == '#'
  54. attr_value = attr_value.lstrip()
  55. if attr_name == 'generating_program':
  56. self.generating_program = attr_value
  57. elif attr_name == 'cvs_version':
  58. self.cvs_version = attr_value.strip('$').rstrip()
  59. elif attr_name == 'mrisurf.c-cvs_version':
  60. self.mrisurf_ccvs_version = attr_value.strip('$').rstrip()
  61. elif attr_name == 'cmdline':
  62. self.cmdline = attr_value
  63. elif attr_name == 'sysname':
  64. self.sysname = attr_value
  65. elif attr_name == 'hostname':
  66. self.hostname = attr_value
  67. elif attr_name == 'machine':
  68. self.machine = attr_value
  69. elif attr_name == 'user':
  70. self.user = attr_value
  71. elif attr_name == 'SUBJECTS_DIR':
  72. self.subjects_dir = attr_value
  73. elif attr_name == 'anatomy_type':
  74. self.anatomy_type = attr_value
  75. elif attr_name == 'subjectname':
  76. self.subject_name = attr_value
  77. elif attr_name == 'hemi':
  78. self.hemisphere = self._HEMISPHERE_PREFIX_TO_SIDE[attr_value]
  79. elif attr_name == 'AnnotationFile':
  80. self.annotation_file = attr_value
  81. elif attr_name == 'AnnotationFileTimeStamp':
  82. self.annotation_file_timestamp = datetime.datetime.strptime(
  83. attr_value, '%Y/%m/%d %H:%M:%S')
  84. else:
  85. raise ValueError(attr_name)
  86. def _read(self, stream: typing.TextIO) -> None:
  87. assert stream.readline().rstrip() \
  88. == '# Table of FreeSurfer cortical parcellation anatomical statistics'
  89. assert stream.readline().rstrip() == '#'
  90. self._read_headers(stream)
  91. @classmethod
  92. def read(cls, path: str) -> 'CorticalParcellationStats':
  93. stats = cls()
  94. with open(path, 'r') as stream:
  95. # pylint: disable=protected-access
  96. stats._read(stream)
  97. return stats