You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何消除共享轴双图间隙?用Vega-Altair实现双端柱状图

如何用Altair实现无间隙的双端柱状图?

目标

我希望生成一个“双端”柱状图,展示某指标的获得分数与丢失分数,示例如下:
目标图表

当前成果

我已写出以下代码:

import altair as alt
import pandas as pd

source = pd.DataFrame(
    {
        "cohort": ["A", "B", "C", "D", "E", "F", "G", "H", "I"],
        "gained": [28, 55, 43, 91, 81, 53, 19, 87, 52],
        "missed": [5, 8, 34, 21, 16, 22, 9, 7, 11],
    }
)

up = (
    alt.Chart(source)
    .mark_bar(color="blue")
    .encode(
        x=alt.X("cohort:N").axis(labels=False, title=None, ticks=False),
        y=alt.Y("gained:Q"),
    )
)
down = (
    alt.Chart(source)
    .mark_bar(color="red")
    .encode(
        x=alt.X("cohort:N").axis(labelAngle=0),
        y=alt.Y("missed:Q", scale=alt.Scale(reverse=True)),
    )
)

alt.vconcat(up, down).resolve_scale(x="shared")

生成的图表如下:
当前成果
请问是否有办法消除两个图表之间的间隙?或者是否有其他用Vega-Altair实现双端柱状图的方法?


解决方案

方法1:消除双图拼接的间隙

通过调整拼接参数和图表配置,移除上下图表间的空隙:

import altair as alt
import pandas as pd

source = pd.DataFrame(
    {
        "cohort": ["A", "B", "C", "D", "E", "F", "G", "H", "I"],
        "gained": [28, 55, 43, 91, 81, 53, 19, 87, 52],
        "missed": [5, 8, 34, 21, 16, 22, 9, 7, 11],
    }
)

up = (
    alt.Chart(source)
    .mark_bar(color="blue")
    .encode(
        x=alt.X("cohort:N").axis(labels=False, title=None, ticks=False),
        y=alt.Y("gained:Q", axis=alt.Axis(grid=False)),
    )
    .configure_view(strokeWidth=0)  # 移除图表边框
)
down = (
    alt.Chart(source)
    .mark_bar(color="red")
    .encode(
        x=alt.X("cohort:N").axis(labelAngle=0, title=None),
        y=alt.Y("missed:Q", scale=alt.Scale(reverse=True), axis=alt.Axis(grid=False)),
    )
    .configure_view(strokeWidth=0)
)

alt.vconcat(up, down, spacing=0).resolve_scale(x="shared")

核心调整:

  • 设置alt.vconcat(..., spacing=0)消除图表间的间距
  • 用.configure_view(strokeWidth=0)去掉图表边框
  • 隐藏Y轴网格线,让上下柱状图衔接更自然

方法2:单图表实现双端柱状图(更优方案)

将数据转换为长格式,通过正负值在同一图表中实现双向柱状图,天然无间隙:

import altair as alt
import pandas as pd

source = pd.DataFrame(
    {
        "cohort": ["A", "B", "C", "D", "E", "F", "G", "H", "I"],
        "gained": [28, 55, 43, 91, 81, 53, 19, 87, 52],
        "missed": [5, 8, 34, 21, 16, 22, 9, 7, 11],
    }
)

# 转换为长格式,将丢失分数设为负值
df_long = source.melt(id_vars="cohort", var_name="type", value_name="score")
df_long.loc[df_long["type"] == "missed", "score"] *= -1

chart = alt.Chart(df_long).mark_bar().encode(
    x=alt.X("cohort:N").axis(labelAngle=0),
    y=alt.Y("score:Q", title="分数"),
    color=alt.Color("type:N", scale=alt.Scale(domain=["gained", "missed"], range=["blue", "red"])),
    tooltip=["cohort", "type", alt.Tooltip("score:Q", format="d")]
).configure_view(strokeWidth=0)

chart

该方案优势:

  • 单图表结构,逻辑更简洁
  • 自动生成图例,区分获得/丢失分数
  • 视觉上完全无间隙,效果更统一

内容的提问来源于stack exchange,提问作者dkapitan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.21 18:45:57