Я унаследовал приложение AngularJS / Django, используя DjangoRestFramework и базу данных Postgres, которая преобразовывается из AngularJS в React / Redux. Одна из вещей, которую мы пытаемся сделать, это представить данные временных рядов с помощью amCharts4. Проблема (среди многих других), с которой мы сталкиваемся, заключается в представлении данных за промежуток времени, для которого в БД может не быть записей. Например, у нас есть результаты, которые могут выглядеть примерно так:
[
{
"date": "2020-01-16T00:00:00.000Z",
"result": 3
},
{
"date": "2020-01-18T00:00:00.000Z",
"result": 2
}
]
И мы хотели бы, чтобы они выглядели примерно так:
[
{
"date": "2020-01-16T00:00:00.000Z",
"result": 3
},
{
"date": "2020-01-17T00:00:00.000Z",
"result": 0
},
{
"date": "2020-01-18T00:00:00.000Z",
"result": 2
}
]
Кроме того, у нас также есть данные с несколькими точками данных на Событие времени:
[
{
"date": "2020-01-13T00:00:00Z",
"result": 1,
"name": "Yes"
},
{
"date": "2020-01-14T00:00:00Z",
"result": 1,
"name": "No"
},
{
"date": "2020-01-16T00:00:00Z",
"result": 1,
"name": "No"
}
]
И хотелось бы, чтобы данные заполнялись нулями для любого name
в любую дату, когда нет результата:
[
{
"date": "2020-01-13T00:00:00Z",
"result": 1,
"name": "Yes"
},
{
"date": "2020-01-13T00:00:00Z",
"result": 0,
"name": "No"
},
{
"date": "2020-01-14T00:00:00Z",
"result": 0,
"name": "Yes"
},
{
"date": "2020-01-14T00:00:00Z",
"result": 1,
"name": "No"
},
{
"date": "2020-01-15T00:00:00Z",
"result": 0,
"name": "Yes"
},
{
"date": "2020-01-15T00:00:00Z",
"result": 0,
"name": "No"
},
{
"date": "2020-01-16T00:00:00Z",
"result": 0,
"name": "Yes"
},
{
"date": "2020-01-16T00:00:00Z",
"result": 1,
"name": "No"
}
]
Диапазон этих результаты также не обязательно зависят от даты начала и окончания даты, но могут быть указаны пользователем. В этом случае нам потребуется заполнить результаты с нулевым значением для всех параметров всех дат в этих диапазонах.
Мне известно о свойстве amCharts skipEmptyPeriods
( amCharts4 - skipEmptyPeriods ) , но мои инженеры по внешнему интерфейсу сказали мне, что это не сработает для случаев с несколькими линиями тренда (т. е. для второго случая, когда существует несколько опций на дату). Кроме того, на самом деле это не проблема внешнего интерфейса, а проблемы с производительностью.
Кроме того, я попытался использовать функцию Postgresql generate_series
с coalesce
Postgresql - generate_series , но не смог заставить это работать для второго случая.
В настоящее время я пытаюсь это сделать в Pandas (который я никогда не использовал) и у меня есть решение для Первая проблема с единичными записями на дату, но, опять же, и проблема со вторым случаем нескольких записей на дату:
from_date = request.query_params.get("from_date")
to_date = request.query_params.get("to_date")
# let's do some zero plotting
filtered_queryset = list(filtered_queryset)
if from_date:
from_date = datetime.strptime(from_date, "%Y-%m-%d").astimezone(pytz.UTC)
else:
from_date = filtered_queryset[0]["date"]
if to_date:
to_date = datetime.strptime(to_date, "%Y-%m-%d").astimezone(pytz.UTC)
_now = localtime(now()).astimezone(pytz.UTC)
to_date = min(to_date, _now)
else:
to_date = localtime(now()).astimezone(pytz.UTC)
pandas_freq_map = {"day": "D", "week": "W-MON", "month": "MS"}
freq = pandas_freq_map.get(request.query_params.get("frequency"))
idx = pd.date_range(from_date.date(), to_date.date(), freq=freq)
df = pd.DataFrame(list(filtered_queryset))
datetime_series = pd.to_datetime(df["date"])
datetime_index = pd.DatetimeIndex(datetime_series.values)
df = df.set_index(datetime_index)
df.drop("date", axis=1, inplace=True)
df = df.asfreq(freq)
df = df.reindex(idx, fill_value=0)
df_json = json.JSONDecoder().decode(df.to_json(date_format="iso"))
# this (result or 0) tomfoolery is bc I don't understand why pandas sometimes reindexes with null as the fill_value
prepared_response = [{"date": date, "result": (result or 0)} for date, result in df_json["result"].items()]