Use log y-scale on energy deposition histograms

Both Edep and PET-spectrum distributions span several orders of magnitude
because of the huge zero-deposit / Compton-continuum populations. Linear
y compresses the structure to a single spike at zero; log y exposes the
photopeak, full-energy peak, and tail features.

Updated:
- lab3 analyze_basic.py:        single-panel hist
- lab3 analyze_advanced.py:     panels 1 & 2
- lab3 compare_particles.py:    all 4 panels (3 individual + density overlay)
- lab4 analyze_spectrum.py:     PET energy spectrum

Regenerated PNGs and committed alongside the .qmd updates.
This commit is contained in:
jwinterm
2026-04-26 22:41:28 -04:00
parent d36b321d0d
commit a9f82765f6
6 changed files with 27 additions and 19 deletions
Binary file not shown.

Before

Width:  |  Height:  |  Size: 324 KiB

After

Width:  |  Height:  |  Size: 331 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 197 KiB

After

Width:  |  Height:  |  Size: 201 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 313 KiB

After

Width:  |  Height:  |  Size: 390 KiB

+24 -17
View File
@@ -406,8 +406,9 @@ plt.axvline(median_edep, color='green', linestyle='--',
plt.title(f'Energy Deposition Distribution for 6 MeV Gammas\n({len(data)} events)',
fontsize=14, fontweight='bold')
plt.xlabel('Energy Deposited (MeV)', fontsize=12)
plt.ylabel('Frequency (Number of Events)', fontsize=12)
plt.grid(True, alpha=0.3)
plt.ylabel('Frequency (log scale)', fontsize=12)
plt.yscale('log')
plt.grid(True, alpha=0.3, which='both')
plt.legend(fontsize=10)
stats_text = f'mu = {mean_edep:.3f} MeV\nsigma = {std_edep:.3f} MeV\nEvents = {len(data)}'
@@ -485,24 +486,26 @@ fig, axes = plt.subplots(2, 2, figsize=(14, 10))
fig.suptitle('Advanced Energy Deposition Analysis',
fontsize=16, fontweight='bold')
# Panel 1: Full distribution
# Panel 1: Full distribution (log y to see the tail past the zero spike)
ax1 = axes[0, 0]
ax1.hist(data['Edep'], bins=100, color='steelblue',
alpha=0.7, edgecolor='black')
ax1.set_xlabel('Energy Deposited (MeV)')
ax1.set_ylabel('Frequency')
ax1.set_ylabel('Frequency (log scale)')
ax1.set_yscale('log')
ax1.set_title(f'Full Distribution (n={len(data)})')
ax1.grid(True, alpha=0.3)
ax1.grid(True, alpha=0.3, which='both')
# Panel 2: Excluding zero-energy events
# Panel 2: Excluding zero-energy events (log y for the long tail)
ax2 = axes[0, 1]
non_zero = data[data['Edep'] > 0]
ax2.hist(non_zero['Edep'], bins=80, color='coral',
alpha=0.7, edgecolor='black')
ax2.set_xlabel('Energy Deposited (MeV)')
ax2.set_ylabel('Frequency')
ax2.set_ylabel('Frequency (log scale)')
ax2.set_yscale('log')
ax2.set_title(f'Non-Zero Events Only (n={len(non_zero)})')
ax2.grid(True, alpha=0.3)
ax2.grid(True, alpha=0.3, which='both')
# Panel 3: Cumulative distribution
ax3 = axes[1, 0]
@@ -644,30 +647,33 @@ ax1 = axes[0, 0]
ax1.hist(gamma_data['Edep'], bins=80, alpha=0.7,
color='blue', label='6 MeV gamma', edgecolor='black')
ax1.set_xlabel('Energy Deposited (MeV)')
ax1.set_ylabel('Frequency')
ax1.set_ylabel('Frequency (log scale)')
ax1.set_yscale('log')
ax1.set_title('Gamma Rays (6 MeV)')
ax1.legend()
ax1.grid(True, alpha=0.3)
ax1.grid(True, alpha=0.3, which='both')
ax2 = axes[0, 1]
ax2.hist(proton_data['Edep'], bins=80, alpha=0.7,
color='red', label='150 MeV p+', edgecolor='black')
ax2.set_xlabel('Energy Deposited (MeV)')
ax2.set_ylabel('Frequency')
ax2.set_ylabel('Frequency (log scale)')
ax2.set_yscale('log')
ax2.set_title('Protons (150 MeV)')
ax2.legend()
ax2.grid(True, alpha=0.3)
ax2.grid(True, alpha=0.3, which='both')
ax3 = axes[1, 0]
ax3.hist(electron_data['Edep'], bins=80, alpha=0.7,
color='green', label='50 MeV e-', edgecolor='black')
ax3.set_xlabel('Energy Deposited (MeV)')
ax3.set_ylabel('Frequency')
ax3.set_ylabel('Frequency (log scale)')
ax3.set_yscale('log')
ax3.set_title('Electrons (50 MeV)')
ax3.legend()
ax3.grid(True, alpha=0.3)
ax3.grid(True, alpha=0.3, which='both')
# Normalized overlay
# Normalized overlay (log y so the three shapes are comparable across orders)
ax4 = axes[1, 1]
ax4.hist(gamma_data['Edep'], bins=60, alpha=0.5, color='blue',
label=f'gamma (mu={gamma_data["Edep"].mean():.2f})', density=True)
@@ -676,10 +682,11 @@ ax4.hist(proton_data['Edep'], bins=60, alpha=0.5, color='red',
ax4.hist(electron_data['Edep'], bins=60, alpha=0.5, color='green',
label=f'e- (mu={electron_data["Edep"].mean():.2f})', density=True)
ax4.set_xlabel('Energy Deposited (MeV)')
ax4.set_ylabel('Probability Density')
ax4.set_ylabel('Probability Density (log scale)')
ax4.set_yscale('log')
ax4.set_title('Normalized Overlay Comparison')
ax4.legend()
ax4.grid(True, alpha=0.3)
ax4.grid(True, alpha=0.3, which='both')
plt.tight_layout()
plt.savefig('particle_comparison.png', dpi=300)
Binary file not shown.

Before

Width:  |  Height:  |  Size: 72 KiB

After

Width:  |  Height:  |  Size: 92 KiB

+3 -2
View File
@@ -236,9 +236,10 @@ plt.axvline(511, color='red', linestyle='--', linewidth=1.5,
plt.title('PET Detector Crystal Energy Spectrum')
plt.xlabel('Energy Deposited per Hit (keV)')
plt.ylabel('Counts')
plt.ylabel('Counts (log scale)')
plt.yscale('log')
plt.legend()
plt.grid(True, alpha=0.3)
plt.grid(True, alpha=0.3, which='both')
plt.tight_layout()
plt.savefig('pet_spectrum.png', dpi=200)
print("Spectrum saved to pet_spectrum.png")