为了账号安全,请及时绑定邮箱和手机立即绑定

在 Altair 中,如何正确地将面积图中的基线移动到特定的 y 位置并相应地更改填充颜色?

在 Altair 中,如何正确地将面积图中的基线移动到特定的 y 位置并相应地更改填充颜色?

HUX布斯 2023-07-05 18:00:16
我希望能够做这样的事情 -注意:你看到的水平线不是在 y=0 处,而是在 y=1 处但使用color或fill编码condition在面积图中并不真正有效。我得到的最接近的是使用yOffset(命中并尝试以获得完美值),但mark_area最大的问题是 y 轴保持不变,因此图表实际上变得无效。示例:(忽略水平连接的图表 - 这只是为了能够得出一个好的值,因为yOffsety 轴根本不移动。)import pandas as pddata = pd.DataFrame({'date': pd.date_range(start='1/1/2018', end='1/11/2018'), 'stock': [0.1, 0.3, 0.9, 1, 1.5, 1.2, 0.8, 1.1, 0.4, 0.8, 1.6]})left = alt.Chart(data).mark_area().encode(    x='date:T',    y='stock:Q',    fill = alt.condition(alt.datum.stock<1, alt.value('grey'), alt.value('red')))right = alt.Chart(data).mark_area(yOffset=190, ).encode(    x='date:T',    y='stock:Q',    fill = alt.condition(alt.datum.stock<1, alt.value('grey'), alt.value('red')))left | right输出右侧的图表非常接近 - y 轴值和颜色是错误的。有没有办法在 Altair 中做这样的事情?编辑1:我尝试了这篇文章中的想法,它有点相似,但它并不像我想象的那样工作 -trial1 = alt.Chart(data).mark_area().transform_calculate(below=alt.datum.stock<=1).encode(    x='date:T',    y=alt.Y('stock:Q'),    color = 'below:N')trial2 = alt.Chart(data).mark_area().transform_calculate(below=alt.datum.stock<=1).encode(    x='date:T',    y=alt.Y('stock:Q', impute={'value': 1}),    color = 'below:N')trial1|trial2输出
查看完整描述

1 回答

?
素胚勾勒不出你

TA贡献1827条经验 获得超9个赞

您可以通过参数提供第二个 y 编码来将基线定义为 1 y2。使用这种方法与条形图相对简单:


import pandas as pd

import altair as alt



data = pd.DataFrame(

    {'date': pd.date_range(start='1/1/2018', end='1/11/2018'),

     'stock': [0.1, 0.3, 0.9, 1, 1.5, 1.2, 0.8, 1.1, 0.4, 0.8, 1.6],

     'baseline': [1]*11})


# You could also set the bar width instead of binning

alt.Chart(data).mark_bar().encode(

    x=alt.X('monthdate(date):T'),

    y='stock:Q',

    y2='baseline',

    color = alt.condition(alt.datum.stock < 1, alt.value('grey'), alt.value('red')))

//img1.sycdn.imooc.com//64a53f850001d03c04900380.jpg

这很有效,因为条形是单独的图形元素,因此它们将单独着色。面积图是单个图形元素,因此仅针对第一个库存值执行条件比较,然后整个区域都以此颜色着色。为了获得不同的颜色,我们需要将区域分成多个标记,如您链接的答案中所示进行分组(这也适用于条形图)。您可以通过预先在数据框中创建分组列或通过transform_calculate.


(alt.Chart(data.reset_index()).mark_area().encode(

    x=alt.X('date:T'),

    y=alt.Y('stock:Q', impute={'value': 1}),

    y2='baseline',

    color=alt.Color('negative:N', scale=alt.Scale(range=['red', 'grey'])))

 .transform_calculate(negative='datum.stock < 1'))

//img1.sycdn.imooc.com//64a53f940001067b05560375.jpg

为什么点之间存在重叠?其原因是数据的稀疏性以及区域和线标记的默认插值方法是“线性”。如果将其更改为mark_area(interpolate='step'),区域之间的边界将变得清晰:

//img1.sycdn.imooc.com//64a53fa30001b46d05590380.jpg

为了在保持其形状的同时实现基线周围区域标记的急剧过渡,数据需要具有更高分辨率。借用您链接的答案,您可以看到当数据稀疏时,那里的区域也会重叠:


import altair as alt

import pandas as pd

import numpy as np



x = np.linspace(2, 4, 4)

df = pd.DataFrame({'x': x, 'y': np.sin(x)})


(alt.Chart(df).mark_area().encode(

    x='x',

    y=alt.Y('y', impute={'value': 0}),

    color='negative:N')

 .transform_calculate(negative='datum.y < 0'))

//img1.sycdn.imooc.com//64a53fae0001894b05650380.jpg

如果我们将点数增加十倍 ( x = np.linspace(2, 4, 40)),随着插值发生在空间中更接近的点之间,过渡会变得更加尖锐(将插值从线性更改为单调,在保持形状的同时也可能有所帮助)。

//img1.sycdn.imooc.com//64a53fc20001c6ee05600375.jpg

要提高时间序列数据的分辨率,您可以使用 pandasresample和interpolate方法进行上采样。做这样的事情时要担心的是,您是否以有意义的方式人为地更改了数据。我发现问问自己该操作是否会改变您对数据得出的结论很有用。


(alt.Chart(data.set_index('date').resample('1h').interpolate().reset_index()).mark_area().encode(

    x=alt.X('date:T'),

    y=alt.Y('stock:Q', impute={'value': 1}),

    y2='baseline',

    color=alt.Color('negative:N', scale=alt.Scale(range=['red', 'grey'])))

 .transform_calculate(negative='datum.stock < 1'))

//img1.sycdn.imooc.com//64a53fd10001436705570378.jpg

在这里,我们上采样到每小时的数据点,并在原始点之间进行线性插值。对我来说,这不会改变我通过研究该图得出的结论,因为线性插值保留了区域的块状外观,因此我们不会使数据看起来人为平滑。我想到的唯一缺点是,我们确实向 Altair 发送了不必要的数据量,您也许可以使用 Altair 中的转换来执行插值,但我不知道该怎么做。



查看完整回答
反对 回复 2023-07-05
  • 1 回答
  • 0 关注
  • 107 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信