2

To my understanding, there is no official support for emitting signals/events from interactions in VegaLite/Altair, such as selecting points in a scatter plot, other than to charts in the same view/composition.

Is there currently any workaround for this that would capture which points are selected in a scatter plot and process them outside VegaLite ("outside" = in Python for me as I am using Altair)?

For example, could I make a selection persistent and saved to a json spec that I could parse in Python? Or could I write a custom javascript function that is triggerd by a chart selection and saved as a Python variable or printed to some stream that I could read from Python?

Example code from the docs for a chart with an interactive selection:

import altair as alt
from vega_datasets import data

brush = alt.selection_interval() 
chart = alt.Chart(data.cars.url).mark_point().encode(
    x='Horsepower:Q',
    y='Displacement:Q',
    color=alt.condition(brush, 'Origin:N', alt.value('lightgray')),
    tooltip='Horsepower:Q').add_selection(brush)
chart
joelostblom
  • 43,590
  • 17
  • 150
  • 159

3 Answers3

2

There is no general way to access Altair selections from Python, but if you're working in Streamlit they have implemented a method to do this on that platform. See https://stackoverflow.com/a/64652229/2937831

jakevdp
  • 77,104
  • 11
  • 125
  • 160
  • Thanks for confirming that it is not possible in general and for the link. [streamlit-vega-lite](https://github.com/domoritz/streamlit-vega-lite) looks very promising and I hope they can integrate something like that into vegalite itself when it matures! – joelostblom Jan 15 '21 at 14:16
  • I think the functionality to access selections needs to be in the platform. Neither Altair (which generates Vega-Lite specs) nor Vega-Lite/Vega (which are the runtime for the chart and give you access to the selection in JavaScript) can give you access to the selection in Python. Vega-Lite should have better APIs to access selections (something we think about). Then making things like https://github.com/domoritz/streamlit-vega-lite should be a bit easier. – dominik Jan 15 '21 at 16:12
0

Hmm, I too am interested in this so I went searching in the Altair docs.

what if you did:

from pprint import pprint
pprint(chart.to_dict())

Here is what I get:

{'$schema': 'https://vega.github.io/schema/vega-lite/v4.8.1.json',
 'config': {'view': {'continuousHeight': 300, 'continuousWidth': 400}},
 'data': {'url': 'https://vega.github.io/vega-datasets/data/cars.json'},
 'encoding': {'color': {'condition': {'field': 'Origin',
                                      'selection': 'selector001',
                                      'type': 'nominal'},
                        'value': 'lightgray'},
              'tooltip': {'field': 'Horsepower', 'type': 'quantitative'},
              'x': {'field': 'Horsepower', 'type': 'quantitative'},
              'y': {'field': 'Displacement', 'type': 'quantitative'}},
 'mark': 'point',
 'selection': {'selector001': {'type': 'interval'}}}

That must be part of it? maybe?

Firas
  • 516
  • 5
  • 10
  • 1
    I was also hoping to use the chart specification for this. However, if you assign the chart to a variable and then select some points, that selection will not be reflected in your already assigned variable. I think we would a custom js function to trigger on selection and write out the updated chart specification somewhere, but I'm not sure. – joelostblom Jan 14 '21 at 22:49
  • 1
    I've found that answer quite interesting. https://stackoverflow.com/a/60894451/12998504 – uhetz Jun 18 '21 at 07:13
0

The capability to listen to Vega events and define custom callback for e.g. selected points was recently merged in Panel and is included in the 0.13 release! This is the only Python dashboarding package that supports custom callbacks on selections in Altair charts. Here is an example from the docs:

penguins_url = "https://raw.githubusercontent.com/vega/vega/master/docs/data/penguins.json"
brush = alt.selection_interval(name='brush')  # selection of type "interval"

chart = alt.Chart(penguins_url).mark_point().encode(
    x=alt.X('Beak Length (mm):Q', scale=alt.Scale(zero=False)),
    y=alt.Y('Beak Depth (mm):Q', scale=alt.Scale(zero=False)),
    color=alt.condition(brush, 'Species:N', alt.value('lightgray'))
).properties(
    width=250,
    height=250
).add_selection(
    brush
)

vega_pane = pn.pane.Vega(chart, debounce=10)

vega_pane

df = pd.read_json(penguins_url)

def filtered_table(selection):
    if not selection:
        return '## No selection'
    query = ' & '.join(
        f'{crange[0]:.3f} <= `{col}` <= {crange[1]:.3f}'
        for col, crange in selection.items()
    )
    return pn.Column(
        f'Query: {query}',
        pn.pane.DataFrame(df.query(query), width=600, height=300)
    )

pn.Row(vega_pane, pn.bind(filtered_table, vega_pane.selection.param.brush))

image

joelostblom
  • 43,590
  • 17
  • 150
  • 159