时间 & 日期#
处理日期、时间和时区通常是数据分析中最具挑战性的方面之一。在Altair中,这些困难因用户编写Python代码而加剧,该代码输出JSON序列化的时间戳,这些时间戳由Javascript解释,然后由您的浏览器呈现。在这些步骤中,总会有可能出错的地方,但Altair和Vega-Lite尽力确保日期以一致的方式被解释和可视化。
Altair 和 pandas 时间日期#
Altair旨在与pandas时间序列协同工作。一个标准的与时区无关的日期/时间列在pandas数据框中将被解释为并显示为当地用户时间。例如,这里有一个包含在西雅图测量的每小时温度的数据集:
import altair as alt
from vega_datasets import data
temps = data.seattle_temps()
temps.head()
date temp
0 2010-01-01 00:00:00 39.4
1 2010-01-01 01:00:00 39.2
2 2010-01-01 02:00:00 39.0
3 2010-01-01 03:00:00 38.9
4 2010-01-01 04:00:00 38.8
我们可以从 dtypes 属性看到,时间被编码为标准的 64 位 datetime,未指定任何时区:
temps.dtypes
date datetime64[ns]
temp float64
dtype: object
我们可以使用Altair来可视化这些日期时间数据;为了清晰起见,在这个例子中,我们将数据限制在前两周:
temps = temps[temps.date < '2010-01-15']
alt.Chart(temps).mark_line().encode(
x='date:T',
y='temp:Q'
)
请注意,对于日期/时间值,我们使用T来表示时间编码:虽然这对于pandas datetime输入是可选的,但明确指定类型是良好的做法;有关更多讨论,请参见数据类型编码。如果您想让Altair将四位整数绘制为年份,您需要在将数据类型更改为时间类型之前将其转换为字符串,请参见数据类型对坐标轴刻度的影响获取详细信息。
对于诸如这些的日期时间输入,有时提取特定的时间单位(例如,天中的小时,月中的日期等)是有用的。在Altair中,可以通过时间单位变换来实现此功能,详细讨论见TimeUnit。例如,我们可能决定我们想要一个热图,x轴为天中的小时,y轴为月中的日期:
alt.Chart(temps).mark_rect().encode(
alt.X('hoursminutes(date):O').title('hour of day'),
alt.Y('monthdate(date):O').title('date'),
alt.Color('temp:Q').title('temperature (F)')
)
除非您正在使用非ES6浏览器(请参见 关于浏览器兼容性的说明), 您会注意到由此代码创建的图表反映了从1月1日00:00:00开始的小时, 正如我们输入的数据一样。这是因为输入的时间戳和图表输出都使用本地时间。
指定时区#
如果您在支持的浏览器中查看上述可视化效果(请参见
关于浏览器合规性的说明),时间都被序列化并以本地时间呈现,因此 January 1st 00:00:00 行在图表中显示为 00:00 在 January 1st。
在Altair中,没有明确时区的简单日期被视为当地时间,而在Vega-Lite中,除非另有说明,否则时间会以执行渲染的浏览器的当地时间显示。
如果您希望您的日期能够识别时区,您可以在输入数据框中明确设置时区。由于西雅图位于US/Pacific时区,我们可以在pandas中如下本地化时间戳:
temps['date_pacific'] = temps['date'].dt.tz_localize('US/Pacific')
temps.dtypes
date datetime64[ns]
temp float64
date_pacific datetime64[ns, US/Pacific]
dtype: object
请注意,时区现在是pandas数据类型的一部分。 如果我们用这个具有时区感知的数据重复上述图表,结果将 根据渲染它的浏览器的时区进行呈现:
alt.Chart(temps).mark_rect().encode(
alt.X('hoursminutes(date_pacific):O').title('hour of day'),
alt.Y('monthdate(date_pacific):O').title('date'),
alt.Color('temp:Q').title('temperature (F)')
)
如果您在将时间设置为美国西海岸的计算机上查看此图表,它应该与第一个版本完全相同。如果您在其他时区中渲染图表,则将使用根据您系统中设置的位置计算的时区修正来渲染。
使用UTC时间#
这种用户本地渲染有时可能会让人困惑,因为它导致相同的输出被不同用户以不同的方式可视化。如果您希望无论用户位于何处,时区感知数据在所有用户面前显示一致,最佳方法是采用一个标准时区来渲染数据。一种常用的标准是 协调世界时 (UTC)。在 Altair 中,任何的 timeUnit 区间都可以前缀 utc 以提取 UTC 时间单位。
这是以上图表以UTC时间可视化的结果,无论系统位置如何,渲染效果都将相同:
alt.Chart(temps).mark_rect().encode(
alt.X('utchoursminutes(date_pacific):O').title('UTC hour of day'),
alt.Y('utcmonthdate(date_pacific):O').title('UTC date'),
alt.Color('temp:Q').title('temperature (F)')
)
为了使您的图表尽可能可移植(即使在解析与时区无关的时间为UTC的非ES6浏览器中),您可以明确地在UTC时间下工作,包括在pandas端和Vega-Lite端:
temps['date_utc'] = temps['date'].dt.tz_localize('UTC')
alt.Chart(temps).mark_rect().encode(
alt.X('utchoursminutes(date_utc):O').title('hour of day'),
alt.Y('utcmonthdate(date_utc):O').title('date'),
alt.Color('temp:Q').title('temperature (F)')
)
这在某种程度上比时区无关的日期的默认行为要不方便一些,pandas和Vega-Lite都假设时间是本地的(除了在非ES6浏览器中;见关于浏览器兼容性的说明),但是通过明确在UTC中工作,它避免了浏览器的不兼容性,即使在较旧的浏览器中也能得到类似的结果。
关于浏览器兼容性的说明#
注意
关于非ES6浏览器的警告
以下讨论适用于支持ECMAScript 6的现代浏览器,在这些浏览器中,像"2018-01-01T12:00:00"这样的时间字符串如果没有一个尾随的"Z",则被视为本地时间,而不是协调世界时间 (UTC)。例如,最近版本的Chrome和Firefox是符合ES6标准的,而Safari 11则不是。如果您使用的是非ES6浏览器,这意味着在Altair图表中显示的时间可能会加上时区偏移,除非您明确使用UTC时间(见使用UTC时间)。
以下图表将帮助您确定您的浏览器是否以 Altair 期望的方式解析日期:
import altair as alt
import pandas as pd
df = pd.DataFrame({'local': ['2018-01-01T00:00:00'],
'utc': ['2018-01-01T00:00:00Z']})
when_compliant = alt.when(compliant=True)
alt.Chart(df).transform_calculate(
compliant="hours(datum.local) != hours(datum.utc) ? true : false",
).mark_text(size=20, baseline="middle").encode(
text=when_compliant.then(alt.value("OK")).otherwise(alt.value("not OK")),
color=when_compliant.then(alt.value("green")).otherwise(alt.value("red")),
).properties(width=80, height=50)
如果上述输出包含一个红色的“未通过”:
Click to show code
alt.Chart(df).mark_text(size=10, baseline='middle').encode(
alt.TextValue('not OK'),
alt.ColorValue('red')
).properties(width=40, height=25)
这意味着您的浏览器的日期解析不符合ES6标准。
如果它包含一个绿色的“确定”:
Click to show code
alt.Chart(df).mark_text(size=10, baseline='middle').encode(
alt.TextValue('OK'),
alt.ColorValue('green')
).properties(width=40, height=25)
那么这意味着你的浏览器解析日期的方式符合Altair的预期,要么是因为它符合ES6,要么是因为你的计算机区域设置恰好设置为UTC+0(GMT)时区。