Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

how can a user toggle a vis element on/off? is this possible in interactive? #954

Closed
jowens opened this issue Jun 20, 2018 · 12 comments
Closed
Labels

Comments

@jowens
Copy link
Contributor

jowens commented Jun 20, 2018

For instance, in:

https://altair-viz.github.io/gallery/poly_fit.html

is it possible to individually toggle the three lines on/off? The interactive plot demos generally either highlight/unhighlight or select subsets of data, but there's no on/off.

The example I'd like to see (as an instance) is Anscombe's quartet where the user could toggle on/off the curve that's fit to the data (and perhaps also display on/near the curve the curve parameters e.g. slope).

@jakevdp
Copy link
Collaborator

jakevdp commented Jun 21, 2018

You can use a selection_single to do this kind of thing; see below for an example based on the poly_fit example you linked to.

I suspect what you really want is an interactive legend. That's not supported yet by vega-lite, but you can track the relevant issue here: vega/vega-lite#1657

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

# Generate some random data
rng = np.random.RandomState(1)
x = rng.rand(40) ** 2
y = 10 - 1. / (x + 0.1) + rng.randn(40)
df = pd.DataFrame({'x': x, 'y': y})

# Define the degree of the polynomial fit
degree_list = [1, 3, 5]

# Build a dataframe with the fitted data
poly_data = pd.DataFrame({'xfit': np.linspace(df['x'].min(), df['x'].max(), 500)})

for degree in degree_list:
    poly_data[str(degree)] = np.poly1d(np.polyfit(df['x'], df['y'], degree))(poly_data['xfit'])

# Tidy the dataframe so 'degree' is a variable
poly_data = pd.melt(poly_data,
                    id_vars=['xfit'],
                    value_vars=[str(deg) for deg in degree_list],
                    var_name='degree', value_name='yfit')

# Plot the data points on an interactive axis
points = alt.Chart(df).mark_circle(color='black').encode(
    x=alt.X('x', axis=alt.Axis(title='x')),
    y=alt.Y('y', axis=alt.Axis(title='y')),
).interactive()

selection = alt.selection_single(encodings=['color'], empty='none')

# Plot the best fit polynomials
polynomial_fit = alt.Chart(poly_data).mark_line(strokeWidth=3).encode(
    x='xfit',
    y='yfit',
    color='degree',
    opacity=alt.condition(selection, alt.value(0.0), alt.value(1.0))
).add_selection(
    selection
)

points + polynomial_fit

@jowens
Copy link
Contributor Author

jowens commented Jun 21, 2018

Thanks @jakevdp. Great example. I think interactive-legend is in fact what I want; a toggle in the legend seems like the right thing here.

@binste
Copy link
Contributor

binste commented Jun 27, 2018

In the meantime you can do something similar to an interactive-legend using a second plot and selections. For the above example this could look like this:

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

# Generate some random data
rng = np.random.RandomState(1)
x = rng.rand(40) ** 2
y = 10 - 1. / (x + 0.1) + rng.randn(40)
df = pd.DataFrame({'x': x, 'y': y})

# Define the degree of the polynomial fit
degree_list = [1, 3, 5]

# Build a dataframe with the fitted data
poly_data = pd.DataFrame({'xfit': np.linspace(df['x'].min(), df['x'].max(), 500)})

for degree in degree_list:
    poly_data[str(degree)] = np.poly1d(np.polyfit(df['x'], df['y'], degree))(poly_data['xfit'])

# Tidy the dataframe so 'degree' is a variable
poly_data = pd.melt(poly_data,
                    id_vars=['xfit'],
                    value_vars=[str(deg) for deg in degree_list],
                    var_name='degree', value_name='yfit')

# Plot the data points on an interactive axis
points = alt.Chart(df).mark_circle(color='black').encode(
    x=alt.X('x', axis=alt.Axis(title='x')),
    y=alt.Y('y', axis=alt.Axis(title='y')),
).interactive()

selection = alt.selection_multi(encodings=['color'], empty='none')

# Plot the best fit polynomials
polynomial_fit = alt.Chart(poly_data).mark_line(strokeWidth=3).encode(
    x='xfit',
    y='yfit',
    color=alt.Color('degree', legend=None),
    opacity=alt.condition(selection, alt.value(0.0), alt.value(1.0))
).add_selection(
    selection
)

# Clickable legend
clickable_legend = alt.Chart(poly_data).mark_circle().encode(
    y='degree:O',
    color=alt.condition(selection, alt.value('lightgray'), 'degree:O', legend=None)
).add_selection(selection)

(points + polynomial_fit) | clickable_legend

Hold down Shift when clicking on the legend entries to select multiple entries.


Reference to jakevdp's talk at PyCon 2018 where the idea came up. It is furthermore also posted in the vega-lite issue mentioned above.

@apahl
Copy link

apahl commented Apr 3, 2019

The example in the documentation uses lightgray as color to mark the deselected points. I found that using transparent as color makes the deselected points completely invisible, which is what I want.

But, of course, the points are still there, which is why tooltips are still shown, when the mouse hovers over them. Is it possible, to suppress this as well?

Kind regards,,
Axel

@jakevdp
Copy link
Collaborator

jakevdp commented Apr 3, 2019

If you do a filter transform on the selection rather than a conditional transparency, the points will go away completely. You can find an example here: https://altair-viz.github.io/user_guide/transform.html#selection-predicates

@apahl
Copy link

apahl commented Apr 4, 2019

Thanks a lot Jake, I was not aware of that possibility.
This is exactly what I was looking for.

Many thanks again for this great library!

Kind regards,
Axel

@jnsprnw
Copy link

jnsprnw commented Apr 23, 2020

hey hey,
I noticed that elements with opacity = 0 are still reactive to tooltips. This sometimes results in the effect, that elements are hidden by invisible elements so their tooltip doesn’t appear.

In contrast, if I use filter transform the chart obviously changes its axis.

I’m looking for a way to actually hide elements through their encoding. Something like visible would be great, but I couldn’t find anything in the documentation.

@jakevdp
Copy link
Collaborator

jakevdp commented Apr 23, 2020

There is no way to hide elements via an encoding; the mechanism available for that is the filter transform.

@HarvsG
Copy link

HarvsG commented Nov 23, 2020

If you do a filter transform on the selection rather than a conditional transparency, the points will go away completely. You can find an example here: https://altair-viz.github.io/user_guide/transform.html#selection-predicates

fixed link

https://altair-viz.github.io/user_guide/transform/filter.html#selection-predicates

@joelostblom
Copy link
Contributor

@jowens I am going through Altair issues to find those that have been resolved and can be closed. Would you be able to close this issue or add a comment if there is something you don't think is resolved yet?

@jowens
Copy link
Contributor Author

jowens commented Feb 23, 2021

I'll take a look! Perhaps not this week, sorry, but I will look.

@joelostblom
Copy link
Contributor

Closing for now, please reopen if there is anything that wasn't resolved solutions provided above.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

7 participants