DEV Community

Mate Technologies
Mate Technologies

Posted on

đź’° Build a Salary Prediction System in Python with a GUI

In this tutorial, we’ll build SalaryPredictor v2.0, a desktop app that predicts employee salaries using Machine Learning. It supports batch predictions, real-time previews, filtering, and live search—all in a beautiful GUI with tkinter and ttkbootstrap.

We’ll break it down step by step so even beginners can follow along.

Step 1: Install Required Packages

Before we start, make sure you have Python installed. Then install the dependencies:

pip install pandas joblib tkinterdnd2 ttkbootstrap

pandas: For handling CSV files

joblib: To load ML models

tkinter + ttkbootstrap: For GUI

tkinterdnd2: Optional, for drag-and-drop support

Step 2: Set Up the Imports

Create a Python file called salary_predictor.py and start with the imports:

import os
import sys
import threading
import pandas as pd
import joblib
import tkinter as tk
from tkinter import filedialog, messagebox, ttk
import ttkbootstrap as tb
from ttkbootstrap.constants import *
Enter fullscreen mode Exit fullscreen mode

Optional drag-and-drop support:

try:
    from tkinterdnd2 import TkinterDnD, DND_FILES
    DND_ENABLED = True
except ImportError:
    DND_ENABLED = False
    print("Drag & Drop requires tkinterdnd2: pip install tkinterdnd2")
Enter fullscreen mode Exit fullscreen mode

âś… Explanation:
We import packages for GUI, CSV handling, threading, and machine learning. tkinterdnd2 enables drag-and-drop of files for convenience.

Step 3: Helper Function for Resource Paths

If you package your app using PyInstaller, you need a helper to locate files:

def resource_path(file_name):
    base_path = getattr(sys, "_MEIPASS", os.path.dirname(os.path.abspath(__file__)))
    return os.path.join(base_path, file_name)
Enter fullscreen mode Exit fullscreen mode

Helps the app locate icons or other files when bundled.

Step 4: Create the Salary Prediction Worker

This class handles predictions in a background thread, so the GUI doesn’t freeze:

class SalaryPredictWorker:
    def __init__(self, files, model_path, callbacks):
        self.files = files
        self.model = joblib.load(model_path)
        self.callbacks = callbacks
        self._running = True

    def stop(self):
        self._running = False
Enter fullscreen mode Exit fullscreen mode

The main prediction loop:

    def run(self):
        feature_cols = ["Age", "Experience", "EducationLevel"]
        for path in self.files:
            if not self._running:
                break
            df = pd.read_csv(path)
            X = df[feature_cols]
            df['PredictedSalary'] = self.model.predict(X)
            for idx, row in df.iterrows():
                if not self._running:
                    break
                row_data = row.to_dict()
                row_data['_row_id'] = idx
                if "found" in self.callbacks:
                    self.callbacks["found"](path, row_data)
Enter fullscreen mode Exit fullscreen mode

âś… Explanation:

Reads each CSV file.

Uses only the model’s features (Age, Experience, EducationLevel).

Predicts salary for each employee.

Sends results back to GUI via callback functions.

Step 5: Build the GUI App

The main app class:

class SalaryPredictApp:
    APP_NAME = "SalaryPredictor"
    APP_VERSION = "2.0"

    def __init__(self):
        self.root = tb.Window(themename="darkly")  # Use ttkbootstrap for a nice theme
        self.root.title(f"{self.APP_NAME} v{self.APP_VERSION}")
        self.root.minsize(1300, 750)
        self.file_set = set()
        self.model_path = tk.StringVar()
        self.filter_min = tk.DoubleVar(value=0)
        self.filter_max = tk.DoubleVar(value=1e9)
        self.search_var = tk.StringVar()
Enter fullscreen mode Exit fullscreen mode

Sets up main variables and GUI window.

Step 6: File Selection and Drag-and-Drop

Allow users to select files or folders:

def browse(self):
    folder = filedialog.askdirectory(title="Select Folder with CSV files")
    if folder:
        self._scan_and_queue_files_thread([folder])
Enter fullscreen mode Exit fullscreen mode

Drag-and-drop (if tkinterdnd2 is installed):

def on_drop(self, event):
    dropped_paths = self.root.tk.splitlist(event.data)
    self._scan_and_queue_files_thread(dropped_paths)
Enter fullscreen mode Exit fullscreen mode

Step 7: Display Employee Predictions in a Table

Use ttk.Treeview to show real-time results:

self.tree = ttk.Treeview(main, columns=("selected", "filename", "employee_name", "predicted_salary"), show="headings")
self.tree.heading("selected", text="âś…")
self.tree.heading("filename", text="Filename")
self.tree.heading("employee_name", text="Employee")
self.tree.heading("predicted_salary", text="Predicted Salary")
self.tree.pack(fill="both", expand=True)
Enter fullscreen mode Exit fullscreen mode

âś… Explanation:
Each row shows:

File name

Employee name

Predicted salary

Checkbox for selecting rows

Step 8: Start Prediction

Start worker in a background thread:

def start(self):
    selected_files = [self.tree.item(i)['values'][1] for i in self.tree.get_children()]
    self.worker_obj = SalaryPredictWorker(selected_files, self.model_path.get(), callbacks={
        "found": self.add_result,
        "progress": self.set_target,
        "finished": self.finish
    })
    threading.Thread(target=self.worker_obj.run, daemon=True).start()
Enter fullscreen mode Exit fullscreen mode

Step 9: Filter and Search

Filter by min/max salary and search by employee name:

def apply_filters(self):
    min_salary = self.filter_min.get()
    max_salary = self.filter_max.get()
    search_text = self.search_var.get().lower()
    self.tree.delete(*self.tree.get_children())
    for key, row in self.all_rows.items():
        if min_salary <= row['predicted_salary'] <= max_salary:
            if search_text in row['employee_name'].lower():
                self.tree.insert("", "end", iid=key, values=(row['selected'], row['filename'], row['employee_name'], f"${row['predicted_salary']:,.2f}"))
Enter fullscreen mode Exit fullscreen mode

âś… Explanation:
Users can filter the table dynamically as data is processed.

Step 10: Export Results

Export selected rows to a CSV:

def export_results(self):
    path = filedialog.asksaveasfilename(defaultextension=".csv")
    if path:
        with open(path, "w", encoding="utf-8") as f:
            f.write("Filename,Employee,PredictedSalary\n")
            for i in self.tree.get_children():
                values = self.tree.item(i)['values']
                f.write(f"{values[1]},{values[2]},{values[3]}\n")
Enter fullscreen mode Exit fullscreen mode

Step 11: Run the App

Finally, start the GUI loop:

if __name__ == "__main__":
    app = SalaryPredictApp()
    app.run()
Enter fullscreen mode Exit fullscreen mode

Step 12: Clone the Full Project

You can find the full source code and download it here:
👉 https://github.com/rogers-cyber/python-tiny-tools/tree/main/Salary-prediction-system

âś… Key Features Recap

Drag & drop CSV files or folders

Real-time per-employee salary prediction

Filter by min/max salary

Search employees live

Batch processing with progress bar

Export results to CSV

This tutorial is designed to be beginner-friendly and easy to follow.

Top comments (0)