Search code examples
altair

How to use altair scale(zero=False)?


When executing the following code I would expect the graph to not include zero, but instead start somewhere around the minimum point in the data shown on the y-axis.

import pandas as pd
import altair as alt

print(alt.__version__)

df = pd.DataFrame(data={"targets": ['A', 'B', 'C', 'D'], "values": [0.91, 0.95, 0.97, 0.9]})
display(df)

alt.Chart(df).mark_bar().encode(
    x='targets:N',
    y=alt.Y('values:Q').scale(zero=False)
)

But I get this:

enter image description here

When applying mean() to the values I am showing on the y-axis, this solves my issue. But I don't understand why this is happening.

alt.Chart(df).mark_bar().encode(
    x='targets:N',
    y=alt.Y('mean(values):Q').scale(zero=False)
)

enter image description here

Does this suggest I should not use a bar chart for individual values?

Using a different encoding seems to support that. For example with a line the zero is excluded:

alt.Chart(df).mark_line().encode(
    x='targets:N',
    y=alt.Y('values:Q').scale(zero=False)
)

enter image description here


Solution

  • I think it has to do with the fact that bar charts are stacked by default (even when there is only one value) and the default stack is zero (docs). So usingy=alt.Y('values:Q', stack=None).scale(zero=False), works, but your lowest bar will become invisible (beneath the x axis).
    For non-zero bar charts I prefer to use domainMin instead as you can set some offset.

    a = alt.Chart(df).mark_bar().encode(
        x='targets:N',
        y=alt.Y('values:Q', stack=None).scale(zero=False)
    )
    b = alt.Chart(df).mark_bar(clip=True).encode(
        x='targets:N',
        y=alt.Y('values:Q').scale(zero=False, domainMin=df['values'].min()*0.99)
    )
    
    a | b
    

    plot