Build an Interactive Iris Flower Classifier GUI with Python
Source: Dev.to
What we’ll use
- scikit‑learn – machine learning
- pandas – CSV handling
- tkinter + ttkbootstrap – GUI
- Optional: tkinterdnd2 – drag & drop support
You can clone the full repository here:
🔗 Iris-Flower-Classifier-GUI on GitHub
Install dependencies
pip install pandas scikit-learn ttkbootstrap
# Optional: for drag & drop
pip install tkinterdnd2
Note:
tkintercomes pre‑installed with Python on most systems.
Import libraries
import os, sys, threading
import pandas as pd
import tkinter as tk
from tkinter import filedialog, messagebox, ttk
import ttkbootstrap as tb
from ttkbootstrap.constants import *
# Optional drag & drop
try:
from tkinterdnd2 import TkinterDnD, DND_FILES
DND_ENABLED = True
except ImportError:
DND_ENABLED = False
print("Drag & Drop requires tkinterdnd2: pip install tkinterdnd2")
Here we import:
pandasfor handling CSV filestkinter&ttkbootstrapfor modern GUI elementstkinterdnd2if you want drag‑&‑drop CSV support
Create the Iris machine‑learning model
from sklearn.datasets import load_iris
from sklearn.ensemble import RandomForestClassifier
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
class IrisModel:
def __init__(self):
data = load_iris()
self.X = data.data
self.y = data.target
self.target_names = data.target_names
self.scaler = StandardScaler()
# Scale features
X_scaled = self.scaler.fit_transform(self.X)
# Train/test split
X_train, X_test, y_train, y_test = train_test_split(
X_scaled, self.y, test_size=0.2, random_state=42
)
# Random Forest classifier
self.clf = RandomForestClassifier(n_estimators=100, random_state=42)
self.clf.fit(X_train, y_train)
def predict(self, X):
X_scaled = self.scaler.transform(X)
preds = self.clf.predict(X_scaled)
return [self.target_names[p] for p in preds]
✅ Explanation
- Features are standardized for better model performance.
- A Random Forest classifier is beginner‑friendly and works well for this classification task.
Worker for CSV processing
This worker lets the GUI handle multiple CSV files without freezing the interface.
class ClassifierWorker:
def __init__(self, files, callbacks):
self.files = files
self.callbacks = callbacks
self._running = True
self.model = IrisModel()
def stop(self):
self._running = False
def run(self):
total = len(self.files)
for i, file in enumerate(self.files):
if not self._running:
break
try:
df = pd.read_csv(file)
required = {"sepal_length", "sepal_width", "petal_length", "petal_width"}
if set(df.columns) >= required:
X = df[["sepal_length", "sepal_width",
"petal_length", "petal_width"]].values
preds = self.model.predict(X)
if "found" in self.callbacks:
self.callbacks["found"](file, preds)
else:
if "found" in self.callbacks:
self.callbacks["found"](file, ["Error: Missing required columns"])
except Exception as e:
if "found" in self.callbacks:
self.callbacks["found"](file, [f"Error: {str(e)}"])
# Progress update
if "progress" in self.callbacks:
self.callbacks["progress"](int((i + 1) / total * 100))
# Finished
if "finished" in self.callbacks:
self.callbacks["finished"]()
✅ Explanation
- Reads CSV files one by one.
- Predicts species using the Iris model.
- Sends progress updates to the GUI asynchronously.
Build the GUI
Main application class
class IrisClassifierApp:
def __init__(self):
if DND_ENABLED:
self.root = TkinterDnD.Tk()
else:
self.root = tb.Window(themename="darkly")
self.root.title("IrisClassifier v1.1")
self.root.minsize(1000, 700)
self.worker_obj = None
self.file_set = set()
self.model = IrisModel()
self._build_ui()
self._apply_styles()
- Checks if drag‑&‑drop is available.
- Initializes
ttkbootstrapfor a modern dark theme.
GUI layout
def _build_ui(self):
main = tb.Frame(self.root, padding=10)
main.pack(fill="both", expand=True)
tb.Label(
main,
text="🌸 Iris Flower Classifier",
font=("Segoe UI", 20, "bold")
).pack(pady=(0, 10))
# File selection row
row1 = tb.Frame(main)
row1.pack(fill="x", pady=(0, 6))
self.path_input = tb.Entry(row1, width=80)
self.path_input.pack(side="left", fill="x", expand=True, padx=(0, 6))
self.path_input.insert(0, "Drag & drop CSV files here…")
✅ Explanation
- Creates an input box for file paths.
- Adds a clear, friendly label.
Buttons & progress bar
browse_btn = tb.Button(
row1, text="📂 Browse", bootstyle="info", command=self.browse
)
browse_btn.pack(side="left", padx=3)
self.start_btn = tb.Button(
row1, text="🚀 Classify CSV", bootstyle="success", command=self.start
)
self.start_btn.pack(side="left", padx=3)
self.cancel_btn = tb.Button(
row1, text="⏹ Cancel", bootstyle="danger", command=self.cancel
)
self.cancel_btn.pack(side="left", padx=3)
self.cancel_btn.config(state="disabled")
self.progress = tb.Progressbar(
main, bootstyle="success-striped", maximum=100
)
self.progress.pack(fill="x", pady=10)
- Browse – opens a file‑dialog.
- Classify CSV – starts the worker thread.
- Cancel – stops processing.
- A progress bar visualises the classification progress.
(The remaining methods – browse, start, cancel, _apply_styles, etc. – are implemented in the original repository. They handle file selection, thread management, and UI updates.)
Run the application
if __name__ == "__main__":
app = IrisClassifierApp()
app.root.mainloop()
That’s it! Drop or browse CSV files containing the four Iris measurements, hit Classify, and watch the predictions appear without freezing the interface. Enjoy experimenting with machine learning and GUI development!
GUI Controls
Browse: Select CSVs
Classify CSV: Start predictions
Cancel: Stop predictions
Progress bar: Visual feedback
Add Manual Input
manual_frame = tb.Labelframe(main, text="Manual Input", padding=10)
manual_frame.pack(fill="x", pady=(10, 6))
labels = ["Sepal Length", "Sepal Width", "Petal Length", "Petal Width"]
self.manual_entries = {}
for i, label in enumerate(labels):
tb.Label(manual_frame, text=label).grid(row=0, column=i * 2, sticky="w")
entry = tb.Entry(manual_frame, width=8)
entry.grid(row=0, column=i * 2 + 1)
entry.insert(0, "0")
self.manual_entries[label] = entry
predict_btn = tb.Button(
manual_frame,
text="🔮 Predict",
bootstyle="info",
command=self.manual_predict,
)
predict_btn.grid(row=0, column=8, padx=10)
self.manual_result = tb.Label(
manual_frame,
text="Prediction: ---",
font=("Segoe UI", 12, "bold"),
)
self.manual_result.grid(row=1, column=0, columnspan=9, pady=(6, 0), sticky="w")
✅ Explanation
- Users can manually enter flower measurements.
- Click Predict to get the species immediately.
Run the App (alternative entry)
if __name__ == "__main__":
app = IrisClassifierApp()
app.run()
And that’s it! Your interactive Iris Flower Classifier is ready to run.
Optional Features
- Drag & Drop CSVs (requires
tkinterdnd2) - Export results to a text file
- Beautiful dark/light theme with ttkbootstrap
🎯 Summary
You’ve learned how to:
- Train a Random Forest classifier on the Iris dataset
- Build a Python GUI to interact with it
- Load CSV files and make manual predictions
- Visualize progress and results
Check out the full project here:
🔗 Iris-Flower-Classifier-GUI on GitHub
