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.
|
Before Width: | Height: | Size: 324 KiB After Width: | Height: | Size: 331 KiB |
|
Before Width: | Height: | Size: 197 KiB After Width: | Height: | Size: 201 KiB |
|
Before Width: | Height: | Size: 313 KiB After Width: | Height: | Size: 390 KiB |
@@ -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)
|
||||
|
||||
|
Before Width: | Height: | Size: 72 KiB After Width: | Height: | Size: 92 KiB |
@@ -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")
|
||||
|
||||