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

在Django中使用Matplotlib绘制费用vs日期柱状图问题求助

解决Django中Matplotlib柱状图显示BarContainer对象的问题

问题原因

你直接将Matplotlib的plt.bar()返回的BarContainer对象传递给了Django模板,模板无法解析这个Python对象,因此显示了它的字符串表示barcontainer object of 2 artists。正确的做法是将图表转换为HTML可识别的格式(如Base64编码或静态图片文件)后再传递给模板。

步骤1:先按日期聚合费用数据

同一日期有多条费用记录时,需要先按日期分组计算总费用,避免图表出现重叠柱子。这里提供两种聚合方式:

方式1:用Python标准库处理

from itertools import groupby
from .models import Expense  # 替换为你的费用模型

# 获取所有费用记录并按日期排序
expenses = Expense.objects.all().order_by('date')
grouped_data = []
# 按日期分组,计算每日总费用
for date, expense_items in groupby(expenses, key=lambda x: x.date.date()):
    daily_total = sum(item.amount for item in expense_items)
    grouped_data.append((date, daily_total))

# 拆分日期和总费用列表
dates = [item[0] for item in grouped_data]
daily_totals = [item[1] for item in grouped_data]

方式2:用Pandas简化处理(推荐)

import pandas as pd
from .models import Expense

# 将查询集转为DataFrame
df = pd.DataFrame(list(expenses.values('date', 'amount')))
# 提取日期部分(去掉时分秒)
df['date'] = pd.to_datetime(df['date']).dt.date
# 按日期分组求和
daily_totals = df.groupby('date')['amount'].sum().reset_index()

dates = daily_totals['date']
daily_totals = daily_totals['amount']

步骤2:生成图表并转换为HTML可识别格式

方案1:将图表转为Base64编码嵌入HTML(适合小流量场景)

在Django视图中:

import matplotlib.pyplot as plt
import io
import base64
from django.shortcuts import render

def expense_chart(request):
    # 先执行上面的费用聚合代码,得到dates和daily_totals
    
    # 设置Matplotlib为非交互式后端(服务器环境必需)
    plt.switch_backend('AGG')
    # 创建图表
    fig, ax = plt.subplots(figsize=(8, 4))
    ax.bar(dates, daily_totals, color='#2ecc71')
    # 设置图表标签和标题
    ax.set_xlabel('日期')
    ax.set_ylabel('总费用')
    ax.set_title('每日支出柱状图')
    # 旋转日期标签避免重叠
    plt.xticks(rotation=45, ha='right')
    
    # 将图表转为Base64字符串
    buf = io.BytesIO()
    plt.savefig(buf, format='png', bbox_inches='tight')  # bbox_inches避免标签被截断
    buf.seek(0)
    chart_base64 = base64.b64encode(buf.getvalue()).decode('utf-8')
    # 关闭图表释放资源
    plt.close(fig)
    
    return render(request, 'expense_chart.html', {'chart_image': chart_base64})

在模板expense_chart.html中:

<div class="chart-container">
    <img src="data:image/png;base64,{{ chart_image }}" alt="每日支出柱状图">
</div>

方案2:保存为静态图片文件(适合大流量场景)

在Django视图中:

import matplotlib.pyplot as plt
import os
from django.conf import settings
from django.shortcuts import render

def expense_chart(request):
    # 先执行费用聚合代码,得到dates和daily_totals
    
    plt.switch_backend('AGG')
    fig, ax = plt.subplots(figsize=(8, 4))
    ax.bar(dates, daily_totals)
    ax.set_xlabel('日期')
    ax.set_ylabel('总费用')
    plt.xticks(rotation=45)
    
    # 保存图片到静态目录
    chart_path = os.path.join(settings.STATIC_ROOT, 'expense_chart.png')
    plt.savefig(chart_path, format='png', bbox_inches='tight')
    plt.close(fig)
    
    # 传递图片URL给模板
    return render(request, 'expense_chart.html', {'chart_url': '/static/expense_chart.png'})

在模板expense_chart.html中:

<div class="chart-container">
    <img src="{{ chart_url }}" alt="每日支出柱状图">
</div>

注意事项

  • 确保已安装依赖:pip install matplotlib pillow pandas(根据使用的方式选择安装Pandas)
  • 服务器环境必须设置非交互式后端(plt.switch_backend('AGG')),否则会因缺少GUI环境报错
  • 若使用静态文件方案,需要确保STATIC_ROOT配置正确,并且运行过collectstatic命令

内容的提问来源于stack exchange,提问作者Aalok karn

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.01 18:01:13