如何使一张图表 "span" 成为串联图中多个图表的高度/宽度?

How can I make one chart "span" the height / width of multiple charts in concatenated plots?

在下面的示例中,我想让 exp 填充绘图的整个宽度(因此,与 sincos 的总和一样宽)。默认情况下,exp 仅填充一列。

我该怎么做,理想情况下使用一些“自动”设置(没有明确地将 width= 设置为数字)?

import altair as alt
import numpy as np
import pandas as pd

x = np.linspace(0, 20, 100)
source = pd.DataFrame({
  'x': x,
  'sin': np.sin(x),
  'cos': np.cos(x),
  'exp': np.exp(x),
})

base = alt.Chart(source).mark_line().encode(x='x')
sin = base.encode(y='sin')
cos = base.encode(y='cos')
exp = base.encode(y='exp')
(sin | cos) & exp

据我所知,没有办法自动指定图表的大小来填充多个连接图表的整个布局(但如果你找到一个它可以帮助解决部分 https://github.com/vega/vega-lite/issues/7194 ).

如果您想避免手动估算数字,您可以通过访问每个图表对象的高度并为每个级联添加 60 个像素以编程方式计算高度(我包括了这 60 个中的大部分位置的细分像素来自下面的代码)。这自然不如 "auto" 值方便,但也许至少有点帮助。

不幸的是,这对于宽度来说不是那么简单,因为这取决于最上面一行连接中所有图表的 y-axis 中的位数(最左边的图表除外) , 它将刻度标签扩展到左侧的填充 space 而不会增加图形的总宽度)。

height = (
    sin.to_dict()['config']['view']['continuousHeight']  # 300
    + exp.to_dict()['config']['view']['continuousHeight']  # 300
    + 5  # The default bottom padding of chart top-left chart
    + 5  # The default top padding of the bottom-left chart
    + 11  # The default x-axis labels font size (+padding?) of the top-left chart
    + 15  # The default x-axis title font size (+padding?) of the top-left chart
    + 20  # The default spacing between concatenated charts
    + 3  # Not sure where these are from
)

# Notice that the concatenation ordering is different to avoid empty space under the `sin` plot
(sin & exp) | cos.properties(height=height)

宽度的类似解决方案

w = 200
spacing = 64

base = alt.Chart(source).mark_line().encode(x='x')
sin = base.encode(y='sin').properties(width=w, height=100)
cos = base.encode(y='cos').properties(width=w, height=100)
exp = base.encode(y='exp').properties(width=2*w+spacing, height=100)

row = alt.hconcat(sin, cos).properties(
    bounds='flush',
    spacing=spacing
)
                  
alt.vconcat(row, exp).configure_axisY(labelLimit=spacing)

未对齐,但使用更少的代码可能在视觉上足够好:

w = 200

base = alt.Chart(source).mark_line().encode(x='x')
sin = base.encode(y='sin').properties(width=w, height=100)
cos = base.encode(y='cos').properties(width=w, height=100)
exp = base.encode(y='exp').properties(width=2*w, height=100)

row = alt.hconcat(sin, cos)
alt.vconcat(row, exp).properties(center=True)