
:orphan:
:html_theme.sidebar_secondary.remove:

.. This document is auto-generated by the altair-gallery extension. Do not modify directly.

.. _gallery_select_detail:


Selection Detail
================
This example shows a selection that links two views of data: the left panel
contains one point per object, and the right panel contains one line per
object. Clicking on either the points or lines will select the corresponding
objects in both views of the data.

The challenge lies in expressing such hierarchical data in a way that Altair
can handle. We do this by merging the data into a "long form" dataframe, and
aggregating identical metadata for the final plot.


.. altair-plot::
    :remove-code:
    


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

    np.random.seed(0)

    n_objects = 20
    n_times = 50

    # Create one (x, y) pair of metadata per object
    locations = pd.DataFrame({
        'id': range(n_objects),
        'x': np.random.randn(n_objects),
        'y': np.random.randn(n_objects)
    })

    # Create a 50-element time-series for each object
    timeseries = pd.DataFrame(np.random.randn(n_times, n_objects).cumsum(0),
                              columns=locations['id'],
                              index=pd.RangeIndex(0, n_times, name='time'))

    # Melt the wide-form timeseries into a long-form view
    timeseries = timeseries.reset_index().melt('time')

    # Merge the (x, y) metadata into the long-form view
    timeseries['id'] = timeseries['id'].astype(int)  # make merge not complain
    data = pd.merge(timeseries, locations, on='id')

    # Data is prepared, now make a chart

    selector = alt.selection_point(fields=['id'])
    color = (
        alt.when(selector)
        .then(alt.Color("id:O", legend=None))
        .otherwise(alt.value("lightgray"))
    )

    base = alt.Chart(data).properties(
        width=250,
        height=250
    ).add_params(selector)

    points = base.mark_point(filled=True, size=200).encode(
        x='mean(x)',
        y='mean(y)',
        color=color,
    )

    line = base.mark_line().encode(
        x='time',
        y=alt.Y('value', scale=alt.Scale(domain=(-15, 15))),
        color=alt.Color('id:O', legend=None)
    ).transform_filter(
        selector
    )

    points | line


.. tab-set::

    .. tab-item:: Method syntax
        :sync: method

        .. code:: python


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

            np.random.seed(0)

            n_objects = 20
            n_times = 50

            # Create one (x, y) pair of metadata per object
            locations = pd.DataFrame({
                'id': range(n_objects),
                'x': np.random.randn(n_objects),
                'y': np.random.randn(n_objects)
            })

            # Create a 50-element time-series for each object
            timeseries = pd.DataFrame(np.random.randn(n_times, n_objects).cumsum(0),
                                      columns=locations['id'],
                                      index=pd.RangeIndex(0, n_times, name='time'))

            # Melt the wide-form timeseries into a long-form view
            timeseries = timeseries.reset_index().melt('time')

            # Merge the (x, y) metadata into the long-form view
            timeseries['id'] = timeseries['id'].astype(int)  # make merge not complain
            data = pd.merge(timeseries, locations, on='id')

            # Data is prepared, now make a chart

            selector = alt.selection_point(fields=['id'])
            color = (
                alt.when(selector)
                .then(alt.Color("id:O").legend(None))
                .otherwise(alt.value("lightgray"))
            )

            base = alt.Chart(data).properties(
                width=250,
                height=250
            ).add_params(selector)

            points = base.mark_point(filled=True, size=200).encode(
                x='mean(x)',
                y='mean(y)',
                color=color,
            )

            line = base.mark_line().encode(
                x='time',
                y=alt.Y('value').scale(domain=(-15, 15)),
                color=alt.Color('id:O').legend(None)
            ).transform_filter(
                selector
            )

            points | line


    .. tab-item:: Attribute syntax
        :sync: attribute

        .. code:: python


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

            np.random.seed(0)

            n_objects = 20
            n_times = 50

            # Create one (x, y) pair of metadata per object
            locations = pd.DataFrame({
                'id': range(n_objects),
                'x': np.random.randn(n_objects),
                'y': np.random.randn(n_objects)
            })

            # Create a 50-element time-series for each object
            timeseries = pd.DataFrame(np.random.randn(n_times, n_objects).cumsum(0),
                                      columns=locations['id'],
                                      index=pd.RangeIndex(0, n_times, name='time'))

            # Melt the wide-form timeseries into a long-form view
            timeseries = timeseries.reset_index().melt('time')

            # Merge the (x, y) metadata into the long-form view
            timeseries['id'] = timeseries['id'].astype(int)  # make merge not complain
            data = pd.merge(timeseries, locations, on='id')

            # Data is prepared, now make a chart

            selector = alt.selection_point(fields=['id'])
            color = (
                alt.when(selector)
                .then(alt.Color("id:O", legend=None))
                .otherwise(alt.value("lightgray"))
            )

            base = alt.Chart(data).properties(
                width=250,
                height=250
            ).add_params(selector)

            points = base.mark_point(filled=True, size=200).encode(
                x='mean(x)',
                y='mean(y)',
                color=color,
            )

            line = base.mark_line().encode(
                x='time',
                y=alt.Y('value', scale=alt.Scale(domain=(-15, 15))),
                color=alt.Color('id:O', legend=None)
            ).transform_filter(
                selector
            )

            points | line
