Python 从数据库中提取数据的 Pygal 图表不匹配值与标签

Python Pygal chart pulling data from database not matching values to labels

我正在做我的第一个项目,我正在使用 Pygal 可视化数据库中的一些数据。

我正在使用最新版本的 Python (3.6.5)、Flask、Pygal,我的 IDE 是 Pycharm

该项目是一个简单的预算应用程序,其中输入每月支出的计划预算,然后输入该支出的实际金额 expense/item(例如每月汽车支出,如汽油)。

我使用 Pygal 来显示 2 个条形图。第一个(按预期工作)显示计划总金额与实际总金额:

第二张图表显示了每个 expense/item 的计划与实际(例如,每月汽车费用,如汽油)

我面临的问题是图表混淆了标签和金额。它们根据输入的顺序而不是项目类型显示在图表中。

例如:

在上图中,有 3 项:Masina(汽车)、Salariu(工资)和 Economii(储蓄)。

蓝色列代表的金额(实际金额)应该显示在标签 Economii 下,而不是 Masina 下,我将其作为数据库中的第一个实际值输入应该无关紧要。

此外,在数据库中为同一支出项目(在我们的例子中为 Economii)添加更多实际金额只会添加更多列,而不会在同一列上求和:

这是我使用的数据库查询功能:

def GraphData():
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
db_path = os.path.join(BASE_DIR, 'budget_db.db')
with sqlite3.connect(db_path) as db:
    c = db.cursor()
    d = db.cursor()
    c.execute('SELECT title, category, name, planned_amount_month FROM Post')
    d.execute('SELECT title_actual, category_actual, actual_amount_name, actual_amount FROM ActualPost')
    data_planned = c.fetchall()
    data_actual = d.fetchall()
return data_planned, data_actual

下面是我为这两个图表创建的路线。标签是从 title_planned 列表中提取的,我觉得我面临的问题是因为我正在创建列表并附加它们。 我想我应该创建字典,但我不知道如何才能不把其他一切都搞砸:

 @posts.route("/home")
def graphing():
data_planned, data_actual = GraphData()
title_planned = []
value_planned = []
title_actual = []
value_actual = []
for planned_row in data_planned:
    title_planned.append(planned_row[2])
    value_planned.append(planned_row[3])
for actual_row in data_actual:
    title_actual.append(actual_row[2])
    value_actual.append(actual_row[3])

graph = pygal.Bar(title=u'Total Planned Values vs Total Actual Values')
graph.add('Planned', [{'value': sum(value_planned), 'label': 'Total for Planned Budget:'}])
graph.add('Actual', [{'value': sum(value_actual), 'label': 'Total for Actual Amounts:'}])
graph_data = graph.render_data_uri()

graph_all = pygal.Bar(title=u'Planned Budget per item vs Actual Amounts per item')
graph_all.x_labels = title_planned
graph_all.add('Planned', value_planned)
graph_all.add('Actual', value_actual)
graph_all_data = graph_all.render_data_uri()

return render_template('home.html', graph_data=graph_data, graph_all_data=graph_all_data)

编辑:

我一直在尝试使用路线中的 2 部词典来做到这一点,费用项目作为字典键 (title_planned_sum / title_actual_sum),金额作为字典值 (value_planned_sum / value_actual_sum):

tv_planned = dict(zip(title_planned, value_planned))
tv_planned_sum = {title_planned_sum: sum(value_planned_sum) for title_planned_sum, value_planned_sum in tv_planned.items()}

tv_actual = dict(zip(title_actual, value_actual))
tv_actual_sum = {title_actual_sum: sum(value_actual_sum) for title_actual_sum, value_actual_sum in tv_actual.items()}

完整路线如下:

@posts.route("/home")
def graphing():
    data_planned, data_actual = GraphData()

    title_planned = []
    value_planned = []
    title_actual = []
    value_actual = []

    for planned_row in data_planned:
        title_planned.append(planned_row[2])
        value_planned.append(planned_row[3])

    for actual_row in data_actual:
        title_actual.append(actual_row[2])
        value_actual.append(actual_row[3])

    tv_planned = dict(zip(title_planned, value_planned))
    tv_planned_sum = {title_planned_sum: sum(value_planned_sum) for title_planned_sum, value_planned_sum in tv_planned.items()}

    tv_actual = dict(zip(title_actual, value_actual))
    tv_actual_sum = {title_actual_sum: sum(value_actual_sum) for title_actual_sum, value_actual_sum in tv_actual.items()}

    graph = pygal.Bar(title=u'Total Planned Values vs Total Actual Values')
    graph.add('Planned', [{'value': sum(value_planned), 'label': 'Total for Planned Budget:'}])
    graph.add('Actual', [{'value': sum(value_actual), 'label': 'Total for Actual Amounts:'}])
    graph_data = graph.render_data_uri()

    graph_all = pygal.Bar(title=u'Planned Budget per item vs Actual Amounts per item')
    graph_all.x_labels = title_planned
    graph_all.add('Planned', tv_planned_sum)
    graph_all.add('Actual', tv_actual_sum)
    graph_all_data = graph_all.render_data_uri()

    return render_template('home.html', graph_data=graph_data, graph_all_data=graph_all_data)

当然,现在我收到了这个调试错误:

TypeError: 'float' object is not iterable

这是因为,在我尝试使用的 2 个词典中,我试图对接收多个值的每个键的值求和 sum(value_planned_sum).

我成功了!

最后我意识到我的问题过于复杂了,所以我拿出笔和纸并开始编写一些伪代码以查看我的代码中可以轻松计算浮点数的第一步在哪里令我头疼的总和。

第 1 步:在我的路线中,我可以创建一个包含嵌套元组的列表(每个元组有 2 个元素:str 和 float)

第 2 步:现在,如果某些元组在索引 [0] 上具有相同的元素,我如何对索引 [1] 上的浮点元素求和?

所以,我问了 this question on reddit.com/r/learnpython 用户 diesch 给了我一个我可以成功使用的想法:导入 itertools 包并从它,使用 groupby().

这是我的路由代码现在的样子:

@posts.route("/home")
def graphing():
    data_planned, data_actual = GraphData()

    title_planned = []
    value_planned = []
    title_actual = []
    value_actual = []
    planned = []
    actual = []

    for planned_row in data_planned:
        title_planned.append(planned_row[2])
        value_planned.append(planned_row[3])
        planned_list = zip(title_planned, value_planned)
        for key, group in itertools.groupby(sorted(planned_list), lambda  x: x[0]):
            asum = 0
            for i in group:
                asum += i[1]
            planned.append((key, asum))

    planned_dict = dict(planned)

    for actual_row in data_actual:
        title_actual.append(actual_row[2])
        value_actual.append(actual_row[3])
        actual_list = zip(title_actual, value_actual)
        for key, group in itertools.groupby(sorted(actual_list), lambda  x: x[0]):
            asum = 0
            for i in group:
                asum += i[1]
            actual.append((key, asum))

    actual_dict = dict(actual)

    graph = pygal.Bar(title=u'Total Planned Values vs Total Actual Values')
    graph.add('Planned', [{'value': sum(value_planned), 'label': 'Total for Planned Budget:'}])
    graph.add('Actual', [{'value': sum(value_actual), 'label': 'Total for Actual Amounts:'}])
    graph_data = graph.render_data_uri()

    graph_all = pygal.Bar(title=u'Planned Budget per item vs Actual Amounts per item')
    graph_all.x_labels = title_planned
    graph_all.add('Planned', planned_dict)
    graph_all.add('Actual', actual_dict)
    graph_all_data = graph_all.render_data_uri()

    return render_template('home.html', graph_data=graph_data, graph_all_data=graph_all_data)