Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/source/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ PyTheranostics is a comprehensive Python library for nuclear medicine image proc

intro/overview
intro/installation
intro/logging
tutorials/getting_started/basic_usage

.. toctree::
Expand Down
262 changes: 262 additions & 0 deletions docs/source/intro/logging.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,262 @@
.. _logging_guide:

Logging and Verbosity Control
==============================

PyTheranostics uses Python's standard ``logging`` module to provide configurable output verbosity. This allows you to control how much information is displayed during processing, making it suitable for both interactive notebook use and automated pipelines.

Overview
--------

The logging system provides four severity levels:

.. list-table::
:widths: 15 30 55
:header-rows: 1

* - Level
- When to Use
- What You'll See
* - ``DEBUG``
- Troubleshooting and development
- Every step: individual timepoint loading, mask resampling operations, registration iterations
* - ``INFO``
- Normal production use
- Important milestones: "Loaded 5 CT timepoints", "Applied mappings", file save operations
* - ``WARNING``
- Default (quiet mode)
- Only important notices: mask overwrites, data quality issues, deprecated features
* - ``ERROR``
- Critical issues only
- Fatal errors that prevent processing

Quick Start
-----------

Set Logging Level in Notebooks
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Add this at the top of your notebook to control verbosity:

.. code-block:: python

import logging

# Quiet mode (recommended for notebooks) - only warnings and errors
logging.basicConfig(level=logging.WARNING, format='%(levelname)s: %(message)s')

# Normal mode - see important milestones
logging.basicConfig(level=logging.INFO, format='%(levelname)s: %(message)s')

# Verbose mode - see every step (for debugging)
logging.basicConfig(level=logging.DEBUG, format='%(levelname)s: %(message)s')

.. note::
Call ``basicConfig()`` **before** importing PyTheranostics modules for the settings to take effect.

Example: Clean Notebook Output
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

.. code-block:: python

import logging
logging.basicConfig(level=logging.WARNING) # Quiet mode

from pytheranostics.imaging_ds.cycle_loader import create_studies_with_masks

# This will now run quietly, only showing warnings/errors
longCT, longSPECT, inj, mappings = create_studies_with_masks(
storage_root="./data",
patient_id="PATIENT001",
cycle_no=1,
calibration_factor=106.0,
auto_map=True
)

Example: Debugging with Verbose Output
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

.. code-block:: python

import logging
logging.basicConfig(level=logging.DEBUG, format='%(name)s - %(levelname)s: %(message)s')

from pytheranostics.imaging_ds.cycle_loader import create_studies_with_masks

# This will show detailed progress:
# - Loading timepoint 0 from CT_TP1...
# - ✓ Timepoint 0 loaded
# - Resampling Masks: Liver ...
# - etc.
longCT, longSPECT, inj, mappings = create_studies_with_masks(...)

Affected Modules
----------------

The following modules use the logging system:

Imaging & Data Loading
~~~~~~~~~~~~~~~~~~~~~~~

* ``pytheranostics.imaging_ds.longitudinal_study``

- Logs timepoint loading progress (parallel and sequential)
- Reports mask addition and overwrites
- Shows registration iterations and Jaccard indices
- Confirms file save operations

* ``pytheranostics.imaging_ds.mapping_summary``

- Reports mapping statistics per timepoint
- Shows applied mappings when verbose mode enabled
- Confirms JSON export of mapping details

* ``pytheranostics.imaging_tools.tools``

- Reports DICOM metadata extraction (injected activity, patient weight)
- Warns about orientation matrix corrections
- Shows mask resampling and registration progress

Common Use Cases
----------------

Case 1: Interactive Notebook (Recommended)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

For clean notebook output, use WARNING level:

.. code-block:: python

import logging
logging.basicConfig(level=logging.WARNING, format='%(message)s')

This gives you a clean interface while still alerting you to important issues like:

* Mask overwrites
* Missing DICOM metadata
* Data quality warnings

Case 2: Production Pipeline
~~~~~~~~~~~~~~~~~~~~~~~~~~~~

For automated workflows, use INFO level with more context:

.. code-block:: python

import logging
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(name)s - %(levelname)s: %(message)s',
filename='processing.log'
)

This logs important milestones to a file for audit trails.

Case 3: Debugging Issues
~~~~~~~~~~~~~~~~~~~~~~~~~

When troubleshooting, enable DEBUG with full context:

.. code-block:: python

import logging
logging.basicConfig(
level=logging.DEBUG,
format='%(asctime)s - %(name)s:%(lineno)d - %(levelname)s: %(message)s'
)

This shows every operation with timestamps and source locations.

Advanced Configuration
----------------------

Module-Specific Levels
~~~~~~~~~~~~~~~~~~~~~~~

You can set different log levels for different modules:

.. code-block:: python

import logging

# Global default: WARNING
logging.basicConfig(level=logging.WARNING)

# But show INFO for longitudinal study operations
logging.getLogger('pytheranostics.imaging_ds.longitudinal_study').setLevel(logging.INFO)

# And DEBUG for mapping summary
logging.getLogger('pytheranostics.imaging_ds.mapping_summary').setLevel(logging.DEBUG)

Custom Formatters
~~~~~~~~~~~~~~~~~

Customize the output format:

.. code-block:: python

import logging

# Simple format for notebooks
logging.basicConfig(level=logging.INFO, format='%(levelname)s: %(message)s')

# Detailed format for log files
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s | %(name)-40s | %(levelname)-8s | %(message)s',
datefmt='%Y-%m-%d %H:%M:%S'
)

Troubleshooting
---------------

"Logging settings not taking effect"
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

**Problem**: You set the logging level but still see too much or too little output.

**Solution**: Make sure to call ``logging.basicConfig()`` **before** importing any PyTheranostics modules:

.. code-block:: python

# ✓ CORRECT ORDER
import logging
logging.basicConfig(level=logging.WARNING)
from pytheranostics.imaging_ds import LongitudinalStudy # Now uses WARNING level

# ✗ WRONG ORDER
from pytheranostics.imaging_ds import LongitudinalStudy # Uses default level
import logging
logging.basicConfig(level=logging.WARNING) # Too late!

"Multiple log messages appearing"
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

**Problem**: Each message appears multiple times or from different loggers.

**Solution**: This happens when ``basicConfig()`` is called multiple times. In Jupyter notebooks, restart the kernel and configure logging once at the start:

.. code-block:: python

# In your first notebook cell:
import logging

# Only call this once per kernel session
if not logging.getLogger().hasHandlers():
logging.basicConfig(level=logging.INFO, format='%(message)s')

Migration from Previous Versions
---------------------------------

If you're upgrading from a version that used ``print()`` statements, no code changes are required. The transition is automatic:

* All previous ``print()`` output is now logged at INFO or WARNING level
* To restore previous behavior (seeing all messages), use ``logging.INFO``
* To reduce output in notebooks, use ``logging.WARNING``

See Also
--------

* :ref:`overview` - General introduction to PyTheranostics
* :ref:`installation` - Installation instructions
* `Python Logging Documentation <https://docs.python.org/3/library/logging.html>`_ - Official Python logging guide
Original file line number Diff line number Diff line change
@@ -1,5 +1,38 @@
{
"_instructions": "Map VOI names between different naming conventions and configure visualization colors. Edit this file to customize organ name mappings and plot appearance.",
"_instructions": "Configure VOI/organ naming conventions, mappings, and visualization settings.",

"valid_organ_names": {
"_description": "List of valid organ/VOI names for validation. These default names are compatible with OLINDA dosimetry calculations. Users can add custom organs as needed for their workflows.",
"names": [
"Kidney_Left",
"Kidney_Right",
"Liver",
"Spleen",
"Bladder",
"SubmandibularGland_Left",
"SubmandibularGland_Right",
"ParotidGland_Left",
"ParotidGland_Right",
"BoneMarrow",
"Skeleton",
"WholeBody",
"RemainderOfBody",
"TotalTumorBurden"
]
},

"canonical_mappings": {
"_description": "Best-effort ROI name normalization for auto_map mode. Maps abbreviated/common names to canonical organ names. Used when auto_map=True is set in create_studies_with_masks.",
"mappings": {
"Kidney_L": "Kidney_Left",
"Kidney_R": "Kidney_Right",
"Parotid_L": "ParotidGland_Left",
"Parotid_R": "ParotidGland_Right",
"Submandibular_L": "SubmandibularGland_Left",
"Submandibular_R": "SubmandibularGland_Right",
"WBCT": "WholeBody"
}
},

"ct_mappings": {
"organ_name_in_ct": "standardized_name"
Expand All @@ -10,6 +43,13 @@
},

"plot_colors": {
"_description": "Configure colors for organ contours in MIP plots. Add entries with organ names or keywords as keys (case-insensitive substring matching) and matplotlib color names or hex codes as values. Leave empty {} to use matplotlib's default color cycle. Example: 'kidney': 'lime', 'liver': '#FFD700', 'tumor': 'red'"
"_description": "Color mapping for organ contours in MIP plots. Keys can be organ names or keywords (case-insensitive substring match). Any matplotlib color name or hex code is valid.",
"kidney": "lime",
"parotid": "red",
"submandibular": "red",
"lesion": "magenta",
"liver": "yellow",
"spleen": "cyan",
"tumor": "magenta"
}
}
Loading