'Altair mark_text position based on condition

enter image description here

I have this chart with mark_text to denote the value of each bar. There is a slider to go back/forth in time. I would like to change the positioning of the text (the numbers in the bars) depending on the Y value: if it is larger than a certain value, it will go just below the top of the bar (baseline='line-top), otherwise just above (baseline='line-bottom'). This way, as I slide through time the text will appear below/above the top of the bar depending on Y.

I think I have to use some condition or expression, but I cannot figure out how.

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

np.random.seed(0)

################################################################################

model_keys = ['M1', 'M2']
scene_keys = ['S1', 'S2']
layer_keys = ['L1', 'L2']
time_keys = [1, 2, 3]

ys = []
models = []
dataset = []
layers = []
scenes = []
times = []

for sc in scene_keys:
    for m in model_keys:
        for l in layer_keys:
            for s in range(10):
                y = np.random.rand(10) / 10
                if m == 'M1':
                    y *= 10
                if l == 'L1':
                    y *= 5
                for t in time_keys:
                    y += 1

                    ys += list(y)
                    scenes += [sc] * len(y)
                    models += [m] * len(y)
                    layers += [l] * len(y)
                    times += [t] * len(y)


# ------------------------------------------------------------------------------

df = pd.DataFrame({'Y': ys,
                   'Model': models,
                   'Layer': layers,
                   'Scenes': scenes,
                   'Time': times})

bars = alt.Chart(df, width=100, height=90).mark_bar().encode(
    x=alt.X('Scenes:N',
        title=None,
        axis=alt.Axis(
            grid=False,
            title=None,
            labels=False,
        ),
    ),
    y=alt.Y('Y:Q',
        aggregate='mean',
        axis=alt.Axis(
            grid=True,
            title='Y',
            titleFontWeight='normal',
        ),
    ),
)

text = alt.Chart(df).mark_text(align='center',
    baseline='line-top',
    color='black',
    dy=5,
    fontSize=13,
).encode(
    x=alt.X('Scenes:N'),
    y=alt.Y('mean(Y):Q'),
    text=alt.Text('mean(Y):Q',
        format='.1f'
    ),
)

bars = bars + text

bars = bars.facet(
    row=alt.Row('Model:N',
        title=None,
    ),
    column=alt.Column('Layer:N',
        title=None,
    ),
    spacing={"row": 10, "column": 10},
)

slider = alt.binding_range(
    min=1,
    max=3,
    step=1,
    name='Time',
)
selector = alt.selection_single(
    name='Selector',
    fields=['Time'],
    bind=slider,
    init={'Time': 3}, 
)
bars = bars.add_selection(
    selector
).transform_filter(
    selector
)

bars.save('test.html')


Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source