How to build an expense tracker in Python
Tikinter, CSV, Matplotlib modules
To build an expense tracker, you need the Tkinter, CSV, and Matplotlib modules. Tkinter allows you to create desktop applications. It provides a series of widgets like buttons, stickers, and text boxes that make application development easy.
The CSV module is a built-in Python library that provides the ability to read and write CSV files.
With Matplotlib, you can build interactive visualizations such as graphs, diagrams, and charts. Using it with modules like OpenCV can help you master image enhancement techniques.
To install these modules, run:
pip install tk matplotlib
Determine the structure of your expense tracking application
Start by importing the necessary modules. Define a class, ExpenseTrackerApp . Set title and size. Define one list to save expenses and another list to the folder. Initialize a StringVar of category name and set its initial value to the first category in the list. Finish by calling the create_widgets method .
import tkinter as tk from tkinter import ttk, messagebox, simpledialog import csv import matplotlib.pyplot as plt class ExpenseTrackerApp(tk.Tk): def __init__(self): super().__init__() self.title("Expense Tracker") self.geometry("1300x600") self.expenses = [] self.categories = [ "Food", "Transportation", "Utilities", "Entertainment", "Other", ] self.category_var = tk.StringVar(self) self.category_var.set(self.categories[0]) self.create_widgets()
The create_widgets method is responsible for adding UI elements to the application. Create a frame for the expense record labels and items. Create 6 labels: one for title, cost amount, item description, category, date, and total cost. Set each element's parent, the content to display, and its font style.
Create 3 entry widgets and a Combobox to get the corresponding input. For input widget, set parent element, font style and width. Specify the parent element, value list, font style and width for the Combobox. Bind category_var to it, so the selected value is automatically updated.
def create_widgets(self): self.label = tk.Label( self, text="Expense Tracker", font=("Helvetica", 20, "bold") ) self.label.pack(pady=10) self.frame_input = tk.Frame(self) self.frame_input.pack(pady=10) self.expense_label = tk.Label( self.frame_input, text="Expense Amount:", font=("Helvetica", 12) ) self.expense_label.grid(row=0, column=0, padx=5) self.expense_entry = tk.Entry( self.frame_input, font=("Helvetica", 12), width=15 ) self.expense_entry.grid(row=0, column=1, padx=5) self.item_label = tk.Label( self.frame_input, text="Item Description:", font=("Helvetica", 12) ) self.item_label.grid(row=0, column=2, padx=5) self.item_entry = tk.Entry(self.frame_input, font=("Helvetica", 12), width=20) self.item_entry.grid(row=0, column=3, padx=5) self.category_label = tk.Label( self.frame_input, text="Category:", font=("Helvetica", 12) ) self.category_label.grid(row=0, column=4, padx=5) self.category_dropdown = ttk.Combobox( self.frame_input, textvariable=self.category_var, values=self.categories, font=("Helvetica", 12), width=15, ) self.category_dropdown.grid(row=0, column=5, padx=5) self.date_label = tk.Label( self.frame_input, text="Date (YYYY-MM-DD):", font=("Helvetica", 12) ) self.date_label.grid(row=0, column=6, padx=5) self.date_entry = tk.Entry(self.frame_input, font=("Helvetica", 12), width=15) self.date_entry.grid(row=0, column=7, padx=5)
Define 5 buttons : Add Expense , Edit Expense , Delete Expense , Save Expenses , and Show Expenses Chart . Set the root element for each button, the content it will display, and the command it will run when you click it. Create a frame for the listbox . Set the element's root, font style, and width.
Create a vertical scrollbar and place it on the right side of the canvas. Use it to scroll through the contents of the listbox . Align the entire element with the necessary padding and call update_total_label() .
self.add_button = tk.Button(self, text="Add Expense", command=self.add_expense) self.add_button.pack(pady=5) self.frame_list = tk.Frame(self) self.frame_list.pack(pady=10) self.scrollbar = tk.Scrollbar(self.frame_list) self.scrollbar.pack(side=tk.RIGHT, fill=tk.Y) self.expense_listbox = tk.Listbox( self.frame_list, font=("Helvetica", 12), width=70, yscrollcommand=self.scrollbar.set, ) self.expense_listbox.pack(pady=5) self.scrollbar.config(command=self.expense_listbox.yview) self.edit_button = tk.Button( self, text="Edit Expense", command=self.edit_expense ) self.edit_button.pack(pady=5) self.delete_button = tk.Button( self, text="Delete Expense", command=self.delete_expense ) self.delete_button.pack(pady=5) self.save_button = tk.Button( self, text="Save Expenses", command=self.save_expenses ) self.save_button.pack(pady=5) self.total_label = tk.Label( self, text="Total Expenses:", font=("Helvetica", 12) ) self.total_label.pack(pady=5) self.show_chart_button = tk.Button( self, text="Show Expenses Chart", command=self.show_expenses_chart ) self.show_chart_button.pack(pady=5) self.update_total_label()
Determine the functionality of the expense tracking tool
Define the method, add_expense . Retrieve the value of expenses, items, categories, and dates. If the expense value and date are valid, add the expense to the expenses list . Insert this record into listbox and format it accordingly. Once inserted, clear the user input in the input boxes for the new input.
Otherwise, a warning shows that the value of the cost and date cannot be empty. Call update_total_label .
def add_expense(self): expense = self.expense_entry.get() item = self.item_entry.get() category = self.category_var.get() date = self.date_entry.get() if expense and date: self.expenses.append((expense, item, category, date)) self.expense_listbox.insert( tk.END, f"{expense} - {item} - {category} ({date})" ) self.expense_entry.delete(0, tk.END) self.item_entry.delete(0, tk.END) self.date_entry.delete(0, tk.END) else: messagebox.showwarning("Warning", "Expense and Date cannot be empty.") self.update_total_label()
Define the method, edit_expense . Retrieve the index of the selected record and get the cost. Opens a dialog box asking for expense entry. If the user has provided new costs, change the cost list accordingly. Call refresh_list and update_total_label .
def edit_expense(self): selected_index = self.expense_listbox.curselection() if selected_index: selected_index = selected_index[0] selected_expense = self.expenses[selected_index] new_expense = simpledialog.askstring( "Edit Expense", "Enter new expense:", initialvalue=selected_expense[0] ) if new_expense: self.expenses[selected_index] = ( new_expense, selected_expense[1], selected_expense[2], selected_expense[3], ) self.refresh_list() self.update_total_label()
Define the method, delete_expense . Retrieve the index of the selected record and get the cost. Change the index of the entry you want to delete. Remove that entry from the listbox and call update_total_label .
def delete_expense(self): selected_index = self.expense_listbox.curselection() if selected_index: selected_index = selected_index[0] del self.expenses[selected_index] self.expense_listbox.delete(selected_index) self.update_total_label()
Define method, refresh_list . Delete the current record and add a new record with the updated values.
def refresh_list(self): self.expense_listbox.delete(0, tk.END) for expense, item, category, date in self.expenses: self.expense_listbox.insert( tk.END, f"{expense} - {item} - {category} ({date})" )
Defines the update_total_label method . Total all costs in the list and update it on the label. Define another method, save_expenses . Create and open a CSV file named expenses.csv in write mode. Add the column headers for the CSV file to the first row. Repeat each expense record and write it in a row.
def update_total_label(self): total_expenses = sum(float(expense[0]) for expense in self.expenses) self.total_label.config(text=f"Total Expenses: USD {total_expenses:.2f}") def save_expenses(self): with open("expenses.csv", "w", newline="") as csvfile: writer = csv.writer(csvfile) column_headers = ["Expense Amount", "Item Description", "Category", "Date"] writer.writerow(column_headers) for expense in self.expenses: writer.writerow(expense))
Define a method, show_expenses_chart . Defines a dictionary, category_totals . Loop through the expenses list and convert the expense amount to float. Store total costs for each category. If the category already exists in the dictionary, increase the total to the current cost amount. If not, create a new entry with the current total cost.
def show_expenses_chart(self): category_totals = {} for expense, _, category, _ in self.expenses: try: amount = float(expense) except ValueError: continue category_totals[category] = category_totals.get(category, 0) + amount
Retrieve categories and costs in two different lists. Create a new style for the map with specific dimensions. Create a pie chart, using the expense list as the data and the categories as the labels. The autopct parameter determines the format for displaying percentage values on chart sections. Convert equal to plt.axis to ensure the data you plot is circular. Give the pie chart a title and display it.
categories = list(category_totals.keys()) expenses = list(category_totals.values()) plt.figure(figsize=(8, 6)) plt.pie( expenses, labels=categories, autopct="%1.1f%%", startangle=140, shadow=True ) plt.axis("equal") plt.title(f"Expense Categories Distribution (USD)") plt.show()
Create an instance of ExpenseTrackerApp . The mainloop() function tells Python to loop Tkinter events and listen for them until you close the window.
if __name__ == "__main__": app = ExpenseTrackerApp() app.mainloop()
Check out the various features of an expense management app in Python
When you run this program, it will open an application window. The inside contains input fields for recording costs, item descriptions, categories, and dates. Enter some data and click the Add Expense button . You will see the record added to the list box. This program also updates the total cost.
Select the record and click the Edit Expenses button . A dialog box appears, allowing you to update each record.
Click the Delete Expenses button to remove the selected record.
When the Show Expenses Chart button is pressed , the program displays a pie chart. The pie chart shows the cost for each category along with its name and percentage.
You can add search functionality to allow users to find specific costs based on description, quantity, folder, or date. You can add sorting and filtering options to records. Localize your app to multiple languages and currency formats.
Hope the article is useful to you.
You should read it
- How to set up Python to program on WSL
- More than 100 Python exercises have solutions (sample code)
- What is Python? Why choose Python?
- 5 choose the best Python IDE for you
- Bookmark 5 best Python programming learning websites
- Multiple choice quiz about Python - Part 3
- Why should you learn Python programming language?
- For in Python loop
- Python data type: string, number, list, tuple, set and dictionary
- Multiple choice quiz about Python - Part 4
- Manage files and folders in Python
- How to use GPT-3 with Python
Maybe you are interested
Basic steps to build self-confidence in children
How to take care of yourself when you are sick
How to try to crack a password yourself to test its strength
Ways to Transform Yourself into a Better Version in the New Year
How to effectively 'market' yourself in the job market
Why not use AI to edit selfies and portraits?