.. DO NOT EDIT. .. THIS FILE WAS AUTOMATICALLY GENERATED BY SPHINX-GALLERY. .. TO MAKE CHANGES, EDIT THE SOURCE PYTHON FILE: .. "auto_examples\03_quantify\plot_05_each_habitat_radiomics.py" .. LINE NUMBERS ARE GIVEN BELOW. .. only:: html .. note:: :class: sphx-glr-download-link-note :ref:`Go to the end ` to download the full example code. .. rst-class:: sphx-glr-example-title .. _sphx_glr_auto_examples_03_quantify_plot_05_each_habitat_radiomics.py: Per-habitat radiomics ===================== **Background.** Classic radiomics computes intensity and texture features over the whole tumour. Per-habitat radiomics computes the same PyRadiomics features separately inside each habitat, so every sub-region gets its own intensity and texture description. **Purpose.** You get one row per subject with columns ``habitat_{id}_{feature}_of_{modality}`` (plus ``has_habitat_{id}``), maps of voxel-wise GLCM Id inside each habitat, and a bar chart comparing the habitats feature by feature. **Key terms.** * **first-order feature** -- a statistic of the voxel intensities alone (e.g. ``Mean``, ``Energy``), ignoring their spatial arrangement. * **GLCM feature** -- texture from the grey-level co-occurrence matrix, i.e. how often pairs of neighbouring voxels share grey levels (e.g. ``Id``). * **binWidth** -- width of the intensity bins used before texture features; bins are set per habitat, as in PyRadiomics ``execute(label=id)``. * **one-step habitats** -- see :doc:`/auto_examples/04_designs/plot_02_inside_each_subject`; match ids before comparing ``habitat_1_*`` across patients (:doc:`/auto_examples/06_matching/plot_07_match_labels`). Extract first-order and GLCM features **within each habitat subregion** using :class:`~habit.habitat_features.EachHabitatRadiomicsFeatures`. .. GENERATED FROM PYTHON SOURCE LINES 33-35 One-step habitats, then per-habitat PyRadiomics on the intensity image. sphinx_gallery_thumbnail_number = 1 .. GENERATED FROM PYTHON SOURCE LINES 35-80 .. code-block:: Python from pathlib import Path from typing import Any, Dict, List, Optional, Tuple import matplotlib.pyplot as plt import numpy as np import pandas as pd from habit.contracts import MaskVolume, cohort_from_directory from habit.datasets import fetch_demo from habit.habitat_features import EachHabitatRadiomicsFeatures from habit.recipes import one_step_habitat from habit.voxel_features import extract_voxel_texture from habit.viz import plot_voxel_texture_slice DATA = fetch_demo() MODALITIES = ("LAP",) ROI = "LAP" cohort = cohort_from_directory(DATA, modalities=MODALITIES, roi=ROI)[:1] result = one_step_habitat( modalities=MODALITIES, n_habitats=3, random_seed=0, roi=ROI ).fit_predict(cohort) subject = cohort[0] habitat_map = result.habitat_maps[0] # Narrow PyRadiomics params keep the gallery table readable. params: Dict[str, Any] = { "imageType": {"Original": {}}, "featureClass": { "firstorder": ["Mean", "Energy"], "glcm": ["Autocorrelation", "Id"], }, "setting": {"binWidth": 25, "voxelArrayShift": 0}, } # One PyRadiomics pass per habitat id, using the habitat map as the mask. table = EachHabitatRadiomicsFeatures(params=params)(subject, habitat_map) row = table.frame.iloc[0] display_cols = [ col for col in table.feature_columns if "firstorder" in col or "glcm" in col ][:8] print("Per-habitat radiomics (sample columns):") print(row[display_cols].to_string()) row[display_cols] .. rst-class:: sphx-glr-script-out .. code-block:: none HABIT demo data (cached) DATA (preprocessed root): C:\Users\dongm\.habit_data\demo-data-v1\preprocessed On-disk inventory of this folder: subjects (5): subj001, subj002, subj003, subj004, subj005 image series: LAP, PVP, delay_3min, pre_contrast mask keys: LAP, PVP, delay_3min, pre_contrast example image: images/subj001/delay_3min/WATER__BH_Ax_LAVA_Flex_3min_Series0012.nrrd example mask: masks/subj001/delay_3min/WATER__BH_Ax_LAVA_Flex_10min_Series0017_mask.nrrd Your own data must use the same folder tree (change IDs / series names): DATA/ images/// masks/// Then load it with the same call the demos use: cohort = cohort_from_directory(DATA, modalities=("LAP",), roi="LAP") Swap DATA / modalities / roi to match your tree. Mask key is often the same as one image series (here LAP). Cohort.map[_DefineAndLabelWithinSubject]: 0%| | 0/1 [00:00 Optional[str]: """Return the first feature column matching habitat id + suffix.""" prefix = f"habitat_{habitat_id}_" for col in table.feature_columns: if col.startswith(prefix) and suffix in col: return col return None panel_rows: List[Dict[str, Any]] = [] for hid in habitat_ids: for label, suffix in feature_specs: col = _column_for(hid, suffix) panel_rows.append( { "habitat": f"H{hid}", "feature": label, "value": float(row[col]) if col is not None else float("nan"), } ) panel = pd.DataFrame(panel_rows) print(panel.to_string(index=False)) panel fig, axes = plt.subplots(1, len(feature_specs), figsize=(9.5, 3.2), sharey=False) if len(feature_specs) == 1: axes = [axes] x = np.arange(len(habitat_ids)) xticklabels = [f"H{hid}" for hid in habitat_ids] for ax, (label, suffix) in zip(axes, feature_specs): values: List[float] = [] for hid in habitat_ids: col = _column_for(hid, suffix) values.append(float(row[col]) if col is not None else float("nan")) ax.bar(x, values, color="#0072B2", width=0.65) ax.set_xticks(x) ax.set_xticklabels(xticklabels) ax.set_ylabel(label) ax.set_title(label) fig.suptitle("Per-habitat radiomics (one scale per feature)", y=1.02) fig.tight_layout() fig.savefig("out/each_habitat_radiomics_bar.png", dpi=150, bbox_inches="tight") plt.show() .. image-sg:: /auto_examples/03_quantify/images/sphx_glr_plot_05_each_habitat_radiomics_004.png :alt: Per-habitat radiomics (one scale per feature), Mean, Energy, GLCM Id :srcset: /auto_examples/03_quantify/images/sphx_glr_plot_05_each_habitat_radiomics_004.png :class: sphx-glr-single-img .. rst-class:: sphx-glr-script-out .. code-block:: none habitat feature value H1 Mean 8.646292e+02 H1 Energy 1.069709e+10 H1 GLCM Id 5.245007e-01 H2 Mean 1.052129e+03 H2 Energy 1.115465e+10 H2 GLCM Id 5.140657e-01 H3 Mean 6.677535e+02 H3 Energy 4.696840e+09 H3 GLCM Id 5.060708e-01 .. rst-class:: sphx-glr-timing **Total running time of the script:** (0 minutes 7.053 seconds) .. _sphx_glr_download_auto_examples_03_quantify_plot_05_each_habitat_radiomics.py: .. only:: html .. container:: sphx-glr-footer sphx-glr-footer-example .. container:: sphx-glr-download sphx-glr-download-jupyter :download:`Download Jupyter notebook: plot_05_each_habitat_radiomics.ipynb ` .. container:: sphx-glr-download sphx-glr-download-python :download:`Download Python source code: plot_05_each_habitat_radiomics.py ` .. container:: sphx-glr-download sphx-glr-download-zip :download:`Download zipped: plot_05_each_habitat_radiomics.zip ` .. only:: html .. rst-class:: sphx-glr-signature `Gallery generated by Sphinx-Gallery `_