Adding a scrollbar in vegalite - vega-lite

I am drawing a horizontal stacked bar-plot involving many datasets and want to add a vertical scrollbar because displaying all at once is not space efficient. I am drawing it using vegalite in observable notebook. So, I am wondering how to include scrollbar in vegalite?

You can create the same bar chart or a simple bar chart in hconcat having all the data but with a selection interval params. Then use the same param name to change the scales of original chart. So initially all the data will be visible but when you perform a selection on your simple bar chart it will give the effect of scrolling of bar chart.
Below is the sample code or refer editor:
{
"$schema": "https://vega.github.io/schema/vega-lite/v5.json",
"data": {"url": "data/sp500.csv"},
"hconcat": [
{
"height": 400,
"width": 50,
"mark": {"type": "bar", "fill": "lightgray"},
"params": [
{"name": "brush", "select": {"type": "interval", "encodings": ["y"]}}
],
"encoding": {
"y": {"field": "date", "type": "temporal", "sort": "-x"},
"x": {
"field": "price",
"type": "quantitative",
"axis": {"tickCount": 3, "grid": false}
}
}
},
{
"height": 400,
"width": 480,
"mark": "bar",
"encoding": {
"y": {
"field": "date",
"type": "temporal",
"scale": {"domain": {"param": "brush"}},
"axis": {"title": ""}
},
"x": {"field": "price", "type": "quantitative"}
}
}
]
}
Other way to add a basic scrollbar by giving max-height and overflow scroll to a div in which the chart is embedded.
Below is the snippet or refer fiddle:
var yourVlSpec = {
"$schema": "https://vega.github.io/schema/vega-lite/v5.json",
"data": {"url": "https://vega.github.io/editor/data/sp500.csv"},
"hconcat": [
{
"height": 1400,
"width": 300,
"mark": "bar",
"encoding": {
"y": {
"field": "date",
"type": "temporal",
"axis": {"title": ""}
},
"x": {"field": "price", "type": "quantitative"}
}
}
]
}
vegaEmbed("#vis", yourVlSpec, {renderer: 'svg'}).then(res => {
var view = res.view;
//console.log(view.data('source_0'));
});
.vegaDiv{
max-height: 300px;
overflow: scroll;
}
<script src="https://cdn.jsdelivr.net/npm/vega#5.20.2/build/vega.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/vega-lite#5.0.0/build/vega-lite.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/vega-embed#6.17.0/build/vega-embed.min.js"></script>
<div class="vegaDiv" id="vis"></div>

Related

Make vega-lite selection only take effect on mouseup

I would like to have an interval selection in a Vega-lite in which other data is filtered in response to the selection, but only after the user releases the mouse. For instance, consider this example where the user can filter the dates in a time series plot by selecting a range on another chart. As the user drags the selection in the bottom chart the top chart filters in real-time. What I would like to do is instead have the top chart only filter once the user has updated the selection in the bottom chart and released the mouse button.
Try this. It seems a bit awkward to me but does what you ask.
Editor
{
"$schema": "https://vega.github.io/schema/vega-lite/v5.json",
"data": {"url": "data/sp500.csv"},
"vconcat": [
{
"width": 480,
"mark": "area",
"encoding": {
"x": {
"field": "date",
"type": "temporal",
"scale": {"domain": {"param": "brush"}},
"axis": {"title": ""}
},
"y": {"field": "price", "type": "quantitative"}
}
},
{
"width": 480,
"height": 60,
"mark": "area",
"params": [
{
"name": "brush",
"select": {
"type": "interval",
"encodings": ["x"],
"on": {
"type": "mousemove",
"between": [{"type": "mouseup"}, {"type": "mousedown"}]
}
}
}
],
"encoding": {
"x": {"field": "date", "type": "temporal"},
"y": {
"field": "price",
"type": "quantitative",
"axis": {"tickCount": 3, "grid": false}
}
}
}
]
}

Vega-lite: How to show multiple "color" legends for multi-layer scatter plot?

My vega lite json: Open the Chart in the Vega Editor
{
"$schema": "https://vega.github.io/schema/vega-lite/v5.json",
"layer": [
{
"data": {"url": "data/cars.json"},
"params": [
{
"name": "grid",
"select": "interval",
"bind": "scales"
}
],
"mark": "circle",
"encoding": {
"x": {"field": "Horsepower", "type": "quantitative"},
"y": {"field": "Miles_per_Gallon", "type": "quantitative"},
"color": {
"field": "Horsepower",
"type": "quantitative",
"scale": {
"range": ["blue", "blue"]
}
}
}
},
{
"data": {"url": "data/cars.json"},
"mark": "circle",
"encoding": {
"x": {"field": "Miles_per_Gallon", "type": "quantitative"},
"y": {"field": "Acceleration", "type": "quantitative"},
"color": {
"field": "Displacement",
"type": "quantitative",
"scale": {
"range": ["black", "black"]
}
}
}
}
]
}
I'm displaying 2 layers of scratter plot, so I want it to have 2 legend color bars.
When I use "color", the second legend is merged, and overriden by the first one.
When I change to use "fill", I manage to have 2 different color bars. But what if I have 4 layers, how to do it?
You need to add the resolve property.
"resolve": {"legend":{"color": "independent"}, "scale": {"color": "independent"} }
Sample on vega editor:
Open the Chart in the Vega Editor

Does vega-lite Having Fixed Y-axis?

I have 2 charts which might have been created using hconcat. The first spec contains only an y-axis which is going to be fixed and it will act as a locked axis for my 2nd chart. If I scroll horizontally, it should only scroll the 2nd chart and my 1st y-axis chart should remain as it is, so it becomes easier to read the measures.
Below is an reproducible example or refer editor:
{
"$schema": "https://vega.github.io/schema/vega-lite/v5.json",
"data": {"url": "data/cars.json"},
"hconcat": [
{
"mark": "text",
"encoding": {"y": {"field": "Displacement", "type": "quantitative"}}
},
{
"hconcat": [
{
"width": 800,
"mark": "line",
"params": [
{
"name": "brush",
"select": {"type": "interval", "encodings": ["x"]}
}
],
"encoding": {
"x": {"field": "Year", "type": "temporal"},
"y": {
"field": "Cylinders",
"type": "quantitative",
"axis": {"grid": false}
}
}
}
]
}
]
}
This image contains Y-axis on left side
This contains only x-axis,Y-axis disappeared

How to position image on top left corner?

I am trying to position an overlayed image in the top left corner of my chart.
To that end, I am using the aggregate transform directly in the encoding of channels x, and y of the image, as it can be seen in this example.
Here is the specific code snippet of the image mark:
{
"mark": {"type":"image", "width":50, "align":"left"},
"encoding": {
"x": {"aggregate": "min", "field":"months", "type":"temporal"},
"y": {"aggregate": "max", "field":"price", "type":"quantitative"},
"url": {"value": "data/ffox.png"}
}
}
The image, is still appearing at around the middle of the y axis, and not at the top:
Image in the middle, not top
How can I place it at the top left corner?
The image is not getting displayed in top because height is not provided for that image mark. Because of that image is getting displayed in center, if you inspect your image you will see some default height. Image for default height
To bring your image on top left, just provide height as done below:
{
"mark": {"type": "image", "width": 50, "align": "left", "height": 40},
"encoding": {
"x": {"aggregate": "min", "field": "months", "type": "temporal"},
"y": {"aggregate": "max", "field": "price", "type": "quantitative"},
"url": {"value": "data/ffox.png"}
}
}
But with the aggregation specified, your image might slighly go outside the chart view, so you can provide the following way as well where you provide hardcoded x and y value for the image mark. Which will always show appropriate position for your image. Below is the code and editor url:
{
"$schema": "https://vega.github.io/schema/vega-lite/v5.1.0.json",
"width": "container",
"data": {"url": "data/sp500.csv"},
"transform": [{"timeUnit": "utcyearmonth", "field": "date", "as": "months"}],
"layer": [
{
"encoding": {
"x": {"field": "months", "type": "temporal", "title": null},
"y": {"field": "price", "type": "quantitative", "title": "Price"}
},
"layer": [
{
"mark": {
"type": "area",
"color": "#3873b9",
"fillOpacity": 0.7,
"tooltip": true
}
},
{"mark": {"type": "line", "color": "#4883c9"}}
]
},
{
"mark": {"type": "image", "width": 50, "height": 40, "align": "left"},
"encoding": {
"x": {
"datum": 0,
"type": "quantitative",
"scale": {"domain": [0, 1]},
"axis": null
},
"y": {
"datum": 0.8,
"type": "quantitative",
"scale": {"domain": [0, 1]},
"axis": null
},
"url": {"value": "data/ffox.png"}
}
}
],
"resolve": {
"axis": {"x": "independent", "y": "independent"},
"scale": {"x": "independent", "y": "independent"}
}
}
As wahab memon mentioned, the image went middle due to the missing of height property.
Simply adding back "height": 50, "baseline": "alphabetic" to mark can fix the position and the overshoot issue as well. (no need for hard coding)
Last but not least, the original code has redundant nested layers, please see the complete code below:
{
"$schema": "https://vega.github.io/schema/vega-lite/v5.1.0.json",
"width": "container",
"data": {"url": "data/sp500.csv"},
"transform": [{"timeUnit": "utcyearmonth", "field": "date", "as": "months"}],
"encoding": {
"x": {"field": "months", "type": "temporal", "title": null},
"y": {"field": "price", "type": "quantitative", "title": "Price"}
},
"layer": [
{
"mark": {
"type": "area",
"color": "#3873b9",
"fillOpacity": 0.7,
"tooltip": true
}
},
{"mark": {"type": "line", "color": "#4883c9"}},
{
"mark": {"type": "image", "width": 50, "align": "left", "height": 50, "baseline": "alphabetic"},
"encoding": {
"x": {"aggregate": "min", "field": "months", "type": "temporal"},
"y": {"aggregate": "max", "field": "price", "type": "quantitative"},
"url": {"value": "data/ffox.png"}
}
}
]
}
Vega Editor

Vega-Lite layered chart: how to get tick marks and tick labels to span the entire axis?

I am working on a layered chart where I have both bars and rule lines. The issue I'm having is that on the x-axis, the tick marks and tick labels only appear under the bars and do not span the entire axis, making it so that there are no tick marks and labels underneath where the rule lines are located. Here is an example of what I'm seeing (link to Vega editor):
{
"$schema": "https://vega.github.io/schema/vega-lite/v4.json",
"data": {"url": "data/movies.json"},
"transform": [
{"calculate": "2*datum.IMDB_Rating", "as": "UpperLimit"}
],
"layer": [
{
"mark": "bar",
"encoding": {
"x": {"bin": true, "field": "IMDB_Rating", "type": "quantitative"},
"y": {"aggregate": "count", "type": "quantitative"}
}
},
{
"mark": "rule",
"encoding": {
"x": {
"aggregate": "max",
"field": "UpperLimit",
"type": "quantitative"
},
"color": {"value": "red"},
"size": {"value": 5}
}
}
]
}
Image of issue
How do I get the tick marks and labels to span the entire axis? Thanks in advance for the help!
When you use a bin transform within an encoding, Vega-Lite adjusts the default axis properties to match the binning. You can re-adjust these manually via the encoding's scale and axis properties, but I think a simpler way is to move the bin transform to the chart's transform specification. Here is an example (Vega Editor):
{
"$schema": "https://vega.github.io/schema/vega-lite/v4.json",
"data": {"url": "data/movies.json"},
"transform": [
{"calculate": "2*datum.IMDB_Rating", "as": "UpperLimit"},
{
"bin": true,
"field": "IMDB_Rating",
"as": ["IMDB_Rating_0", "IMDB_Rating_1"]
}
],
"layer": [
{
"mark": "bar",
"encoding": {
"x": {
"field": "IMDB_Rating_0",
"type": "quantitative",
"bin": "binned"
},
"x2": {"field": "IMDB_Rating_1"},
"y": {"aggregate": "count", "type": "quantitative"}
}
},
{
"mark": "rule",
"encoding": {
"x": {
"aggregate": "max",
"field": "UpperLimit",
"type": "quantitative"
},
"color": {"value": "red"},
"size": {"value": 5}
}
}
]
}