Vigilant Data Analyzer Python GUI

👤 Sharing: AI
import tkinter as tk
from tkinter import ttk
from tkinter import filedialog, messagebox
import pandas as pd
import matplotlib.pyplot as plt
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
import seaborn as sns
import io
from PIL import Image, ImageTk

class DataAnalyzerApp:
    def __init__(self, master):
        self.master = master
        master.title("Vigilant Data Analyzer")
        master.geometry("800x600")

        self.data = None
        self.filename = None

        # --- Menu Bar ---
        self.menubar = tk.Menu(master)
        self.filemenu = tk.Menu(self.menubar, tearoff=0)
        self.filemenu.add_command(label="Open", command=self.load_data)
        self.filemenu.add_separator()
        self.filemenu.add_command(label="Exit", command=master.quit)
        self.menubar.add_cascade(label="File", menu=self.filemenu)
        master.config(menu=self.menubar)

        # --- Left Frame (Data Display) ---
        self.left_frame = ttk.Frame(master, padding=10)
        self.left_frame.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)

        self.tree = ttk.Treeview(self.left_frame, show="headings")
        self.tree.pack(fill=tk.BOTH, expand=True)

        self.tree_scroll_y = ttk.Scrollbar(self.left_frame, orient=tk.VERTICAL, command=self.tree.yview)
        self.tree_scroll_y.pack(side=tk.RIGHT, fill=tk.Y)
        self.tree.configure(yscrollcommand=self.tree_scroll_y.set)

        self.tree_scroll_x = ttk.Scrollbar(self.left_frame, orient=tk.HORIZONTAL, command=self.tree.xview)
        self.tree_scroll_x.pack(side=tk.BOTTOM, fill=tk.X)
        self.tree.configure(xscrollcommand=self.tree_scroll_x.set)

        # --- Right Frame (Controls and Visualizations) ---
        self.right_frame = ttk.Frame(master, padding=10)
        self.right_frame.pack(side=tk.RIGHT, fill=tk.BOTH, expand=True)

        # --- Visualization Selection ---
        self.visualization_label = ttk.Label(self.right_frame, text="Select Visualization:")
        self.visualization_label.pack()

        self.visualization_choices = ["Scatter Plot", "Histogram", "Box Plot", "Bar Chart"]
        self.visualization_var = tk.StringVar(value=self.visualization_choices[0])
        self.visualization_dropdown = ttk.Combobox(self.right_frame, textvariable=self.visualization_var, values=self.visualization_choices, state="readonly")
        self.visualization_dropdown.pack()

        # --- Column Selection ---
        self.x_column_label = ttk.Label(self.right_frame, text="X Column:")
        self.x_column_label.pack()
        self.x_column_var = tk.StringVar()
        self.x_column_dropdown = ttk.Combobox(self.right_frame, textvariable=self.x_column_var, state="readonly")
        self.x_column_dropdown.pack()

        self.y_column_label = ttk.Label(self.right_frame, text="Y Column (for Scatter Plot/Box Plot):")
        self.y_column_label.pack()
        self.y_column_var = tk.StringVar()
        self.y_column_dropdown = ttk.Combobox(self.right_frame, textvariable=self.y_column_var, state="readonly")
        self.y_column_dropdown.pack()

        # --- Generate Button ---
        self.generate_button = ttk.Button(self.right_frame, text="Generate Visualization", command=self.generate_visualization)
        self.generate_button.pack()

        # --- Visualization Area ---
        self.visualization_frame = ttk.Frame(self.right_frame)
        self.visualization_frame.pack(fill=tk.BOTH, expand=True)
        self.visualization_canvas = None
        self.visualization_widget = None # Store the widget (e.g., canvas, image label)

        # --- Summary Statistics ---
        self.summary_label = ttk.Label(self.right_frame, text="Summary Statistics:")
        self.summary_label.pack()
        self.summary_text = tk.Text(self.right_frame, height=10, width=40, wrap=tk.WORD, state=tk.DISABLED)
        self.summary_text.pack()

        self.summary_scrollbar = ttk.Scrollbar(self.right_frame, command=self.summary_text.yview)
        self.summary_scrollbar.pack(side=tk.RIGHT, fill=tk.Y)
        self.summary_text.configure(yscrollcommand=self.summary_scrollbar.set)


    def load_data(self):
        self.filename = filedialog.askopenfilename(initialdir=".", title="Select a File", filetypes=(("CSV files", "*.csv"), ("Excel files", "*.xlsx;*.xls"), ("All files", "*.*")))
        if self.filename:
            try:
                if self.filename.endswith(('.xls', '.xlsx')):
                    self.data = pd.read_excel(self.filename)
                else:
                    self.data = pd.read_csv(self.filename)

                self.populate_treeview()
                self.update_column_options()
                self.calculate_summary_statistics()

            except Exception as e:
                messagebox.showerror("Error", f"Error loading data: {e}")
                self.data = None
                self.filename = None

    def populate_treeview(self):
        if self.data is None:
            return

        self.tree.delete(*self.tree.get_children())

        self.tree["columns"] = list(self.data.columns)
        for col in self.data.columns:
            self.tree.heading(col, text=col)
            self.tree.column(col, width=100, stretch=False) # Prevent columns from stretching by default

        for index, row in self.data.iterrows():
            self.tree.insert("", tk.END, values=list(row))

    def update_column_options(self):
        if self.data is None:
            return

        columns = list(self.data.columns)
        self.x_column_dropdown['values'] = columns
        self.y_column_dropdown['values'] = columns
        if columns:
            self.x_column_var.set(columns[0]) # Set a default value
            if len(columns) > 1:
                 self.y_column_var.set(columns[1])  # Set a default value
            else:
                 self.y_column_var.set(columns[0]) # Set the same if only one column

    def calculate_summary_statistics(self):
        if self.data is None:
            return

        try:
            description = self.data.describe(include='all').to_string()
            self.summary_text.config(state=tk.NORMAL)
            self.summary_text.delete("1.0", tk.END)
            self.summary_text.insert(tk.END, description)
            self.summary_text.config(state=tk.DISABLED)
        except Exception as e:
            messagebox.showerror("Error", f"Error calculating summary statistics: {e}")

    def generate_visualization(self):
        if self.data is None:
            messagebox.showerror("Error", "Please load data first.")
            return

        visualization_type = self.visualization_var.get()
        x_column = self.x_column_var.get()
        y_column = self.y_column_var.get()

        try:
            # Clear previous visualization
            self.clear_visualization()

            # Generate new visualization
            fig, ax = plt.subplots(figsize=(6, 4))

            if visualization_type == "Scatter Plot":
                sns.scatterplot(x=x_column, y=y_column, data=self.data, ax=ax)
                ax.set_title(f"Scatter Plot of {y_column} vs {x_column}")
                ax.set_xlabel(x_column)
                ax.set_ylabel(y_column)

            elif visualization_type == "Histogram":
                self.data[x_column].hist(ax=ax)
                ax.set_title(f"Histogram of {x_column}")
                ax.set_xlabel(x_column)
                ax.set_ylabel("Frequency")

            elif visualization_type == "Box Plot":
                sns.boxplot(x=x_column, y=y_column, data=self.data, ax=ax)
                ax.set_title(f"Box Plot of {y_column} by {x_column}")
                ax.set_xlabel(x_column)
                ax.set_ylabel(y_column)

            elif visualization_type == "Bar Chart":
                # Assuming x_column is categorical
                counts = self.data[x_column].value_counts()
                counts.plot(kind='bar', ax=ax)
                ax.set_title(f"Bar Chart of {x_column}")
                ax.set_xlabel(x_column)
                ax.set_ylabel("Count")
                plt.xticks(rotation=45, ha='right') # Rotate x-axis labels for readability

            else:
                messagebox.showerror("Error", f"Invalid visualization type: {visualization_type}")
                return

            plt.tight_layout()

            # Embed plot in Tkinter window
            canvas = FigureCanvasTkAgg(fig, master=self.visualization_frame)
            self.visualization_canvas = canvas
            self.visualization_widget = canvas.get_tk_widget()
            self.visualization_widget.pack(fill=tk.BOTH, expand=True)
            canvas.draw()

        except Exception as e:
            messagebox.showerror("Error", f"Error generating visualization: {e}")

    def clear_visualization(self):
        if self.visualization_widget:
            self.visualization_widget.destroy()
            self.visualization_widget = None
        if self.visualization_canvas:
            self.visualization_canvas.get_tk_widget().destroy()
            self.visualization_canvas = None
        plt.close('all')  # Close all matplotlib figures



root = tk.Tk()
app = DataAnalyzerApp(root)
root.mainloop()
👁️ Viewed: 5

Comments