Weโve all been there. You write a Python script that processes data beautifully, calculates complex metrics, and works without a hitch. Then, you decide to give it a user interface using standard Tkinter.
The result? An application that looks like it belongs in Windows 95.
Today, we are done with ugly apps. We are going to build a standalone Data Analysis Dashboard that embeds live Matplotlib charts inside a modern, dark-mode interface using CustomTkinter.
Originally published on LogicPy.com
๐ Quick Overview
- Goal: Build a GUI App that visualizes live data.
- Difficulty: Intermediate.
- Time: ~20 Minutes.
- Stack: Python, CustomTkinter, Matplotlib.
The Goal: A Professional Analytics Tool
We aren't just making a window with random buttons. We are building a layout that follows the "Golden Rules of GUI Design":
- Simplicity: A clean 2-column grid layout.
- Consistency: A unified dark color theme that matches the charts.
- Feedback: Immediate visual updates when selecting different metrics.
The Tech Stack
To achieve this, we need three ingredients:
- CustomTkinter: For the modern UI styling (Dark mode ready).
- Matplotlib: To generate the graphs.
- FigureCanvasTkAgg: The critical connector that lets Matplotlib "draw" inside a Tkinter window.
The Code Implementation
Below is the complete code. Notice how we use a Sidebar for controls (inputs) and a Main Frame for the visual output. This separates the doing from the seeing.
import customtkinter as ctk
import matplotlib.pyplot as plt
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
# --- Rule 2: Consistency (Theme Setup) ---
ctk.set_appearance_mode("Dark")
ctk.set_default_color_theme("blue")
class AnalyticsDashboard(ctk.CTk):
def __init__(self):
super().__init__()
# Window Configuration
self.title("LogicPy Data Analyzer")
self.geometry("1000x600")
# --- Rule 4: Responsiveness (Grid Layout) ---
self.grid_columnconfigure(1, weight=1)
self.grid_rowconfigure(0, weight=1)
# --- Component 1: The Sidebar (Controls) ---
self.sidebar = ctk.CTkFrame(self, width=200, corner_radius=0)
self.sidebar.grid(row=0, column=0, sticky="nsew")
self.logo_label = ctk.CTkLabel(self.sidebar, text="LOGICPY\nANALYTICS", font=ctk.CTkFont(size=20, weight="bold"))
self.logo_label.pack(padx=20, pady=(20, 10))
# Control Buttons
self.btn_sales = ctk.CTkButton(self.sidebar, text="Show Sales Trend", command=self.show_sales_data)
self.btn_sales.pack(padx=20, pady=10)
self.btn_users = ctk.CTkButton(self.sidebar, text="Show User Growth", command=self.show_user_data)
self.btn_users.pack(padx=20, pady=10)
# --- Component 2: The Main Display (Visualization) ---
self.main_view = ctk.CTkFrame(self, corner_radius=0, fg_color="transparent")
self.main_view.grid(row=0, column=1, sticky="nsew", padx=20, pady=20)
# Placeholder for the chart canvas
self.chart_canvas = None
# Initialize with first dataset
self.show_sales_data()
def render_chart(self, x_data, y_data, title, line_color):
"""
Refreshes the main view with a new Matplotlib chart.
"""
# Rule 5: Feedback (Clear old data before showing new)
if self.chart_canvas:
self.chart_canvas.get_tk_widget().destroy()
# Create the Matplotlib Figure
# Note: We set the facecolor to match the CustomTkinter Dark Theme
fig, ax = plt.subplots(figsize=(6, 5), dpi=100)
fig.patch.set_facecolor('#242424')
ax.set_facecolor('#242424')
# Plotting the Data
ax.plot(x_data, y_data, marker='o', color=line_color, linewidth=3)
# Styling the Chart to look "Modern"
ax.set_title(title, color='white', fontsize=14, pad=15)
ax.tick_params(axis='x', colors='gray')
ax.tick_params(axis='y', colors='gray')
ax.spines['bottom'].set_color('gray')
ax.spines['left'].set_color('gray')
ax.spines['top'].set_visible(False)
ax.spines['right'].set_visible(False)
# Embedding into Tkinter
self.chart_canvas = FigureCanvasTkAgg(fig, master=self.main_view)
self.chart_canvas.draw()
self.chart_canvas.get_tk_widget().pack(fill="both", expand=True)
def show_sales_data(self):
# Simulated Data Source
months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun']
sales = [12, 19, 24, 35, 42, 58]
self.render_chart(months, sales, "Monthly Revenue ($k)", "#3B8ED0")
def show_user_data(self):
# Simulated Data Source
months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun']
users = [50, 120, 150, 210, 300, 450]
self.render_chart(months, users, "Active User Count", "#2CC985")
if __name__ == "__main__":
app = AnalyticsDashboard()
app.mainloop()
Why This Matters
Take a close look at the render_chart function. By matching the Matplotlib background color (#242424) to the CustomTkinter background, the chart feels like a native part of the application, not a pasted image.
What's Next?
You now have the skeleton of a professional data tool. In my next post on LogicPy.com, Iโll be showing how to package this script into an .EXE file so you can send it to friends or clients.
๐ Check out the full Data Visualization Series here.
Before you go, Iโd love to hear from you. If something here sparked your curiosity or youโre stuck on a design problem of your own, drop your questions in the comments.
Top comments (0)