Cohan
Cohan

Reputation: 4544

Altair Layer Chart Y Axis Not Resolving to Same Scale

I'm trying to plot data and compare it to a threshold set at a fixed value. When creating a layered chart, the y axis does not appear to hold for both layers. The same goes for hconcat.

I found this issue which mentions .resolve_scale(y='shared'), but that doesn't seem to work. When I specify the rule to be at 5, it appears above 15.

np.random.seed(42)
df = pd.DataFrame({
    'x': np.linspace(0, 10, 500),
    'y': np.random.randn(500).cumsum()
})

base = alt.Chart(df)
line = base.mark_line().encode(x='x', y='y')
rule = base.mark_rule().encode(y=alt.value(5))

alt.layer(line, rule).resolve_scale(y='shared')

layered chart incorrect display

To get the rule to appear at the value 5, I have to set it at 110.

rule = base.mark_rule().encode(y=alt.value(110))

alt.layer(line, rule).resolve_scale(y='shared')

layered chart incorrect value

How can I edit the chart so that the rule shows at the y-value specified?

Upvotes: 1

Views: 1904

Answers (1)

jakevdp
jakevdp

Reputation: 86330

Altair scales map a domain to a range. The domain describes the extent of the data values, while the range describes the extent of the visual features to which those values are mapped. For color encodings, the range might be "red", "blue", "green", etc. For positional encodings like x and y, the range is the pixel position of the mark on the chart.

When you use alt.value, you are specifying the range value, not the domain value. This is why you can use an encoding like color=alt.value('red'), to specify that you want the mark to appear as the color red. When you do y=alt.value(5), you are saying you want the mark to appear 5 pixels from the top of the y-axis.

Recent versions of Vega-Lite added the ability to specify the domain value via datum rather than value, but unfortunately Altair does not yet support this, and so the only way to make this work is to have a data field with the desired value. For example:

line = base.mark_line().encode(x='x', y='y')
rule = alt.Chart(pd.DataFrame({'y': [5]})).mark_rule().encode(y='y')

alt.layer(line, rule).resolve_scale(y='shared')

enter image description here

Upvotes: 2

Related Questions