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

Unexpected behaviour when using alt.Scale(domain=selection) with both x and y axes #2037

Open
jonathangjertsen opened this issue Mar 23, 2020 · 4 comments

Comments

@jonathangjertsen
Copy link
Contributor

jonathangjertsen commented Mar 23, 2020

I want to create a chart with a "minimap" similar to https://altair-viz.github.io/gallery/histogram_responsive.html, but where the selection is a box that I can click and drag (i.e., encodings=["x", "y"] when calling selection_interval).

The zooming works along the x-axis if I recreate the example, setting scale=alt.Scale(domain=zoom) for the x-axis only:

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

t = np.linspace(0, 100, 1000)
data = pd.DataFrame({ "t": x, "V": np.sin(x) })

zoom = alt.selection_interval(encodings=["x", "y"])

minimap = alt.Chart(data).mark_line().add_selection(zoom).encode(x="t", y="V").properties(height=100)
detail = alt.Chart(data).mark_point().encode(
    x=alt.X("t", scale=alt.Scale(domain=zoom)),
    y="V"
)

minimap & detail

but if I change y="V" to y=alt.Y("V", scale=alt.Scale(domain=zoom)), the limits on the Y axis are set to the x-axis bounds of the selection rather than the y-axis bounds.

After looking at https://vega.github.io/vega-lite/docs/selection.html#scale-domains I found a workaround that does exactly what I want:

detail = alt.Chart(data).mark_point().encode(x="t", y="V")
detail.encoding.x.scale = {"domain": {"selection": zoom.name, "encoding": "x"}}
detail.encoding.y.scale = {"domain": {"selection": zoom.name, "encoding": "y"}}

Is there a better way to do it though?

@jakevdp
Copy link
Collaborator

jakevdp commented Mar 23, 2020

There's not a great higher-level syntax for this yet, but you can accomplish it using:

detail = alt.Chart(data).mark_point().encode(
    x=alt.X("t", scale=alt.Scale(domain={'selection': zoom.name, 'encoding': 'x'})),
    y=alt.Y("V", scale=alt.Scale(domain={'selection': zoom.name, 'encoding': 'y'}))
)

@jakevdp
Copy link
Collaborator

jakevdp commented Mar 23, 2020

Going forward, we could probably make domain=zoom.x and domain=zoom.y shorthands for this, but we'd have to think about how this interacts with other places selection objects are used.

@jonathangjertsen
Copy link
Contributor Author

Thanks!

Would it make sense to automatically set 'encoding': 'y' as the default in usages like alt.Y(..., scale=alt.Scale(domain=selection))? And 'encoding': 'color' when used in alt.Color(..., scale=alt.Scale(domain=selection)), etc.

@jakevdp
Copy link
Collaborator

jakevdp commented Mar 23, 2020

The selection object only has x and y encodings, so there's not generally a good way to guess user intent. I'd prefer to make it easier for the user to be explicit.

I took a look: the problem is that zoom.x is already shorthand to refer to the x attribute of the selection object within expressions, so any attribute-based approach to this would potentially break existing code.

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

No branches or pull requests

3 participants