Cari
Cari

Reputation: 67

Can you add a label for "missing data" to a legend for an Altair chart?

I have a heatmap plotted using Altair that includes a colorbar, but the missing data (blank/white) in the heatmap is not labeled on the colorbar. Is there a way to add a separate label to the legend (e.g. below the colorbar) to show how missing data is represented in the chart?

I've come up with a solution that includes a "ghost" layer on top of my chart -- a ruler chart with size = 0 (so that the line is invisible) that is colored by a column filled with string values of "No Data" (see code below). This forces a legend item, but I'm wondering if there's a better way. (See my full example at link here:heatmap plot)

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

# Example heatmap data
heatmap_df = pd.DataFrame([["NY",1999,1],["NY",2000,np.nan], ["MA",1999,np.nan], ["MA",2000,4]], columns = ["state","year","rate"])

# Example Legend dataframe
legend_no_data = pd.DataFrame([[1999, "No Data"]], columns = ["year", "text"])


# Example chart with "No Data" label
heatmap = alt.Chart(heatmap_df).mark_rect().encode(alt.X("year:O"), alt.Y("state:N"), alt.Color("rate:Q"))

# Chart for "No Data" legend item
vacc_legend_no_data = alt.Chart(legend_no_data).mark_line(
    size=0
).encode(
    x='year:O',
    color = alt.Color("text:N", legend = alt.Legend(title = "", symbolType = "square")))

heatmap + vacc_legend_no_data

The "ghost layer" adds the empty square labeled "No Data" at the bottom of the colorbar, but I hope there is a better way to represent this!

Upvotes: 3

Views: 1088

Answers (1)

jakevdp
jakevdp

Reputation: 86443

Unfortunately, I don't know an easy way to handle nulls within a quantitative scale. But you can handle them naturally within nominal scales; I would probably generate the Null dataset layer in the chart spec using a calculate transform, to avoid having to construct a second dataframe. It might look something like this:

heatmap = alt.Chart(heatmap_df).mark_rect().encode(
  alt.X("year:O"),
  alt.Y("state:N"),
  alt.Color("rate:Q")
)

nulls = heatmap.transform_filter(
  "!isValid(datum.rate)"
).mark_rect(opacity=0.5).encode(
  alt.Color('rate:N', scale=alt.Scale(scheme='greys'))
)

heatmap + nulls

enter image description here

Upvotes: 7

Related Questions