Прямое обозначение линейного графика с помощью Altair

#python #python-3.x #altair

#python #python-3.x #altair

Вопрос:

Я строю линейный график в Altair (4.1.0) и хотел бы использовать прямую маркировку (аннотации) вместо обычной легенды.
Таким образом, текстовая метка для каждой строки (скажем, временных рядов) должна появляться только один раз и в самой правой точке оси x (в отличие от этого примера точечной диаграммы, обозначающего каждую точку данных).).
Хотя я могу использовать pandas для манипулирования данными для получения желаемых результатов, я думаю, что было бы более элегантно использовать реализацию pure-Altair, но, похоже, я не могу понять это правильно.

Например, учитывая следующие данные:

 import numpy as np
import pandas as pd
import altair as alt

np.random.seed(10)
time = pd.date_range(start="10/21/2020", end="10/22/2020", periods=n)
data = pd.concat([
    pd.DataFrame({
        "time": time,
        "group": "One",
        "value": np.random.normal(10, 2, n)}),
    pd.DataFrame({
        "time": time,
        "group": "Two",
        "value": np.random.normal(5, 2, n)}).iloc[:-1]
], ignore_index=True)
  

Я могу сгенерировать удовлетворительный результат, используя pandas для создания подмножества, включающего последний момент времени для каждой группы:

 lines = alt.Chart(data).mark_line(
    point=True
).encode(
    x="time:T",
    y="value:Q",
    color=alt.Color("group:N", legend=None),  # Remove legend
)

text_data = data.loc[data.groupby('group')['time'].idxmax()]  # Subset the data for text positions
labels = alt.Chart(text_data).mark_text(
    # some adjustments
).encode(
    x="time:T",
    y="value:Q",
    color="group:N",
    text="group:N"
)

chart = lines   labels
  

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

Однако, если я попытаюсь использовать основные данные и добавить агрегации Altair, например, используя x=max(time) или явно transform_aggregate() , я либо получаю текстовые аннотации по всем точкам, либо вообще ничего (соответственно).

Есть ли лучший способ получить приведенный выше результат?

Ответ №1:

Вы можете сделать это, используя argmax агрегат в кодировке y. Например, ваш слой labels может выглядеть следующим образом:

 labels = alt.Chart(data).mark_text(
    align='left', dx=5
).encode(
    x='max(time):T',
    y=alt.Y('value:Q', aggregate={'argmax': 'time'}),
    text='group:N',
    color='group:N',
)
  

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

Комментарии:

1. Ах-ха! Агрегирование y в соответствии с x. это для меня ново. Могу я спросить, зачем это нужно? (почему этого было x=max(time) недостаточно?) и в любом случае, большое спасибо, Джейк, ты лучший (и самый быстрый! 🙂

2. Если вам нужна одна текстовая аннотация на строку, вам необходимо определить ее значение x и значение y. Вы хотите, чтобы значение y было связано с максимальным значением x, и способ получить это — использовать argmax . Если вы обходитесь x='max(time)', y='value' без агрегирования значений, вы указываете, что вам нужна точка для каждого уникального значения, и в каждом наборе уникальных значений эта точка должна быть нарисована за максимальное время. В терминах реляционной алгебры неагрегированные столбцы используются в качестве входных данных для группирования.