Whimsical Data Sculptor Python GUI

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

class DataSculptor:
    def __init__(self, master):
        self.master = master
        master.title("Whimsical Data Sculptor")

        # --- Data Storage --- #
        self.data = None
        self.filepath = None

        # --- Styling --- #
        self.font_family = "Arial, sans-serif"
        self.bg_color = "#f0f0f0"
        self.button_color = "#4CAF50"
        self.text_color = "#333333"

        # --- UI Elements --- #
        self.create_widgets()

    def create_widgets(self):
        # --- Main Frames --- #
        self.input_frame = ttk.Frame(self.master, padding=10)
        self.input_frame.pack(pady=10, fill=tk.X)

        self.analysis_frame = ttk.Frame(self.master, padding=10)
        self.analysis_frame.pack(pady=10, fill=tk.BOTH, expand=True)

        # --- Input Frame Widgets --- #
        self.load_button = ttk.Button(self.input_frame, text="Load Data (CSV, Excel)", command=self.load_data, style="Accent.TButton")
        self.load_button.pack(side=tk.LEFT, padx=5)

        self.view_button = ttk.Button(self.input_frame, text="View Data", command=self.view_data, state=tk.DISABLED)
        self.view_button.pack(side=tk.LEFT, padx=5)

        self.analyze_button = ttk.Button(self.input_frame, text="Analyze Data", command=self.analyze_data, state=tk.DISABLED)
        self.analyze_button.pack(side=tk.LEFT, padx=5)

        # --- Styling the buttons --- #
        style = ttk.Style()
        style.configure("Accent.TButton", foreground=self.text_color, background=self.button_color, font=(self.font_family, 10))

        # --- Analysis Frame Widgets --- #
        self.notebook = ttk.Notebook(self.analysis_frame)
        self.notebook.pack(fill=tk.BOTH, expand=True)

        self.summary_tab = ttk.Frame(self.notebook)
        self.visualization_tab = ttk.Frame(self.notebook)
        self.custom_analysis_tab = ttk.Frame(self.notebook)

        self.notebook.add(self.summary_tab, text="Data Summary")
        self.notebook.add(self.visualization_tab, text="Data Visualization")
        self.notebook.add(self.custom_analysis_tab, text="Custom Analysis")

        # --- Summary Tab --- #
        self.summary_text = tk.Text(self.summary_tab, wrap=tk.WORD, height=10, width=80, font=(self.font_family, 10))
        self.summary_text.pack(padx=10, pady=10, fill=tk.BOTH, expand=True)

        # --- Visualization Tab --- #
        self.figure = plt.Figure(figsize=(8, 6), dpi=100)
        self.canvas = FigureCanvasTkAgg(self.figure, master=self.visualization_tab)
        self.canvas.get_tk_widget().pack(padx=10, pady=10, fill=tk.BOTH, expand=True)

        self.visualization_options_frame = ttk.Frame(self.visualization_tab)
        self.visualization_options_frame.pack(pady=5)

        self.plot_type_label = ttk.Label(self.visualization_options_frame, text="Plot Type:", font=(self.font_family, 10))
        self.plot_type_label.pack(side=tk.LEFT, padx=5)

        self.plot_type_var = tk.StringVar(value="scatter")
        self.plot_type_dropdown = ttk.Combobox(self.visualization_options_frame, textvariable=self.plot_type_var, values=["scatter", "hist", "box", "violin", "bar"], state="readonly")
        self.plot_type_dropdown.pack(side=tk.LEFT, padx=5)
        self.plot_type_dropdown.bind("<<ComboboxSelected>>", self.update_visualization)

        self.x_axis_label = ttk.Label(self.visualization_options_frame, text="X Axis:", font=(self.font_family, 10))
        self.x_axis_label.pack(side=tk.LEFT, padx=5)

        self.x_axis_var = tk.StringVar()
        self.x_axis_dropdown = ttk.Combobox(self.visualization_options_frame, textvariable=self.x_axis_var, values=[], state="readonly")
        self.x_axis_dropdown.pack(side=tk.LEFT, padx=5)
        self.x_axis_dropdown.bind("<<ComboboxSelected>>", self.update_visualization)

        self.y_axis_label = ttk.Label(self.visualization_options_frame, text="Y Axis:", font=(self.font_family, 10))
        self.y_axis_label.pack(side=tk.LEFT, padx=5)

        self.y_axis_var = tk.StringVar()
        self.y_axis_dropdown = ttk.Combobox(self.visualization_options_frame, textvariable=self.y_axis_var, values=[], state="readonly")
        self.y_axis_dropdown.pack(side=tk.LEFT, padx=5)
        self.y_axis_dropdown.bind("<<ComboboxSelected>>", self.update_visualization)

        # --- Custom Analysis Tab --- #
        self.custom_analysis_text = tk.Text(self.custom_analysis_tab, wrap=tk.WORD, height=10, width=80, font=(self.font_family, 10))
        self.custom_analysis_text.pack(padx=10, pady=10, fill=tk.BOTH, expand=True)

        self.run_analysis_button = ttk.Button(self.custom_analysis_tab, text="Run Analysis", command=self.run_custom_analysis)
        self.run_analysis_button.pack(pady=5)

        # --- Status Bar --- #
        self.status_var = tk.StringVar(value="Ready")
        self.status_bar = ttk.Label(self.master, textvariable=self.status_var, relief=tk.SUNKEN, anchor=tk.W, font=(self.font_family, 8))
        self.status_bar.pack(side=tk.BOTTOM, fill=tk.X)

    def load_data(self):
        self.filepath = filedialog.askopenfilename(filetypes=[("CSV files", "*.csv"), ("Excel files", "*.xlsx;*.xls")])
        if self.filepath:
            try:
                if self.filepath.endswith(('.xlsx', '.xls')):
                    self.data = pd.read_excel(self.filepath)
                else:
                    self.data = pd.read_csv(self.filepath)
                self.status_var.set(f"Data loaded from: {self.filepath}")
                self.view_button["state"] = tk.NORMAL
                self.analyze_button["state"] = tk.NORMAL

                # Update dropdown options
                columns = list(self.data.columns)
                self.x_axis_dropdown["values"] = columns
                self.y_axis_dropdown["values"] = columns
                if columns:
                    self.x_axis_var.set(columns[0])  # Set a default value
                    if len(columns) > 1:
                        self.y_axis_var.set(columns[1])
                    self.update_visualization()

            except Exception as e:
                messagebox.showerror("Error", f"Failed to load data: {e}")
                self.status_var.set("Error loading data")

    def view_data(self):
        if self.data is not None:
            try:
                # Open in a new window
                view_window = tk.Toplevel(self.master)
                view_window.title("Data View")
                tree = ttk.Treeview(view_window, columns=list(self.data.columns), show='headings')
                for col in self.data.columns:
                    tree.heading(col, text=col)
                    tree.column(col, width=100)

                for index, row in self.data.iterrows():
                    tree.insert('', tk.END, values=list(row))
                tree.pack(fill=tk.BOTH, expand=True, padx=10, pady=10)

            except Exception as e:
                messagebox.showerror("Error", f"Error displaying data: {e}")
        else:
            messagebox.showinfo("Info", "No data loaded.")


    def analyze_data(self):
        if self.data is not None:
            try:
                # Generate summary statistics
                summary = self.data.describe().to_string()
                self.summary_text.delete("1.0", tk.END)
                self.summary_text.insert(tk.END, summary)

                # Display basic info
                info = self.data.info(verbose=False, memory_usage='deep').to_string()
                self.summary_text.insert(tk.END, "\n\nData Info:\n")
                self.summary_text.insert(tk.END, info)


                self.status_var.set("Data analysis complete.")
            except Exception as e:
                messagebox.showerror("Error", f"Error analyzing data: {e}")
                self.status_var.set("Error analyzing data")
        else:
            messagebox.showinfo("Info", "No data loaded.")

    def update_visualization(self, event=None):
        if self.data is not None:
            try:
                self.figure.clear()
                ax = self.figure.add_subplot(111)
                plot_type = self.plot_type_var.get()
                x_col = self.x_axis_var.get()
                y_col = self.y_axis_var.get()

                if plot_type == "scatter":
                    ax.scatter(self.data[x_col], self.data[y_col])
                    ax.set_xlabel(x_col)
                    ax.set_ylabel(y_col)
                elif plot_type == "hist":
                    self.data[x_col].hist(ax=ax)
                    ax.set_xlabel(x_col)
                elif plot_type == "box":
                    sns.boxplot(x=self.data[x_col], ax=ax)
                    ax.set_xlabel(x_col)
                elif plot_type == "violin":
                    sns.violinplot(x=self.data[x_col], ax=ax)
                    ax.set_xlabel(x_col)
                elif plot_type == "bar":
                    self.data[x_col].value_counts().plot(kind='bar', ax=ax)
                    ax.set_xlabel(x_col)

                ax.set_title(f"{plot_type.capitalize()} Plot of {x_col} vs {y_col if plot_type == 'scatter' else ''}")
                self.canvas.draw()

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

        else:
            messagebox.showinfo("Info", "No data loaded.")

    def run_custom_analysis(self):
        if self.data is not None:
            try:
                code = self.custom_analysis_text.get("1.0", tk.END)
                # --- Security Warning --- #
                messagebox.showwarning("Warning", "Executing arbitrary code can be dangerous. Proceed with caution!")

                # --- Execute Code --- #
                local_vars = {"df": self.data, "pd": pd, "np": pd.np}
                try:
                    exec(code, globals(), local_vars)
                    messagebox.showinfo("Success", "Custom analysis executed successfully.")
                except Exception as e:
                    messagebox.showerror("Error", f"Error executing custom analysis: {e}")

            except Exception as e:
                messagebox.showerror("Error", f"Error running custom analysis: {e}")
        else:
            messagebox.showinfo("Info", "No data loaded.")



root = tk.Tk()
root.geometry("800x600")
app = DataSculptor(root)
root.mainloop()
👁️ Viewed: 7

Comments