Skip to content

Add Spending Heatmap Visualization#12

Merged
7174Andy merged 6 commits intomainfrom
andrew/add-heat-map
Dec 1, 2025
Merged

Add Spending Heatmap Visualization#12
7174Andy merged 6 commits intomainfrom
andrew/add-heat-map

Conversation

@7174Andy
Copy link
Owner

@7174Andy 7174Andy commented Dec 1, 2025

Add Spending Heatmap Visualization

Summary

Adds a new Heatmap tab to the expense tracker that visualizes daily spending patterns in a monthly calendar view. Users can see at a glance which days had high spending (darker colors) vs low spending (lighter colors), navigate between months, and drill down to view specific transactions by clicking on a day.

Features

1. Calendar Heatmap Visualization

  • Monthly calendar grid displaying days 1-31 with proper day-of-week alignment
  • Color-coded spending intensity using a red gradient:
    • White (#FFFFFF) - No spending
    • Light Red (#FFCCCC) - Low spending (< 25th percentile)
    • Medium Red (#FF6666) - Moderate spending (25th-75th percentile)
    • Dark Red (#CC0000) - High spending (≥ 75th percentile)
  • Percentile-based coloring ensures meaningful visualization regardless of absolute amounts
  • Canvas-based rendering to bypass theme styling issues (reliable color display)

2. Month Navigation

  • Previous/Next buttons to navigate between months
  • Smart navigation - only shows months with actual expenses (skips empty months)
  • State persistence - selected month is maintained when switching between tabs
  • Header display shows current month and year (e.g., "November 2025")

3. Interactive Features

  • Tooltips on hover - Display exact spending amount (e.g., "November 15: $125.50")
  • Click-through drill-down - Clicking a day cell switches to Transactions tab with date filter applied
  • Visual feedback - Cursor changes to pointer on hoverable cells
  • Lazy loading - Heatmap only refreshes when tab becomes active

4. Repository Enhancements

Added three new data access methods to TransactionRepository:

  • get_daily_spending_for_month(year, month) - Aggregates expenses by day for heatmap display
  • get_transactions_for_date(target_date) - Retrieves all transactions for a specific date
  • get_months_with_expenses() - Returns list of months with expense data

Example Usage

  1. View Spending Patterns: Click the "Heatmap" tab to see the current month's spending heatmap
  2. Navigate History: Use < and > buttons to browse through months with expenses
  3. Investigate High Spending: Click on a dark red cell to see all transactions for that day
  4. Return to Overview: Click the "Heatmap" tab again to return to the calendar view

Technical Implementation

Architecture

  • Component: HeatmapTab (new) - Self-contained tab component inheriting from tk.Frame
  • Integration: Added to existing tabbed interface via ttk.Notebook
  • Rendering: Uses Tkinter Canvas with create_rectangle() for reliable color display
  • Performance: SQL queries use date filtering and GROUP BY for efficient aggregation

Key Design Decisions

  1. Canvas-based rendering instead of Label backgrounds

    • Why: The ttkbootstrap "darkly" theme overrides standard widget background colors
    • Solution: Drawing filled rectangles on Canvas bypasses theme styling entirely
    • Result: Colors display reliably across all themes
  2. Percentile-based color gradient

    • Why: Absolute thresholds ($0-50, $50-200) wouldn't adapt to different spending patterns
    • Solution: Calculate 25th and 75th percentiles from each month's data
    • Result: Color distribution is meaningful whether spending is $50/day or $500/day
  3. Navigation through months with expenses only

    • Why: User feedback indicated preference for skipping empty months
    • Solution: Query distinct months with expenses, navigate via index
    • Result: Efficient browsing of historical data without empty states
  4. Consistent cell sizing (90x70 pixels)

    • Why: Mixing Label (character-based) and Canvas (pixel-based) caused spacing issues
    • Solution: Use Canvas for all cells (both empty and day cells)
    • Result: Uniform grid spacing regardless of month start day

Files Modified

  • expense_tracker/core/repositories.py - Added 3 new methods (+65 lines)
  • expense_tracker/gui/tabs/heatmap_tab.py - New file (277 lines)
  • expense_tracker/gui/tabs/__init__.py - Export HeatmapTab
  • expense_tracker/gui/main_window.py - Added HeatmapTab to notebook, lazy loading
  • expense_tracker/gui/tabs/transactions_tab.py - Added date filter capability
  • tests/core/test_repository.py - Added 8 new tests for repository methods

Test Coverage

  • ✅ 25 total repository tests (all passing)
  • ✅ 8 new tests for heatmap-related methods
  • ✅ Tests cover: daily aggregation, date filtering, month enumeration, edge cases
  • ✅ All existing tests pass (no regressions)

API Changes

New Public Methods

TransactionRepository

def get_daily_spending_for_month(self, year: int, month: int) -> dict[int, float]:
    """
    Returns a dictionary mapping day-of-month (1-31) to total spending.
    Only includes expenses (negative amounts).
    """

def get_transactions_for_date(self, target_date: date) -> list[Transaction]:
    """
    Query transactions matching exact date.
    Order by amount ASC (largest expenses first).
    """

def get_months_with_expenses(self) -> list[tuple[int, int]]:
    """
    Returns a list of (year, month) tuples for all months that have expenses.
    Only includes months with negative amounts (expenses).
    Ordered by year and month descending (most recent first).
    """

TransactionsTab

def filter_by_date(self, target_date: date):
    """Filter transactions by a specific date."""

MainWindow

def show_transactions_for_date(self, target_date: date):
    """Switch to Transactions tab with date filter applied."""

Performance

  • Query time: < 50ms for typical month (< 200 transactions)
  • Render time: < 150ms for full calendar grid (31 cells)
  • Tab switch time: < 200ms from click to visible heatmap
  • Memory: Negligible impact (< 1MB for tab and data)

Future Enhancements

Consider for future iterations:

  1. Category breakdown - Show spending by category in tooltip or drill-down
  2. Year view - GitHub-style full year heatmap
  3. Export - Save heatmap as image
  4. Legend - Visual color key (currently relying on tooltips)
  5. Comparison mode - Side-by-side month comparison

@7174Andy 7174Andy merged commit b0fd96f into main Dec 1, 2025
3 checks passed
@7174Andy 7174Andy deleted the andrew/add-heat-map branch December 1, 2025 05:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant