diff --git a/examples/compiled/interactive_crossfilter.png b/examples/compiled/interactive_crossfilter.png new file mode 100644 index 0000000000..e68befa8f3 Binary files /dev/null and b/examples/compiled/interactive_crossfilter.png differ diff --git a/examples/compiled/interactive_crossfilter.svg b/examples/compiled/interactive_crossfilter.svg new file mode 100644 index 0000000000..04569718d1 --- /dev/null +++ b/examples/compiled/interactive_crossfilter.svg @@ -0,0 +1 @@ +02004006008001,0001,2001,4001,6001,8002,0002,2002,400distance (binned)−40−20020406080100120140160180200220240260delay (binned)024681012141618202224time (binned) \ No newline at end of file diff --git a/examples/compiled/interactive_crossfilter.vg.json b/examples/compiled/interactive_crossfilter.vg.json new file mode 100644 index 0000000000..32ea6aecfd --- /dev/null +++ b/examples/compiled/interactive_crossfilter.vg.json @@ -0,0 +1,1122 @@ +{ + "$schema": "https://vega.github.io/schema/vega/v5.json", + "background": "white", + "padding": 5, + "data": [ + {"name": "brush_store"}, + { + "name": "source_0", + "url": "data/flights-2k.json", + "format": {"type": "json", "parse": {"date": "date"}}, + "transform": [ + { + "type": "extent", + "field": "delay", + "signal": "child__column_delay_layer_0_bin_maxbins_20_delay_extent" + }, + { + "type": "bin", + "field": "delay", + "as": ["bin_maxbins_20_delay", "bin_maxbins_20_delay_end"], + "signal": "child__column_delay_layer_0_bin_maxbins_20_delay_bins", + "extent": { + "signal": "child__column_delay_layer_0_bin_maxbins_20_delay_extent" + }, + "maxbins": 20 + }, + { + "type": "extent", + "field": "distance", + "signal": "child__column_distance_layer_0_bin_maxbins_20_distance_extent" + }, + { + "type": "bin", + "field": "distance", + "as": ["bin_maxbins_20_distance", "bin_maxbins_20_distance_end"], + "signal": "child__column_distance_layer_0_bin_maxbins_20_distance_bins", + "extent": { + "signal": "child__column_distance_layer_0_bin_maxbins_20_distance_extent" + }, + "maxbins": 20 + }, + {"type": "formula", "expr": "hours(datum.date)", "as": "time"} + ] + }, + { + "name": "data_0", + "source": "source_0", + "transform": [ + { + "type": "extent", + "field": "time", + "signal": "child__column_time_layer_0_bin_maxbins_20_time_extent" + }, + { + "type": "bin", + "field": "time", + "as": ["bin_maxbins_20_time", "bin_maxbins_20_time_end"], + "signal": "child__column_time_layer_0_bin_maxbins_20_time_bins", + "extent": { + "signal": "child__column_time_layer_0_bin_maxbins_20_time_extent" + }, + "maxbins": 20 + }, + { + "type": "filter", + "expr": "!length(data(\"brush_store\")) || vlSelectionTest(\"brush_store\", datum)" + }, + { + "type": "aggregate", + "groupby": ["bin_maxbins_20_time", "bin_maxbins_20_time_end"], + "ops": ["count"], + "fields": [null], + "as": ["__count"] + }, + { + "type": "filter", + "expr": "isValid(datum[\"bin_maxbins_20_time\"]) && isFinite(+datum[\"bin_maxbins_20_time\"])" + } + ] + }, + { + "name": "data_1", + "source": "source_0", + "transform": [ + { + "type": "filter", + "expr": "!length(data(\"brush_store\")) || vlSelectionTest(\"brush_store\", datum)" + } + ] + }, + { + "name": "data_2", + "source": "data_1", + "transform": [ + { + "type": "aggregate", + "groupby": ["bin_maxbins_20_delay", "bin_maxbins_20_delay_end"], + "ops": ["count"], + "fields": [null], + "as": ["__count"] + }, + { + "type": "filter", + "expr": "isValid(datum[\"bin_maxbins_20_delay\"]) && isFinite(+datum[\"bin_maxbins_20_delay\"])" + } + ] + }, + { + "name": "data_3", + "source": "data_1", + "transform": [ + { + "type": "aggregate", + "groupby": ["bin_maxbins_20_distance", "bin_maxbins_20_distance_end"], + "ops": ["count"], + "fields": [null], + "as": ["__count"] + }, + { + "type": "filter", + "expr": "isValid(datum[\"bin_maxbins_20_distance\"]) && isFinite(+datum[\"bin_maxbins_20_distance\"])" + } + ] + } + ], + "signals": [ + {"name": "childWidth", "value": 200}, + {"name": "childHeight", "value": 200}, + { + "name": "unit", + "value": {}, + "on": [ + {"events": "pointermove", "update": "isTuple(group()) ? group() : unit"} + ] + }, + { + "name": "brush", + "update": "vlSelectionResolve(\"brush_store\", \"union\")" + } + ], + "layout": {"padding": 20, "columns": 3, "bounds": "full", "align": "all"}, + "marks": [ + { + "type": "group", + "name": "child__column_distance_group", + "style": "cell", + "encode": { + "update": { + "width": {"signal": "childWidth"}, + "height": {"signal": "childHeight"} + } + }, + "signals": [ + { + "name": "brush_x", + "value": [], + "on": [ + { + "events": { + "source": "scope", + "type": "pointerdown", + "filter": [ + "!event.item || event.item.mark.name !== \"brush_brush\"" + ] + }, + "update": "[x(unit), x(unit)]" + }, + { + "events": { + "source": "window", + "type": "pointermove", + "consume": true, + "between": [ + { + "source": "scope", + "type": "pointerdown", + "filter": [ + "!event.item || event.item.mark.name !== \"brush_brush\"" + ] + }, + {"source": "window", "type": "pointerup"} + ] + }, + "update": "[brush_x[0], clamp(x(unit), 0, childWidth)]" + }, + { + "events": {"signal": "brush_scale_trigger"}, + "update": "[scale(\"child__column_distance_x\", brush_distance[0]), scale(\"child__column_distance_x\", brush_distance[1])]" + }, + { + "events": [{"source": "view", "type": "dblclick"}], + "update": "[0, 0]" + }, + { + "events": {"signal": "brush_translate_delta"}, + "update": "clampRange(panLinear(brush_translate_anchor.extent_x, brush_translate_delta.x / span(brush_translate_anchor.extent_x)), 0, childWidth)" + }, + { + "events": {"signal": "brush_zoom_delta"}, + "update": "clampRange(zoomLinear(brush_x, brush_zoom_anchor.x, brush_zoom_delta), 0, childWidth)" + } + ] + }, + { + "name": "brush_distance", + "on": [ + { + "events": {"signal": "brush_x"}, + "update": "brush_x[0] === brush_x[1] ? null : invert(\"child__column_distance_x\", brush_x)" + } + ] + }, + { + "name": "brush_scale_trigger", + "value": {}, + "on": [ + { + "events": [{"scale": "child__column_distance_x"}], + "update": "(!isArray(brush_distance) || (+invert(\"child__column_distance_x\", brush_x)[0] === +brush_distance[0] && +invert(\"child__column_distance_x\", brush_x)[1] === +brush_distance[1])) ? brush_scale_trigger : {}" + } + ] + }, + { + "name": "brush_tuple", + "on": [ + { + "events": [{"signal": "brush_distance"}], + "update": "brush_distance ? {unit: \"child__column_distance_layer_0\", fields: brush_tuple_fields, values: [brush_distance]} : null" + } + ] + }, + { + "name": "brush_tuple_fields", + "value": [{"field": "distance", "channel": "x", "type": "R"}] + }, + { + "name": "brush_translate_anchor", + "value": {}, + "on": [ + { + "events": [ + { + "source": "scope", + "type": "pointerdown", + "markname": "brush_brush" + } + ], + "update": "{x: x(unit), y: y(unit), extent_x: slice(brush_x)}" + } + ] + }, + { + "name": "brush_translate_delta", + "value": {}, + "on": [ + { + "events": [ + { + "source": "window", + "type": "pointermove", + "consume": true, + "between": [ + { + "source": "scope", + "type": "pointerdown", + "markname": "brush_brush" + }, + {"source": "window", "type": "pointerup"} + ] + } + ], + "update": "{x: brush_translate_anchor.x - x(unit), y: brush_translate_anchor.y - y(unit)}" + } + ] + }, + { + "name": "brush_zoom_anchor", + "on": [ + { + "events": [ + { + "source": "scope", + "type": "wheel", + "consume": true, + "markname": "brush_brush" + } + ], + "update": "{x: x(unit), y: y(unit)}" + } + ] + }, + { + "name": "brush_zoom_delta", + "on": [ + { + "events": [ + { + "source": "scope", + "type": "wheel", + "consume": true, + "markname": "brush_brush" + } + ], + "force": true, + "update": "pow(1.001, event.deltaY * pow(16, event.deltaMode))" + } + ] + }, + { + "name": "brush_modify", + "on": [ + { + "events": {"signal": "brush_tuple"}, + "update": "modify(\"brush_store\", brush_tuple, true)" + } + ] + } + ], + "marks": [ + { + "name": "brush_brush_bg", + "type": "rect", + "clip": true, + "encode": { + "enter": { + "fill": {"value": "#333"}, + "fillOpacity": {"value": 0.125} + }, + "update": { + "x": [ + { + "test": "data(\"brush_store\").length && data(\"brush_store\")[0].unit === \"child__column_distance_layer_0\"", + "signal": "brush_x[0]" + }, + {"value": 0} + ], + "y": [ + { + "test": "data(\"brush_store\").length && data(\"brush_store\")[0].unit === \"child__column_distance_layer_0\"", + "value": 0 + }, + {"value": 0} + ], + "x2": [ + { + "test": "data(\"brush_store\").length && data(\"brush_store\")[0].unit === \"child__column_distance_layer_0\"", + "signal": "brush_x[1]" + }, + {"value": 0} + ], + "y2": [ + { + "test": "data(\"brush_store\").length && data(\"brush_store\")[0].unit === \"child__column_distance_layer_0\"", + "field": {"group": "height"} + }, + {"value": 0} + ] + } + } + }, + { + "name": "child__column_distance_layer_0_marks", + "type": "rect", + "style": ["bar"], + "interactive": true, + "from": {"data": "data_3"}, + "encode": { + "update": { + "fill": {"value": "#4c78a8"}, + "ariaRoleDescription": {"value": "bar"}, + "description": { + "signal": "\"distance (binned): \" + (!isValid(datum[\"bin_maxbins_20_distance\"]) || !isFinite(+datum[\"bin_maxbins_20_distance\"]) ? \"null\" : format(datum[\"bin_maxbins_20_distance\"], \"\") + \" – \" + format(datum[\"bin_maxbins_20_distance_end\"], \"\")) + \"; Count of Records: \" + (format(datum[\"__count\"], \"\"))" + }, + "x2": { + "scale": "child__column_distance_x", + "field": "bin_maxbins_20_distance", + "offset": { + "signal": "0.5 + (abs(scale(\"child__column_distance_x\", datum[\"bin_maxbins_20_distance_end\"]) - scale(\"child__column_distance_x\", datum[\"bin_maxbins_20_distance\"])) < 0.25 ? -0.5 * (0.25 - (abs(scale(\"child__column_distance_x\", datum[\"bin_maxbins_20_distance_end\"]) - scale(\"child__column_distance_x\", datum[\"bin_maxbins_20_distance\"])))) : 0.5)" + } + }, + "x": { + "scale": "child__column_distance_x", + "field": "bin_maxbins_20_distance_end", + "offset": { + "signal": "0.5 + (abs(scale(\"child__column_distance_x\", datum[\"bin_maxbins_20_distance_end\"]) - scale(\"child__column_distance_x\", datum[\"bin_maxbins_20_distance\"])) < 0.25 ? 0.5 * (0.25 - (abs(scale(\"child__column_distance_x\", datum[\"bin_maxbins_20_distance_end\"]) - scale(\"child__column_distance_x\", datum[\"bin_maxbins_20_distance\"])))) : -0.5)" + } + }, + "y": {"scale": "child__column_distance_y", "field": "__count"}, + "y2": {"scale": "child__column_distance_y", "value": 0} + } + } + }, + { + "name": "brush_brush", + "type": "rect", + "clip": true, + "encode": { + "enter": {"fill": {"value": "transparent"}}, + "update": { + "x": [ + { + "test": "data(\"brush_store\").length && data(\"brush_store\")[0].unit === \"child__column_distance_layer_0\"", + "signal": "brush_x[0]" + }, + {"value": 0} + ], + "y": [ + { + "test": "data(\"brush_store\").length && data(\"brush_store\")[0].unit === \"child__column_distance_layer_0\"", + "value": 0 + }, + {"value": 0} + ], + "x2": [ + { + "test": "data(\"brush_store\").length && data(\"brush_store\")[0].unit === \"child__column_distance_layer_0\"", + "signal": "brush_x[1]" + }, + {"value": 0} + ], + "y2": [ + { + "test": "data(\"brush_store\").length && data(\"brush_store\")[0].unit === \"child__column_distance_layer_0\"", + "field": {"group": "height"} + }, + {"value": 0} + ], + "stroke": [ + {"test": "brush_x[0] !== brush_x[1]", "value": "white"}, + {"value": null} + ] + } + } + } + ], + "axes": [ + { + "scale": "child__column_distance_x", + "orient": "bottom", + "grid": false, + "title": "distance (binned)", + "labelFlush": true, + "labelOverlap": true, + "tickCount": {"signal": "ceil(childWidth/10)"}, + "zindex": 0 + } + ] + }, + { + "type": "group", + "name": "child__column_delay_group", + "style": "cell", + "encode": { + "update": { + "width": {"signal": "childWidth"}, + "height": {"signal": "childHeight"} + } + }, + "signals": [ + { + "name": "brush_x", + "value": [], + "on": [ + { + "events": { + "source": "scope", + "type": "pointerdown", + "filter": [ + "!event.item || event.item.mark.name !== \"brush_brush\"" + ] + }, + "update": "[x(unit), x(unit)]" + }, + { + "events": { + "source": "window", + "type": "pointermove", + "consume": true, + "between": [ + { + "source": "scope", + "type": "pointerdown", + "filter": [ + "!event.item || event.item.mark.name !== \"brush_brush\"" + ] + }, + {"source": "window", "type": "pointerup"} + ] + }, + "update": "[brush_x[0], clamp(x(unit), 0, childWidth)]" + }, + { + "events": {"signal": "brush_scale_trigger"}, + "update": "[scale(\"child__column_delay_x\", brush_delay[0]), scale(\"child__column_delay_x\", brush_delay[1])]" + }, + { + "events": [{"source": "view", "type": "dblclick"}], + "update": "[0, 0]" + }, + { + "events": {"signal": "brush_translate_delta"}, + "update": "clampRange(panLinear(brush_translate_anchor.extent_x, brush_translate_delta.x / span(brush_translate_anchor.extent_x)), 0, childWidth)" + }, + { + "events": {"signal": "brush_zoom_delta"}, + "update": "clampRange(zoomLinear(brush_x, brush_zoom_anchor.x, brush_zoom_delta), 0, childWidth)" + } + ] + }, + { + "name": "brush_delay", + "on": [ + { + "events": {"signal": "brush_x"}, + "update": "brush_x[0] === brush_x[1] ? null : invert(\"child__column_delay_x\", brush_x)" + } + ] + }, + { + "name": "brush_scale_trigger", + "value": {}, + "on": [ + { + "events": [{"scale": "child__column_delay_x"}], + "update": "(!isArray(brush_delay) || (+invert(\"child__column_delay_x\", brush_x)[0] === +brush_delay[0] && +invert(\"child__column_delay_x\", brush_x)[1] === +brush_delay[1])) ? brush_scale_trigger : {}" + } + ] + }, + { + "name": "brush_tuple", + "on": [ + { + "events": [{"signal": "brush_delay"}], + "update": "brush_delay ? {unit: \"child__column_delay_layer_0\", fields: brush_tuple_fields, values: [brush_delay]} : null" + } + ] + }, + { + "name": "brush_tuple_fields", + "value": [{"field": "delay", "channel": "x", "type": "R"}] + }, + { + "name": "brush_translate_anchor", + "value": {}, + "on": [ + { + "events": [ + { + "source": "scope", + "type": "pointerdown", + "markname": "brush_brush" + } + ], + "update": "{x: x(unit), y: y(unit), extent_x: slice(brush_x)}" + } + ] + }, + { + "name": "brush_translate_delta", + "value": {}, + "on": [ + { + "events": [ + { + "source": "window", + "type": "pointermove", + "consume": true, + "between": [ + { + "source": "scope", + "type": "pointerdown", + "markname": "brush_brush" + }, + {"source": "window", "type": "pointerup"} + ] + } + ], + "update": "{x: brush_translate_anchor.x - x(unit), y: brush_translate_anchor.y - y(unit)}" + } + ] + }, + { + "name": "brush_zoom_anchor", + "on": [ + { + "events": [ + { + "source": "scope", + "type": "wheel", + "consume": true, + "markname": "brush_brush" + } + ], + "update": "{x: x(unit), y: y(unit)}" + } + ] + }, + { + "name": "brush_zoom_delta", + "on": [ + { + "events": [ + { + "source": "scope", + "type": "wheel", + "consume": true, + "markname": "brush_brush" + } + ], + "force": true, + "update": "pow(1.001, event.deltaY * pow(16, event.deltaMode))" + } + ] + }, + { + "name": "brush_modify", + "on": [ + { + "events": {"signal": "brush_tuple"}, + "update": "modify(\"brush_store\", brush_tuple, true)" + } + ] + } + ], + "marks": [ + { + "name": "brush_brush_bg", + "type": "rect", + "clip": true, + "encode": { + "enter": { + "fill": {"value": "#333"}, + "fillOpacity": {"value": 0.125} + }, + "update": { + "x": [ + { + "test": "data(\"brush_store\").length && data(\"brush_store\")[0].unit === \"child__column_delay_layer_0\"", + "signal": "brush_x[0]" + }, + {"value": 0} + ], + "y": [ + { + "test": "data(\"brush_store\").length && data(\"brush_store\")[0].unit === \"child__column_delay_layer_0\"", + "value": 0 + }, + {"value": 0} + ], + "x2": [ + { + "test": "data(\"brush_store\").length && data(\"brush_store\")[0].unit === \"child__column_delay_layer_0\"", + "signal": "brush_x[1]" + }, + {"value": 0} + ], + "y2": [ + { + "test": "data(\"brush_store\").length && data(\"brush_store\")[0].unit === \"child__column_delay_layer_0\"", + "field": {"group": "height"} + }, + {"value": 0} + ] + } + } + }, + { + "name": "child__column_delay_layer_0_marks", + "type": "rect", + "style": ["bar"], + "interactive": true, + "from": {"data": "data_2"}, + "encode": { + "update": { + "fill": {"value": "#4c78a8"}, + "ariaRoleDescription": {"value": "bar"}, + "description": { + "signal": "\"delay (binned): \" + (!isValid(datum[\"bin_maxbins_20_delay\"]) || !isFinite(+datum[\"bin_maxbins_20_delay\"]) ? \"null\" : format(datum[\"bin_maxbins_20_delay\"], \"\") + \" – \" + format(datum[\"bin_maxbins_20_delay_end\"], \"\")) + \"; Count of Records: \" + (format(datum[\"__count\"], \"\"))" + }, + "x2": { + "scale": "child__column_delay_x", + "field": "bin_maxbins_20_delay", + "offset": { + "signal": "0.5 + (abs(scale(\"child__column_delay_x\", datum[\"bin_maxbins_20_delay_end\"]) - scale(\"child__column_delay_x\", datum[\"bin_maxbins_20_delay\"])) < 0.25 ? -0.5 * (0.25 - (abs(scale(\"child__column_delay_x\", datum[\"bin_maxbins_20_delay_end\"]) - scale(\"child__column_delay_x\", datum[\"bin_maxbins_20_delay\"])))) : 0.5)" + } + }, + "x": { + "scale": "child__column_delay_x", + "field": "bin_maxbins_20_delay_end", + "offset": { + "signal": "0.5 + (abs(scale(\"child__column_delay_x\", datum[\"bin_maxbins_20_delay_end\"]) - scale(\"child__column_delay_x\", datum[\"bin_maxbins_20_delay\"])) < 0.25 ? 0.5 * (0.25 - (abs(scale(\"child__column_delay_x\", datum[\"bin_maxbins_20_delay_end\"]) - scale(\"child__column_delay_x\", datum[\"bin_maxbins_20_delay\"])))) : -0.5)" + } + }, + "y": {"scale": "child__column_delay_y", "field": "__count"}, + "y2": {"scale": "child__column_delay_y", "value": 0} + } + } + }, + { + "name": "brush_brush", + "type": "rect", + "clip": true, + "encode": { + "enter": {"fill": {"value": "transparent"}}, + "update": { + "x": [ + { + "test": "data(\"brush_store\").length && data(\"brush_store\")[0].unit === \"child__column_delay_layer_0\"", + "signal": "brush_x[0]" + }, + {"value": 0} + ], + "y": [ + { + "test": "data(\"brush_store\").length && data(\"brush_store\")[0].unit === \"child__column_delay_layer_0\"", + "value": 0 + }, + {"value": 0} + ], + "x2": [ + { + "test": "data(\"brush_store\").length && data(\"brush_store\")[0].unit === \"child__column_delay_layer_0\"", + "signal": "brush_x[1]" + }, + {"value": 0} + ], + "y2": [ + { + "test": "data(\"brush_store\").length && data(\"brush_store\")[0].unit === \"child__column_delay_layer_0\"", + "field": {"group": "height"} + }, + {"value": 0} + ], + "stroke": [ + {"test": "brush_x[0] !== brush_x[1]", "value": "white"}, + {"value": null} + ] + } + } + } + ], + "axes": [ + { + "scale": "child__column_delay_x", + "orient": "bottom", + "grid": false, + "title": "delay (binned)", + "labelFlush": true, + "labelOverlap": true, + "tickCount": {"signal": "ceil(childWidth/10)"}, + "zindex": 0 + } + ] + }, + { + "type": "group", + "name": "child__column_time_group", + "style": "cell", + "encode": { + "update": { + "width": {"signal": "childWidth"}, + "height": {"signal": "childHeight"} + } + }, + "signals": [ + { + "name": "brush_x", + "value": [], + "on": [ + { + "events": { + "source": "scope", + "type": "pointerdown", + "filter": [ + "!event.item || event.item.mark.name !== \"brush_brush\"" + ] + }, + "update": "[x(unit), x(unit)]" + }, + { + "events": { + "source": "window", + "type": "pointermove", + "consume": true, + "between": [ + { + "source": "scope", + "type": "pointerdown", + "filter": [ + "!event.item || event.item.mark.name !== \"brush_brush\"" + ] + }, + {"source": "window", "type": "pointerup"} + ] + }, + "update": "[brush_x[0], clamp(x(unit), 0, childWidth)]" + }, + { + "events": {"signal": "brush_scale_trigger"}, + "update": "[scale(\"child__column_time_x\", brush_time[0]), scale(\"child__column_time_x\", brush_time[1])]" + }, + { + "events": [{"source": "view", "type": "dblclick"}], + "update": "[0, 0]" + }, + { + "events": {"signal": "brush_translate_delta"}, + "update": "clampRange(panLinear(brush_translate_anchor.extent_x, brush_translate_delta.x / span(brush_translate_anchor.extent_x)), 0, childWidth)" + }, + { + "events": {"signal": "brush_zoom_delta"}, + "update": "clampRange(zoomLinear(brush_x, brush_zoom_anchor.x, brush_zoom_delta), 0, childWidth)" + } + ] + }, + { + "name": "brush_time", + "on": [ + { + "events": {"signal": "brush_x"}, + "update": "brush_x[0] === brush_x[1] ? null : invert(\"child__column_time_x\", brush_x)" + } + ] + }, + { + "name": "brush_scale_trigger", + "value": {}, + "on": [ + { + "events": [{"scale": "child__column_time_x"}], + "update": "(!isArray(brush_time) || (+invert(\"child__column_time_x\", brush_x)[0] === +brush_time[0] && +invert(\"child__column_time_x\", brush_x)[1] === +brush_time[1])) ? brush_scale_trigger : {}" + } + ] + }, + { + "name": "brush_tuple", + "on": [ + { + "events": [{"signal": "brush_time"}], + "update": "brush_time ? {unit: \"child__column_time_layer_0\", fields: brush_tuple_fields, values: [brush_time]} : null" + } + ] + }, + { + "name": "brush_tuple_fields", + "value": [{"field": "time", "channel": "x", "type": "R"}] + }, + { + "name": "brush_translate_anchor", + "value": {}, + "on": [ + { + "events": [ + { + "source": "scope", + "type": "pointerdown", + "markname": "brush_brush" + } + ], + "update": "{x: x(unit), y: y(unit), extent_x: slice(brush_x)}" + } + ] + }, + { + "name": "brush_translate_delta", + "value": {}, + "on": [ + { + "events": [ + { + "source": "window", + "type": "pointermove", + "consume": true, + "between": [ + { + "source": "scope", + "type": "pointerdown", + "markname": "brush_brush" + }, + {"source": "window", "type": "pointerup"} + ] + } + ], + "update": "{x: brush_translate_anchor.x - x(unit), y: brush_translate_anchor.y - y(unit)}" + } + ] + }, + { + "name": "brush_zoom_anchor", + "on": [ + { + "events": [ + { + "source": "scope", + "type": "wheel", + "consume": true, + "markname": "brush_brush" + } + ], + "update": "{x: x(unit), y: y(unit)}" + } + ] + }, + { + "name": "brush_zoom_delta", + "on": [ + { + "events": [ + { + "source": "scope", + "type": "wheel", + "consume": true, + "markname": "brush_brush" + } + ], + "force": true, + "update": "pow(1.001, event.deltaY * pow(16, event.deltaMode))" + } + ] + }, + { + "name": "brush_modify", + "on": [ + { + "events": {"signal": "brush_tuple"}, + "update": "modify(\"brush_store\", brush_tuple, true)" + } + ] + } + ], + "marks": [ + { + "name": "brush_brush_bg", + "type": "rect", + "clip": true, + "encode": { + "enter": { + "fill": {"value": "#333"}, + "fillOpacity": {"value": 0.125} + }, + "update": { + "x": [ + { + "test": "data(\"brush_store\").length && data(\"brush_store\")[0].unit === \"child__column_time_layer_0\"", + "signal": "brush_x[0]" + }, + {"value": 0} + ], + "y": [ + { + "test": "data(\"brush_store\").length && data(\"brush_store\")[0].unit === \"child__column_time_layer_0\"", + "value": 0 + }, + {"value": 0} + ], + "x2": [ + { + "test": "data(\"brush_store\").length && data(\"brush_store\")[0].unit === \"child__column_time_layer_0\"", + "signal": "brush_x[1]" + }, + {"value": 0} + ], + "y2": [ + { + "test": "data(\"brush_store\").length && data(\"brush_store\")[0].unit === \"child__column_time_layer_0\"", + "field": {"group": "height"} + }, + {"value": 0} + ] + } + } + }, + { + "name": "child__column_time_layer_0_marks", + "type": "rect", + "style": ["bar"], + "interactive": true, + "from": {"data": "data_0"}, + "encode": { + "update": { + "fill": {"value": "#4c78a8"}, + "ariaRoleDescription": {"value": "bar"}, + "description": { + "signal": "\"time (binned): \" + (!isValid(datum[\"bin_maxbins_20_time\"]) || !isFinite(+datum[\"bin_maxbins_20_time\"]) ? \"null\" : format(datum[\"bin_maxbins_20_time\"], \"\") + \" – \" + format(datum[\"bin_maxbins_20_time_end\"], \"\")) + \"; Count of Records: \" + (format(datum[\"__count\"], \"\"))" + }, + "x2": { + "scale": "child__column_time_x", + "field": "bin_maxbins_20_time", + "offset": { + "signal": "0.5 + (abs(scale(\"child__column_time_x\", datum[\"bin_maxbins_20_time_end\"]) - scale(\"child__column_time_x\", datum[\"bin_maxbins_20_time\"])) < 0.25 ? -0.5 * (0.25 - (abs(scale(\"child__column_time_x\", datum[\"bin_maxbins_20_time_end\"]) - scale(\"child__column_time_x\", datum[\"bin_maxbins_20_time\"])))) : 0.5)" + } + }, + "x": { + "scale": "child__column_time_x", + "field": "bin_maxbins_20_time_end", + "offset": { + "signal": "0.5 + (abs(scale(\"child__column_time_x\", datum[\"bin_maxbins_20_time_end\"]) - scale(\"child__column_time_x\", datum[\"bin_maxbins_20_time\"])) < 0.25 ? 0.5 * (0.25 - (abs(scale(\"child__column_time_x\", datum[\"bin_maxbins_20_time_end\"]) - scale(\"child__column_time_x\", datum[\"bin_maxbins_20_time\"])))) : -0.5)" + } + }, + "y": {"scale": "child__column_time_y", "field": "__count"}, + "y2": {"scale": "child__column_time_y", "value": 0} + } + } + }, + { + "name": "brush_brush", + "type": "rect", + "clip": true, + "encode": { + "enter": {"fill": {"value": "transparent"}}, + "update": { + "x": [ + { + "test": "data(\"brush_store\").length && data(\"brush_store\")[0].unit === \"child__column_time_layer_0\"", + "signal": "brush_x[0]" + }, + {"value": 0} + ], + "y": [ + { + "test": "data(\"brush_store\").length && data(\"brush_store\")[0].unit === \"child__column_time_layer_0\"", + "value": 0 + }, + {"value": 0} + ], + "x2": [ + { + "test": "data(\"brush_store\").length && data(\"brush_store\")[0].unit === \"child__column_time_layer_0\"", + "signal": "brush_x[1]" + }, + {"value": 0} + ], + "y2": [ + { + "test": "data(\"brush_store\").length && data(\"brush_store\")[0].unit === \"child__column_time_layer_0\"", + "field": {"group": "height"} + }, + {"value": 0} + ], + "stroke": [ + {"test": "brush_x[0] !== brush_x[1]", "value": "white"}, + {"value": null} + ] + } + } + } + ], + "axes": [ + { + "scale": "child__column_time_x", + "orient": "bottom", + "grid": false, + "title": "time (binned)", + "labelFlush": true, + "labelOverlap": true, + "tickCount": {"signal": "ceil(childWidth/10)"}, + "zindex": 0 + } + ] + } + ], + "scales": [ + { + "name": "child__column_distance_x", + "type": "linear", + "domain": { + "signal": "[child__column_distance_layer_0_bin_maxbins_20_distance_bins.start, child__column_distance_layer_0_bin_maxbins_20_distance_bins.stop]" + }, + "range": [0, {"signal": "childWidth"}], + "bins": { + "signal": "child__column_distance_layer_0_bin_maxbins_20_distance_bins" + }, + "zero": false + }, + { + "name": "child__column_distance_y", + "type": "linear", + "domain": {"data": "data_3", "field": "__count"}, + "range": [{"signal": "childHeight"}, 0], + "nice": true, + "zero": true + }, + { + "name": "child__column_delay_x", + "type": "linear", + "domain": { + "signal": "[child__column_delay_layer_0_bin_maxbins_20_delay_bins.start, child__column_delay_layer_0_bin_maxbins_20_delay_bins.stop]" + }, + "range": [0, {"signal": "childWidth"}], + "bins": { + "signal": "child__column_delay_layer_0_bin_maxbins_20_delay_bins" + }, + "zero": false + }, + { + "name": "child__column_delay_y", + "type": "linear", + "domain": {"data": "data_2", "field": "__count"}, + "range": [{"signal": "childHeight"}, 0], + "nice": true, + "zero": true + }, + { + "name": "child__column_time_x", + "type": "linear", + "domain": { + "signal": "[child__column_time_layer_0_bin_maxbins_20_time_bins.start, child__column_time_layer_0_bin_maxbins_20_time_bins.stop]" + }, + "range": [0, {"signal": "childWidth"}], + "bins": {"signal": "child__column_time_layer_0_bin_maxbins_20_time_bins"}, + "zero": false + }, + { + "name": "child__column_time_y", + "type": "linear", + "domain": {"data": "data_0", "field": "__count"}, + "range": [{"signal": "childHeight"}, 0], + "nice": true, + "zero": true + } + ] +} diff --git a/examples/compiled/selection_type_point_zorder.png b/examples/compiled/selection_type_point_zorder.png new file mode 100644 index 0000000000..329c5edb02 Binary files /dev/null and b/examples/compiled/selection_type_point_zorder.png differ diff --git a/examples/compiled/selection_type_point_zorder.svg b/examples/compiled/selection_type_point_zorder.svg new file mode 100644 index 0000000000..87a5f5c033 --- /dev/null +++ b/examples/compiled/selection_type_point_zorder.svg @@ -0,0 +1 @@ +050100150200Horsepower01020304050Miles_per_Gallon \ No newline at end of file diff --git a/examples/compiled/selection_type_point_zorder.vg.json b/examples/compiled/selection_type_point_zorder.vg.json new file mode 100644 index 0000000000..aee261c023 --- /dev/null +++ b/examples/compiled/selection_type_point_zorder.vg.json @@ -0,0 +1,179 @@ +{ + "$schema": "https://vega.github.io/schema/vega/v5.json", + "background": "white", + "padding": 5, + "width": 200, + "height": 200, + "style": "cell", + "data": [ + { + "name": "param_122_store", + "transform": [{"type": "collect", "sort": {"field": "_vgsid_"}}] + }, + { + "name": "source_0", + "url": "https://cdn.jsdelivr.net/npm/vega-datasets@v1.29.0/data/cars.json", + "format": {"type": "json"}, + "transform": [ + {"type": "identifier", "as": "_vgsid_"}, + { + "type": "filter", + "expr": "isValid(datum[\"Horsepower\"]) && isFinite(+datum[\"Horsepower\"]) && isValid(datum[\"Miles_per_Gallon\"]) && isFinite(+datum[\"Miles_per_Gallon\"])" + } + ] + } + ], + "signals": [ + { + "name": "unit", + "value": {}, + "on": [ + {"events": "pointermove", "update": "isTuple(group()) ? group() : unit"} + ] + }, + { + "name": "param_122", + "update": "vlSelectionResolve(\"param_122_store\", \"union\", true, true)" + }, + { + "name": "param_122_tuple", + "on": [ + { + "events": [{"source": "scope", "type": "pointerover"}], + "update": "datum && item().mark.marktype !== 'group' && indexof(item().mark.role, 'legend') < 0 ? {unit: \"\", _vgsid_: (item().isVoronoi ? datum.datum : datum)[\"_vgsid_\"]} : null", + "force": true + }, + {"events": [{"source": "view", "type": "dblclick"}], "update": "null"} + ] + }, + { + "name": "param_122_toggle", + "value": false, + "on": [ + { + "events": [{"source": "scope", "type": "pointerover"}], + "update": "event.shiftKey" + }, + {"events": [{"source": "view", "type": "dblclick"}], "update": "false"} + ] + }, + { + "name": "param_122_modify", + "on": [ + { + "events": {"signal": "param_122_tuple"}, + "update": "modify(\"param_122_store\", param_122_toggle ? null : param_122_tuple, param_122_toggle ? null : true, param_122_toggle ? param_122_tuple : null)" + } + ] + } + ], + "marks": [ + { + "name": "marks", + "type": "symbol", + "style": ["circle"], + "interactive": true, + "from": {"data": "source_0"}, + "encode": { + "update": { + "opacity": {"value": 1}, + "fill": [ + { + "test": "length(data(\"param_122_store\")) && vlSelectionIdTest(\"param_122_store\", datum)", + "value": "coral" + }, + {"value": "grey"} + ], + "zindex": [ + { + "test": "length(data(\"param_122_store\")) && vlSelectionIdTest(\"param_122_store\", datum)", + "value": 1 + }, + {"value": 0} + ], + "ariaRoleDescription": {"value": "circle"}, + "description": { + "signal": "\"Horsepower: \" + (format(datum[\"Horsepower\"], \"\")) + \"; Miles_per_Gallon: \" + (format(datum[\"Miles_per_Gallon\"], \"\"))" + }, + "x": {"scale": "x", "field": "Horsepower"}, + "y": {"scale": "y", "field": "Miles_per_Gallon"}, + "size": [ + { + "test": "length(data(\"param_122_store\")) && vlSelectionIdTest(\"param_122_store\", datum)", + "value": 400 + }, + {"value": 100} + ], + "shape": {"value": "circle"} + } + } + } + ], + "scales": [ + { + "name": "x", + "type": "linear", + "domain": {"data": "source_0", "field": "Horsepower"}, + "range": [0, {"signal": "width"}], + "nice": true, + "zero": true + }, + { + "name": "y", + "type": "linear", + "domain": {"data": "source_0", "field": "Miles_per_Gallon"}, + "range": [{"signal": "height"}, 0], + "nice": true, + "zero": true + } + ], + "axes": [ + { + "scale": "x", + "orient": "bottom", + "gridScale": "y", + "grid": true, + "tickCount": {"signal": "ceil(width/40)"}, + "domain": false, + "labels": false, + "aria": false, + "maxExtent": 0, + "minExtent": 0, + "ticks": false, + "zindex": 0 + }, + { + "scale": "y", + "orient": "left", + "gridScale": "x", + "grid": true, + "tickCount": {"signal": "ceil(height/40)"}, + "domain": false, + "labels": false, + "aria": false, + "maxExtent": 0, + "minExtent": 0, + "ticks": false, + "zindex": 0 + }, + { + "scale": "x", + "orient": "bottom", + "grid": false, + "title": "Horsepower", + "labelFlush": true, + "labelOverlap": true, + "tickCount": {"signal": "ceil(width/40)"}, + "zindex": 0 + }, + { + "scale": "y", + "orient": "left", + "grid": false, + "title": "Miles_per_Gallon", + "labelOverlap": true, + "tickCount": {"signal": "ceil(height/40)"}, + "zindex": 0 + } + ] +} diff --git a/examples/specs/interactive_crossfilter.vl.json b/examples/specs/interactive_crossfilter.vl.json new file mode 100644 index 0000000000..dd6f563ea6 --- /dev/null +++ b/examples/specs/interactive_crossfilter.vl.json @@ -0,0 +1,26 @@ +{ + "$schema": "https://vega.github.io/schema/vega-lite/v5.json", + "data": { + "url": "data/flights-2k.json", + "format": {"parse": {"date": "date"}} + }, + "transform": [{"calculate": "hours(datum.date)", "as": "time"}], + "repeat": {"column": ["distance", "delay", "time"]}, + "spec": { + "layer": [{ + "params": [{ + "name": "brush", + "select": {"type": "interval", "encodings": ["x"]} + }], + "transform": [{"filter": {"param": "brush"}}], + "mark": "bar", + "encoding": { + "x": { + "field": {"repeat": "column"}, + "bin": {"maxbins": 20} + }, + "y": {"aggregate": "count", "axis": null} + } + }] + } +} diff --git a/examples/specs/normalized/interactive_crossfilter_normalized.vl.json b/examples/specs/normalized/interactive_crossfilter_normalized.vl.json new file mode 100644 index 0000000000..c71f86e60f --- /dev/null +++ b/examples/specs/normalized/interactive_crossfilter_normalized.vl.json @@ -0,0 +1,69 @@ +{ + "data": { + "url": "data/flights-2k.json", + "format": {"parse": {"date": "date"}} + }, + "align": "all", + "$schema": "https://vega.github.io/schema/vega-lite/v5.json", + "transform": [{"calculate": "hours(datum.date)", "as": "time"}], + "columns": 3, + "concat": [ + { + "layer": [ + { + "params": [ + { + "name": "brush", + "select": {"type": "interval", "encodings": ["x"]} + } + ], + "mark": "bar", + "encoding": { + "x": {"field": "distance", "bin": {"maxbins": 20}}, + "y": {"aggregate": "count", "axis": null} + }, + "transform": [{"filter": {"param": "brush"}}] + } + ], + "name": "child__column_distance" + }, + { + "layer": [ + { + "params": [ + { + "name": "brush", + "select": {"type": "interval", "encodings": ["x"]} + } + ], + "mark": "bar", + "encoding": { + "x": {"field": "delay", "bin": {"maxbins": 20}}, + "y": {"aggregate": "count", "axis": null} + }, + "transform": [{"filter": {"param": "brush"}}] + } + ], + "name": "child__column_delay" + }, + { + "layer": [ + { + "params": [ + { + "name": "brush", + "select": {"type": "interval", "encodings": ["x"]} + } + ], + "mark": "bar", + "encoding": { + "x": {"field": "time", "bin": {"maxbins": 20}}, + "y": {"aggregate": "count", "axis": null} + }, + "transform": [{"filter": {"param": "brush"}}] + } + ], + "name": "child__column_time" + } + ] +} \ No newline at end of file diff --git a/examples/specs/selection_type_point_zorder.vl.json b/examples/specs/selection_type_point_zorder.vl.json new file mode 100644 index 0000000000..a3ef7186bf --- /dev/null +++ b/examples/specs/selection_type_point_zorder.vl.json @@ -0,0 +1,26 @@ +{ + "$schema": "https://vega.github.io/schema/vega-lite/v5.json", + "data": { + "url": "https://cdn.jsdelivr.net/npm/vega-datasets@v1.29.0/data/cars.json" + }, + "mark": {"type": "circle", "opacity": 1}, + "encoding": { + "color": { + "condition": {"param": "param_122", "value": "coral", "empty": false}, + "value": "grey" + }, + "order": { + "condition": {"param": "param_122", "value": 1, "empty": false}, + "value": 0 + }, + "size": { + "condition": {"param": "param_122", "value": 400, "empty": false}, + "value": 100 + }, + "x": {"field": "Horsepower", "type": "quantitative"}, + "y": {"field": "Miles_per_Gallon", "type": "quantitative"} + }, + "params": [ + {"name": "param_122", "select": {"type": "point", "on": "pointerover"}} + ] +} diff --git a/site/_data/examples.json b/site/_data/examples.json index a1fab1f006..a04bc1af32 100644 --- a/site/_data/examples.json +++ b/site/_data/examples.json @@ -904,6 +904,11 @@ "name": "param_search_input", "description": "Search to highlight the relevant car models. Regexes are supported so you can type e.g. `mazda|ford`", "title": "Search Input" + }, + { + "name": "selection_type_point_zorder", + "description": "Show points on top when hovered over with the pointer", + "title": "Change zorder on hover" } ], "Interactive Multi-View Displays": [ @@ -911,9 +916,13 @@ "name": "interactive_overview_detail", "title": "Overview and Detail" }, + { + "name": "interactive_crossfilter", + "title": "Crossfilter (Filter)" + }, { "name": "interactive_layered_crossfilter", - "title": "Crossfilter" + "title": "Crossfilter (Highlight)" }, { "name": "interactive_splom", diff --git a/site/docs/encoding.md b/site/docs/encoding.md index ca61832a65..99b361e508 100644 --- a/site/docs/encoding.md +++ b/site/docs/encoding.md @@ -413,7 +413,7 @@ The key channel can enable object constancy for transitions over dynamic data. W ## Order Channel -`order` channel can define a data field (or a ordered list of data fields) that are used to sorts stacking order for stacked charts (see [an example in the `stack` page](stack.html#order)) and the order of data points in line marks for connected scatterplots (see [an example in the `line` page](line.html#connected-scatter-plot)). +`order` channel can define a data field (or a ordered list of data fields) that are used to sorts stacking order for stacked charts (see [an example in the `stack` page](stack.html#order)), the order of data points in line marks for connected scatterplots (see [an example in the `line` page](line.html#connected-scatter-plot)), and which data points are plotted on top in a chart (the "zorder", see [an example in the gallery]({{ site.baseurl }}/examples/selection_type_point_zorder.html)). {% include table.html props="order" source="Encoding" %} diff --git a/site/ecosystem.md b/site/ecosystem.md index 74d184aae5..8c49364b00 100644 --- a/site/ecosystem.md +++ b/site/ecosystem.md @@ -106,6 +106,8 @@ We mark featured plugins and tools with a