You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

数据库加载异常导致可视化不完整:仅生成1个饼图且柱状图为空

数据库加载异常导致可视化不完整:仅生成1个饼图且柱状图为空

看起来你遇到了数据查询和可视化的双重问题——只生成了一个饼图,柱状图还空着,这肯定让人头大!咱们一步步拆解问题,先找数据根源,再修复可视化逻辑。

第一步:先确认数据是否真的加载正确

很多时候可视化出问题,本质是数据查询没返回预期结果。先在代码里加几行打印,看看两个DataFrame的内容:

# 执行完查询后添加这几行
print("=== 支出子类别数据 ===")
print(df_expenses)
print("\n=== 收支对比数据 ===")
print(df_income_expenses)

如果df_expenses里只有1个唯一的month值,那自然只会生成1个饼图;如果df_income_expenses是空的,说明你的收支查询根本没拿到数据。

第二步:排查SQL查询的核心问题

1. 日期格式与筛选逻辑

SQLite的date()和strftime()函数只认YYYY-MM-DD格式的日期字符串。如果你的Transactions.date字段是其他格式(比如DD/MM/YYYY或MM-DD-YYYY),那日期比较会完全失效,导致只拿到部分数据甚至空数据。

  • 先验证日期格式:运行这条SQL单独查询(可以用SQLiteStudio等工具):
    SELECT t.date FROM Transactions LIMIT 5;
    
  • 如果日期格式不是YYYY-MM-DD,需要先转换格式再筛选。比如如果是DD-MM-YYYY,修改WHERE子句:
    WHERE date(substr(t.date,7,4)||'-'||substr(t.date,4,2)||'-'||substr(t.date,1,2)) >= date('now', '-3 months')
    
  • 另外,date('now', '-3 months')返回的是当前日期往前推3个月的当天,如果你的数据里最近3个月的某几天没有记录,那对应的month可能不会出现在结果里,但如果完全空的话,大概率是日期格式不匹配。

2. JOIN语句的完整性

你的查询用了JOIN(内连接),这意味着只要某条Transaction没有对应的TransactionItems或Subcategories,就会被过滤掉。如果你的数据库里存在这样的记录,会导致数据丢失:

  • 改成LEFT JOIN保留所有Transaction记录,即使关联表没有匹配项:
    -- 支出查询修改后的JOIN部分
    FROM Transactions t
    LEFT JOIN TransactionItems ti ON t.transactionID = ti.transactionID
    LEFT JOIN Subcategories s ON t.subcategoryID = s.subcategoryID
    
    收支对比查询也做同样的修改。

3. 收支分类的判断逻辑

确认Subcategories.category里确实有值为'Income'的记录——如果分类名是其他写法(比如'income'小写、'工资收入'等),那CASE WHEN s.category = 'Income'就不会匹配到任何数据,导致total_income全为0,收支对比图也会异常。

第三步:修复可视化代码的小细节

即使数据正确,可视化代码也有小瑕疵可能导致空图:

  • 柱状图部分,用pandas的plot()后,最好显式绑定到指定的figure和axes,避免和其他figure混淆;
  • 加个判断,避免空DataFrame生成无效图表:
    # 替换原来的柱状图代码
    if not df_income_expenses.empty:
        fig, ax = plt.subplots(figsize=(10, 6))
        df_income_expenses.plot(x='month', y=['total_income', 'total_expense'], kind='bar', ax=ax)
        ax.set_title('Income vs Expenses for the Last 3 Months')
        ax.set_xlabel('Month')
        ax.set_ylabel('Amount')
        ax.legend(loc='upper right')
        pdf_pages.savefig(fig)
        plt.close(fig)
    

修复后的完整代码示例

import sqlite3
import pandas as pd
import matplotlib.pyplot as plt
from matplotlib.backends.backend_pdf import PdfPages
from datetime import datetime

# Path to SQLite Database
db_path = r"D:\Python\pythonProject\Project\Project\98661737.sqlite"

# Connect to the SQLite database
conn = sqlite3.connect(db_path)

# Query to get expenses per subcategory for the last 3 months
query_expenses = """
SELECT strftime('%Y-%m', t.date) as month, s.category as subcategory, SUM(COALESCE(ti.baseAmount, 0)) as total_expense
FROM Transactions t
LEFT JOIN TransactionItems ti ON t.transactionID = ti.transactionID
LEFT JOIN Subcategories s ON t.subcategoryID = s.subcategoryID
WHERE date(t.date) >= date('now', '-3 months')
GROUP BY month, subcategory
"""

# Query to get income vs expenses for the last 3 months
query_income_expenses = """
SELECT strftime('%Y-%m', t.date) as month,
       SUM(CASE WHEN s.category = 'Income' THEN COALESCE(ti.baseAmount, 0) ELSE 0 END) as total_income,
       SUM(CASE WHEN s.category != 'Income' THEN COALESCE(ti.baseAmount, 0) ELSE 0 END) as total_expense
FROM Transactions t
LEFT JOIN TransactionItems ti ON t.transactionID = ti.transactionID
LEFT JOIN Subcategories s ON t.subcategoryID = s.subcategoryID
WHERE date(t.date) >= date('now', '-3 months')
GROUP BY month
"""

# Execute the queries
df_expenses = pd.read_sql_query(query_expenses, conn)
df_income_expenses = pd.read_sql_query(query_income_expenses, conn)

# 打印数据验证
print("=== 支出子类别数据 ===")
print(df_expenses)
print("\n=== 收支对比数据 ===")
print(df_income_expenses)

# Close the database connection
conn.close() 

# Create a PDF file to save the plots
date_time = datetime.now().strftime('%Y%m%d_%H%M%S')
pdf_filename = f'{date_time}.pdf'
pdf_pages = PdfPages(pdf_filename)

# Pie charts of expenses per subcategory for the last 3 months
months = df_expenses['month'].unique()
for month in months:
    df_month = df_expenses[df_expenses['month'] == month]
    # 过滤掉总支出为0的子类别
    df_month = df_month[df_month['total_expense'] > 0]
    if not df_month.empty:
        plt.figure(figsize=(8, 8))
        plt.pie(df_month['total_expense'], labels=df_month['subcategory'], autopct='%1.1f%%')
        plt.title(f'Expenses per Subcategory for {month}')
        pdf_pages.savefig()
        plt.close()

# Column chart showing income vs expenses for the last 3 months
if not df_income_expenses.empty:
    fig, ax = plt.subplots(figsize=(10, 6))
    df_income_expenses.plot(x='month', y=['total_income', 'total_expense'], kind='bar', ax=ax)
    ax.set_title('Income vs Expenses for the Last 3 Months')
    ax.set_xlabel('Month')
    ax.set_ylabel('Amount')
    ax.legend(loc='upper right')
    pdf_pages.savefig(fig)
    plt.close(fig)

# Close the PDF file
pdf_pages.close()
print(f"Report saved as {pdf_filename}")

最后提醒

  • 优先看打印出来的DataFrame内容,这是定位问题最快的方式;
  • 如果日期格式确实不是YYYY-MM-DD,一定要先调整SQL里的日期转换逻辑,否则所有日期筛选都是无效的;
  • 用COALESCE(ti.baseAmount, 0)可以避免NULL值导致SUM结果为NULL的问题。

备注:内容来源于stack exchange,提问作者Arbab Qaisar

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.14 14:53:05