Altair 图表 - 自定义轴格式化程序功能

Altair chart - Custom axis formatter function

我可以在 Matplotlib 中使用以下表达式:

def format_func(value, tick_number):
    d = datetime.date(1998,1,1) + datetime.timedelta(value)
    return d.strftime("%B")

ax.xaxis.set_major_formatter(plt.FuncFormatter(format_func))

当X-Axis值包含一年中的某一天(1-365)时,转换为对应月份的名称。

我可以在 Altair 中实现相同的功能吗?

编辑:

感谢@joelostblom。添加一段代码以指定我正在使用的确切数据框。下面代码的当前问题是,在我的示例中,我有

# pre-existing dataframe
num_days = 365 * 4 # four days
df = pd.DataFrame(
    {
    'Timestamp': [
        (datetime.datetime.now() - datetime.timedelta(num_days) ) + datetime.timedelta(days=x) 
        for x in range(num_days)
    ],
    'value': pd.Series(np.random.randn(num_days))
    }
)
df = df.set_index('Timestamp')

# extra columns that may be needed by altair
df['Month'] = df.index.month_name()
df['Year'] = df.index.year

到目前为止,我已经尝试通过两种方式使用 Altair:

alt.Chart(df.reset_index()).mark_line().encode(
    x='Month',
    y='value',
    color=alt.Color('Year:O', scale=alt.Scale(scheme='category10')),
)

或者像你建议的那样:

alt.Chart(df.reset_index()).mark_line().encode(
    x=alt.X('Timestamp', axis=alt.Axis(format='%b')),
    y='value',
    color=alt.Color('Year:O', scale=alt.Scale(scheme='category10')),
)

你能帮我理解我做错了什么吗?

您可以使用 pandas.to_datetime:

转换日期戳
import altair as alt
import numpy as np
import pandas as pd


# Setup data
x = np.arange(365)
source = pd.DataFrame({
  'x': x,
  'f(x)': np.sin(x / 50)
})

# Convert to date
source['date'] = pd.to_datetime(source['x'], unit='D', origin='2020')

alt.Chart(source).mark_line().encode(
    x='date',
    y='f(x)'
)

如果您想要轴上的所有月份名称,您可以更改轴格式:

alt.Chart(source).mark_line().encode(
    x=alt.X('date', axis=alt.Axis(format='%b')),
    y='f(x)'
)

对于您更新的示例,当有多个年份时,您可以使用 time unit aggregations in Altair/Vega-Lite。例如,使用 'monthdate(Timestamp)' 将忽略年份并按月份和日期聚合(请注意,并非 Vega-Lite 文档中的所有聚合都在 Altair 中可用)。

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


# pre-existing dataframe
num_days = 365 * 4 # four years
df = pd.DataFrame(
    {
    'Timestamp': [
        (datetime.datetime.now() - datetime.timedelta(num_days) ) + datetime.timedelta(days=x) 
        for x in range(num_days)
    ],
    'value': pd.Series(np.random.randn(num_days))
    }
)

alt.Chart(df).mark_line().encode(
    x=alt.X('monthdate(Timestamp)', axis=alt.Axis(format='%b')),
    y='value',
    color=alt.Color('year(Timestamp):O', scale=alt.Scale(scheme='category10')),
)