Search code examples
pythonjupyter-notebookaltair

Altair: scatterplot with image preview on click


I am very new to altair. I'm trying to write code creates a scatterplot on the left and an image preview pane on the right. When you click on a point on the scatterplot, the image in the preview pane will update to show the image for that point.

Getting the following error:

SchemaValidationError: Invalid specification

        altair.vegalite.v4.api.Chart->0, validating 'additionalProperties'

        Additional properties are not allowed ('encoding', 'transform', 'data', 'mark' were unexpected)

Not sure where I got it wrong. Here is my code so far:

import altair as alt
import pandas as pd

images = ['../resources/random_images/image1.png', '../resources/random_images/image2.png', '../resources/random_images/image3.png']

# Create a dataframe with columns for x and y coordinates, and a column for the image filename
df = pd.DataFrame({'x': [1, 2, 3], 'y': [4, 5, 6], 'image': images})

# Create the scatterplot
scatterplot = alt.Chart(df).mark_circle().encode(
    x='x',
    y='y'
).add_selection(
    alt.selection_single(on='click')
)

# Use the `selection_single` selection to create a new dataframe that contains the image filename
# for the point that is selected
selected_image = alt.Chart(df).transform_filter(
    alt.datum.index == alt.selection_single().value
).encode(
    x=alt.X('x:Q', axis=alt.Axis(title=None)),
    y=alt.Y('y:Q', axis=alt.Axis(title=None))
).mark_image()

# Use the `image` data transformer to display the image
image = alt.Chart(selected_image).mark_image(
    height=200,
    width=200
).encode(
    url='image:N'
)

# Use `hconcat` to combine the scatterplot and image into a single chart
chart = alt.hconcat(scatterplot, image, spacing=10)

# Display the chart
chart.display()

Solution

  • I don't have access to the images you are referencing, but there is an example of how to show image on selection here https://github.com/altair-viz/altair/issues/2278

    import altair as alt
    import pandas as pd
    
    source = pd.DataFrame.from_records(
        [{'a': 1, 'b': 1, 'image': 'https://altair-viz.github.io/_static/altair-logo-light.png'},
         {'a': 2, 'b': 2, 'image': 'https://avatars.githubusercontent.com/u/11796929?s=200&v=4'}]
    )
    
    brush = alt.selection_interval()
    points = alt.Chart(source).mark_circle(size=200).encode(
        x='a',
        y='b',
    ).add_selection(
        brush
    )
    
    imgs = alt.Chart(source, width=200, height=200).mark_image().encode(
        url='image'
    ).facet(
        alt.Facet('image', title='', header=alt.Header(labelFontSize=0))
    ).transform_filter(
        brush
    )
    
    points & imgs