Search code examples
pythonaltair

How to make Altair display NaN points with a quantitative color scale?


In Altair, is there a way to plot NaN/None colors in quantitative encodings? Possibly even assigning a specific color such as in Matplotlib's set_bad?

For example, the third data point is missing using quantitative encoding for color 'c:Q'

df = pd.DataFrame(dict(x=[0, 1, 2, 3], c=[0, 1, None, 3]))
alt.Chart(df).mark_circle().encode(x='x:Q', y='x:Q', color='c:Q')

enter image description here

but it shows up (as null) when using ordinal encoding 'c:O':

df = pd.DataFrame(dict(x=[0, 1, 2, 3], c=[0, 1, None, 3]))
alt.Chart(df).mark_circle().encode(x='x:Q', y='x:Q', color='c:O')

enter image description here


Solution

  • Null data is filtered by default for some chart types and scales, but we can include them with invalid=None (the "invalid" param for marks in the docs). Then we can use a condition that assigns points the color grey if they are not valid numerical data:

    import pandas as pd
    import altair as alt
    
    
    df = pd.DataFrame(dict(x=[0, 1, 2, 3], c=[0, 1, None, 3]))
    
    alt.Chart(df).mark_circle(size=200, invalid=None).encode(
        x='x:Q',
        y='x:Q',
        color=alt.condition('isValid(datum.c)', 'c:Q', alt.value('gray'))
    )
    

    enter image description here

    If you want the legend to include the NaN, I think you need a layered chart:

    points = alt.Chart(df).mark_circle(size=200).encode(
        x='x:Q',
        y='x:Q',
        color='c:Q'
    )
    
    points + points.encode(
        color=alt.Color('c:O', scale=alt.Scale(range=['grey']), title=None)
    ).transform_filter(
        '!isValid(datum.c)'
    )
    

    enter image description here

    It would be convenient if you could avoid layering and simply type out something like this instead, but that is not allowed currently:

        alt.condition(
            'isValid(datum.c)',
            'c:Q',
            alt.Color('c:O', scale=alt.Scale(range=['grey']), title=None)
        )
    

    Ref Dealing with missing values / nulls in Altair choropleth map