Interactive Visualizations with Vega

Reactive Building Blocks
Interactive Visualizations with Vega
Arvind Satyanarayan @arvindsatya1
Stanford University
Jane Hoffswell
Dominik Moritz @domoritz
Kanit "Ham" Wongsuphasawat @kanitw
Jeffrey Heer @jeffrey_heer
University of Washington
1
Three Little Circles *
Visual Design
var circle = svg.selectAll('circle')
.data([32, 57, 293]);
circle.enter().append('circle')
.attr('fill', 'steelblue')
.attr('cy', 60)
.attr('cx',
function(d, i) { return i * 100 + 30; })
.attr('r',
function(d) { return Math.sqrt(d); });
Map data values to visual properties.
Declarative design: specify what we want,
rather than how it should be computed.
* Mike Bostock, 2014. https://bost.ocks.org/mike/circles/
Interaction Design
var dragging = null;
circle.on('mousedown', function() {
dragging = d3.select(this)
.attr('fill', 'goldenrod');
});
d3.select(window).on('mouseup', function() {
dragging.attr('fill', 'steelblue');
dragging = null;
}).on('mousemove', function() {
if (!dragging) return;
dragging.attr('cy', d3.event.pageY);
d3.event.stopPropagation();
});
Imperative design: define explicit steps
of how it should be computed.
2
The Trouble with Imperative Interaction
var dragging = null;
circle.on('mousedown', function() {
dragging = d3.select(this)
.attr('fill', 'goldenrod');
});
d3.select(window).on('mouseup', function() {
dragging.attr('fill', 'steelblue');
dragging = null;
}).on('mousemove', function() {
if (!dragging) return;
dragging.attr('cy', d3.event.pageY);
d3.event.stopPropagation();
});
1. Manually maintain state.
2. Re-define visual appearance
in multiple locations.
3. Low-level idiosyncrasies.
4. Callback Hell: unpredictable
and interleaved execution.
7
1. Manually maintain state.
2. Re-define visual appearance
in multiple locations.
3. Low-level idiosyncrasies.
4. Callback Hell: unpredictable
and interleaved execution.
8
1. Manually maintain state.
2. Re-define visual appearance
in multiple locations.
3. Low-level idiosyncrasies.
4. Callback Hell: unpredictable
and interleaved execution.
9
Reactive Programming
10
Reactive Programming
Events are streaming data. Dynamic variables (signals) automatically update.
10
Data +
Transforms
Scales
Guides
Marks
{...
"width": 650, "height": 300,
"data": [...
{"name": "iris", "url": "data/iris.json"},
{"name": "fields", "values": ["sepalWidth", ...]
],
"scales": [...
{...
"name": "color", "type": "ordinal",
"domain": {"data": "iris", "field": "species"}
"range": "category20"
}, ...
],
"legends": [...
{"fill": "x", "scale": "color"}
],
"marks": [{...
"type": "group",
"from": {...
"data": "fields",
"transform": [{"type": "cross"}]...
},
"marks": [{...
"type": "symbol",
"from": {"data": "iris"},
"properties": { "enter": {...
"x": {"scale": "sx", "field": "date"},
"y": {"scale": "sy", "field": "price"},
"stroke": {"scale": "sc", "field": "symbol"}
}}
}],
"scales": [{...
"name": "sx", "type": "linear",
"domain": {"data": "iris", "field": {"parent": "a.data"},
15
Data +
Event Streams +
[mousedown, mouseup] > mousemove
Transforms
Signals
minX = min(width, event.x)
Scales
Scale Inversions
minVal = xScale.invert(minX)
Guides
Predicates
p(t) = minVal ≤ t.value ≤ maxVal
Marks
Production Rules
fill = p(t) ! colorScale(t.category)
∅ ! gray
16
Example
Brushing & Linking
17
Events are a form of streaming data.
mousemove
mousemove
mousemove
A stream of mousemove events that occur on rect marks .
rect:mousemove
19
*:mousedown, *:mouseup
a single stream merges mousedown and
*:mousedown, *:mouseup
mouseup
streams
single
stream merges
mousedown and mouseup streams.
mousedown
[*:mousedown, *:mouseup] > *:mousemove
A stream of mousemove events that occur between
[*:mousedown,
> *:mousemove
a mousedown*:mouseup]
and a mouseup
(aka drag)
stream of mousemove events that occur between mousedown and mouseup
mousedown
mousedown
mousedown
mouseup
mousedown
mousemove
mousemove
mousemove
mousemove
mouseup
mousemove
mouseup
*:click[event.pageY >= 300]
[data.price < 500]
filtered stream of click events
click
click
click
click
click
price = 300
pageY = 500
price = 750
pageY = 310
price = 425
pageY = 170
price = 115
pageY = 333
price = 500
pageY = 55
click
click
*:mousemove{3ms,5ms}
stream of mousemove events that occur at least
3ms, and at most 5ms, apart
*:mousemove{3ms,5ms}
(debouncing/throttling)
stream of mousemove events that occur at least 3ms, and at most 5ms, apart
mousemove
mousemove
mousemove
mousemove
mousemove
mousemove
0ms
mouseup
2ms
4ms
mousemove
6ms
8ms
10ms
20
mousedown
[mousedown, mouseup] >
mousemove
21
mousedown
Signal
[mousedown, mouseup] >
mousemove
Signal
21
mousedown
Signal
Start
(x, y)
Signal
End
(x, y)
[mousedown, mouseup] >
mousemove
21
mousedown
Signal
Start
(x, y)
Rect
Mark
[mousedown, mouseup] >
mousemove
Signal
End
(x, y)
22
mousedown
Signal
Start
(x, y)
Rect
Mark
[mousedown, mouseup] >
mousemove
Signal
End
(x, y)
22
mousedown
Signal
Start
(x, y)
Predicate
[mousedown, mouseup] >
mousemove
Signal
End
(x, y)
23
mousedown
Signal
Start
(x, y)
Predicate
[mousedown, mouseup] >
mousemove
Signal
End
Selection
xstart ≤ xpt ≤ xend
&&
ystart ≤ ypt ≤ yend
(x, y)
23
mousedown
Signal
Start
(x, y)
Inside Brush
[mousedown, mouseup] >
mousemove
Signal
End
Selection
xstart ≤ xpt ≤ xend
&&
ystart ≤ ypt ≤ yend
(x, y)
24
Circle Mark
mousedown
Signal
Start
(x, y)
Inside Brush
[mousedown, mouseup] >
mousemove
Signal
End
Fill Rule
Selection
xstart ≤ xpt ≤ xend
&&
ystart ≤ ypt ≤ yend
(x, y)
24
Circle Mark
Signal
Start
(x, y)
Fill Rule
if
Inside Brush
[mousedown, mouseup] >
mousemove
Signal
End
Inside Brush
(Scaled
species)
mousedown
blue
orange
green
Selection
xstart ≤ xpt ≤ xend
&&
ystart ≤ ypt ≤ yend
(x, y)
24
Circle Mark
Signal
Start
(x, y)
Fill Rule
if
Inside Brush
else
gray
Inside Brush
[mousedown, mouseup] >
mousemove
Signal
End
(Scaled
species)
mousedown
blue
orange
green
Selection
xstart ≤ xpt ≤ xend
&&
ystart ≤ ypt ≤ yend
(x, y)
24
mousedown
Signal
Start
(x, y)
Inside Brush
[mousedown, mouseup] >
mousemove
Signal
End
Selection
xstart ≤ xpt ≤ xend
&&
ystart ≤ ypt ≤ yend
(x, y)
26
mousedown
Signal
Start
event.target
Scatterplot
[mousedown, mouseup] >
mousemove
Signal
End
(x, y)
Inside Brush
Selection
xstart ≤ xpt ≤ xend
&&
ystart ≤ ypt ≤ yend
(x, y)
26
mousedown
Signal
Start
(x, y)
Scale Inversion
event.target
Scatterplot
Inside Brush
Selection
xstart ≤ xpt ≤ xend
&&
ystart ≤ ypt ≤ yend
Scale Inversion
[mousedown, mouseup] >
mousemove
Signal
End
(x, y)
27
mousedown
Signal
Start
(x, y)
Scale Inversion
event.target
Scatterplot
Inside Brush
Query
sepalstart ≤ sepalpt ≤ sepalend
&&
petalstart ≤ petalpt ≤ petalend
Scale Inversion
[mousedown, mouseup] >
mousemove
Signal
End
(x, y)
28
Circle Mark
Signal
Start
(x, y)
Fill Rule
if
Scale Inversion
event.target
Scatterplot
Inside Brush
Inside Brush
else
gray
(Scaled
species)
mousedown
blue
orange
green
Query
sepalstart ≤ sepalpt ≤ sepalend
&&
petalstart ≤ petalpt ≤ petalend
Scale Inversion
[mousedown, mouseup] >
mousemove
Signal
End
(x, y)
28
Circle Mark
Signal
Start
(x, y)
Fill Rule
if
Scale Inversion
event.target
Scatterplot
Inside Brush
else
gray
(Scaled
species)
mousedown
blue
orange
green
Inside Brush
Scale Inversion
[mousedown, mouseup] >
mousemove
Signal
End
(x, y)
29
mousedown
Start
(x, y)
Scale Inversion
Scatterplot
Inside Brush
Scale Inversion
[mousedown, mouseup] >
mousemove
End
(x, y)
Circle Mark
if
Inside Brush
else
gray
(Scaled
species)
Fill Rule
blue
orange
green
30
mousedown
Start
(x, y)
Declarative Interaction Design
Scale Inversion
Scatterplot
Inside Brush
Scale Inversion
[mousedown, mouseup] >
mousemove
End
(x, y)
Circle Mark
if
Inside Brush
else
gray
(Scaled
species)
Fill Rule
blue
orange
green
30
mousedown
Start
(x, y)
Scale Inversion
Scatterplot
Declarative Interaction Design
✓
Faster iteration + accessible to a
larger audience.
Inside Brush
Scale Inversion
[mousedown, mouseup] >
mousemove
End
(x, y)
Circle Mark
if
Inside Brush
else
gray
(Scaled
species)
Fill Rule
blue
orange
green
30
mousedown
Start
(x, y)
Declarative Interaction Design
✓
Faster iteration + accessible to a
larger audience.
✓
Performance + scalability.
Scale Inversion
Scatterplot
Inside Brush
At least 2x faster than D3 + callbacks†.
Scale Inversion
[mousedown, mouseup] >
mousemove
End
(x, y)
Circle Mark
if
Inside Brush
else
gray
(Scaled
species)
Fill Rule
blue
orange
green
† http://github.com/vega/vega-benchmarks
30
mousedown
Start
(x, y)
Declarative Interaction Design
✓
Faster iteration + accessible to a
larger audience.
✓
Performance + scalability.
Scale Inversion
Scatterplot
Inside Brush
Scale Inversion
[mousedown, mouseup] >
mousemove
End
(x, y)
At least 2x faster than D3 + callbacks†.
✓
Reuse + portability.
Write once. Re-apply with different
input data. Re-target to multiple
devices, renderers, or modalities.
Circle Mark
if
Inside Brush
else
gray
(Scaled
species)
Fill Rule
blue
orange
green
† http://github.com/vega/vega-benchmarks
30
Start
(x, y)
Declarative Interaction Design
✓
Faster iteration + accessible to a
larger audience.
✓
Performance + scalability.
Scale Inversion
Scatterplot
Inside Brush
Scale Inversion
End
(x, y)
At least 2x faster than D3 + callbacks†.
✓
Reuse + portability.
Write once. Re-apply with different
input data. Re-target to multiple
devices, renderers, or modalities.
Circle Mark
if
Inside Brush
else
gray
(Scaled
species)
Fill Rule
blue
orange
green
† http://github.com/vega/vega-benchmarks
31
touchstart
Start
(x, y)
Declarative Interaction Design
✓
Faster iteration + accessible to a
larger audience.
✓
Performance + scalability.
Scale Inversion
Scatterplot
Inside Brush
Scale Inversion
[touchstart, touchend] >
touchmove
End
(x, y)
At least 2x faster than D3 + callbacks†.
✓
Reuse + portability.
Write once. Re-apply with different
input data. Re-target to multiple
devices, renderers, or modalities.
Circle Mark
if
Inside Brush
else
gray
(Scaled
species)
Fill Rule
blue
orange
green
† http://github.com/vega/vega-benchmarks
32
Demo
http://vega.github.io/vega-editor
33
vega.github.io/vega/
34
One more thing...
35
Interactive Vega-Lite
36
Interactive Vega-Lite
(A Sneak Peak)
36
can be initialized
{
"repeat": {"column": ["hour", "delay", "distance"]},
{...
"data": {"url": "data/flights.json"}, Data
"mark": "bar",
Mark
"encoding": {...
"x": {"field": "hour", "bin": true, "type": "quantitative",},
"y": {"field": "*", "aggregate": "count", "type": "quantitative"}
}...
Transforms + Scales & Guides (not shown)
}...
}
41
can be initialized
{...
"repeat": {"column": ["hour", "delay", "distance"]},
"spec": {
"data": {"url": "data/flights.json"},
"mark": "bar",
"encoding": {
"x": {"field": {"repeat": "column"}, "bin": true, "type": "quantitative"},
"y": {"field": "*", "aggregate": "count", "type": "quantitative"}
}...
}...
}...
43
{
can be initialized
"repeat": {"column": ["hour", "delay", "distance"]},
"spec": {
"layers": [{
"data": {"url": "data/flights.json"},
"mark": "bar",
"encoding": {
"x": {"field": {"repeat": "column"}, "bin": true, "type": "quantitative"},
"y": {"field": "*", "aggregate": "count", "type": "quantitative"}
}
}, {
...,
"encoding": {
...,
"color": {"value": "goldenrod"}
}
}]
}
}
45
{
can be initialized
"repeat": {"column": ["hour", "delay", "distance"]},
"spec": {
"layers": [{
...,
"mark": "bar",
"encoding": {
"x": {"field": {"repeat": "column"}, "type": "Q", "bin": true},
"y": {"aggregate": "count", "field": "*", "type": "Q"}
}
}, {
...,
}]
}
}
46
{
can be initialized
"repeat": {"column": ["hour", "delay", "distance"]},
"spec": {
"layers": [{
...,
"select": {
"region": {
"type": "interval", "project": {"channels": ["x"]}, ...
}
}
}, {
...,
}]
}
}
47
{
can be initialized
"repeat": {"column": ["hour", "delay", "distance"]},
"spec": {
"layers": [{
...,
"select": {
"region": {
"type": "interval", "project": {"channels": ["x"]}, ...
}
}
}, {
...,
"transform": {"filterWith": "region"}
}]
}
}
48
{
can be initialized
"repeat": {"column": ["hour", "delay", "distance"]},
"spec": {
"layers": [{
...,
"select": {
"region": {
"type": "interval", "project": {"channels": ["x"]}, ...
}
}
}, {
...,
"transform": {"filterWith": "region"}
}]
}
35 Lines
of JSON!!
}
48
can be initialized
49
Lyra
Vega-Lite
Wikipedia
Altair
PoleStar
Voyager
Vega: A Platform for Visualization
Vega
D3
JavaScript
SVG
Canvas
50
Lyra
Vega-Lite
Wikipedia
Altair
PoleStar
Voyager
Vega: A Platform for Visualization
Vega
D3
JavaScript
SVG
Canvas
50
Lyra
Vega-Lite
Wikipedia
Altair
PoleStar
Voyager
Vega: A Platform for Visualization
Vega
D3
JavaScript
SVG
Canvas
50
Lyra
Vega-Lite
Wikipedia
Altair
PoleStar
Voyager
Vega: A Platform for Visualization
?
Vega
D3
JavaScript
SVG
Canvas
50
vega.github.io
51