Диаграмма Python Pygal, извлекающая данные из базы данных, не соответствующие значениям меткам

Я работаю над своим первым проектом и использую Pygal для визуализации некоторых данных из базы данных.

Я использую последнюю версию Python (3.6.5), Flask, Pygal и Pycharm.

Проект представляет собой простое бюджетное приложение, в котором нужно ввести запланированный бюджет для ежемесячных расходов, а затем фактические суммы для этого расхода/статьи (например, ежемесячные расходы на автомобиль, например, на бензин).

Я использую Pygal для отображения двух гистограмм. Первый (который работает по назначению) показывает общие запланированные суммы по сравнению с общими фактическими суммами:

введите здесь описание изображения

На втором графике показаны запланированные и фактические расходы/статьи (например, ежемесячные расходы на автомобиль, например, на бензин).

Проблема, с которой я сталкиваюсь, заключается в том, что диаграмма смешивает метки и суммы. Они отображаются на диаграмме в порядке их ввода, а не в зависимости от типа элемента.

Например:

введите здесь описание изображения

На изображении выше 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 словаря на маршруте со статьей расходов в качестве ключа dict (title_planned_sum/title_actual_sum) и суммой в качестве значения dict (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

И это потому, что в двух словарях, с которыми я пытаюсь работать, я пытаюсь суммировать значения для каждого ключа, который получает несколько значений с помощью sum(value_planned_sum).


person derzemel    schedule 07.06.2018    source источник


Ответы (1)


У меня все получилось!

В конце концов я понял, что слишком усложняю свой вопрос, поэтому я вытащил ручку и бумагу и начал делать некоторый псевдокод, чтобы увидеть, где был первый шаг в моем коде, где я мог бы удобно вычислить сумму с плавающей запятой, которая вызывала у меня головные боли.

Шаг 1: В моем маршруте я мог бы создать список, содержащий вложенные кортежи (с двумя элементами в каждом: str и float)

Шаг 2: Теперь, если некоторые из кортежей имеют одинаковые элементы по индексу [0], как мне суммировать элементы с плавающей запятой по индексу [1]?

Итак, я задал этот вопрос на 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)    
person derzemel    schedule 10.06.2018