-
Notifications
You must be signed in to change notification settings - Fork 630
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
feat: interactive legends #5305
Conversation
…ega-lite into djbarnwal-db/legendInteractive
🎉 I'm very excited about this |
b05535e
to
2646d20
Compare
Alright, I'm nearing the end with this feature PR. Before I finalize the design via unit tests, I'd like to get some eyes and hands on how interactive legends work and confirm that the current design is desirable. To that end, here are some interesting specifications to try. I'm purposely not including any GIFs so as not to prime you. Single selection projected over the legend domain{
"$schema": "https://vega.github.io/schema/vega-lite/v3.json",
"description": "A scatterplot showing horsepower and miles per gallons.",
"data": {"url": "data/cars.json"},
"mark": "circle",
"selection": {
"foo": {"type": "single", "fields": ["Origin"]}
},
"encoding": {
"x": {"field": "Horsepower", "type": "quantitative"},
"y": {"field": "Miles_per_Gallon", "type": "quantitative"},
"color": {
"condition": {"selection": "foo", "field": "Origin", "type": "nominal"},
"value": "grey"
}
}
} Multi selection projected over the legend domain{
"$schema": "https://vega.github.io/schema/vega-lite/v3.json",
"description": "A scatterplot showing horsepower and miles per gallons.",
"data": {"url": "data/cars.json"},
"mark": "circle",
"selection": {
"foo": {"type": "multi", "fields": ["Origin"]}
},
"encoding": {
"x": {"field": "Horsepower", "type": "quantitative"},
"y": {"field": "Miles_per_Gallon", "type": "quantitative"},
"color": {
"condition": {"selection": "foo", "field": "Origin", "type": "nominal"},
"value": "grey"
}
}
} Multi selection projected over several fields, only one of which includes the legend domain{
"$schema": "https://vega.github.io/schema/vega-lite/v3.json",
"description": "A scatterplot showing horsepower and miles per gallons.",
"data": {"url": "data/cars.json"},
"mark": "circle",
"selection": {
"foo": {"type": "multi", "fields": ["Origin", "Cylinders"]}
},
"encoding": {
"x": {"field": "Horsepower", "type": "quantitative"},
"y": {"field": "Miles_per_Gallon", "type": "quantitative"},
"color": {
"condition": {"selection": "foo", "field": "Origin", "type": "nominal"},
"value": "grey"
}
}
} Multi selection projected over several fields, where each field has a corresponding legend{
"$schema": "htts://vega.github.io/schema/vega-lite/v3.json",
"description": "A scatterplot showing horsepower and miles per gallons.",
"data": {"url": "data/cars.json"},
"mark": "circle",
"selection": {
"foo": {"type": "multi", "fields": ["Origin", "Cylinders"]}
},
"encoding": {
"x": {"field": "Horsepower", "type": "quantitative"},
"y": {"field": "Miles_per_Gallon", "type": "quantitative"},
"color": {
"condition": {"selection": "foo", "field": "Origin", "type": "nominal"},
"value": "grey"
},
"size": {
"condition": {"selection": "foo", "field": "Cylinders", "type": "nominal"},
"value": 0
}
}
} Multiple selections each that map to one legend{
"$schema": "htts://vega.github.io/schema/vega-lite/v3.json",
"description": "A scatterplot showing horsepower and miles per gallons.",
"data": {"url": "data/cars.json"},
"mark": "circle",
"selection": {
"foo": {"type": "multi", "fields": ["Origin"]},
"bar": {"type": "multi", "fields": ["Cylinders"]}
},
"encoding": {
"x": {"field": "Horsepower", "type": "quantitative"},
"y": {"field": "Miles_per_Gallon", "type": "quantitative"},
"color": {
"condition": {"selection": "foo", "field": "Origin", "type": "nominal"},
"value": "grey"
},
"size": {
"condition": {"selection": "bar", "field": "Cylinders", "type": "nominal"},
"value": 0
}
}
} Interactive Legends when unioning a selection across multiple views{
"$schema": "https://vega.github.io/schema/vega-lite/v3.json",
"repeat": {
"row": ["Horsepower", "Acceleration", "Miles_per_Gallon"],
"column": ["Miles_per_Gallon", "Acceleration", "Horsepower"]
},
"spec": {
"data": {"url": "data/cars.json"},
"mark": "circle",
"selection": {
"brush": {
"type": "multi", "fields": ["Origin"],
"resolve": "union"
}
},
"encoding": {
"x": {"field": {"repeat": "column"}, "type": "quantitative"},
"y": {
"field": {"repeat": "row"},
"type": "quantitative",
"axis": {"minExtent": 30}
},
"color": {
"condition": {
"selection": "brush",
"field": "Origin",
"type": "nominal"
},
"value": "grey"
}
}
}
}
Let me know what you think. Besides bugs, do interactive legends work as you expect them to or are there cases where their behavior is unexpected? /cc @djbarnwal, @domoritz, @kanitw, @jheer |
|
This is necessary when a selection is projected over several fields. Using vlSelectionTest will cause all legend items to appear unselected, even if one of the values is within in the selection. Instead, we now test only for the legend item itself, via the top-level resolved signal.
Augmenting existing signal logic with legend events yields buggy behavior when toggling values from the store based on unit name. It is also less efficient in multi-view cases, as each individual view would modify the store based on legend events. Instead, the legend selection transform adds a top-level signal to coordinate all legends for a given selection. Moreover, it allows users to selectively disable interactive legend processing (i.e., "legends": false in a selection definition).
e531677
to
f96e699
Compare
c98e8aa
to
d799578
Compare
Are we changing the design based on @jheer's comment in #1657 (comment)? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See my comments. Otherwise, it looks good. Feel free to merge when this is done.
"encode": {"symbols": {"update": {"opacity": {"value": 0.7}}}} | ||
"encode": { | ||
"symbols": { | ||
"name": "gender_legend_symbols", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This chart isn't interactive so it shouldn't have a name for the legend, right?
55d8462
to
edf24d5
Compare
edf24d5
to
473eefa
Compare
9ba36ec
to
d002977
Compare
76bdf54
to
47cec23
Compare
This spec leads to an error "Converting circular structure to JSON" {
"$schema": "https://vega.github.io/schema/vega-lite/v4.json",
"data": {"url": "data/cars.json"},
"selection": {
"sel": {
"type": "multi", "fields": ["Origin"], "bind": "legend"
}
},
"mark": "point",
"encoding": {
"x": {"field": "Horsepower", "type": "quantitative"},
"y": {"field": "Miles_per_Gallon", "type": "quantitative"},
"shape": {"field": "Origin", "type": "nominal"},
"color": {
"condition": {"selection": "sel", "field": "Origin", "type": "nominal"},
"value": "gray"
}
}
} |
In this spec below, I would expect the shape to depend on the selection. Instead, Vega-Lite filters the data by the selection. I think the actual behavior makes a lot more sense but it's not what the spec says, no? {
"$schema": "https://vega.github.io/schema/vega-lite/v4.json",
"data": {"url": "data/cars.json"},
"selection": {
"sel": {
"type": "multi", "fields": ["Origin"], "bind": "legend"
}
},
"mark": "point",
"encoding": {
"x": {"field": "Horsepower", "type": "quantitative"},
"y": {"field": "Miles_per_Gallon", "type": "quantitative"},
"shape": {
"condition": {"selection": "sel", "field": "Origin", "type": "nominal"},
"value": "rectangle"
}
}
}
|
#5305 (comment) seems to be happening in legend assemble. It looks like the problem is coming from the |
Fixed in 17bb58d but I'm not happy with the fix. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good except #5305 (comment)
Co-Authored-By: Dominik Moritz <[email protected]>
This PR supersedes #4732 and makes legends interactive when there exists a selection that has been projected over the legend's domain. If the legend only partially matches the selection's projection (e.g., a color legend for
Origin
when the selection is projected over["Origin", "Cylinders"]
) the legend is still interactive and only partially populates the selection predicate (i.e., clicking "Europe" will select all "Europe" cars without any "Cylinders" specified.)/cc @djbarnwal