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,17 +1,9 @@
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 not file_path:
return
df = pd.read_csv(file_path, delimiter='|', dtype=str).fillna('')
# Normalize modalities to upper case and flatten list-like strings
def normalize_modalities(val):
if val.startswith("[") and val.endswith("]"): if val.startswith("[") and val.endswith("]"):
try: try:
return ", ".join(eval(val)) return ", ".join(eval(val))
@@ -19,9 +11,25 @@ def load_and_analyze_file():
return val return val
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
output_path = filedialog.asksaveasfilename(
title="Save Analysis Output As",
defaultextension=".txt",
filetypes=[("Text Files", "*.txt")]
)
if not output_path:
return
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():
row = 0 f.write(f"{key}\t{value}\n")
for key, val in stats.items(): f.write("\nModality Breakdown\n")
tk.Label(output_window, text=f"{key}:").grid(row=row, column=0, sticky='w', padx=5, pady=2) f.write("-"*40 + "\n")
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)
row += 1
for modality, count in modality_counts.items(): 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) f.write(f"{modality}\t{count}\n")
tk.Label(output_window, text=f"{count}").grid(row=row, column=1, sticky='w', padx=5, pady=2)
row += 1
# GUI setup tk.messagebox.showinfo("Analysis Complete", f"Analysis saved to:\n{output_path}")
# GUI
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()