I've created a dual-axis chart with VegaLite following this example:
{
"data": {
"values": [
{"date": "2021-01-22", "var": "A", "value": 2.4},
// ...
{"date": "2022-07-22", "var": "A", "value": -0.45},
{"date": "2021-01-22", "var": "B", "value": 15.971434953055383},
// ...
{"date": "2022-07-22", "var": "B", "value": 19.00449486480307}
]
},
"encoding": {
"x": {"type": "temporal", "field": "date", "title": null},
"y": {
"type": "quantitative",
"field": "value",
"scale": {"nice": false, "zero": false}
},
"color": { "field": "var" }
},
"layer": [
{
"name": "leftAxis",
"layer": [
{ "mark": {"type": "line", "point": false } }
],
"transform": [ { "filter": "datum.var == 'A'" } ],
"encoding": {
"y": {
"type": "quantitative",
"field": "value",
"scale": {"nice": false, "zero": false},
"axis": { "title": "A", "tickCount": 5 }
}
}
},
{
"name": "rightAxis",
"layer": [
{
"mark": {"type": "line", "point": false }
}
],
"transform": [ { "filter": "datum.var == 'B'" } ],
"encoding": {
"y": {
"type": "quantitative",
"field": "value",
"scale": {"nice": false, "zero": false},
"axis": { "title": "B", "tickCount": 5 }
}
}
}
],
"resolve": {
"scale": {
"y": "independent"
}
}
}
(full playground) This renders roughly as I'd expect:
Now I'd like to add a hover interaction to display a circle and tooltip for the closest point, which could be on either series (on either axis).
I can do this by adding a circle mark on left axis (full playground):
{
"mark": {
"type": "circle",
"tooltip": true
},
"params": [
{
"name": "hover",
"select": {
"type": "point",
"on": "pointerover",
"clear": "pointerout",
"nearest": true
}
}
],
"encoding": {
"opacity": {
"value": 0,
"condition": {"test": {"param": "hover", "empty": false}}
},
"size": { "value": 100 }
}
}
Of course, this only selects points on series A, even if the mouse is much closer to a point on series B:
If I define an identical "hover" param on the right axis (playground), I get the following error:
Duplicate signal name: "hover_tuple"
If I give it a different name ("hover2"), then I'm only able to highlight points on the right axis (playground).
If I move that param to the top level (playground), I also get a duplicate signal error, which surprises me since the signal only seems to be defined in one place.
Is there any way to combine a highlight effect with dual axes in VegaLite?
{
"$schema": "https://vega.github.io/schema/vega/v6.json",
"description": "A basic line chart example.",
"width": 800,
"height": 400,
"padding": 5,
"signals": [
{
"name": "hover",
"value": null,
"on": [
{"events": "@cell:pointerover", "update": "datum.id"},
{"events": "@cell:pointerout", "update": "null"}
]
}
],
"data": [
{
"name": "table",
"values": [
{"date": "2021-01-22", "var": "A", "value": 2.4},
{"date": "2021-02-26", "var": "A", "value": 2.15},
{"date": "2021-04-02", "var": "A", "value": 2.65},
{"date": "2021-05-07", "var": "A", "value": 4.94},
{"date": "2021-06-11", "var": "A", "value": 7.03},
{"date": "2021-07-16", "var": "A", "value": 2.62},
{"date": "2021-08-20", "var": "A", "value": 2.32},
{"date": "2021-10-22", "var": "A", "value": 1.39},
{"date": "2021-12-03", "var": "A", "value": 1.27},
{"date": "2022-01-28", "var": "A", "value": 0.83},
{"date": "2022-03-11", "var": "A", "value": 0.61},
{"date": "2022-03-18", "var": "A", "value": 0.54},
{"date": "2022-03-25", "var": "A", "value": 0.5},
{"date": "2022-05-13", "var": "A", "value": -0.03},
{"date": "2022-05-20", "var": "A", "value": -0.08},
{"date": "2022-07-22", "var": "A", "value": -0.45},
{"date": "2021-01-22", "var": "B", "value": 15.971434953055383},
{"date": "2021-02-26", "var": "B", "value": 13.966284390867731},
{"date": "2021-04-02", "var": "B", "value": 16.358341860127812},
{"date": "2021-05-07", "var": "B", "value": 11.754610521151442},
{"date": "2021-06-11", "var": "B", "value": 13.05470556984986},
{"date": "2021-07-16", "var": "B", "value": 14.570909286399319},
{"date": "2021-08-20", "var": "B", "value": 12.504173067976124},
{"date": "2021-10-22", "var": "B", "value": 11.385928956770012},
{"date": "2021-12-03", "var": "B", "value": 15.50068082291583},
{"date": "2022-01-28", "var": "B", "value": 12.68456514521299},
{"date": "2022-03-11", "var": "B", "value": 12.81006294043777},
{"date": "2022-03-18", "var": "B", "value": 17.39343219509385},
{"date": "2022-03-25", "var": "B", "value": 12.388043904430008},
{"date": "2022-05-13", "var": "B", "value": 14.424112206944333},
{"date": "2022-05-20", "var": "B", "value": 18.653838013972276},
{"date": "2022-07-22", "var": "B", "value": 19.00449486480307}
],
"transform": [
{"type": "formula", "expr": "toDate(datum[\"date\"])", "as": "date"}
]
},
{
"name": "data_1",
"source": "table",
"transform": [{"type": "filter", "expr": "datum.var == 'A'"}]
},
{
"name": "data_2",
"source": "table",
"transform": [{"type": "filter", "expr": "datum.var == 'B'"}]
},
{
"name": "data_3",
"source": "table",
"transform": [
{
"type": "formula",
"expr": "datum.var=='A'?scale('y1', datum.value):scale('y2', datum.value)",
"as": "y"
},
{"type": "formula", "expr": "scale('x', datum.date)", "as": "x"},
{"type": "window", "ops": ["row_number"], "as": ["id"]},
{
"type": "voronoi",
"x": "x",
"y": "y",
"size": [{"signal": "width"}, {"signal": "height"}]
}
]
}
],
"scales": [
{
"name": "x",
"type": "time",
"domain": {"fields": [{"data": "table", "field": "date"}]},
"range": [0, {"signal": "width"}]
},
{
"name": "y1",
"type": "linear",
"range": "height",
"nice": true,
"domain": {"data": "data_1", "field": "value"}
},
{
"name": "y2",
"type": "linear",
"range": "height",
"nice": true,
"zero": false,
"domain": {"data": "data_2", "field": "value"}
}
],
"axes": [
{"orient": "bottom", "scale": "x"},
{"orient": "left", "scale": "y1"},
{"orient": "right", "scale": "y2"}
],
"marks": [
{
"type": "line",
"from": {"data": "data_1"},
"encode": {
"enter": {
"x": {"scale": "x", "field": "date"},
"y": {"scale": "y1", "field": "value"},
"stroke": {"value": "blue"},
"strokeWidth": {"value": 2}
},
"update": {
"interpolate": {"signal": "'linear'"},
"strokeOpacity": {"value": 1}
}
}
},
{
"type": "line",
"from": {"data": "data_2"},
"encode": {
"enter": {
"x": {"scale": "x", "field": "date"},
"y": {"scale": "y2", "field": "value"},
"stroke": {"value": "orange"},
"strokeWidth": {"value": 2}
},
"update": {
"interpolate": {"signal": "'linear'"},
"strokeOpacity": {"value": 1}
}
}
},
{
"name": "cell",
"type": "path",
"from": {"data": "data_3"},
"encode": {
"enter": {
"stroke": {"value": "transparent"},
"path": {"field": "path"}
},
"update": {"fill": {"signal": "'transparent'"}}
}
},
{
"type": "symbol",
"from": {"data": "cell"},
"encode": {
"update": {
"x": {"signal": "datum.datum.x"},
"y": {"signal": "datum.datum.y"},
"fill": {"value": "red"},
"size": {"signal": "100"},
"opacity": {"signal": "datum.datum.id==hover?1:0"}
}
}
}
]
}