Stirling
Stirling

Reputation: 391

Dynamic Text Just Above an Altair Chart

In the chart produced by the code below, the user can hover over the line segment to display a point on the chart, and information about the point is shown above the chart.

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

df = pd.DataFrame({'x': np.linspace(0, 4, 1000)})
# df['y'] = np.sin(2 * np.pi * df['x'])
df['y'] = 1.9 * df['x']

select_point = alt.selection_single(fields=('x',), nearest=True, on='mouseover', empty='none')
line = alt.Chart(df).mark_line().encode(
    x='x:Q',
    y='y:Q',
)
points = line.mark_point(filled=True, size=100).encode(
    opacity=alt.condition(select_point, alt.value(1.0), alt.value(0.0)),
).add_selection(select_point)
texts = alt.Chart(df, width=600, height=400).mark_text(
    align='left', baseline='bottom', dx=+5, dy=-5, fontSize=12,
).encode(
    x=alt.value(0.0),
    y=alt.value(df['y'].max()),
    text='_label:N',
    opacity=alt.condition(select_point, alt.value(1.0), alt.value(0.0)),
).transform_calculate(
    _label='"x = " + format(datum.x, ".2f") + ", y = " + format(datum.y, ".2f")',
)
alt.layer(line, points, texts)

There is code to plot both a sine curve and a line, although the code to plot the sine curve is commented out. When I run the script to display the sine curve I get the following.

sine curve

And when I run the script to display the line I get the following.

line

I think the label text on the plot of the sine curve is just right. However, the label text on the plot of the line is too close to the top of the chart. Is there a way to consistently place the label text offset from the top of the rest of the chart?

Upvotes: 2

Views: 1099

Answers (1)

jakevdp
jakevdp

Reputation: 86328

Altair scales have both a domain and a range. The domain refers to the extent of the data, and the range refers to the extent of the visual scale.

In the case of x and y encodings, the range is measured in pixels from the left of the chart (for x) and from the top of the chart (for y). Setting an encoding value always refers to the range, not the domain.

So if you want the text to appear in a specific place regardless of the dataset, don't tie the text range position to values in the dataset. For example, you could do:

y=alt.value(-1)

and remove the dy setting from your mark properties. This would specify that you want the text baseline to be 1 pixel above the top of the y axis.

Upvotes: 3

Related Questions