Update analyize_discovery.py

 New Features

    Graphical file selectors for both:

        Choosing the discovery output file

        Choosing the name and location of the analysis output file

    Output saved to a text file formatted for easy copy/paste into Excel

    Tab-separated values in the summary for compatibility with Excel columns

    Modality breakdown + exam statistics in one concise report

📝 How to Use It

    Save the code below as dicom_analysis_tool.py.

    Run it (python dicom_analysis_tool.py or double-click if .py is registered).

    Click the button to:

        Select the discovery results .txt file.

        Specify the output .txt destination.

    It will create a text summary that can be easily opened in Excel (tab-delimited).
This commit is contained in:
2025-05-16 13:52:44 +00:00
parent f1cdd200df
commit a01fe8a35c

View File

@@ -1,27 +1,35 @@
import tkinter as tk import tkinter as tk
from tkinter import filedialog, ttk from tkinter import filedialog, simpledialog
import pandas as pd import pandas as pd
import os import os
def load_and_analyze_file(): def normalize_modalities(val):
file_path = filedialog.askopenfilename(title="Select DICOM Discovery Output File", filetypes=[("Text Files", "*.txt")]) if val.startswith("[") and val.endswith("]"):
if not file_path: try:
return ", ".join(eval(val))
except:
return val
return val
def analyze_and_save():
input_path = filedialog.askopenfilename(
title="Select DICOM Discovery Output File",
filetypes=[("Text Files", "*.txt")]
)
if not input_path:
return return
df = pd.read_csv(file_path, delimiter='|', dtype=str).fillna('') output_path = filedialog.asksaveasfilename(
title="Save Analysis Output As",
# Normalize modalities to upper case and flatten list-like strings defaultextension=".txt",
def normalize_modalities(val): filetypes=[("Text Files", "*.txt")]
if val.startswith("[") and val.endswith("]"): )
try: if not output_path:
return ", ".join(eval(val)) return
except:
return val
return val
df = pd.read_csv(input_path, delimiter='|', dtype=str).fillna('')
df['ModalitiesInStudy'] = df['ModalitiesInStudy'].apply(normalize_modalities) df['ModalitiesInStudy'] = df['ModalitiesInStudy'].apply(normalize_modalities)
# Prepare metrics
stats = { stats = {
"Distinct StudyInstanceUIDs": df['StudyInstanceUID'].nunique(), "Distinct StudyInstanceUIDs": df['StudyInstanceUID'].nunique(),
"Distinct AccessionNumbers": df['AccessionNumber'].nunique(), "Distinct AccessionNumbers": df['AccessionNumber'].nunique(),
@@ -38,9 +46,9 @@ def load_and_analyze_file():
"*TEST* in PatientName": df['PatientName'].str.contains('TEST', case=False, na=False).sum() "*TEST* in PatientName": df['PatientName'].str.contains('TEST', case=False, na=False).sum()
} }
# Modality breakdown
modality_counts = { modality_counts = {
"CR": 0, "DX": 0, "CT": 0, "MR": 0, "NM": 0, "US": 0, "XA": 0, "PR": 0, "SC": 0, "OT": 0, "Other": 0 "CR": 0, "DX": 0, "CT": 0, "MR": 0, "NM": 0, "US": 0,
"XA": 0, "PR": 0, "SC": 0, "OT": 0, "Other": 0
} }
for val in df['ModalitiesInStudy']: for val in df['ModalitiesInStudy']:
@@ -50,30 +58,26 @@ def load_and_analyze_file():
else: else:
modality_counts["Other"] += 1 modality_counts["Other"] += 1
# Display results with open(output_path, 'w') as f:
output_window = tk.Toplevel(root) f.write("DICOM Discovery Analysis Summary\n")
output_window.title("DICOM Discovery Analysis") f.write("="*40 + "\n\n")
for key, value in stats.items():
f.write(f"{key}\t{value}\n")
f.write("\nModality Breakdown\n")
f.write("-"*40 + "\n")
for modality, count in modality_counts.items():
f.write(f"{modality}\t{count}\n")
row = 0 tk.messagebox.showinfo("Analysis Complete", f"Analysis saved to:\n{output_path}")
for key, val in stats.items():
tk.Label(output_window, text=f"{key}:").grid(row=row, column=0, sticky='w', padx=5, pady=2)
tk.Label(output_window, text=f"{val}").grid(row=row, column=1, sticky='w', padx=5, pady=2)
row += 1
tk.Label(output_window, text="Modality Breakdown:").grid(row=row, column=0, sticky='w', padx=5, pady=10) # GUI
row += 1
for modality, count in modality_counts.items():
tk.Label(output_window, text=f"{modality}:").grid(row=row, column=0, sticky='w', padx=20, pady=2)
tk.Label(output_window, text=f"{count}").grid(row=row, column=1, sticky='w', padx=5, pady=2)
row += 1
# GUI setup
root = tk.Tk() root = tk.Tk()
root.title("DICOM Discovery Analyzer") root.title("DICOM Discovery Analyzer")
root.geometry("400x150")
frame = tk.Frame(root, padx=10, pady=10) frame = tk.Frame(root, padx=10, pady=20)
frame.pack() frame.pack(expand=True)
ttk.Button(frame, text="Select and Analyze Output File", command=load_and_analyze_file).pack() tk.Button(frame, text="Select Input File and Analyze", command=analyze_and_save, width=30).pack(pady=10)
root.mainloop() root.mainloop()