Преобразователи данных
Перед передачей спецификации Vega-Lite или Vega средству отображения обычно нужна подготовка данных:
- DataFrame pandas нужно привести к допустимому виду и сериализовать в JSON.
- Может потребоваться выборка строк или ограничение их максимального числа.
- Для повышения производительности DataFrame может записываться в отдельный файл
.csvили.json.
Этими операциями управляет API преобразователей данных Altair.
Преобразователь данных — функция Python, принимающая словарь данных Vega-Lite dict или DataFrame pandas и возвращающая преобразованное значение одного из этих типов:
from typing import Union
Data = Union[dict, pd.DataFrame]
def data_transformer(data: Data) -> Data:
# Transform and return the data
return transformed_data
Объединение одинаковых наборов данных
DataFrame pandas может быть представлен в диаграмме двумя способами:
- Непосредственными значениями в атрибуте
dataна любом уровне спецификации. - Именованным набором в атрибуте
datasetsверхнего уровня.
Первый вариант проще, но при обычной работе с Altair полный набор может многократно повторяться внутри одной спецификации.
Поэтому начиная с Altair 2.2 все непосредственно заданные наборы по умолчанию переносятся в datasets верхнего уровня. Ссылки на них используют уникальное имя, определяемое хешем представления данных. Благодаря этому даже многократно указанный набор включается в спецификацию только один раз.
Поведение можно изменить атрибутом consolidate_datasets преобразователя данных. Рассмотрим простую диаграмму со слоями:
import altair as alt
import pandas as pd
df = pd.DataFrame({'x': range(5),
'y': [1, 3, 4, 3, 5]})
line = alt.Chart(df).mark_line().encode(x='x', y='y')
points = alt.Chart(df).mark_point().encode(x='x', y='y')
chart = line + points
Несмотря на двукратное указание набора, итоговая спецификация содержит одну его копию:
from pprint import pprint
pprint(chart.to_dict())
Объединение одинаковых наборов — дополнительная обработка, по умолчанию включённая во всех средствах отображения.
Если её нужно отключить, задайте alt.data_transformers.consolidate_datasets = False или временно используйте контекстный менеджер enable():
with alt.data_transformers.enable(consolidate_datasets=False):
pprint(chart.to_dict())
Теперь данные находятся не в datasets верхнего уровня, а в data каждого слоя. Именно из-за такого дублирования объединение по умолчанию включено — True.
Встроенные преобразователи данных
Altair предоставляет стандартный набор преобразователей со следующими сигнатурами.
Вызвать MaxRowsError, если DataFrame содержит больше max_rows строк:
limit_rows(data, max_rows=5000)
Получить случайную выборку из DataFrame без возвращения перед визуализацией:
sample(data, n=None, frac=None)
Преобразовать DataFrame в отдельный .json-файл:
to_json(data, prefix='altair-data'):
Преобразовать DataFrame в отдельный .csv-файл:
to_csv(data, prefix='altair-data'):
Преобразовать DataFrame в значения JSON, встроенные в спецификацию:
to_values(data):
Объединение в цепочку
Несколько преобразователей можно объединять через pipe:
from altair import limit_rows, to_values
from toolz.curried import pipe
pipe(data, limit_rows(10000), to_values)
Управление преобразователями
Altair хранит реестр преобразователей данных, включая стандартный, который автоматически применяется ко всем DataFrame перед отрисовкой.
Посмотреть зарегистрированные преобразователи:
>>> import altair as alt
>>> alt.data_transformers.names()
['default', 'json', 'csv']
Стандартный преобразователь устроен так:
def default_data_transformer(data):
return pipe(data, limit_rows, to_values)
Преобразователи json и csv перед отрисовкой сохраняют DataFrame во временный файл .json или .csv. Их преимущества:
- Полный набор не сохраняется в документе notebook.
- Vega-Lite/Vega в JavaScript, по наблюдениям авторов, быстрее работает с отдельными JSON/CSV-файлами, чем со встроенными значениями.
Недостатки:
- DataFrame экспортируется во временный файл рядом с notebook.
- Без этого файла или повторного выполнения ячейки notebook не сможет заново отрисовать диаграмму.
По опыту авторов, ускорение достаточно существенно, чтобы рекомендовать json для больших наборов:
alt.data_transformers.enable('json')
Авторы надеются на появление дополнительных преобразователей. Например, преобразователь, сохраняющий JSON в S3, можно зарегистрировать и включить так:
alt.data_transformers.register('s3', lambda data: pipe(data, to_s3('mybucket')))
alt.data_transformers.enable('s3')
Хранение JSON в отдельном каталоге
При создании множества диаграмм с alt.data_transformers.enable('json') рабочий каталог может переполниться файлами. Чтобы избежать этого, создадим простой преобразователь, сохраняющий JSON в отдельный каталог:
import os
import altair as alt
from toolz.curried import pipe
def json_dir(data, data_dir='altairdata'):
os.makedirs(data_dir, exist_ok=True)
return pipe(data, alt.to_json(filename=data_dir + '/{prefix}-{hash}.{extension}') )
alt.data_transformers.register('json_dir', json_dir)
alt.data_transformers.enable('json_dir', data_dir='mydata')
После включения файлы записываются в каталог, указанный через data_dir, либо в altairdata по умолчанию. Достаточно добавить нужный каталог перед именем файла в аргументе filename функции alt.to_json и убедиться, что каталог существует.