Skip to content
python
# stage5_visualization.py
import matplotlib.pyplot as plt
import json
from collections import defaultdict

# 设置中文字体
plt.rcParams['font.sans-serif'] = ['SimHei']  # 用来正常显示中文标签
plt.rcParams['axes.unicode_minus'] = False    # 用来正常显示负号

def load_financial_data(filename="finance_data.json"):
    """加载财务数据"""
    try:
        with open(filename, 'r', encoding='utf-8') as f:
            return json.load(f)
    except FileNotFoundError:
        print("数据文件不存在,请先运行前面的程序")
        return None

def create_expense_pie_chart(data):
    """创建支出饼图"""
    # 按类别统计支出
    category_expenses = defaultdict(float)
    for expense in data["expenses"]:
        category_expenses[expense["category"]] += expense["amount"]
    
    if not category_expenses:
        print("没有支出数据可显示")
        return
    
    # 准备饼图数据
    categories = list(category_expenses.keys())
    amounts = list(category_expenses.values())
    
    # 创建饼图
    plt.figure(figsize=(10, 8))
    plt.pie(amounts, labels=categories, autopct='%1.1f%%', startangle=90)
    plt.title('支出分类比例')
    plt.axis('equal')  # 确保饼图是圆的
    plt.tight_layout()
    plt.savefig('expense_pie_chart.png')
    plt.show()

def create_income_vs_expense_bar(data):
    """创建收入vs支出柱状图"""
    total_income = sum(item["amount"] for item in data["income"])
    total_expenses = sum(item["amount"] for item in data["expenses"])
    
    # 创建柱状图
    plt.figure(figsize=(8, 6))
    categories = ['收入', '支出']
    amounts = [total_income, total_expenses]
    colors = ['green', 'red']
    
    bars = plt.bar(categories, amounts, color=colors, alpha=0.7)
    plt.title('收入 vs 支出')
    plt.ylabel('金额 (元)')
    
    # 在柱子上显示数值
    for bar, amount in zip(bars, amounts):
        plt.text(bar.get_x() + bar.get_width()/2, bar.get_height() + 50, 
                f'{amount:.0f}元', ha='center', va='bottom')
    
    plt.tight_layout()
    plt.savefig('income_vs_expense.png')
    plt.show()

def create_monthly_trend(data):
    """创建月度趋势图(模拟数据)"""
    # 这里我们模拟6个月的数据来展示趋势
    months = ['1月', '2月', '3月', '4月', '5月', '6月']
    
    # 模拟收入数据(基于现有数据估算)
    base_income = sum(item["amount"] for item in data["income"]) or 8000
    income_trend = [base_income * (1 + i * 0.05) for i in range(6)]
    
    # 模拟支出数据
    base_expense = sum(item["amount"] for item in data["expenses"]) or 4500
    expense_trend = [base_expense * (1 + i * 0.02) for i in range(6)]
    
    # 创建趋势图
    plt.figure(figsize=(10, 6))
    plt.plot(months, income_trend, marker='o', label='收入', color='green', linewidth=2)
    plt.plot(months, expense_trend, marker='s', label='支出', color='red', linewidth=2)
    plt.title('月度收支趋势')
    plt.xlabel('月份')
    plt.ylabel('金额 (元)')
    plt.legend()
    plt.grid(True, alpha=0.3)
    plt.tight_layout()
    plt.savefig('monthly_trend.png')
    plt.show()

def create_savings_progress(data):
    """创建储蓄进度图"""
    total_income = sum(item["amount"] for item in data["income"])
    total_expenses = sum(item["amount"] for item in data["expenses"])
    savings = total_income - total_expenses
    
    # 假设储蓄目标
    savings_goal = 10000
    
    # 创建进度图
    fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(12, 5))
    
    # 左侧:当前储蓄 vs 目标
    labels = ['已储蓄', '剩余目标']
    amounts = [savings, max(0, savings_goal - savings)]
    colors = ['lightblue', 'lightgray']
    
    ax1.pie(amounts, labels=labels, colors=colors, autopct='%1.1f%%', startangle=90)
    ax1.set_title('储蓄进度')
    
    # 右侧:进度条
    progress = min(savings / savings_goal, 1.0) * 100
    ax2.barh([0], [progress], color='lightgreen', alpha=0.7)
    ax2.barh([0], [100 - progress], left=[progress], color='lightgray', alpha=0.7)
    ax2.set_xlim(0, 100)
    ax2.set_yticks([])
    ax2.set_xlabel('完成百分比 (%)')
    ax2.set_title(f'储蓄目标进度: {progress:.1f}%')
    ax2.text(progress/2, 0, f'{savings:.0f}元', ha='center', va='center', fontsize=12)
    ax2.text(progress + (100-progress)/2, 0, f'{savings_goal-savings:.0f}元', 
             ha='center', va='center', fontsize=12)
    
    plt.tight_layout()
    plt.savefig('savings_progress.png')
    plt.show()

def main():
    print("=== 财务数据可视化 ===")
    
    # 加载数据
    data = load_financial_data()
    if not data:
        return
    
    # 显示基本统计
    total_income = sum(item["amount"] for item in data["income"])
    total_expenses = sum(item["amount"] for item in data["expenses"])
    balance = total_income - total_expenses
    
    print(f"数据统计:")
    print(f"- 总收入: {total_income:.2f} 元")
    print(f"- 总支出: {total_expenses:.2f} 元")
    print(f"- 当前余额: {balance:.2f} 元")
    
    # 创建可视化图表
    print("\n生成可视化图表...")
    
    if data["expenses"]:
        create_expense_pie_chart(data)
    
    create_income_vs_expense_bar(data)
    create_monthly_trend(data)
    create_savings_progress(data)
    
    print("所有图表已生成并保存为PNG文件!")

if __name__ == "__main__":
    main()

Released under the MIT License.