在 altair 中手动计算箱线图须
Manually calculate the boxplot whiskers in altair
我正在寻找一种在 altair 中手动查找箱线图须值的方法(因此无需在数据框中添加额外的列)。
下面是我正在尝试创建的情节。橙色区域应与箱线图须对齐,因此 'x' 的第一个值在 1.5*iqr 范围内。
我一直在研究 vega 表达式(inrange、clampRange ...),但找不到这样做的方法。
Open the Chart in the Vega Editor
import altair as alt
import pandas as pd
values = [0, 3, 4.4, 4.5, 4.6, 5, 7]
df = pd.DataFrame({'x': values})
points = alt.Chart(df).mark_circle(color='black', size=120).encode(
x=alt.X('x:Q', scale=alt.Scale(zero=False)),
)
boxplot = alt.Chart(df).mark_boxplot(ticks=True, extent=1.5, outliers=True).encode(
x='x:Q',
)
iqr = alt.Chart(df).mark_rect(color='lime').encode(
x='q1(x):Q',
x2='q3(x):Q'
)
whiskers = alt.Chart(df).mark_rect(color='orange').transform_aggregate(
q1='q1(x)',
q3='q3(x)',
).transform_calculate(
iqr=alt.datum.q3 - alt.datum.q1,
q0=alt.datum.q1 - (alt.datum.iqr * 1.5),
q100=alt.datum.q3 + (alt.datum.iqr * 1.5),
).encode(
x='q0:Q',
x2='q100:Q',
)
minmax = alt.Chart(df).mark_rect(color='red').transform_aggregate(
xmin='min(x)',
xmax='max(x)'
).encode(
x='xmin:Q',
x2='xmax:Q',
).properties(width=1000)
((boxplot + points) & (minmax + whiskers + iqr + points)).resolve_scale(x='shared')
这里的关键是能够使用四分位数的聚合值来过滤原始数据。当您使用 transform_aggregate
时,您正在减少数据框以仅包含您正在创建的聚合值。如果您改为使用 transform_joinaggregate
,则将聚合值连接到原始数据框,这意味着您可以使用 transform_filter
到 return 范围内的最大和最小原始数据点q1/q3 -/+ 1.5 * IQR:
whiskers = alt.Chart(df).mark_rect(color='orange').transform_joinaggregate(
q1='q1(x)',
q3='q3(x)',
).transform_calculate(
iqr='datum.q3 - datum.q1'
).transform_filter(
# VL concatenates these strings so we can split
# them on two lines to improve readability
'datum.x < (datum.q3 + datum.iqr * 1.5)'
'&& datum.x > (datum.q1 - datum.iqr * 1.5)'
).encode(
x='min(x)',
x2='max(x)',
)
我正在寻找一种在 altair 中手动查找箱线图须值的方法(因此无需在数据框中添加额外的列)。
下面是我正在尝试创建的情节。橙色区域应与箱线图须对齐,因此 'x' 的第一个值在 1.5*iqr 范围内。
我一直在研究 vega 表达式(inrange、clampRange ...),但找不到这样做的方法。
Open the Chart in the Vega Editor
import altair as alt
import pandas as pd
values = [0, 3, 4.4, 4.5, 4.6, 5, 7]
df = pd.DataFrame({'x': values})
points = alt.Chart(df).mark_circle(color='black', size=120).encode(
x=alt.X('x:Q', scale=alt.Scale(zero=False)),
)
boxplot = alt.Chart(df).mark_boxplot(ticks=True, extent=1.5, outliers=True).encode(
x='x:Q',
)
iqr = alt.Chart(df).mark_rect(color='lime').encode(
x='q1(x):Q',
x2='q3(x):Q'
)
whiskers = alt.Chart(df).mark_rect(color='orange').transform_aggregate(
q1='q1(x)',
q3='q3(x)',
).transform_calculate(
iqr=alt.datum.q3 - alt.datum.q1,
q0=alt.datum.q1 - (alt.datum.iqr * 1.5),
q100=alt.datum.q3 + (alt.datum.iqr * 1.5),
).encode(
x='q0:Q',
x2='q100:Q',
)
minmax = alt.Chart(df).mark_rect(color='red').transform_aggregate(
xmin='min(x)',
xmax='max(x)'
).encode(
x='xmin:Q',
x2='xmax:Q',
).properties(width=1000)
((boxplot + points) & (minmax + whiskers + iqr + points)).resolve_scale(x='shared')
这里的关键是能够使用四分位数的聚合值来过滤原始数据。当您使用 transform_aggregate
时,您正在减少数据框以仅包含您正在创建的聚合值。如果您改为使用 transform_joinaggregate
,则将聚合值连接到原始数据框,这意味着您可以使用 transform_filter
到 return 范围内的最大和最小原始数据点q1/q3 -/+ 1.5 * IQR:
whiskers = alt.Chart(df).mark_rect(color='orange').transform_joinaggregate(
q1='q1(x)',
q3='q3(x)',
).transform_calculate(
iqr='datum.q3 - datum.q1'
).transform_filter(
# VL concatenates these strings so we can split
# them on two lines to improve readability
'datum.x < (datum.q3 + datum.iqr * 1.5)'
'&& datum.x > (datum.q1 - datum.iqr * 1.5)'
).encode(
x='min(x)',
x2='max(x)',
)