Search code examples
altairvega-lite

Mark properties when there is no selection


When there is no selection, I would like to have an opacity setting that is different from what is specified in the condition.

You can see below that when there are no selections, opacity is equal to 1 for all points—despite the mark property. I would like to be able to do the following:

  1. When no selections are made, opacity is 0.6 for all points.
  2. When a selection is made, the selected point has opacity of 1 and non-selected points have opacity of 0.2.

enter image description here

I thought perhaps the empty property would help but it can only have the values True or False (I'm using Altair 5.1.1).

single = alt.selection_point(on='click', fields=['account_name'], empty=True)

gaussian_jitter = (
    alt.Chart(df_melt, title="Primary Customer Characteristics")
    .mark_point(size=50, opacity=.6, filled=True)
    .encode(
        y=alt.Y("customer_characteristic:N", title="Customer Characteristics"),
        x=alt.X("z_scores:Q", title="Z Scores"),
        yOffset="jitter:Q",
        color=alt.condition(single, 'customer_characteristic', alt.value('lightgray')),
        opacity=alt.condition(single, alt.value(1), alt.value(.1)),
        size=alt.condition(single, alt.value(50), alt.value(10)),
        # tooltip=alt.Tooltip(id_vars, bandPosition=0.5),
    )
    .transform_calculate(
        # Generate Gaussian jitter with a Box-Muller transform
        jitter="sqrt(-2*log(random()))*cos(2*PI*random())"
    )
).add_params(single)

Solution

  • Yes! I found a way to do this as follows:

    1. Layer two charts

    2. Use two different selections, setting one to empty=True and one to empty=False.

    3. Set the size and opacity conditions to, in effect, treat one layer as invisible until a point is clicked.

    I'd love to know if there is an easier way to accomplish this 🙌.

    enter image description here

    default_selection = alt.selection_point(on='mouseover', fields=['account_name'], empty=True)
    point_selection = alt.selection_point(on='mouseover', fields=['account_name'], empty=False)
    
    base_chart = (
        alt.Chart(title="Primary Customer Characteristics")
        .mark_point(filled=True)
        .encode(
            y=alt.Y("customer_characteristic:N", title="Customer Characteristics"),
            x=alt.X("z_scores:Q", title="Z Scores"),
            yOffset="jitter:Q",
            # tooltip=alt.Tooltip(id_vars),
        ).transform_calculate(
            # Generate Gaussian jitter with a Box-Muller transform
            jitter="sqrt(-2*log(random()))*cos(2*PI*random())")
    )
    
    default_chart = base_chart.encode(
        color=alt.condition(default_selection, 'customer_characteristic', alt.value('lightgray')),
        opacity=alt.condition(default_selection, alt.value(.4), alt.value(.2)),
        size=alt.condition(default_selection, alt.value(75), alt.value(10))
    ).add_params(default_selection)
    
    point_chart=base_chart.encode(
            color=alt.condition(point_selection, 'customer_characteristic', alt.value('lightgray')),
            opacity=alt.condition(point_selection, alt.value(1), alt.value(0)),
            size=alt.condition(point_selection, alt.value(300), alt.value(10)),
    ).add_params(point_selection)
    
    (default_chart + point_chart).properties(data=df_melt, height=400, width=800)