Velvet Star Monitor

Standout celebrity highlights with iconic style.

updates

Tooltips in Altair line charts

Writer Andrew Henderson

When specifying a tooltip for a line chart, the tooltip only appears when hovering over points along a line, but not when hovering anywhere else along a line. This is especially problematic when using a non-linear interpolation... Is there way to explicitly set tooltips on the lines themselves?

import altair as alt
from vega_datasets import data
source = data.jobs.url
alt.Chart(source).mark_line(interpolate="basis").encode( alt.X('year:O'), alt.Y('perc:Q', axis=alt.Axis(format='%')), color='sex:N', tooltip='sex:N'
).properties( title='Percent of work-force working as Welders'
).transform_filter( alt.datum.job == 'Welder'
)

enter image description here

3 Answers

Extending from @Philipp_Kats's answer and @dominik's comment (and for anyone else who stumbled upon this thread and wish to see the Altair code example), the current way of achieving a "tooltip" effect along the lines is to:

  1. Create the line (mark_line())
  2. Create a selection that chooses the nearest point & selects based on x-value
  3. Snap some transparent selectors across the line, informing the x-value across different positions of the line
  4. Layer (mark_text()) on top of 1 - 3 above

A real example is this line chart on a simple Flask app I made. Only difference was that I didn't make the selectors transparent (opacity=alt.value(0)) but otherwise it's a line chart with tooltips snapped on it.

Here's a reproducible example using OP's original dataset:

# Step 1: create the line
line = alt.Chart().mark_line(interpolate="basis").encode( x=alt.X("year:O"), y=alt.Y("perc:Q", axis=alt.Axis(format='%')), color='sex:N'
).transform_filter( alt.datum.job == 'Welder'
)
# Step 2: Selection that chooses nearest point based on value on x-axis
nearest = alt.selection(type='single', nearest=True, on='mouseover', fields=['year'])
# Step 3: Transparent selectors across the chart. This is what tells us
# the x-value of the cursor
selectors = alt.Chart().mark_point().encode( x="year:O", opacity=alt.value(0),
).add_selection( nearest
)
# Step 4: Add text, show values in Sex column when it's the nearest point to
# mouseover, else show blank
text = line.mark_text(align='left', dx=3, dy=-3).encode( text=alt.condition(nearest, 'sex:N', alt.value(' '))
)
# Layer them all together
chart = alt.layer(line, selectors, text, data=source, width=300)
chart

Resulting plot:

enter image description here

As of March 2022, a workaround for this without complicating your spec too much with selectors and Voronoi tesselation: Use a thick transparent line in the background (opacity should not be exactly 0, because then it is not rendered) and create a layer chart.

base = ( alt.Chart( pd.DataFrame( [{"x": 1, "y": 1}, {"x": 2, "y": 2}, {"x": 3, "y": 1}, {"x": 4, "y": 4}] ) ) .mark_line() .encode(x="x:Q", y="y:Q", tooltip="tt:N") .transform_calculate(tt="datum.x+' value'")
)
tt = base.mark_line(strokeWidth=30, opacity=0.01)
base + tt

I doubt that there is a direct technical solution at the moment :-(

One workaround solution is to explicitly add points on top of lines so it is easier to hover. I usually make them relatively large, but hide until the hover event, like here As a cherry on the top, one could use Voronoi to show the closest point at any given point, as they do in this tutorial

Let me know if you need Altair code example, I used raw vega, but implementing Altair version should be relatively trivial

3

Your Answer

Sign up or log in

Sign up using Google Sign up using Facebook Sign up using Email and Password

Post as a guest

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.