Independently maintained fork of PySkinDose. Original author: Max Hellström. This fork is not an official or endorsed PySkinDose release unless upstream maintainers say otherwise.
Current maintainer: @kgrizz-git — see SUPPORT.md and GOVERNANCE.md.
This repository estimates peak skin dose (PSD) and 3D skin dose maps from DICOM X-ray Radiation Dose Structured Reports (RDSR) and supported tabular exports, while allowing local modifications beyond upstream.
The distribution and import package name is mypyskindose (distinct from upstream).
MyPySkinDose is intended for research, education, development, and institutional quality-assurance workflows. It is not FDA-cleared (or otherwise certified) as a medical device, and results are not independently validated for making patient-care decisions on their own.
Physicists and physicians remain responsible for reviewing outputs, confirming that inputs and geometry settings are appropriate, and making any clinical or patient-care decisions. Do not treat dose maps or PSD values as a substitute for professional judgment, institutional policy, or regulatory clearance.
Never commit or attach real patient data to issues, pull requests, or the repository — see CONTRIBUTING.md and dev-docs/PRIVACY_AND_SENSITIVE_ASSETS.md.
- Python 3.11 or above
- A settings configuration, typically based on src/mypyskindose/settings_example.json
- A DICOM RDSR file (
.dcm), a pre-parsed JSON export, or a supported tabular event-table export (.csv,.tsv,.xlsx)
For local development, install the project in editable mode:
pip install -e .To include the GUI dependencies:
pip install -e ".[gui]"For full development setup (linting, testing, docs, Jupyter), install the optional extras you need:
pip install -e ".[dev,gui]" # lint/type/test toolchain + GUI
pip install -e ".[dev,gui,docs,notebooks]" # everything (docs + JupyterLab)MyPySkinDose includes a NiceGUI-based graphical interface.
Quick launch (macOS/Linux):
chmod +x run_gui.sh # one-time setup, enables executing the sh script
./run_gui.shThe script prompts you to run in browser mode (default) or native window mode.
Direct Python command:
python -m mypyskindose --mode gui # browser mode
python -m mypyskindose --mode gui --native # native window (requires pywebview)Native window mode remembers the last window size, position, and maximized state in
~/.mypyskindose/gui.json (first launch opens maximized; Restore returns to the saved
normal size).
The GUI has no authentication and loads PHI-derived RDSR data into a single
shared, process-global state. To keep that off the network, browser mode binds to
127.0.0.1 (localhost only) by default — reachable only from the machine it runs
on.
Serving it to other hosts is opt-in via --host:
python -m mypyskindose --mode gui --host 0.0.0.0 # serve on the LANOnly do this on a trusted network, and behind your own access controls, since anyone who can reach the port can view loaded patient data, trigger exports, and mutate shared settings.
The CLI and browser-mode GUI log to the console only. Native mode has no console, so it also writes a diagnostic log to your system temp directory:
<tempdir>/mypyskindose-gui.log
This file is truncated at each launch and size-capped (rotating, ~4 MB
max across .log/.log.1–.3), so it does not accumulate across sessions.
To protect PHI, the app does not log file names or paths (RDSR filenames
often contain patient name/MRN/accession) — only file type, size, and event
counts. By default the file sink records INFO and above; verbose DEBUG output
is opt-in per category via a debug.json in the working directory, e.g.:
{ "GUI": true, "PROCESSING": true, "CALCULATION": true, "RENDERING": true }Even with debug enabled, identifiers are still redacted. The log lives outside the repo by design (temp dir); delete it any time — it is recreated on next launch.
The GUI works fully without Tkinter, but uses it for two niceties: the native
Save As file dialog when exporting, and detecting your screen size to size
the native window. If Tkinter is missing you'll see a log line like
No module named '_tkinter', exports fall back to a browser-style download, and
the window opens at a default size — nothing crashes.
Tkinter ships with Python but is only built when the Tcl/Tk libraries are present
at build time, so it can be absent (commonly with pyenv builds). It is not a
pip package — do not add it to the project dependencies. To install it:
| Platform | Command |
|---|---|
| macOS, Homebrew Python | brew install python-tk (or python-tk@3.12 for a specific version) |
| macOS, pyenv Python | brew install tcl-tk, then reinstall the interpreter: pyenv install 3.12.9 |
| Debian / Ubuntu | sudo apt install python3-tk |
| Fedora | sudo dnf install python3-tkinter |
| Windows | Included with the python.org installer — keep "tcl/tk and IDLE" checked |
Verify with: python -c "import tkinter; print(tkinter.TkVersion)".
If you only need the documentation tooling as well:
pip install -e ".[docs]"Within the intended-use boundary above, MyPySkinDose is meant to be used in a few different ways:
- Inspect or debug the examination geometry before doing dose calculations.
- Step through irradiation events from an RDSR study to understand beam orientation and positioning.
- Calculate a skin dose map on a mathematical or human phantom.
- Export the calculation result as HTML, JSON, XLSX, PDF, or DOCX rich audit report, or as a Python dictionary for downstream processing.
- Run the analysis headlessly from your own Python scripts.
The main user-facing workflow is:
- Load or create a
PyskindoseSettingsobject. - Choose a phantom and positioning.
- Select a mode such as
plot_setup,plot_procedure,plot_event, orcalculate_dose. - Run
main()with a path to an RDSR file, a JSON export, or a tabular file (.csv,.tsv,.xlsx). - Review the interactive plot or exported result.
New to MyPySkinDose? The easiest way to learn is to start with the interactive getting-started notebook:
📓 docs/source/getting_started/getting_started.ipynb
This notebook walks you through:
- Loading and configuring settings
- Setting up different phantom models and positioning
- Inspecting RDSR procedures interactively
- Running calculations and generating dose maps
- Exporting results in different formats
To run the notebook:
pip install -e .
pip install jupyter
jupyter notebook docs/source/getting_started/getting_started.ipynbIf you prefer to learn by example with code snippets instead, continue to the section below.
from mypyskindose import PyskindoseSettings, load_settings_example_json
from mypyskindose.main import main
settings = PyskindoseSettings(settings=load_settings_example_json())
settings.mode = "plot_setup"
settings.phantom.model = "cylinder"
main(settings=settings)This is useful for checking the initial geometry, patient/table positioning, and phantom choice before loading a real study.
from mypyskindose import PyskindoseSettings, get_path_to_example_rdsr_files, load_settings_example_json
from mypyskindose.main import main
settings = PyskindoseSettings(settings=load_settings_example_json())
settings.mode = "plot_procedure"
settings.phantom.model = "cylinder"
settings.plot.max_events_for_patient_inclusion = 0
rdsr_dir = get_path_to_example_rdsr_files()
main(settings=settings, file_path=rdsr_dir / "siemens_axiom_example_procedure.dcm")Use plot_procedure to scroll through irradiation events and understand how the beam geometry changes over the study.
from mypyskindose import PyskindoseSettings, get_path_to_example_rdsr_files, load_settings_example_json
from mypyskindose.main import main
settings = PyskindoseSettings(settings=load_settings_example_json())
settings.mode = "calculate_dose"
settings.output_format = "dict"
settings.plot.plot_dosemap = True
settings.phantom.model = "human"
settings.phantom.human_mesh = "hudfrid"
rdsr_dir = get_path_to_example_rdsr_files()
output = main(settings=settings, file_path=rdsr_dir / "siemens_axiom_example_procedure.dcm")
print(f"Estimated PSD: {output['psd']:.1f} mGy")When settings.output_format is set to dict or json, the result can be used programmatically. The exported result includes items such as patient/table/pad data, event geometry, correction factors, dose map data, and peak skin dose.
If you already have normalized RDSR data in a pandas DataFrame, use analyze_normalized_data_with_custom_settings_object().
import pandas as pd
from mypyskindose import load_settings_example_json
from mypyskindose.main import analyze_normalized_data_with_custom_settings_object
settings = load_settings_example_json()
normalized_data = pd.DataFrame(...) # your normalized RDSR data
result = analyze_normalized_data_with_custom_settings_object(
data_norm=normalized_data,
settings=settings,
output_format="json",
)The package includes helper functions that make exploration easier:
load_settings_example_json()loads a ready-made settings template.print_available_human_phantoms()lists available human phantom meshes.get_path_to_example_rdsr_files()returns the folder containing bundled example RDSR files.print_example_rdsr_files()prints the bundled example filenames.
Important settings live in src/mypyskindose/settings_example.json and the settings classes under src/mypyskindose/settings.
Common modes are:
plot_setup: plot the initial geometry without loading an irradiation sequenceplot_event: inspect one irradiation eventplot_procedure: inspect the full event sequencecalculate_dose: compute the dose map and peak skin dose estimate
Common phantom models are:
planecylinderhuman
Documentation sources live under docs/source, including the getting-started notebook and user guide material.
To build the HTML documentation locally from this repository (use the docs
optional extra — there are no requirements*.txt files):
pip install -e ".[docs]"
python -m sphinx -b html docs/source docs/build/htmlThen open the built site locally (path exists only after the Sphinx step above):
docs/build/html/index.html
- Independently maintained fork of PySkinDose; MIT license and upstream copyright preserved.
- Package identity:
mypyskindose(see dev-docs/MYPYSKINDOSE_MIGRATION_STATUS.md). - How we maintain the fork: dev-docs/FORK_MAINTAINER_GUIDE.md.
- Bugs and features: GitHub Issues (templates require a no-PHI/PII confirmation; see dev-docs/PRIVACY_AND_SENSITIVE_ASSETS.md).
- Questions and contribution ideas: GitHub Discussions. Ideas welcome — prefer Issues/Discussions over cold PRs (CONTRIBUTING.md).
- Security: SECURITY.md. Support channels: SUPPORT.md.