elksie5000
elksie5000

Reputation: 7752

How to highlight multiline graph in Altair python

I'm trying to create an interactive timeseries chart with more than 20 lines of data using the Altair module in Python.

The code to create the dataframe of the shape I'm looking at is here:

import numpy as np
import altair as alt
year = np.arange(1995, 2020)
day = np.arange(1, 91)

def gen_next_number(previous, limit, max_reached):
    if max_reached:
        return np.NAN, True
    increment = np.random.randint(0, 10)
    output = previous + increment
    if output >= 100:
        output = 100
        max_reached = True
    return output, max_reached

def gen_list():
    output_list = []
    initial = 0
    limit = 100
    max_reached = False
    value = 0 
    for i in range(1, 91):
        value, max_reached = gen_next_number(value, limit, max_reached)
        if max_reached:
            value = np.NAN 
        output_list.append(value)
    return output_list

df = pd.DataFrame(index = day, columns=year )
for y in year:
    data = gen_list()
    df[y] = data

df['day'] = df.index
df = df.melt("day")
df = df.dropna(subset=["value"])

I can use the following Altair code to produce the initial plot, but it's not pretty:

alt.Chart(df).mark_line().encode(
    x='day:N',
    color="variable:N",
    y='value:Q',
    tooltip=["variable:N", "value"]
)

enter image description here

But when I've tried this code to create something interactive, it fails:

highlight = alt.selection(type='single', on='mouseover',
                          fields='variable', nearest=True, empty="none")

alt.Chart(plottable).mark_line().encode(
    x='day:N',
    color="variable:N",
    y=alt.condition(highlight, 'value:Q', alt.value("lightgray")),
    tooltip=["variable:N", "value"]
).add_selection(
    highlight
)

It fails with the error:

TypeError: sequence item 1: expected str instance, int found

Can someone help me out?

Also, is it possible to make the legend interactive? So a hover over a year highlights a line?

Upvotes: 0

Views: 2039

Answers (2)

MVigoda
MVigoda

Reputation: 93

I would like to create a multi-line plot similar to the one above

  • without a legend
  • without hovering or mouseover.

Would simply like to pass a highlighted_value and have a single line be highlighted.

I have modified the code because I am not terribly familiar with the proper use of "selection" and recognize that it is somewhat kludgy to get the result that I want.

Is there a cleaner way to do this?

highlight = alt.selection(type='single', on='mouseover',
                          fields=['variable'], nearest=True, empty="none")

background = alt.Chart(df[df['variable'] != 1995]).mark_line().encode(
    x='day:N',
    y='value:Q',
    color=alt.condition( highlight, 'variable:N', alt.value("lightgray")),
    tooltip=["variable:N", "value"],
).add_selection(
    highlight
)


foreground = alt.Chart(df[df['variable'] == 1995]).mark_line(color= "blue").encode(
    x='day:N',
    y='value:Q',
    color=alt.Color('variable',legend=None)
)
foreground + background

enter image description here

Upvotes: 0

jakevdp
jakevdp

Reputation: 86320

Two issues:

  • In alt.condition, you need to provide a list of fields rather than a single field
  • The y encoding does not accept a condition. I suspect you meant to put the condition on color.

With these two fixes, your chart works:

highlight = alt.selection(type='single', on='mouseover',
                          fields=['variable'], nearest=True, empty="none")

alt.Chart(df).mark_line().encode(
    x='day:N',
    y='value:Q',
    color=alt.condition(highlight, 'variable:N', alt.value("lightgray")),
    tooltip=["variable:N", "value"]
).add_selection(
    highlight
)

enter image description here

Because the selection doesn't change z-order, you'll find that the highlighted line is often hidden behind other gray lines. If you want it to pop out in front, you could use an approach similar to the one in https://stackoverflow.com/a/55796860/2937831

Upvotes: 1

Related Questions