clabtoolkit 0.4.2__tar.gz → 0.4.4__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (95) hide show
  1. clabtoolkit-0.4.4/HISTORY.rst +81 -0
  2. {clabtoolkit-0.4.2 → clabtoolkit-0.4.4}/PKG-INFO +10 -1
  3. {clabtoolkit-0.4.2 → clabtoolkit-0.4.4}/README.rst +5 -0
  4. {clabtoolkit-0.4.2 → clabtoolkit-0.4.4}/clabtoolkit/__init__.py +1 -1
  5. {clabtoolkit-0.4.2 → clabtoolkit-0.4.4}/clabtoolkit/bidstools.py +105 -18
  6. {clabtoolkit-0.4.2 → clabtoolkit-0.4.4}/clabtoolkit/colorstools.py +21 -7
  7. {clabtoolkit-0.4.2 → clabtoolkit-0.4.4}/clabtoolkit/config/config.json +1 -0
  8. {clabtoolkit-0.4.2 → clabtoolkit-0.4.4}/clabtoolkit/connectivitytools.py +489 -194
  9. {clabtoolkit-0.4.2 → clabtoolkit-0.4.4}/clabtoolkit/dicomtools.py +329 -66
  10. {clabtoolkit-0.4.2 → clabtoolkit-0.4.4}/clabtoolkit/dwitools.py +330 -147
  11. clabtoolkit-0.4.4/clabtoolkit/dwitools_utils.py +107 -0
  12. {clabtoolkit-0.4.2 → clabtoolkit-0.4.4}/clabtoolkit/freesurfertools.py +1037 -440
  13. {clabtoolkit-0.4.2 → clabtoolkit-0.4.4}/clabtoolkit/imagetools.py +325 -79
  14. clabtoolkit-0.4.4/clabtoolkit/imagetools_utils.py +81 -0
  15. {clabtoolkit-0.4.2 → clabtoolkit-0.4.4}/clabtoolkit/misctools.py +71 -2
  16. {clabtoolkit-0.4.2 → clabtoolkit-0.4.4}/clabtoolkit/morphometrytools.py +317 -35
  17. {clabtoolkit-0.4.2 → clabtoolkit-0.4.4}/clabtoolkit/networktools.py +78 -214
  18. {clabtoolkit-0.4.2 → clabtoolkit-0.4.4}/clabtoolkit/parcellationtools.py +1308 -17
  19. {clabtoolkit-0.4.2 → clabtoolkit-0.4.4}/clabtoolkit/plottools.py +83 -0
  20. {clabtoolkit-0.4.2 → clabtoolkit-0.4.4}/clabtoolkit/surfacetools.py +5 -7
  21. {clabtoolkit-0.4.2 → clabtoolkit-0.4.4}/clabtoolkit/tracttools.py +384 -202
  22. {clabtoolkit-0.4.2 → clabtoolkit-0.4.4}/clabtoolkit/visualization_utils.py +11 -0
  23. {clabtoolkit-0.4.2 → clabtoolkit-0.4.4}/clabtoolkit/visualizationtools.py +535 -1
  24. {clabtoolkit-0.4.2 → clabtoolkit-0.4.4}/clabtoolkit.egg-info/PKG-INFO +10 -1
  25. {clabtoolkit-0.4.2 → clabtoolkit-0.4.4}/clabtoolkit.egg-info/SOURCES.txt +14 -2
  26. {clabtoolkit-0.4.2 → clabtoolkit-0.4.4}/clabtoolkit.egg-info/requires.txt +4 -0
  27. clabtoolkit-0.4.4/docs/source/_static/clabtoolkit_ecosystem.png +0 -0
  28. clabtoolkit-0.4.4/docs/source/_static/clabtoolkit_favicon.png +0 -0
  29. clabtoolkit-0.4.4/docs/source/_static/clabtoolkit_logo.png +0 -0
  30. clabtoolkit-0.4.4/docs/source/_static/clabtoolkit_logo_notext.png +0 -0
  31. {clabtoolkit-0.4.2 → clabtoolkit-0.4.4}/docs/source/conf.py +3 -0
  32. {clabtoolkit-0.4.2 → clabtoolkit-0.4.4}/docs/source/index.rst +3 -0
  33. clabtoolkit-0.4.4/docs/source/modules/colorstools.rst +142 -0
  34. {clabtoolkit-0.4.2 → clabtoolkit-0.4.4}/docs/source/modules/connectivitytools.rst +1 -1
  35. {clabtoolkit-0.4.2 → clabtoolkit-0.4.4}/docs/source/modules/dicomtools.rst +12 -37
  36. clabtoolkit-0.4.4/docs/source/modules/dwitools.rst +115 -0
  37. clabtoolkit-0.4.4/docs/source/modules/freesurfertools.rst +181 -0
  38. clabtoolkit-0.4.4/docs/source/modules/imagetools.rst +168 -0
  39. clabtoolkit-0.4.4/docs/source/modules/morphometrytools.rst +151 -0
  40. {clabtoolkit-0.4.2 → clabtoolkit-0.4.4}/docs/source/modules/networktools.rst +1 -1
  41. clabtoolkit-0.4.4/docs/source/modules/parcellationtools.rst +154 -0
  42. {clabtoolkit-0.4.2 → clabtoolkit-0.4.4}/docs/source/modules/pipelinetools.rst +1 -1
  43. clabtoolkit-0.4.4/docs/source/modules/pointstools.rst +113 -0
  44. {clabtoolkit-0.4.2 → clabtoolkit-0.4.4}/docs/source/modules/segmentationtools.rst +1 -1
  45. clabtoolkit-0.4.4/docs/source/modules/surfacetools.rst +143 -0
  46. clabtoolkit-0.4.4/docs/source/modules/tracttools.rst +168 -0
  47. clabtoolkit-0.4.4/docs/source/modules/visualizationtools.rst +139 -0
  48. {clabtoolkit-0.4.2 → clabtoolkit-0.4.4}/pyproject.toml +5 -1
  49. clabtoolkit-0.4.4/usage_examples/VisClasses4Paper.ipynb +1011 -0
  50. clabtoolkit-0.4.4/usage_examples/clabtoolkit-OHBM2026-final.ipynb +2069 -0
  51. clabtoolkit-0.4.4/usage_examples/clabtoolkit_examples.ipynb +1358 -0
  52. clabtoolkit-0.4.4/usage_examples/examples-bidstools-methods.ipynb +1366 -0
  53. clabtoolkit-0.4.4/usage_examples/examples-freesurfertools-methods.ipynb +2595 -0
  54. clabtoolkit-0.4.4/usage_examples/examples-parcellationtools-methods.ipynb +2351 -0
  55. {clabtoolkit-0.4.2 → clabtoolkit-0.4.4}/usage_examples/examples-surfacetools-methods.ipynb +44 -6
  56. {clabtoolkit-0.4.2 → clabtoolkit-0.4.4}/usage_examples/examples-visualizationtools-methods.ipynb +3 -5
  57. clabtoolkit-0.4.2/HISTORY.rst +0 -35
  58. clabtoolkit-0.4.2/clabtoolkit/connectome.py +0 -723
  59. clabtoolkit-0.4.2/clabtoolkit/old_dwitool.py +0 -1537
  60. clabtoolkit-0.4.2/docs/source/modules/dwitools.rst +0 -90
  61. clabtoolkit-0.4.2/docs/source/modules/freesurfertools.rst +0 -85
  62. clabtoolkit-0.4.2/docs/source/modules/imagetools.rst +0 -114
  63. clabtoolkit-0.4.2/docs/source/modules/morphometrytools.rst +0 -96
  64. clabtoolkit-0.4.2/docs/source/modules/parcellationtools.rst +0 -71
  65. clabtoolkit-0.4.2/docs/source/modules/surfacetools.rst +0 -95
  66. clabtoolkit-0.4.2/docs/source/modules/visualizationtools.rst +0 -82
  67. clabtoolkit-0.4.2/usage_examples/examples-parcellationtools-methods.ipynb +0 -1808
  68. {clabtoolkit-0.4.2 → clabtoolkit-0.4.4}/AUTHORS.rst +0 -0
  69. {clabtoolkit-0.4.2 → clabtoolkit-0.4.4}/CONTRIBUTING.rst +0 -0
  70. {clabtoolkit-0.4.2 → clabtoolkit-0.4.4}/LICENSE +0 -0
  71. {clabtoolkit-0.4.2 → clabtoolkit-0.4.4}/MANIFEST.in +0 -0
  72. {clabtoolkit-0.4.2 → clabtoolkit-0.4.4}/clabtoolkit/build_visualization_layout.py +0 -0
  73. {clabtoolkit-0.4.2 → clabtoolkit-0.4.4}/clabtoolkit/config/bids.json +0 -0
  74. {clabtoolkit-0.4.2 → clabtoolkit-0.4.4}/clabtoolkit/config/lobes.json +0 -0
  75. {clabtoolkit-0.4.2 → clabtoolkit-0.4.4}/clabtoolkit/config/stats_mapping.json +0 -0
  76. {clabtoolkit-0.4.2 → clabtoolkit-0.4.4}/clabtoolkit/config/viz_views.json +0 -0
  77. {clabtoolkit-0.4.2 → clabtoolkit-0.4.4}/clabtoolkit/config/viz_views_test.json +0 -0
  78. {clabtoolkit-0.4.2 → clabtoolkit-0.4.4}/clabtoolkit/misctools_utils.py +0 -0
  79. {clabtoolkit-0.4.2 → clabtoolkit-0.4.4}/clabtoolkit/pipelinetools.py +0 -0
  80. {clabtoolkit-0.4.2 → clabtoolkit-0.4.4}/clabtoolkit/pointstools.py +0 -0
  81. {clabtoolkit-0.4.2 → clabtoolkit-0.4.4}/clabtoolkit/qcqatools.py +0 -0
  82. {clabtoolkit-0.4.2 → clabtoolkit-0.4.4}/clabtoolkit/segmentationtools.py +0 -0
  83. {clabtoolkit-0.4.2 → clabtoolkit-0.4.4}/clabtoolkit.egg-info/dependency_links.txt +0 -0
  84. {clabtoolkit-0.4.2 → clabtoolkit-0.4.4}/clabtoolkit.egg-info/top_level.txt +0 -0
  85. {clabtoolkit-0.4.2 → clabtoolkit-0.4.4}/docs/Makefile +0 -0
  86. {clabtoolkit-0.4.2 → clabtoolkit-0.4.4}/docs/clabtoolkit.rst +0 -0
  87. {clabtoolkit-0.4.2 → clabtoolkit-0.4.4}/docs/make.bat +0 -0
  88. {clabtoolkit-0.4.2 → clabtoolkit-0.4.4}/docs/modules.rst +0 -0
  89. {clabtoolkit-0.4.2 → clabtoolkit-0.4.4}/docs/source/modules/bidstools.rst +0 -0
  90. {clabtoolkit-0.4.2 → clabtoolkit-0.4.4}/docs/source/modules/misctools.rst +0 -0
  91. {clabtoolkit-0.4.2 → clabtoolkit-0.4.4}/docs/source/modules/plottools.rst +0 -0
  92. {clabtoolkit-0.4.2 → clabtoolkit-0.4.4}/docs/source/modules/qcqatools.rst +0 -0
  93. {clabtoolkit-0.4.2 → clabtoolkit-0.4.4}/setup.cfg +0 -0
  94. {clabtoolkit-0.4.2 → clabtoolkit-0.4.4}/usage_examples/examples-colorstools-methods.ipynb +0 -0
  95. {clabtoolkit-0.4.2 → clabtoolkit-0.4.4}/usage_examples/examples-misctools-methods.ipynb +0 -0
@@ -0,0 +1,81 @@
1
+ =======
2
+ History
3
+ =======
4
+
5
+ 0.4.4 (2026-07-17)
6
+ ------------------
7
+
8
+ * Added get/set accessor methods for Parcellation attributes (data, affine, index, names and colors) with validation
9
+ * Added support for organizing DICOM folders without requiring individual per-series folders
10
+ * Improved the method to compress DICOM sessions
11
+ * Fixed save_tractogram writing the wrong format when overwriting an existing file
12
+ * Fixed colortable loading in tracttools for point-only maps and for maps absent from both data_per_point and data_per_streamline
13
+ * Fixed tractogram merging in tracttools
14
+ * Fixed out_image=None crash and added pathlib.Path support in delete_dwi_volumes
15
+ * Fixed docstrings and type hints in tracttools
16
+ * Renamed the streamline point count variable to nb_points for consistency
17
+ * Removed surf as a variable name for tractograms
18
+ * Removed the old connectome and old_dwitool modules (use connectivitytools and dwitools instead)
19
+ * Reorganized the package imports
20
+ * Documented the tracttools, pointstools and colorstools modules for the first time
21
+ * Corrected the module documentation to match the actual API
22
+
23
+ 0.4.3 (2026-06-10)
24
+ ------------------
25
+
26
+ * Added compute_fc_matrix method to Parcellation class
27
+ * Added get_info method to Connectome and Parcellation classes
28
+ * Added create_carpet_plot function in visualizationtools
29
+ * Added compute_scalar_maps_from_tensor in diffusiontools
30
+ * Added RegionTimeSeries object and integration across the package
31
+ * Added method to generate connectomes
32
+ * Added connected components computation from edge arrays
33
+ * Added region lookup methods in AnnotParcellation
34
+ * Added comprehensive get_info() for AnnotParcellation
35
+ * Added method to binarize and dilate 3D arrays by millimeter distance
36
+ * Added support for pathlib.Path objects as inputs
37
+ * Added option to make TSV file compatible with templateflow
38
+ * Added new colors to the bcolors class
39
+ * Added bundle id map and updated names
40
+ * Added notebook with examples for OHBM 2026
41
+ * Added new ecosystem figure and logo
42
+ * Refactored stats_from_vector for edge cases with nonzeros_only=True
43
+ * Refactored AnnotParcellation gii2annot/annot2gii to use nibabel instead of FreeSurfer mris_convert
44
+ * Extended merge_to_4d method to deal with DWI data
45
+ * Fixed strict entity and suffix validation in is_bids_filename
46
+ * Fixed pyvista notebook crash from threaded display
47
+ * Fixed color table names bug
48
+ * Fixed dimensions field bugs ("dims" vs "dim")
49
+ * Multiple bug fixes, dependency updates, and documentation improvements
50
+
51
+ 0.4.1 (2026-02-19)
52
+ ------------------
53
+
54
+ * Major refactoring of Parcellation class with improved attribute handling
55
+ * Enhanced color table loading and export with multiple format support
56
+ * Added region adjacency computation to Parcellation
57
+ * Improved BIDS file entity extraction with parallel processing
58
+ * Added DiffusionScheme class for gradient visualization
59
+ * Enhanced Connectome class initialization and metrics computation
60
+ * Added derivatives inventory functionality
61
+ * Improved surface tools with PyVista fallback support
62
+ * Added usage examples notebooks
63
+ * Multiple bug fixes in mask handling, color processing, and data type conversion
64
+ * Improved documentation and code organization
65
+
66
+ 0.3.4 (2025-01-09)
67
+ ------------------
68
+
69
+ * Enhanced documentation and ReadTheDocs configuration
70
+ * Moved region growing method to imagetools module
71
+ * Improved Sphinx autodoc configuration for better API documentation
72
+ * Multiple improvements to surface visualization and plotting functionality
73
+ * Added new morphometry and connectivity analysis tools
74
+ * Enhanced BIDS dataset handling and entity management
75
+ * Improved surface mesh operations and color mapping
76
+ * Added network analysis tools and visualization capabilities
77
+
78
+ 0.3.1 (2025-05-22)
79
+ ------------------
80
+
81
+ * Fourth release on PyPI.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: clabtoolkit
3
- Version: 0.4.2
3
+ Version: 0.4.4
4
4
  Summary: A comprehensive toolkit for neuroimaging data processing and analysis
5
5
  Author-email: Yasser Alemán-Gómez <yasseraleman@protonmail.com>
6
6
  Maintainer-email: Yasser Alemán-Gómez <yasseraleman@protonmail.com>
@@ -39,6 +39,10 @@ Requires-Dist: matplotlib>=3.10.3
39
39
  Requires-Dist: pyvista>=0.45.3
40
40
  Requires-Dist: nilearn>=0.12.0
41
41
  Requires-Dist: joblib>=1.5.1
42
+ Requires-Dist: colorama>=0.4.6
43
+ Requires-Dist: dipy>=1.11.0
44
+ Requires-Dist: screeninfo>=0.8.1
45
+ Requires-Dist: ipython>=8.0.0
42
46
  Provides-Extra: dev
43
47
  Requires-Dist: pytest>=8.4.1; extra == "dev"
44
48
  Requires-Dist: pytest-cov>=6.2.1; extra == "dev"
@@ -63,6 +67,11 @@ Dynamic: license-file
63
67
  Connectomics Lab Toolkit
64
68
  ========================
65
69
 
70
+ .. image:: docs/source/_static/clabtoolkit_logo.png
71
+ :alt: clabtoolkit logo
72
+ :align: center
73
+ :width: 400
74
+
66
75
 
67
76
  .. image:: https://img.shields.io/pypi/v/clabtoolkit.svg
68
77
  :target: https://pypi.python.org/pypi/clabtoolkit
@@ -2,6 +2,11 @@
2
2
  Connectomics Lab Toolkit
3
3
  ========================
4
4
 
5
+ .. image:: docs/source/_static/clabtoolkit_logo.png
6
+ :alt: clabtoolkit logo
7
+ :align: center
8
+ :width: 400
9
+
5
10
 
6
11
  .. image:: https://img.shields.io/pypi/v/clabtoolkit.svg
7
12
  :target: https://pypi.python.org/pypi/clabtoolkit
@@ -2,4 +2,4 @@
2
2
 
3
3
  __author__ = """Yasser Alemán-Gómez"""
4
4
  __email__ = "yasseraleman@protonmail.com"
5
- __version__ = "0.4.1"
5
+ __version__ = "0.4.4"
@@ -389,7 +389,18 @@ def insert_entity(
389
389
  # If `entity2add` is empty after filtering, return the original entity
390
390
  if not entity2add:
391
391
  if is_string:
392
+ # Restore `suffix` and `extension` if they were removed
393
+ if suffix:
394
+ entity["suffix"] = suffix
395
+ if extension:
396
+ entity["extension"] = extension
392
397
  return entity2str(entity)
398
+
399
+ # Restore `suffix` and `extension` if they were removed
400
+ if suffix:
401
+ entity["suffix"] = suffix
402
+ if extension:
403
+ entity["extension"] = extension
393
404
  return entity
394
405
 
395
406
  else:
@@ -561,6 +572,7 @@ def recursively_replace_entity_key(root_dir: str, replacements: dict):
561
572
  cltmisc.rename_folders(all_dirs, replacements)
562
573
 
563
574
 
575
+ ####################################################################################################
564
576
  def recursively_delete_entity(root_dir: str, key2rem: Union[List[str], str, dict]):
565
577
  """
566
578
  This method deletes entities in all the files and folders of a BIDs dataset.
@@ -627,6 +639,7 @@ def recursively_delete_entity(root_dir: str, key2rem: Union[List[str], str, dict
627
639
  cltmisc.rename_folders(all_dirs, key2rem_dict)
628
640
 
629
641
 
642
+ ####################################################################################################
630
643
  def recursively_insert_entity(
631
644
  root_dir: str, entity2add: Dict[str, str], prev_entity: str = None
632
645
  ) -> None:
@@ -788,7 +801,6 @@ def get_all_entities(root_dir: str) -> Tuple[Dict[str, Set[str]], List[str]]:
788
801
  suffix = ent_dict.pop("suffix")
789
802
 
790
803
  ent_dict.pop("extension", None)
791
- ent_dict.pop("run", None)
792
804
 
793
805
  return list(ent_dict.keys()), suffix
794
806
 
@@ -1040,7 +1052,12 @@ def entities_to_table(
1040
1052
  entities_dict.pop("extension")
1041
1053
 
1042
1054
  # Extract suffix before removing it
1043
- suffix = entities_dict.pop("suffix", "")
1055
+ if "suffix" in entities_dict:
1056
+ if include_suffix:
1057
+ # Add an entity at the end called "Type"
1058
+ tmp_suffix = entities_dict["suffix"]
1059
+
1060
+ entities_dict.pop("suffix")
1044
1061
 
1045
1062
  if entities_to_extract is not None:
1046
1063
  if isinstance(entities_to_extract, str):
@@ -1079,8 +1096,8 @@ def entities_to_table(
1079
1096
  result_df.insert(0, entity.capitalize(), value)
1080
1097
 
1081
1098
  # Append Type column at the end if requested
1082
- if include_suffix:
1083
- result_df["Type"] = suffix
1099
+ if "tmp_suffix" in locals() and include_suffix:
1100
+ result_df.insert(0, "Type", tmp_suffix)
1084
1101
 
1085
1102
  else:
1086
1103
  if result_df.empty:
@@ -1754,36 +1771,106 @@ def get_derivatives_folders(
1754
1771
 
1755
1772
 
1756
1773
  ####################################################################################################
1757
- def is_bids_filename(filename: str) -> bool:
1774
+ def is_bids_filename(filename: str, extensive: bool = False) -> bool:
1758
1775
  """
1759
1776
  Validates a BIDS filename structure, handling extensions and entity order.
1760
1777
 
1761
- Args:
1762
- filename (str): The filename to validate.
1778
+ Parameters:
1779
+ -----------
1780
+ filename : str
1781
+ The filename to validate, which may include extensions (e.g., .nii.gz).
1782
+
1783
+ extensive : bool, default=False
1784
+ If True, performs additional checks against a BIDS configuration file to ensure that all
1785
+ entities in the filename are defined in the config. If False, only checks the basic structure
1786
+ of the filename.
1787
+
1788
+ Returns:
1789
+ --------
1790
+ bool
1791
+ True if the filename follows BIDS conventions, False otherwise.
1792
+
1793
+ Examples:
1794
+ ---------
1795
+ >>> is_bids_filename("sub-01_ses-pre_task-rest_bold.nii.gz")
1796
+ True
1797
+ >>> is_bids_filename("sub-01_ses-pre_task-rest_bold")
1798
+ True
1799
+ >>> is_bids_filename("sub-01_ses-pre_task-rest.nii.gz")
1800
+ True
1801
+ >>> is_bids_filename("sub-01_ses-pre_task-rest")
1802
+ True
1803
+ >>> is_bids_filename("sub-01_ses-pre_task-rest_bold_extra.nii.gz")
1804
+ False
1805
+ >>> is_bids_filename("sub-01_ses-pre_task-rest_bold_extra")
1763
1806
 
1764
- Returns
1765
- bool: True if valid BIDS filename, False otherwise.
1766
1807
  """
1767
1808
  # Remove extension if present
1768
1809
  filename = cltmisc.get_real_basename(filename)
1769
1810
  base_filename = filename.split(".")[0]
1770
1811
 
1771
1812
  parts = base_filename.split("_")
1772
- if not parts:
1813
+ if len(parts) < 2:
1814
+ # Need at least one entity-label pair + a suffix
1773
1815
  return False
1774
1816
 
1775
1817
  entity_pattern = re.compile(r"^[a-zA-Z0-9]+-[a-zA-Z0-9]+$")
1818
+ suffix_pattern = re.compile(r"^[a-zA-Z0-9]+$")
1776
1819
 
1777
- # Check that at least one entity-label pair is present
1778
- has_entity_label = False
1779
- for part in parts:
1780
- if "-" in part:
1781
- has_entity_label = True
1782
- if not entity_pattern.match(part):
1783
- return False
1784
- if not has_entity_label:
1820
+ # All parts except the last must be valid entity-label pairs (e.g. sub-01, ses-M00)
1821
+ for part in parts[:-1]:
1822
+ if not entity_pattern.match(part):
1823
+ return False
1824
+
1825
+ # The last part is the suffix (e.g. T1w, bold) — no dash allowed
1826
+ if not suffix_pattern.match(parts[-1]):
1785
1827
  return False
1786
1828
 
1829
+ # Check also that all the entities are on the json config file
1830
+ cwd = os.path.dirname(os.path.abspath(__file__))
1831
+ default_config_path = os.path.join(cwd, "config", "bids.json")
1832
+
1833
+ if extensive:
1834
+ try:
1835
+ with open(default_config_path, "r") as f:
1836
+ config_data = json.load(f)
1837
+
1838
+ if (
1839
+ "bids_entities" in config_data
1840
+ and "raw_entities" in config_data["bids_entities"]
1841
+ and "derivatives_entities" in config_data["bids_entities"]
1842
+ ):
1843
+ valid_entities = set(
1844
+ list(config_data["bids_entities"]["raw_entities"].keys())
1845
+ + list(config_data["bids_entities"]["derivatives_entities"].keys())
1846
+ )
1847
+ valid_suffixes = set(
1848
+ config_data["bids_entities"].get("raw_suffix", [])
1849
+ + config_data["bids_entities"].get("derivatives_suffix", [])
1850
+ )
1851
+ else:
1852
+ raise ValueError(
1853
+ "Default config JSON does not have the expected structure."
1854
+ )
1855
+ except FileNotFoundError:
1856
+ raise FileNotFoundError(
1857
+ f"Default configuration file not found at: {default_config_path}"
1858
+ )
1859
+ except json.JSONDecodeError:
1860
+ raise ValueError(
1861
+ f"Error parsing the default configuration file: {default_config_path}"
1862
+ )
1863
+
1864
+ # Validate each entity key against the known BIDS entities
1865
+ for part in parts[:-1]:
1866
+ entity_key = part.split("-")[0]
1867
+ if entity_key not in valid_entities:
1868
+ return False
1869
+
1870
+ # Validate the suffix against the known BIDS suffixes
1871
+ if parts[-1] not in valid_suffixes:
1872
+ return False
1873
+
1787
1874
  return True
1788
1875
 
1789
1876
 
@@ -122,6 +122,9 @@ class bcolors:
122
122
  BOLD = "\033[1m"
123
123
  ITALIC = "\033[3m"
124
124
  UNDERLINE = "\033[4m"
125
+ DIM = "\033[2m"
126
+ NORMAL = "\033[22m"
127
+ RESET_ALL = "\033[0m"
125
128
 
126
129
 
127
130
  ####################################################################################################
@@ -899,27 +902,38 @@ def harmonize_colors(
899
902
 
900
903
  >>> harmonize_colors(colors, output_format='rgb')
901
904
  array([[255, 87, 51],
902
- [255, 87, 51],
903
- [ 51, 87, 255]], dtype=uint8)
905
+ [255, 87, 51],
906
+ [ 51, 87, 255]], dtype=uint8)
904
907
 
905
908
  >>> harmonize_colors(colors, output_format='rgbnorm')
906
909
  array([[1. , 0.34117647, 0.2 ],
907
- [1. , 0.34117647, 0.2 ],
908
- [0.2 , 0.34117647, 1. ]])
910
+ [1. , 0.34117647, 0.2 ],
911
+ [0.2 , 0.34117647, 1. ]])
909
912
 
910
913
  >>> # Single color input
911
914
  >>> harmonize_colors((255, 87, 51))
912
915
  ['#ff5733']
913
916
  """
914
917
 
915
- # Handle single color inputs
918
+ # Normalize input into iterable of colors
916
919
  if isinstance(colors, str):
917
920
  colors = [colors]
921
+
918
922
  elif isinstance(colors, tuple):
919
923
  colors = [colors]
920
924
 
921
- # Validate input type
922
- if not isinstance(colors, (list, np.ndarray)):
925
+ elif isinstance(colors, np.ndarray):
926
+ if colors.ndim == 1:
927
+ # Single color (e.g., [R,G,B] or [R,G,B,A])
928
+ colors = [colors]
929
+ elif colors.ndim == 2:
930
+ # Multiple colors (Nx3 or Nx4)
931
+ colors = [row for row in colors]
932
+ else:
933
+ raise ValueError("NumPy array must be 1D or 2D for colors")
934
+
935
+ # Final validation
936
+ if not isinstance(colors, list):
923
937
  raise TypeError("Input must be a string, tuple, list, or numpy array")
924
938
 
925
939
  # Validate output format
@@ -1,6 +1,7 @@
1
1
  {
2
2
  "metrics_units": {
3
3
  "thickness": "mm",
4
+ "nvertices": "au",
4
5
  "area": "cm2",
5
6
  "volume": "cm3",
6
7
  "curv": "mm-1",