Search code examples
altairvega-lite

Can't get transform_filter to work in Altair


For my teaching notes I am trying to implement this vega-lite example in Altair:

{
  "data": {"url": "data/seattle-weather.csv"},
  "layer": [{
    "params": [{
      "name": "brush",
      "select": {"type": "interval", "encodings": ["x"]}
    }],
    "mark": "bar",
    "encoding": {
      "x": {
        "timeUnit": "month",
        "field": "date",
        "type": "ordinal"
      },
      "y": {
        "aggregate": "mean",
        "field": "precipitation",
        "type": "quantitative"
      },
      "opacity": {
        "condition": {
          "param": "brush", "value": 1
        },
        "value": 0.7
      }
    }
  }, {
    "transform": [{
      "filter": {"param": "brush"}
    }],
    "mark": "rule",
    "encoding": {
      "y": {
        "aggregate": "mean",
        "field": "precipitation",
        "type": "quantitative"
      },
      "color": {"value": "firebrick"},
      "size": {"value": 3}
    }
  }]
}

I getting the separate charts (bar and rule to work) was easy, but I run into issues in making mark_rule interactive.

import altair as alt
from vega_datasets import data


df = data.seattle_weather()
selection = alt.selection_interval(encodings=['x'])

base = alt.Chart(df).add_selection(selection)

bar_i = base.mark_bar().encode(
    x="month(date):T",
    y="mean(precipitation):Q",
    opacity=alt.condition(selection, alt.value(1.0), alt.value(0.7)))

rule_i = base.mark_rule().transform_filter(selection).encode(y="mean(precipitation):Q")

(bar_i + rule_i).properties(width=600)

The error reads

Javascript Error: Duplicate signal name: "selector013_scale_trigger"
This usually means there's a typo in your chart specification. See the javascript console for the full traceback.

Solution

  • It looks like the chart you're interested in creating is part of Altair's example gallery: https://altair-viz.github.io/gallery/selection_layer_bar_month.html

    import altair as alt
    from vega_datasets import data
    
    source = data.seattle_weather()
    brush = alt.selection(type='interval', encodings=['x'])
    
    bars = alt.Chart(source).mark_bar().encode(
        x='month(date):O',
        y='mean(precipitation):Q',
        opacity=alt.condition(brush, alt.OpacityValue(1), alt.OpacityValue(0.7)),
    ).add_selection(
        brush
    )
    
    line = alt.Chart(source).mark_rule(color='firebrick').encode(
        y='mean(precipitation):Q',
        size=alt.SizeValue(3)
    ).transform_filter(
        brush
    )
    
    bars + line
    

    The error you're seeing comes from the fact that base includes the selection, and both layers are derived from base, so the same selection is declared twice within the single chart.