Создание данных для отображения на графике в python

Я пишу конечную точку API во фреймворке Django Rest и хочу сделать данные для отображения графика У меня есть такие данные, которые я получаю из базы данных.

data = [
{
    "name": "Test 3",
    "status": "Active",
    "count": 1
},
{
    "name": "Test 2",
    "status": "Failed",
    "count": 1
},
{
    "name": "Test",
    "status": "In Progress",
    "count": 85
},
{
    "name": "Test",
    "status": "Failed",
    "count": 40
},
{
    "name": "Test",
    "status": "Active",
    "count": 1
},
{
    "name": "Test",
    "status": "Success",
    "count": 218
},
{
    "name": "Test 2",
    "status": "Active",
    "count": 1
}

]

и я хочу сделать окончательный график данных сверху вот так, чтобы показать его на графике.

    [
    "labels": ['Test', 'Test 2', 'Test 3'],
    "data": [
        {
            name: 'Active',
            data: [1, 1, 1]
        },
        {
            name: 'Failed',
            data: [40, 1, 0]
        },
        {
            name: 'Success',
            data: [218, 0, 0]
        },
        {
            name: 'In Progress',
            data: [85, 0, 0]
        }
    ]
]

Я пытаюсь сделать данные таким образом, но у меня не получается сделать правильный формат данных, может ли кто-нибудь помочь, есть ли встроенные функции, которые я могу использовать, чтобы сделать данные правильными.

response = [
        {
            'labels': [],
            'data':[],
        }
    ]
    for row in data:
        if row['name'] not in response[0]['labels']:
            response[0]['labels'].append(row['name'])
            innerData = []
            for status in ['Active', 'Failed', 'Success', 'In Progress']:
                if status in row['status']:
                    innerData.append(row['count'])
                else:
                    innerData.append(0)
            response[0]['data'].append(
                {
                    'name': status,
                    'data': innerData,
                }
            )

Для получения уникальных меток можно использовать set comprehension. Затем вы можете использовать defaultdict для получения из key:value пары, в которой каждый статус является именем ключа, а count - соответствующими значениями.

from collections import defaultdict

data = [{"name": "Test 3", "status": "Active", "count": 1}, {"name": "Test 2", "status": "Failed", "count": 1}, {"name": "Test", "status": "In Progress", "count": 85},{"name": "Test", "status": "Failed", "count": 40},{"name": "Test", "status": "Active", "count": 1},{"name": "Test", "status": "Success", "count": 218}, {"name": "Test 2", "status": "Active", "count": 1}]

d = defaultdict(list)
labels = sorted({each['name'] for each in data})

for each in data:
    d[each['status']].append(each['count'])
# -> defaultdict(<class 'list'>, {'Active': [1, 1, 1], 'Failed': [1, 40], 'In Progress': [85], 'Success': [218]})

final_result = {'labels': labels, 'data': []}
for k, v in d.items():
    final_result['data'].append({'name': k, 'data': v})

final_result будет выглядеть так:

{'labels': ['Test', 'Test 2', 'Test 3'], 'data': [{'name': 'Active', 'data': [1, 1, 1]}, {'name': 'Failed', 'data': [1, 40]}, {'name': 'In Progress', 'data': [85]}, {'name': 'Success', 'data': [218]}]}

Для того чтобы заполнить нулями списки малого размера, обратитесь к этому ответу.

Развивая ответ Рустама:

  1. Добавьте словарь label_to_idx, который будет использоваться для определения индекса по метке.
  2. Передайте функцию lambda в defaultdict для инициализации списков правильного размера и значения по умолчанию.
  3. Заполните d для каждого статуса, используя label_to_idx для нахождения правильного индекса для заполнения графа.
from collections import defaultdict

data = [
    {"name": "Test 3", "status": "Active",      "count": 1},
    {"name": "Test 2", "status": "Failed",      "count": 1},
    {"name": "Test",   "status": "In Progress", "count": 85},
    {"name": "Test",   "status": "Failed",      "count": 40},
    {"name": "Test",   "status": "Active",      "count": 1},
    {"name": "Test",   "status": "Success",     "count": 218},
    {"name": "Test 2", "status": "Active",      "count": 1},
]

labels = sorted({each['name'] for each in data})
label_to_idx = {label: idx for idx, label in enumerate(labels)}    # Added
d = defaultdict(lambda: [0] * len(labels))                         # Modified

for each in data:
    d[each['status']][label_to_idx[each['name']]] = each['count']  # Modified

final_result = {'labels': labels, 'data': []}
for k, v in d.items():
    final_result['data'].append({'name': k, 'data': v})
from pprint import pprint as pp

pp(final_result)
# {'data': [{'data': [1, 1, 1], 'name': 'Active'},
#           {'data': [40, 1, 0], 'name': 'Failed'},
#           {'data': [85, 0, 0], 'name': 'In Progress'},
#           {'data': [218, 0, 0], 'name': 'Success'}],
#  'labels': ['Test', 'Test 2', 'Test 3']}
Вернуться на верх