radiapy 0.1.0__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.
radiapy-0.1.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024 Radiapy Contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
radiapy-0.1.0/PKG-INFO ADDED
@@ -0,0 +1,285 @@
1
+ Metadata-Version: 2.4
2
+ Name: radiapy
3
+ Version: 0.1.0
4
+ Summary: Interactive visualization of radiation experiments and radiation-matter interactions
5
+ Author: Radiapy Contributors
6
+ License: MIT License
7
+
8
+ Copyright (c) 2024 Radiapy Contributors
9
+
10
+ Permission is hereby granted, free of charge, to any person obtaining a copy
11
+ of this software and associated documentation files (the "Software"), to deal
12
+ in the Software without restriction, including without limitation the rights
13
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14
+ copies of the Software, and to permit persons to whom the Software is
15
+ furnished to do so, subject to the following conditions:
16
+
17
+ The above copyright notice and this permission notice shall be included in all
18
+ copies or substantial portions of the Software.
19
+
20
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
26
+ SOFTWARE.
27
+
28
+ Project-URL: Homepage, https://github.com/radviz/radiapy
29
+ Project-URL: Documentation, https://radiapy.readthedocs.io
30
+ Project-URL: Bug Tracker, https://github.com/radviz/radiapy/issues
31
+ Keywords: radiation,physics,visualization,geiger,attenuation,beer-lambert
32
+ Classifier: Development Status :: 3 - Alpha
33
+ Classifier: Intended Audience :: Science/Research
34
+ Classifier: License :: OSI Approved :: MIT License
35
+ Classifier: Programming Language :: Python :: 3
36
+ Classifier: Programming Language :: Python :: 3.10
37
+ Classifier: Programming Language :: Python :: 3.11
38
+ Classifier: Programming Language :: Python :: 3.12
39
+ Classifier: Topic :: Scientific/Engineering :: Physics
40
+ Classifier: Topic :: Scientific/Engineering :: Visualization
41
+ Requires-Python: >=3.10
42
+ Description-Content-Type: text/markdown
43
+ License-File: LICENSE
44
+ Requires-Dist: plotly>=5.15.0
45
+ Requires-Dist: pandas>=2.0.0
46
+ Requires-Dist: numpy>=1.24.0
47
+ Requires-Dist: scipy>=1.10.0
48
+ Requires-Dist: click>=8.1.0
49
+ Provides-Extra: dev
50
+ Requires-Dist: pytest>=7.0; extra == "dev"
51
+ Requires-Dist: pytest-cov; extra == "dev"
52
+ Requires-Dist: jupyter>=1.0.0; extra == "dev"
53
+ Requires-Dist: kaleido>=0.2.1; extra == "dev"
54
+ Requires-Dist: build>=1.0.0; extra == "dev"
55
+ Requires-Dist: twine>=4.0.0; extra == "dev"
56
+ Dynamic: license-file
57
+
58
+ # Radiapy
59
+
60
+ **Interactive visualization of radiation experiments and radiation-matter interactions.**
61
+
62
+ Radiapy is an open-source Python library for analysing and visualising Geiger-counter radiation attenuation experiments. It implements the Beer-Lambert law, the inverse-square law, and NIST photon attenuation data, and renders every plot as an interactive Plotly figure exportable to standalone HTML — no ROOT, VTK, or GEANT4 required.
63
+
64
+ ---
65
+
66
+ ## Installation
67
+
68
+ ```bash
69
+ pip install radiapy
70
+ ```
71
+
72
+ Or from source:
73
+
74
+ ```bash
75
+ git clone https://github.com/radviz/radiapy
76
+ cd radiapy
77
+ pip install -e ".[dev]"
78
+ ```
79
+
80
+ **Requirements:** Python ≥ 3.10, plotly, pandas, numpy, scipy, click
81
+
82
+ ---
83
+
84
+ ## Quick start
85
+
86
+ ```python
87
+ from radviz import RadViz
88
+
89
+ rv = RadViz("radviz/demo/dataset_geiger.csv")
90
+
91
+ # Generate a complete standalone HTML dashboard
92
+ rv.generate_dashboard("dashboard.html")
93
+
94
+ # Individual interactive plots
95
+ fig = rv.plot_attenuation() # Bar chart: T by material + NIST overlay
96
+ fig = rv.plot_inverse_square() # Counts vs distance + 1/r² fit
97
+ fig = rv.plot_heatmap() # 2-D transmission heatmap
98
+ fig = rv.plot_comparison() # Cd109 vs Am241 side-by-side
99
+ fig = rv.plot_particles() # Animated photon trajectories
100
+ fig.show()
101
+
102
+ # Physics report
103
+ print(rv.physics_report())
104
+ ```
105
+
106
+ ## Command-line interface
107
+
108
+ ```bash
109
+ # Full dashboard
110
+ radviz dashboard dataset_geiger.csv --output dashboard.html
111
+
112
+ # Physics report
113
+ radviz report dataset_geiger.csv
114
+
115
+ # Particle animation (no CSV needed)
116
+ radviz simulate --isotope Cd109 --material Pb --output anim.html
117
+
118
+ # Legacy single-command form
119
+ radviz --input dataset_geiger.csv --output dashboard.html
120
+ ```
121
+
122
+ ---
123
+
124
+ ## Dataset format
125
+
126
+ The bundled `dataset_geiger.csv` has the following columns:
127
+
128
+ | Column | Description |
129
+ |--------|-------------|
130
+ | `isotope` | Source isotope (`Cd109` or `Am241`) |
131
+ | `distance_cm` | Source-detector distance (10, 20, 30 cm) |
132
+ | `counts_free` | Raw counts without absorber |
133
+ | `counts_Al` | Counts through aluminium filter |
134
+ | `counts_Cu` | Counts through copper filter |
135
+ | `counts_Pb` | Counts through lead filter |
136
+ | `counts_free_mean` | Mean free-field counts for this (isotope, distance) group |
137
+ | `Al_ratio` | Transmission fraction: `counts_Al / counts_free` |
138
+ | `Cu_ratio` | Transmission fraction: `counts_Cu / counts_free` |
139
+ | `Pb_ratio` | Transmission fraction: `counts_Pb / counts_free` |
140
+
141
+ To use a custom CSV, pass a `schema` dict to `RadViz`:
142
+
143
+ ```python
144
+ schema = {
145
+ "isotope_col": "source",
146
+ "distance_col": "dist_cm",
147
+ "free_count_col": "N_free",
148
+ "filter_cols": {"Al": "N_Al", "Cu": "N_Cu", "Pb": "N_Pb"},
149
+ }
150
+ rv = RadViz("my_data.csv", schema=schema)
151
+ ```
152
+
153
+ ---
154
+
155
+ ## Physics Background
156
+
157
+ ### Beer-Lambert attenuation law
158
+
159
+ When a beam of photons passes through a material of thickness *x* (cm), its intensity is reduced according to:
160
+
161
+ ```
162
+ I = I₀ · exp(−μ · x)
163
+ ```
164
+
165
+ where:
166
+ - `I₀` is the incident intensity (counts without absorber),
167
+ - `I` is the transmitted intensity,
168
+ - `μ` (cm⁻¹) is the **linear attenuation coefficient**, which depends on the material and the photon energy,
169
+ - `T = I / I₀ ∈ [0, 1]` is the **transmission fraction**.
170
+
171
+ The linear coefficient relates to the tabulated **mass attenuation coefficient** as `μ = (μ/ρ) · ρ`, where `ρ` is the material density (g/cm³).
172
+
173
+ Radiapy fits `μ` experimentally from the measured transmission ratios via `scipy.optimize.curve_fit` (with full covariance matrix for uncertainty propagation), and compares each fitted value against the NIST reference. The experimental coefficient is back-calculated as `μ_exp = −ln(T_exp) / x`.
174
+
175
+ ### Inverse-square law
176
+
177
+ For a point source radiating isotropically, the intensity at distance *r* from the source falls off as:
178
+
179
+ ```
180
+ I(r) = A / r²
181
+ ```
182
+
183
+ where `A` is a constant proportional to the source activity and detector efficiency. This geometric dilution of intensity over the surface of an expanding sphere means that doubling the distance reduces counts to one quarter. Radiapy fits `A` with uncertainty via `scipy.optimize.curve_fit` and reports R² as a goodness-of-fit metric.
184
+
185
+ A diagnostic plot of `I · r²` vs `r` (the "1/r² diagnostic" tab) should yield a horizontal line; deviations indicate room scatter, geometry effects, or a non-point-like source.
186
+
187
+ ### The Pb K-edge and the counterintuitive Cd-109 / Am-241 reversal
188
+
189
+ Every element has characteristic **absorption edges** — energies at which a new inner-shell photoelectric absorption channel opens as photon energy increases past the binding energy of that electron shell. For **lead (Pb)**, the K-shell binding energy is **88.005 keV**.
190
+
191
+ The two isotopes in this experiment straddle that edge:
192
+
193
+ | Isotope | Main γ energy | Position relative to Pb K-edge |
194
+ |---------|--------------|-------------------------------|
195
+ | Am-241 | 59.54 keV | **Below** — K shell cannot be ionised |
196
+ | Cd-109 | 88.034 keV | **Just above** — K shell is ionised |
197
+
198
+ This creates a **counterintuitive reversal**: even though Cd-109 photons are *higher energy* than Am-241 photons (and high-energy photons generally penetrate matter more easily), Pb attenuates Cd-109 *more strongly* because the K-shell photoelectric cross-section is suddenly available. The `μ/ρ` of Pb jumps from ~2.0 cm²/g just below the edge to ~13.9 cm²/g just above — a ~7× increase. This effect is clearly visible in the **Cd109 vs Am241** comparison tab of the dashboard.
199
+
200
+ ### NIST reference data
201
+
202
+ All theoretical values are taken from:
203
+
204
+ - **NIST XCOM** — *Photon Cross Sections Database*, Standard Reference Database 8 (XGAM).
205
+ Berger, M.J., Hubbell, J.H., Seltzer, S.M., Chang, J., Coursey, J.S., Sukumar, R., Zucker, D.S., and Olsen, K.
206
+ https://physics.nist.gov/PhysRefData/Xcom/html/xcom1.html
207
+
208
+ - **NIST Standard Reference Database 126** — *X-Ray Mass Attenuation Coefficients*, J.H. Hubbell and S.M. Seltzer.
209
+ https://www.nist.gov/pml/x-ray-mass-attenuation-coefficients
210
+
211
+ ---
212
+
213
+ ## NIST data
214
+
215
+ Hardcoded `μ/ρ` values (cm²/g) from [NIST XCOM](https://physics.nist.gov/PhysRefData/Xcom/html/xcom1.html):
216
+
217
+ | Material | ρ (g/cm³) | μ/ρ @ 59.5 keV | μ/ρ @ 88.034 keV |
218
+ |----------|-----------|----------------|------------------|
219
+ | Al | 2.699 | 0.3219 | 0.2226 |
220
+ | Cu | 8.960 | 0.8156 | 0.5082 |
221
+ | Pb | 11.35 | 5.549 | 13.93* |
222
+
223
+ \* Above Pb K-edge (88.005 keV).
224
+
225
+ ---
226
+
227
+ ## Demo dataset
228
+
229
+ Regenerate the synthetic demo dataset (Poisson-distributed, 50 replicates × 6 conditions):
230
+
231
+ ```bash
232
+ python scripts/generate_demo_data.py
233
+ ```
234
+
235
+ ---
236
+
237
+ ## Project structure
238
+
239
+ ```
240
+ radiapy/
241
+ ├── __init__.py # from radiapy import RadViz
242
+ ├── __main__.py # python -m radiapy CSV [--output FILE]
243
+ ├── core.py # RadViz orchestrator class
244
+ ├── cli.py # Click CLI (radiapy dashboard / report / simulate)
245
+ ├── parsers/
246
+ │ ├── base_parser.py # Abstract base + GroupStats + ParsedDataset
247
+ │ ├── csv_parser.py # Generic CSV → ParsedDataset
248
+ │ └── geant4_parser.py # GEANT4 ASCII output → ParsedDataset
249
+ ├── physics/
250
+ │ ├── attenuation.py # Beer-Lambert fit (curve_fit + pcov)
251
+ │ ├── inverse_square.py# 1/r² fit
252
+ │ └── nist_data.py # NIST μ/ρ table, filter thicknesses
253
+ ├── visualizers/
254
+ │ ├── attenuation_viz.py
255
+ │ ├── distance_viz.py
256
+ │ ├── comparison_viz.py
257
+ │ └── particle_viz.py # Photon trajectories with thickness slider
258
+ ├── exporters/
259
+ │ └── html_exporter.py # Standalone HTML dashboard (Plotly.js inline)
260
+ └── demo/
261
+ └── dataset_geiger.csv
262
+ ```
263
+
264
+ ---
265
+
266
+ ## Citation
267
+
268
+ If you use Radiapy in scientific work, please cite:
269
+
270
+ ```bibtex
271
+ @software{radiapy2024,
272
+ title = {Radiapy: Interactive visualization of radiation experiments},
273
+ year = {2024},
274
+ url = {https://github.com/radviz/radiapy},
275
+ version = {0.1.0}
276
+ }
277
+ ```
278
+
279
+ Dataset: experimental Geiger-counter measurements of Cd-109 and Am-241 attenuation through Al, Cu, and Pb absorbers.
280
+
281
+ ---
282
+
283
+ ## License
284
+
285
+ MIT — see [LICENSE](LICENSE).
@@ -0,0 +1,228 @@
1
+ # Radiapy
2
+
3
+ **Interactive visualization of radiation experiments and radiation-matter interactions.**
4
+
5
+ Radiapy is an open-source Python library for analysing and visualising Geiger-counter radiation attenuation experiments. It implements the Beer-Lambert law, the inverse-square law, and NIST photon attenuation data, and renders every plot as an interactive Plotly figure exportable to standalone HTML — no ROOT, VTK, or GEANT4 required.
6
+
7
+ ---
8
+
9
+ ## Installation
10
+
11
+ ```bash
12
+ pip install radiapy
13
+ ```
14
+
15
+ Or from source:
16
+
17
+ ```bash
18
+ git clone https://github.com/radviz/radiapy
19
+ cd radiapy
20
+ pip install -e ".[dev]"
21
+ ```
22
+
23
+ **Requirements:** Python ≥ 3.10, plotly, pandas, numpy, scipy, click
24
+
25
+ ---
26
+
27
+ ## Quick start
28
+
29
+ ```python
30
+ from radviz import RadViz
31
+
32
+ rv = RadViz("radviz/demo/dataset_geiger.csv")
33
+
34
+ # Generate a complete standalone HTML dashboard
35
+ rv.generate_dashboard("dashboard.html")
36
+
37
+ # Individual interactive plots
38
+ fig = rv.plot_attenuation() # Bar chart: T by material + NIST overlay
39
+ fig = rv.plot_inverse_square() # Counts vs distance + 1/r² fit
40
+ fig = rv.plot_heatmap() # 2-D transmission heatmap
41
+ fig = rv.plot_comparison() # Cd109 vs Am241 side-by-side
42
+ fig = rv.plot_particles() # Animated photon trajectories
43
+ fig.show()
44
+
45
+ # Physics report
46
+ print(rv.physics_report())
47
+ ```
48
+
49
+ ## Command-line interface
50
+
51
+ ```bash
52
+ # Full dashboard
53
+ radviz dashboard dataset_geiger.csv --output dashboard.html
54
+
55
+ # Physics report
56
+ radviz report dataset_geiger.csv
57
+
58
+ # Particle animation (no CSV needed)
59
+ radviz simulate --isotope Cd109 --material Pb --output anim.html
60
+
61
+ # Legacy single-command form
62
+ radviz --input dataset_geiger.csv --output dashboard.html
63
+ ```
64
+
65
+ ---
66
+
67
+ ## Dataset format
68
+
69
+ The bundled `dataset_geiger.csv` has the following columns:
70
+
71
+ | Column | Description |
72
+ |--------|-------------|
73
+ | `isotope` | Source isotope (`Cd109` or `Am241`) |
74
+ | `distance_cm` | Source-detector distance (10, 20, 30 cm) |
75
+ | `counts_free` | Raw counts without absorber |
76
+ | `counts_Al` | Counts through aluminium filter |
77
+ | `counts_Cu` | Counts through copper filter |
78
+ | `counts_Pb` | Counts through lead filter |
79
+ | `counts_free_mean` | Mean free-field counts for this (isotope, distance) group |
80
+ | `Al_ratio` | Transmission fraction: `counts_Al / counts_free` |
81
+ | `Cu_ratio` | Transmission fraction: `counts_Cu / counts_free` |
82
+ | `Pb_ratio` | Transmission fraction: `counts_Pb / counts_free` |
83
+
84
+ To use a custom CSV, pass a `schema` dict to `RadViz`:
85
+
86
+ ```python
87
+ schema = {
88
+ "isotope_col": "source",
89
+ "distance_col": "dist_cm",
90
+ "free_count_col": "N_free",
91
+ "filter_cols": {"Al": "N_Al", "Cu": "N_Cu", "Pb": "N_Pb"},
92
+ }
93
+ rv = RadViz("my_data.csv", schema=schema)
94
+ ```
95
+
96
+ ---
97
+
98
+ ## Physics Background
99
+
100
+ ### Beer-Lambert attenuation law
101
+
102
+ When a beam of photons passes through a material of thickness *x* (cm), its intensity is reduced according to:
103
+
104
+ ```
105
+ I = I₀ · exp(−μ · x)
106
+ ```
107
+
108
+ where:
109
+ - `I₀` is the incident intensity (counts without absorber),
110
+ - `I` is the transmitted intensity,
111
+ - `μ` (cm⁻¹) is the **linear attenuation coefficient**, which depends on the material and the photon energy,
112
+ - `T = I / I₀ ∈ [0, 1]` is the **transmission fraction**.
113
+
114
+ The linear coefficient relates to the tabulated **mass attenuation coefficient** as `μ = (μ/ρ) · ρ`, where `ρ` is the material density (g/cm³).
115
+
116
+ Radiapy fits `μ` experimentally from the measured transmission ratios via `scipy.optimize.curve_fit` (with full covariance matrix for uncertainty propagation), and compares each fitted value against the NIST reference. The experimental coefficient is back-calculated as `μ_exp = −ln(T_exp) / x`.
117
+
118
+ ### Inverse-square law
119
+
120
+ For a point source radiating isotropically, the intensity at distance *r* from the source falls off as:
121
+
122
+ ```
123
+ I(r) = A / r²
124
+ ```
125
+
126
+ where `A` is a constant proportional to the source activity and detector efficiency. This geometric dilution of intensity over the surface of an expanding sphere means that doubling the distance reduces counts to one quarter. Radiapy fits `A` with uncertainty via `scipy.optimize.curve_fit` and reports R² as a goodness-of-fit metric.
127
+
128
+ A diagnostic plot of `I · r²` vs `r` (the "1/r² diagnostic" tab) should yield a horizontal line; deviations indicate room scatter, geometry effects, or a non-point-like source.
129
+
130
+ ### The Pb K-edge and the counterintuitive Cd-109 / Am-241 reversal
131
+
132
+ Every element has characteristic **absorption edges** — energies at which a new inner-shell photoelectric absorption channel opens as photon energy increases past the binding energy of that electron shell. For **lead (Pb)**, the K-shell binding energy is **88.005 keV**.
133
+
134
+ The two isotopes in this experiment straddle that edge:
135
+
136
+ | Isotope | Main γ energy | Position relative to Pb K-edge |
137
+ |---------|--------------|-------------------------------|
138
+ | Am-241 | 59.54 keV | **Below** — K shell cannot be ionised |
139
+ | Cd-109 | 88.034 keV | **Just above** — K shell is ionised |
140
+
141
+ This creates a **counterintuitive reversal**: even though Cd-109 photons are *higher energy* than Am-241 photons (and high-energy photons generally penetrate matter more easily), Pb attenuates Cd-109 *more strongly* because the K-shell photoelectric cross-section is suddenly available. The `μ/ρ` of Pb jumps from ~2.0 cm²/g just below the edge to ~13.9 cm²/g just above — a ~7× increase. This effect is clearly visible in the **Cd109 vs Am241** comparison tab of the dashboard.
142
+
143
+ ### NIST reference data
144
+
145
+ All theoretical values are taken from:
146
+
147
+ - **NIST XCOM** — *Photon Cross Sections Database*, Standard Reference Database 8 (XGAM).
148
+ Berger, M.J., Hubbell, J.H., Seltzer, S.M., Chang, J., Coursey, J.S., Sukumar, R., Zucker, D.S., and Olsen, K.
149
+ https://physics.nist.gov/PhysRefData/Xcom/html/xcom1.html
150
+
151
+ - **NIST Standard Reference Database 126** — *X-Ray Mass Attenuation Coefficients*, J.H. Hubbell and S.M. Seltzer.
152
+ https://www.nist.gov/pml/x-ray-mass-attenuation-coefficients
153
+
154
+ ---
155
+
156
+ ## NIST data
157
+
158
+ Hardcoded `μ/ρ` values (cm²/g) from [NIST XCOM](https://physics.nist.gov/PhysRefData/Xcom/html/xcom1.html):
159
+
160
+ | Material | ρ (g/cm³) | μ/ρ @ 59.5 keV | μ/ρ @ 88.034 keV |
161
+ |----------|-----------|----------------|------------------|
162
+ | Al | 2.699 | 0.3219 | 0.2226 |
163
+ | Cu | 8.960 | 0.8156 | 0.5082 |
164
+ | Pb | 11.35 | 5.549 | 13.93* |
165
+
166
+ \* Above Pb K-edge (88.005 keV).
167
+
168
+ ---
169
+
170
+ ## Demo dataset
171
+
172
+ Regenerate the synthetic demo dataset (Poisson-distributed, 50 replicates × 6 conditions):
173
+
174
+ ```bash
175
+ python scripts/generate_demo_data.py
176
+ ```
177
+
178
+ ---
179
+
180
+ ## Project structure
181
+
182
+ ```
183
+ radiapy/
184
+ ├── __init__.py # from radiapy import RadViz
185
+ ├── __main__.py # python -m radiapy CSV [--output FILE]
186
+ ├── core.py # RadViz orchestrator class
187
+ ├── cli.py # Click CLI (radiapy dashboard / report / simulate)
188
+ ├── parsers/
189
+ │ ├── base_parser.py # Abstract base + GroupStats + ParsedDataset
190
+ │ ├── csv_parser.py # Generic CSV → ParsedDataset
191
+ │ └── geant4_parser.py # GEANT4 ASCII output → ParsedDataset
192
+ ├── physics/
193
+ │ ├── attenuation.py # Beer-Lambert fit (curve_fit + pcov)
194
+ │ ├── inverse_square.py# 1/r² fit
195
+ │ └── nist_data.py # NIST μ/ρ table, filter thicknesses
196
+ ├── visualizers/
197
+ │ ├── attenuation_viz.py
198
+ │ ├── distance_viz.py
199
+ │ ├── comparison_viz.py
200
+ │ └── particle_viz.py # Photon trajectories with thickness slider
201
+ ├── exporters/
202
+ │ └── html_exporter.py # Standalone HTML dashboard (Plotly.js inline)
203
+ └── demo/
204
+ └── dataset_geiger.csv
205
+ ```
206
+
207
+ ---
208
+
209
+ ## Citation
210
+
211
+ If you use Radiapy in scientific work, please cite:
212
+
213
+ ```bibtex
214
+ @software{radiapy2024,
215
+ title = {Radiapy: Interactive visualization of radiation experiments},
216
+ year = {2024},
217
+ url = {https://github.com/radviz/radiapy},
218
+ version = {0.1.0}
219
+ }
220
+ ```
221
+
222
+ Dataset: experimental Geiger-counter measurements of Cd-109 and Am-241 attenuation through Al, Cu, and Pb absorbers.
223
+
224
+ ---
225
+
226
+ ## License
227
+
228
+ MIT — see [LICENSE](LICENSE).
@@ -0,0 +1,60 @@
1
+ [build-system]
2
+ requires = ["setuptools>=61", "wheel"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "radiapy"
7
+ version = "0.1.0"
8
+ description = "Interactive visualization of radiation experiments and radiation-matter interactions"
9
+ readme = "README.md"
10
+ license = {file = "LICENSE"}
11
+ authors = [
12
+ {name = "Radiapy Contributors"}
13
+ ]
14
+ keywords = ["radiation", "physics", "visualization", "geiger", "attenuation", "beer-lambert"]
15
+ classifiers = [
16
+ "Development Status :: 3 - Alpha",
17
+ "Intended Audience :: Science/Research",
18
+ "License :: OSI Approved :: MIT License",
19
+ "Programming Language :: Python :: 3",
20
+ "Programming Language :: Python :: 3.10",
21
+ "Programming Language :: Python :: 3.11",
22
+ "Programming Language :: Python :: 3.12",
23
+ "Topic :: Scientific/Engineering :: Physics",
24
+ "Topic :: Scientific/Engineering :: Visualization",
25
+ ]
26
+ requires-python = ">=3.10"
27
+ dependencies = [
28
+ "plotly>=5.15.0", # interactive figures + offline JS bundle
29
+ "pandas>=2.0.0", # CSV parsing and DataFrame operations
30
+ "numpy>=1.24.0", # numerical arrays and Poisson statistics
31
+ "scipy>=1.10.0", # curve_fit (Beer-Lambert + 1/r² fits), t-distribution
32
+ "click>=8.1.0", # CLI (radiapy dashboard / report / simulate)
33
+ ]
34
+
35
+ [project.optional-dependencies]
36
+ dev = [
37
+ "pytest>=7.0",
38
+ "pytest-cov",
39
+ "jupyter>=1.0.0",
40
+ "kaleido>=0.2.1", # static image export (PNG/SVG) from Plotly figures
41
+ "build>=1.0.0", # python -m build
42
+ "twine>=4.0.0", # twine upload dist/*
43
+ ]
44
+
45
+ [project.scripts]
46
+ radiapy = "radiapy.cli:main"
47
+
48
+ [project.urls]
49
+ Homepage = "https://github.com/radviz/radiapy"
50
+ Documentation = "https://radiapy.readthedocs.io"
51
+ "Bug Tracker" = "https://github.com/radviz/radiapy/issues"
52
+
53
+ [tool.setuptools.packages.find]
54
+ where = ["."]
55
+ include = ["radiapy*"]
56
+
57
+ [tool.setuptools.package-data]
58
+ # The demo CSV is in demo/ at the project root, not inside the package.
59
+ # Users access it via the bundled path or their own datasets.
60
+ radiapy = []
@@ -0,0 +1,20 @@
1
+ """
2
+ Radiapy — Interactive visualization of radiation experiments.
3
+
4
+ Quick start::
5
+
6
+ from radiapy import RadViz
7
+
8
+ rv = RadViz("dataset_geiger.csv")
9
+ rv.generate_dashboard("dashboard.html")
10
+
11
+ Or visualize a single plot::
12
+
13
+ fig = rv.plot_attenuation()
14
+ fig.show()
15
+ """
16
+
17
+ from radiapy.core import RadViz
18
+
19
+ __version__ = "0.1.0"
20
+ __all__ = ["RadViz"]
@@ -0,0 +1,82 @@
1
+ """Entry point for ``python -m radiapy CSV_FILE [options]``.
2
+
3
+ Usage
4
+ -----
5
+ python -m radiapy demo/dataset_geiger.csv
6
+ python -m radiapy demo/dataset_geiger.csv --output my_report.html
7
+ python -m radiapy demo/dataset_geiger.csv --report-only
8
+ """
9
+
10
+ from __future__ import annotations
11
+
12
+ import argparse
13
+ import sys
14
+ from pathlib import Path
15
+
16
+
17
+ def _parse_args(argv: list[str] | None = None) -> argparse.Namespace:
18
+ p = argparse.ArgumentParser(
19
+ prog="python -m radiapy",
20
+ description="Radiapy — interactive radiation experiment visualizer",
21
+ formatter_class=argparse.RawDescriptionHelpFormatter,
22
+ epilog="""
23
+ examples:
24
+ python -m radiapy demo/dataset_geiger.csv
25
+ python -m radiapy demo/dataset_geiger.csv --output report.html
26
+ python -m radiapy demo/dataset_geiger.csv --report-only
27
+ """,
28
+ )
29
+ p.add_argument("csv_file", metavar="CSV_FILE", help="Geiger-counter CSV dataset")
30
+ p.add_argument(
31
+ "--output", "-o",
32
+ default="dashboard.html",
33
+ metavar="FILE",
34
+ help="Output HTML dashboard path (default: dashboard.html)",
35
+ )
36
+ p.add_argument(
37
+ "--report-only",
38
+ action="store_true",
39
+ help="Print the physics report to stdout without generating HTML",
40
+ )
41
+ return p.parse_args(argv)
42
+
43
+
44
+ def main(argv: list[str] | None = None) -> int:
45
+ args = _parse_args(argv)
46
+ csv_path = Path(args.csv_file)
47
+
48
+ if not csv_path.exists():
49
+ print(f"ERROR: file not found — {csv_path}", file=sys.stderr)
50
+ return 1
51
+
52
+ from radiapy.core import RadViz
53
+
54
+ print("=" * 60)
55
+ print(" Radiapy v0.1.0 — Radiation Experiment Visualizer")
56
+ print("=" * 60)
57
+
58
+ rv = RadViz(csv_path)
59
+
60
+ print(f"\nDataset loaded: {csv_path}")
61
+ print(f" Isotopes : {', '.join(rv.dataset.isotopes)}")
62
+ print(f" Distances : {rv.dataset.distances} cm")
63
+ print(f" Materials : {', '.join(rv.dataset.materials)}")
64
+ print(f" Total rows : {len(rv.dataset.raw)}")
65
+ print()
66
+
67
+ print(rv.physics_report())
68
+
69
+ if args.report_only:
70
+ return 0
71
+
72
+ out = rv.generate_dashboard(args.output)
73
+ size_kb = out.stat().st_size // 1024
74
+ print(f"\nDashboard saved : {out.resolve()}")
75
+ print(f"File size : {size_kb} KB")
76
+ print(f"\nOpen in browser :")
77
+ print(f" open {out}")
78
+ return 0
79
+
80
+
81
+ if __name__ == "__main__":
82
+ sys.exit(main())