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

如何构建带双轴的Altair分层图表?现有代码问题求助

Fixing Dual-Axis for Your Altair Faceted Charts

Got it, let's sort out that dual-axis issue you're facing! The core problem with your current code is that while you set resolve_scale(y='independent'), you didn't explicitly tell Altair to render the rate plot's y-axis on a separate side (right) from the scatter plot's y-axis (left). Here's how to adjust your code to get the desired layered, faceted dual-axis chart with the reference line included:

Step-by-Step Modifications

  1. Explicitly Define Dual Y-Axes
    Update your rate chart's y-axis to specify it should be on the right side, with its own title. This tells Altair to create a separate axis instead of merging it with the scatter plot's y-axis:

    rate = alt.Chart(source).mark_line(strokeDash=[5,3]).encode(
        x=alt.X('X', title='X'),
        # Set right-side axis for rate, with offset to avoid overlap
        y=alt.Y('rate:Q', title='Rate of Change', axis=alt.Axis(orient='right', offset=30)),
        color=alt.Color('rate-label', title=''),
        tooltip=['rate','X','Y']
    )
    
  2. Layer Charts Properly
    The scatter plot and reference line (line_plot) share the left y-axis, so layer those two first. Then layer the rate plot (with its right y-axis) on top. Finally, apply the facet and resolve the scale to keep y-axes independent:

    # Combine scatter and reference line (share left y-axis)
    scatter_with_reference = alt.layer(scatter, line_plot)
    
    # Combine with rate plot (right y-axis) and add facet
    final_chart = alt.layer(scatter_with_reference, rate).facet(
        'Series:N', columns=2
    ).resolve_scale(
        y='independent'  # Critical to keep both y-axes separate
    ).configure_axis(
        # Optional: Clean up axis styling for readability
        labelFontSize=10,
        titleFontSize=12
    )
    
    final_chart.display()
    

Why This Works

  • By setting orient='right' on the rate plot's y-axis, Altair recognizes it should render a second axis instead of reusing the left one.
  • Layering scatter and line_plot first keeps the reference line aligned with the scatter plot's data (since both use the original X/Y values).
  • resolve_scale(y='independent') ensures the two y-axes maintain their own scales (so the rate values don't get squashed or stretched to match the scatter plot's Y range).

Full Updated Code

Here's the complete code with all adjustments:

import altair as alt
from vega_datasets import data
import pandas as pd

source = data.anscombe().copy()
source['line-label'] = 'x=y'
source = pd.concat([source,source.groupby('Series').agg(x_diff=('X','diff'), y_diff=('Y','diff'))],axis=1)
source['rate'] = source.y_diff/source.x_diff
source['rate-label'] = 'rate of change'
source['line-label'] = 'line y=x'

source_linear = source.groupby(by=['Series']).agg(x_linear=('X','max'), y_linear=('X', 'max')).reset_index().sort_values(by=['Series'])
source_origin = source_linear.copy()
source_origin['y_linear'] = 0
source_origin['x_linear'] = 0
source_linear = pd.concat([source_origin,source_linear]).sort_values(by=['Series'])
source = source.merge(source_linear,on='Series').drop_duplicates()

scatter = alt.Chart(source).mark_circle(size=60, opacity=0.60).encode(
    x=alt.X('X', title='X'),
    y=alt.Y('Y', title='Y'),
    color='Series:N',
    tooltip=['X','Y','rate']
)

line_plot = alt.Chart(source).mark_line(color= 'black', strokeDash=[3,8]).encode(
    x=alt.X('x_linear', title = ''),
    y=alt.Y('y_linear', title = ''),
    shape = alt.Shape('line-label', title = 'Break Even'),
    color = alt.value('black')
)

rate = alt.Chart(source).mark_line(strokeDash=[5,3]).encode(
    x=alt.X('X', title='X'),
    y=alt.Y('rate:Q', title='Rate of Change', axis=alt.Axis(orient='right', offset=30)),
    color=alt.Color('rate-label', title=''),
    tooltip=['rate','X','Y']
)

# Combine and render
scatter_with_reference = alt.layer(scatter, line_plot)
final_chart = alt.layer(scatter_with_reference, rate).facet(
    'Series:N', columns=2
).resolve_scale(
    y='independent'
).configure_axis(
    labelFontSize=10,
    titleFontSize=12
)

final_chart.display()

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.09 17:17:39