Vega-lite: line mark not consistent in overview+ detailed responsive chart - javascript

<!DOCTYPE html>
<html>
<head>
<script src="https://cdn.jsdelivr.net/npm/vega#5.22.1"></script>
<script src="https://cdn.jsdelivr.net/npm/vega-lite#5.2.0"></script>
<script src="https://cdn.jsdelivr.net/npm/vega-embed#6.20.8"></script>
</head>
<body>
<div id="vis"/>
<script>
const spec = {
"$schema": "https://vega.github.io/schema/vega-lite/v5.json",
"name": "source_0",
"data": {
"values": [
{"Items": "3", "Items_Rate": "0.20", "Month": "Jan-21"},
{"Items": "6", "Items_Rate": "0.40", "Month": "Feb-21"},
{"Items": "2", "Items_Rate": "0.20", "Month": "Mar-21"},
{"Items": "4", "Items_Rate": "0.30", "Month": "Apr-21"},
{"Items": "8", "Items_Rate": "0.45", "Month": "May-21"},
{"Items": "9", "Items_Rate": "0.50", "Month": "Jun-21"},
{"Items": "1", "Items_Rate": "0.10", "Month": "Jul-21"},
{"Items": "5", "Items_Rate": "0.35", "Month": "Aug-21"},
{"Items": "4", "Items_Rate": "0.28", "Month": "Sep-21"},
{"Items": "7", "Items_Rate": "0.37", "Month": "Oct-21"},
{"Items": "1", "Items_Rate": "0.50", "Month": "Nov-21"},
{"Items": "4", "Items_Rate": "0.35", "Month": "Dec-21"}
]
},
"vconcat": [
{
"width": 850,
"height": 250,
"layer": [
{
"mark": {"type": "bar", "size": 50, "tooltip": true},
"transform": [{"filter": {"param": "brush"}}],
"encoding": {
"x": {
"field": "Month",
"type": "ordinal",
"sort": null,
"scale": {"domain": {"param": "brush"}, "zero": true},
"axis": {
"title": "",
"labelAngle": 360,
"tickSize": 20,
"position": 0
}
},
"y": {
"field": "Items",
"type": "quantitative",
"axis": {"tickMinStep": 1}
},
"color": {
"datum": "No. of Items",
"scale": {"range": ["#0065ad"]}
},
"tooltip": [
{"field": "Month", "type": "nominal", "title": "Month"},
{
"field": "Items",
"type": "quantitative",
"title": "No. of Items"
}
]
}
},
{
"mark": {
"type": "line",
"point": {"shape": "square", "size": "50"},
"size": "2",
"tooltip": true
},
"transform": [{"filter": {"param": "brush"}}],
"encoding": {
"x": {
"field": "Month",
"type": "nominal",
"title": "",
"sort": null,
"scale": {"domain": {"param": "brush"}}
},
"y": {
"field": "Items_Rate",
"type": "quantitative",
"title": "Items",
"scale": {"zero": false},
"sort": null
},
"color": {
"datum": "Items Rate",
"scale": {"range": ["black"]},
"legend": {"symbolType": "square"}
},
"tooltip": [
{"field": "Month", "type": "nominal", "title": "Month"},
{
"field": "Items_Rate",
"type": "quantitative",
"title": "Rate"
}
]
}
}
],
"resolve": {
"scale": {
"y": "independent",
"shape": "independent",
"color": "independent",
"size": "independent"
}
}
},
{
"width": "850",
"height": 100,
"mark": "bar",
"params": [
{
"name": "brush",
"select": {"type": "interval", "encodings": ["x"], "translate": true}
}
],
"encoding": {
"x": {
"field": "Month",
"type": "nominal",
"sort": null,
"axis": {"title": "", "labels": false, "ticks": false}
},
"y": {
"field": "Items",
"type": "quantitative",
"axis": {
"tickCount": 3,
"grid": false,
"title": "",
"labels": false,
"ticks": false
}
},
"color": {"value": "#0065ad"}
}
}
],
"config": {
"axisY": {"minExtent": 40},
"legend": {
"orient": "top",
"layout": {"top": {"anchor": "middle"}},
"labelFont": "arial",
"titleFont": "arial"
}
}
};
vegaEmbed("#vis", spec, {mode: "vega-lite"}).then(console.log).catch(console.warn);
</script>
</body>
</html>
It can also be viewed in Vega lite editor here:
https://vega.github.io/editor/#/gist/da859f07e288d51da47a309ef2718ab2/responsive_chart.json
My query is that when I select 4 or more graphs and scroll forwards, everything is working properly. However when I scroll the same backwards, the line graphs becomes incorrect.
Instead of the nearest point creating a line to join the newly visible point, the farthest or the second-last visible graph now is joining the points.
How could I change the code to have only the nearest point join with the new point and not the order of how they became visible?
For example, in the screenshot below, the Sept-21 point should join the Aug-21 point and NOT Nov-21 when I take the scroll backwards.
Thank you for the help.

You need a sort field. I added an index and used that but you can use anything you like.
Editor
{
"$schema": "https://vega.github.io/schema/vega-lite/v5.json",
"name": "source_0",
"data": {
"values": [
{"Items": "3", "Items_Rate": "0.20", "Month": "Jan-21", "Index":1},
{"Items": "6", "Items_Rate": "0.40", "Month": "Feb-21", "Index":2},
{"Items": "2", "Items_Rate": "0.20", "Month": "Mar-21", "Index":3},
{"Items": "4", "Items_Rate": "0.30", "Month": "Apr-21", "Index":4},
{"Items": "8", "Items_Rate": "0.45", "Month": "May-21", "Index":5},
{"Items": "9", "Items_Rate": "0.50", "Month": "Jun-21", "Index":6},
{"Items": "1", "Items_Rate": "0.10", "Month": "Jul-21", "Index":7},
{"Items": "5", "Items_Rate": "0.35", "Month": "Aug-21", "Index":8},
{"Items": "4", "Items_Rate": "0.28", "Month": "Sep-21", "Index":9},
{"Items": "7", "Items_Rate": "0.37", "Month": "Oct-21", "Index":10},
{"Items": "1", "Items_Rate": "0.50", "Month": "Nov-21", "Index":11},
{"Items": "4", "Items_Rate": "0.35", "Month": "Dec-21", "Index":12}
]
},
"vconcat": [
{
"width": 850,
"height": 250,
"layer": [
{
"mark": {"type": "bar", "size": 50, "tooltip": true},
"transform": [{"filter": {"param": "brush"}}],
"encoding": {
"x": {
"field": "Month",
"type": "ordinal",
"sort": null,
"scale": {"domain": {"param": "brush"}, "zero": true},
"axis": {
"title": "",
"labelAngle": 360,
"tickSize": 20,
"position": 0
}
},
"y": {
"field": "Items",
"type": "quantitative",
"axis": {"tickMinStep": 1}
},
"color": {"datum": "No. of Items", "scale": {"range": ["#0065ad"]}},
"tooltip": [
{"field": "Month", "type": "nominal", "title": "Month"},
{
"field": "Items",
"type": "quantitative",
"title": "No. of Items"
}
]
}
},
{
"mark": {
"type": "line",
"point": {"shape": "square", "size": "50"},
"size": "2",
"tooltip": true
},
"transform": [{"filter": {"param": "brush"}}],
"encoding": {
"x": {
"field": "Month",
"type": "nominal",
"title": "",
"sort": {"field": "Index"},
"scale": {"domain": {"param": "brush"}}
},
"y": {
"field": "Items_Rate",
"type": "quantitative",
"title": "Items",
"scale": {"zero": false},
"sort": null
},
"color": {
"datum": "Items Rate",
"scale": {"range": ["black"]},
"legend": {"symbolType": "square"}
},
"tooltip": [
{"field": "Month", "type": "nominal", "title": "Month"},
{"field": "Items_Rate", "type": "quantitative", "title": "Rate"}
]
}
}
],
"resolve": {
"scale": {
"y": "independent",
"shape": "independent",
"color": "independent",
"size": "independent"
}
}
},
{
"width": "850",
"height": 100,
"mark": "bar",
"params": [
{
"name": "brush",
"select": {"type": "interval", "encodings": ["x"], "translate": true}
}
],
"encoding": {
"x": {
"field": "Month",
"type": "nominal",
"sort": null,
"axis": {"title": "", "labels": true, "ticks": false}
},
"y": {
"field": "Items",
"type": "quantitative",
"axis": {
"tickCount": 3,
"grid": false,
"title": "",
"labels": false,
"ticks": false
}
},
"color": {"value": "#0065ad"}
}
}
],
"config": {
"axisY": {"minExtent": 40},
"legend": {
"orient": "top",
"layout": {"top": {"anchor": "middle"}},
"labelFont": "arial",
"titleFont": "arial"
}
}
}

Related

Display multi-colors according to graph values in Vega bar charts

How can i display the individual bars with a lighter color range based on the graph values. I came to know that vega has sequential multi-hue schemes.
Click here to check Image for MultiColor Scheme. I want to use this color scheme, for different values in the graph. For example, if i have value=3, then in the graph it should display lighter color as compared to the value=10. How can i include the multicolor scheme into the bar graph so it displays the color according to the value. Below is my snippet which i tried, i am actually looking for the color changing according to the amount instead of category. I included color in scales and in fill color in mark. Can someone guide me on how this can be achieved. I am new to this
{
"$schema": "https://vega.github.io/schema/vega/v5.json",
"description": "A basic bar chart example, with value labels shown upon mouse hover.",
"width": 400,
"height": 200,
"padding": 5,
"data": [
{
"name": "table",
"values": [
{"category": "A", "amount": 28},
{"category": "B", "amount": 55},
{"category": "C", "amount": 43},
{"category": "D", "amount": 91},
{"category": "E", "amount": 81},
{"category": "F", "amount": 53},
{"category": "G", "amount": 19},
{"category": "H", "amount": 87}
]
}
],
"signals": [
{
"name": "tooltip",
"value": {},
"on": [
{"events": "rect:mouseover", "update": "datum"},
{"events": "rect:mouseout", "update": "{}"}
]
}
],
"scales": [
{
"name": "xscale",
"type": "band",
"domain": {"data": "table", "field": "category"},
"range": "width",
"padding": 0.05,
"round": true
},
{
"name": "yscale",
"domain": {"data": "table", "field": "amount"},
"nice": true,
"range": "height"
},
{
"name": "color",
"type": "ordinal",
"domain": {"data": "table", "field": "category"},
"range": {"scheme": "category10"}
}
],
"axes": [
{ "orient": "bottom", "scale": "xscale" },
{ "orient": "left", "scale": "yscale" }
],
"marks": [
{
"type": "rect",
"from": {"data":"table"},
"encode": {
"enter": {
"x": {"scale": "xscale", "field": "category"},
"width": {"scale": "xscale", "band": 1},
"y": {"scale": "yscale", "field": "amount"},
"y2": {"scale": "yscale", "value": 0}
},
"update": {
"fill": {"value": "steelblue"}
},
"hover": {
"fill": {"value": "red"}
}
}
},
{
"type": "text",
"encode": {
"enter": {
"align": {"value": "center"},
"baseline": {"value": "bottom"},
"fill": {"scale": "color", "field": "category"}
},
"update": {
"x": {"scale": "xscale", "signal": "tooltip.category", "band": 0.5},
"y": {"scale": "yscale", "signal": "tooltip.amount", "offset": -2},
"text": {"signal": "tooltip.amount"},
"fillOpacity": [
{"test": "datum === tooltip", "value": 0},
{"value": 1}
]
}
}
}
]
}
Update: I found out that i have added the fill color in type='text' in mark property, instead of type='rect'
"fill": {"scale": "color", "field": "category"}.
{
"$schema": "https://vega.github.io/schema/vega/v5.json",
"description": "A basic bar chart example, with value labels shown upon mouse hover.",
"width": 400,
"height": 200,
"padding": 5,
"data": [
{
"name": "table",
"values": [
{"category": "A", "amount": 28},
{"category": "B", "amount": 55},
{"category": "C", "amount": 43},
{"category": "D", "amount": 91},
{"category": "E", "amount": 81},
{"category": "F", "amount": 53},
{"category": "G", "amount": 19},
{"category": "H", "amount": 87}
]
}
],
"signals": [
{
"name": "tooltip",
"value": {},
"on": [
{"events": "rect:mouseover", "update": "datum"},
{"events": "rect:mouseout", "update": "{}"}
]
}
],
"scales": [
{
"name": "xscale",
"type": "band",
"domain": {"data": "table", "field": "category"},
"range": "width",
"padding": 0.05,
"round": true
},
{
"name": "yscale",
"domain": {"data": "table", "field": "amount"},
"nice": true,
"range": "height"
},
{
"name": "color",
"type": "ordinal",
"domain": {"data": "table", "field": "category"},
"range": {"scheme": "category10"}
}
],
"axes": [
{ "orient": "bottom", "scale": "xscale" },
{ "orient": "left", "scale": "yscale" }
],
"marks": [
{
"type": "rect",
"from": {"data":"table"},
"encode": {
"enter": {
"x": {"scale": "xscale", "field": "category"},
"width": {"scale": "xscale", "band": 1},
"y": {"scale": "yscale", "field": "amount"},
"y2": {"scale": "yscale", "value": 0}
},
"update": {
"fill": {"scale": "color", "field": "category"}
},
"hover": {
"fill": {"value": "red"}
}
}
},
{
"type": "text",
"encode": {
"enter": {
"align": {"value": "center"},
"baseline": {"value": "bottom"}
},
"update": {
"x": {"scale": "xscale", "signal": "tooltip.category", "band": 0.5},
"y": {"scale": "yscale", "signal": "tooltip.amount", "offset": -2},
"text": {"signal": "tooltip.amount"},
"fillOpacity": [
{"test": "datum === tooltip", "value": 0},
{"value": 1}
]
}
}
}
]
}

Node Red smart Thermostat

I need help with increments in Node Red (on Raspberry Pi). I am trying to make a smart thermostat with a LCD touchscreen and an app for remote access (ex. coming home on a cold winter day and want to start heating your apartment).
Some suggestions on how to connect to the Raspberry Pi over the Internet (not local network) with an android and a link on a tutorial or example would be much appreciated.
P.S. I am doing this for a friend and I promised him some good results.
Sorry for messy code... => cleaned it up in the edit
I have tried everything I could think of to make my code work as I am not very experienced with NodeRed nor JS.
Global variables May just do the trick... I haven't figured it out yet...
Another barrier I have encountered is the ability to access and interact with the code outside the local network.
[
{
"id": "9f63513b.e227a",
"type": "ui_slider",
"z": "f216bae9.be3b68",
"name": "",
"label": "",
"group": "b344cd03.40f29",
"order": 2,
"width": "0",
"height": "0",
"passthru": true,
"topic": "slide",
"min": "10",
"max": "45",
"step": 1,
"x": 650,
"y": 140,
"wires": [
[
"4e35591.c5466a8",
"ef681f9b.17845"
]
]
},
{
"id": "4e35591.c5466a8",
"type": "delay",
"z": "f216bae9.be3b68",
"name": "Buffer",
"pauseType": "queue",
"timeout": "5",
"timeoutUnits": "seconds",
"rate": "1",
"nbRateUnits": "1",
"rateUnits": "second",
"randomFirst": "1",
"randomLast": "5",
"randomUnits": "seconds",
"drop": true,
"x": 810,
"y": 60,
"wires": [
[
"eec05221.3091e"
]
]
},
{
"id": "82848cf2.b33d1",
"type": "function",
"z": "f216bae9.be3b68",
"name": "delete payload",
"func": "msg.buton = msg.payload;\ndelete msg.payload;\nmsg.incalzire=msg.buton;\nreturn msg;",
"outputs": 1,
"noerr": 0,
"x": 480,
"y": 240,
"wires": [
[
"9f63513b.e227a"
]
]
},
{
"id": "ef681f9b.17845",
"type": "ui_gauge",
"z": "f216bae9.be3b68",
"name": "",
"group": "b344cd03.40f29",
"order": 1,
"width": 0,
"height": 0,
"gtype": "gage",
"title": "",
"label": "",
"format": "{{value}}",
"min": "0",
"max": "60",
"colors": [
"#00b500",
"#e6e600",
"#ca3838"
],
"seg1": "",
"seg2": "",
"x": 810,
"y": 220,
"wires": []
},
{
"id": "eec05221.3091e",
"type": "function",
"z": "f216bae9.be3b68",
"name": "delete payload",
"func": "msg.tempslide=msg.payload;\ndelete msg.payload;\n\nreturn msg;",
"outputs": 1,
"noerr": 0,
"x": 1000,
"y": 60,
"wires": [
[
"f5853672.5fe148"
]
]
},
{
"id": "6b57c137.8c136",
"type": "function",
"z": "f216bae9.be3b68",
"name": "Switch",
"func": "if(msg.payload===0){\n msg.payload=1;\n}\nelse if (msg.payload==1){\n msg.payload=0;\n}\nreturn msg;",
"outputs": 1,
"noerr": 0,
"x": 310,
"y": 460,
"wires": [
[
"82848cf2.b33d1"
]
]
},
{
"id": "f5853672.5fe148",
"type": "function",
"z": "f216bae9.be3b68",
"name": "working mess",
"func": "if (msg.incalzire===0||msg.payload===0){\n\nif (msg.temp<=msg.tempslide){\n msg.payload=0;\n}\n\nelse if (msg.temp>msg.tempslide){\n msg.payload=1;\n}\n\nelse{\n msg.payload=1;}\n \n}\n\n\nelse{\n msg.payload=1;\n \n}\n\n\n\n\nreturn msg;",
"outputs": 1,
"noerr": 0,
"x": 1058,
"y": 140,
"wires": [
[
"3f6977e5.b44158",
"ee3a7840.808ad8",
"7726596c.b74228"
]
]
},
{
"id": "d34a3234.79712",
"type": "ui_switch",
"z": "f216bae9.be3b68",
"name": "",
"label": "Override Window",
"group": "b344cd03.40f29",
"order": 4,
"width": 0,
"height": 0,
"passthru": true,
"decouple": "false",
"topic": "",
"style": "",
"onvalue": "1",
"onvalueType": "num",
"onicon": "",
"oncolor": "",
"offvalue": "0",
"offvalueType": "num",
"officon": "",
"offcolor": "",
"x": 250,
"y": 420,
"wires": [
[
"6b57c137.8c136"
]
]
},
{
"id": "3f6977e5.b44158",
"type": "debug",
"z": "f216bae9.be3b68",
"name": "",
"active": false,
"tosidebar": true,
"console": false,
"tostatus": false,
"complete": "true",
"x": 1293,
"y": 140,
"wires": []
},
{
"id": "ee3a7840.808ad8",
"type": "function",
"z": "f216bae9.be3b68",
"name": "Message",
"func": "if(msg.payload===0){\n msg.payload='PORNITA'; //ON\n}\nelse if (msg.payload==1){\n msg.payload='OPRITA'; //OFF\n}\nreturn msg;",
"outputs": 1,
"noerr": 0,
"x": 1183,
"y": 340,
"wires": [
[
"eaeac5fb.c27728"
]
]
},
{
"id": "7726596c.b74228",
"type": "rpi-gpio out",
"z": "f216bae9.be3b68",
"name": "Rel1",
"pin": "22",
"set": "",
"level": "0",
"freq": "",
"out": "out",
"x": 1233,
"y": 220,
"wires": []
},
{
"id": "c0784b3b.c1fcb8",
"type": "function",
"z": "f216bae9.be3b68",
"name": "Switch",
"func": "if(msg.payload===0){\n msg.payload=1;\n}\nelse if (msg.payload==1){\n msg.payload=0;\n}\nreturn msg;",
"outputs": 1,
"noerr": 0,
"x": 250,
"y": 380,
"wires": [
[
"d34a3234.79712"
]
]
},
{
"id": "eaeac5fb.c27728",
"type": "ui_text",
"z": "f216bae9.be3b68",
"group": "b344cd03.40f29",
"order": 3,
"width": 0,
"height": 0,
"name": "",
"label": "Incalzirea este",
"format": "{{msg.payload}}",
"layout": "row-right",
"x": 1220,
"y": 380,
"wires": []
},
{
"id": "248c4825.00c018",
"type": "rpi-gpio in",
"z": "f216bae9.be3b68",
"name": "",
"pin": "40",
"intype": "tri",
"debounce": "25",
"read": false,
"x": 90,
"y": 300,
"wires": [
[
"c0784b3b.c1fcb8"
]
]
},
{
"id": "afb8009a.49841",
"type": "function",
"z": "f216bae9.be3b68",
"name": "delete payload",
"func": "//nu umbla la asta\nmsg.temp=msg.payload;\ndelete msg.payload;\nreturn msg;",
"outputs": 1,
"noerr": 0,
"x": 320,
"y": 140,
"wires": [
[
"c0784b3b.c1fcb8"
]
]
},
{
"id": "c696dbbc.58ee98",
"type": "rpi-dht22",
"z": "f216bae9.be3b68",
"name": "",
"topic": "Interior",
"dht": "22",
"pintype": "1",
"pin": "29",
"x": 140,
"y": 180,
"wires": [
[
"afb8009a.49841",
"33ec6fb6.fda7f"
]
]
},
{
"id": "33ec6fb6.fda7f",
"type": "ui_gauge",
"z": "f216bae9.be3b68",
"name": "",
"group": "d2bfb34b.1c943",
"order": 1,
"width": 0,
"height": 0,
"gtype": "gage",
"title": "",
"label": "° C",
"format": "{{value}}",
"min": 0,
"max": "60",
"colors": [
"#00b500",
"#e6e600",
"#ca3838"
],
"seg1": "",
"seg2": "",
"x": 150,
"y": 220,
"wires": []
},
{
"id": "d3a6bff.b99a44",
"type": "inject",
"z": "f216bae9.be3b68",
"name": "",
"topic": "",
"payload": "",
"payloadType": "date",
"repeat": "50",
"crontab": "",
"once": false,
"onceDelay": 0.1,
"x": 110,
"y": 120,
"wires": [
[
"c696dbbc.58ee98"
]
]
},
{
"id": "b344cd03.40f29",
"type": "ui_group",
"z": "",
"name": "Reglarea Incalzirii",
"tab": "af80de11.bfd15",
"order": 2,
"disp": true,
"width": "6",
"collapse": true
},
{
"id": "d2bfb34b.1c943",
"type": "ui_group",
"z": "",
"name": "Temperatura Curenta",
"tab": "af80de11.bfd15",
"order": 1,
"disp": true,
"width": "6",
"collapse": true
},
{
"id": "af80de11.bfd15",
"type": "ui_tab",
"z": "",
"name": "Sergiu",
"icon": "fa-thermometer-full",
"order": 4
}
]
The old thermostat was basically an automated relay switch. I have to make it smart and my best bet is a raspberry pi.
The increment part can replace the slider(I have Backups) and has to be triggered by a button in the Dashboard UI.
Everything except of what I mentioned works corectly.
Thank you for your help!! (or at least your time)

Parallel coordinates in Vega-Lite?

Is it possible to create parallel coordinates in Vega-Lite? I'm looking for a simple yet powerful plotting library for JavaScript and support for parallel coordinates is a requirement.
I have googled it but only found how to do it in Vega.
Yes, you can create a parallel coordinates plot in Vega-Lite by combining a window transform and a fold transform. Here is an example with the Iris dataset (vega editor link):
{
"data": {
"url": "data/iris.json"
},
"transform": [
{"window": [{"op": "count", "as": "index"}]},
{"fold": ["petalLength", "petalWidth", "sepalLength", "sepalWidth"]}
],
"mark": "line",
"encoding": {
"color": {"type": "nominal", "field": "species"},
"detail": {"type": "nominal", "field": "index"},
"opacity": {"value": 0.3},
"x": {"type": "nominal", "field": "key"},
"y": {"type": "quantitative", "field": "value"}
},
"width": 600,
"height": 300
}
Notice we use a window transform to construct an index, followed by a fold transform to restructure the data for plotting.
Building on #jakevdp's answer, here is an improved version that normalizes each variables and manually draw axes with rule, text and tick marks.
Note that parallel coordinates are often useful when you have interactivity though, so there is more work to be done here.
{
"data": {
"url": "data/iris.json"
},
"width": 600,
"height": 300,
"transform": [
{"window": [{"op": "count", "as": "index"}]},
{"fold": ["petalLength", "petalWidth", "sepalLength", "sepalWidth"]},
{
"window": [
{"op": "min", "field": "value", "as": "min"},
{"op": "max", "field": "value", "as": "max"}
],
"frame": [null, null],
"groupby": ["key"]
},
{
"calculate": "(datum.value - datum.min) / (datum.max-datum.min)",
"as": "norm_val"
},
{
"calculate": "(datum.min + datum.max) / 2",
"as": "mid"
}
],
"layer": [{
"mark": {"type": "rule", "color": "#ccc", "tooltip": null},
"encoding": {
"detail": {"aggregate": "count", "type": "quantitative"},
"x": {"type": "nominal", "field": "key"}
}
}, {
"mark": "line",
"encoding": {
"color": {"type": "nominal", "field": "species"},
"detail": {"type": "nominal", "field": "index"},
"opacity": {"value": 0.3},
"x": {"type": "nominal", "field": "key"},
"y": {"type": "quantitative", "field": "norm_val", "axis": null},
"tooltip": [{
"field": "petalLength"
}, {
"field": "petalWidth"
}, {
"field": "sepalLength"
}, {
"field": "sepalWidth"
}]
}
},{
"encoding": {
"x": {"type": "nominal", "field": "key"},
"y": {"value": 0}
},
"layer": [{
"mark": {"type": "text", "style": "label"},
"encoding": {
"text": {"aggregate": "max", "field": "max", "type": "quantitative"}
}
}, {
"mark": {"type": "tick", "style": "tick", "size": 8, "color": "#ccc"}
}]
},{
"encoding": {
"x": {"type": "nominal", "field": "key"},
"y": {"value": 150}
},
"layer": [{
"mark": {"type": "text", "style": "label"},
"encoding": {
"text": {"aggregate": "min", "field": "mid", "type": "quantitative"}
}
}, {
"mark": {"type": "tick", "style": "tick", "size": 8, "color": "#ccc"}
}]
},{
"encoding": {
"x": {"type": "nominal", "field": "key"},
"y": {"value": 300}
},
"layer": [{
"mark": {"type": "text", "style": "label"},
"encoding": {
"text": {"aggregate": "min", "field": "min", "type": "quantitative"}
}
}, {
"mark": {"type": "tick", "style": "tick", "size": 8, "color": "#ccc"}
}]
}],
"config": {
"axisX": {"domain": false, "labelAngle": 0, "tickColor": "#ccc", "title": false},
"view": {"stroke": null},
"style": {
"label": {"baseline": "middle", "align": "right", "dx": -5, "tooltip": null},
"tick": {"orient": "horizontal", "tooltip": null}
}
}
}

Add Y values as labels on a line chart, for some data points

I have a line chart, quite basic (see below for a simplified example that works on the Vega Editor). Basically, it draws lines, the X axis is successive dates, the Y axis is some numerical values.
I am trying to add labels for some of the data points on the line, with the value of Y at that point. Only for some of the data points, because some charts can be for over a year, so there can be hundreds of days (X values).
This is by the way how labels are put on the X axis automatically by Vega. If there are too many X values, it does not display every day, it says e.g. "Jan 1", then "Jan 8", then "Jan 15", etc. (nice one!)
Just for reference, with C3 (a charting library for D3), I used the following to draw one label out of every 7 data point:
data: {
json: data.data,
type: 'spline',
labels: {
format: function(v, id, i, j) {
if ( i % 7 === 3 ) {
return d3.format('.2f')(v);
}
}
...
Unfortunately, I have no idea where to start. I did not find any such example, and could not find anything related in the documentation.
Just for reference, here is an example chart to which I'd like to add these labels:
{
"$schema": "https://vega.github.io/schema/vega/v3.json",
"width": 500,
"height": 250,
"autosize": {
"type": "fit",
"resize": true
},
"data": [{
"name": "table",
"format": {
"parse": {
"date": "date",
"value": "number"
}
},
"values": [
{ "date": "2017-09-01", "value": "12.34", "what": "one" },
{ "date": "2017-09-01", "value": "4.34", "what": "two" },
{ "date": "2017-09-02", "value": "13.34", "what": "one" },
{ "date": "2017-09-02", "value": "13.34", "what": "two" },
{ "date": "2017-09-03", "value": "4.34", "what": "one" },
{ "date": "2017-09-03", "value": "15.34", "what": "two" },
{ "date": "2017-09-04", "value": "15.34", "what": "one" },
{ "date": "2017-09-04", "value": "5.34", "what": "two" },
{ "date": "2017-09-05", "value": "16.34", "what": "one" },
{ "date": "2017-09-05", "value": "6.34", "what": "two" },
{ "date": "2017-09-06", "value": "17.34", "what": "one" },
{ "date": "2017-09-06", "value": "17.34", "what": "two" },
{ "date": "2017-09-07", "value": "18.34", "what": "one" },
{ "date": "2017-09-07", "value": "8.34", "what": "two" },
{ "date": "2017-09-08", "value": "18.34", "what": "one" },
{ "date": "2017-09-08", "value": "14.34", "what": "two" },
{ "date": "2017-09-09", "value": "9.34", "what": "one" },
{ "date": "2017-09-09", "value": "14.34", "what": "two" },
{ "date": "2017-09-10", "value": "20.34", "what": "one" },
{ "date": "2017-09-10", "value": "4.34", "what": "two" }
]
}],
"scales": [{
"name": "x",
"type": "utc",
"range": "width",
"domain": {"data": "table", "field": "date"}
}, {
"name": "y",
"type": "linear",
"range": "height",
"nice": true,
"zero": true,
"domain": {"data": "table", "field": "value"}
}, {
"name": "color",
"type": "ordinal",
"range": "category",
"domain": {"data": "table", "field": "what"}
}],
"axes": [{
"orient": "bottom",
"scale": "x",
"encode": {
"labels": {
"interactive": true,
"update": {
"fill": {"value": "steelblue"},
"angle": {"value": 50},
"fontSize": {"value": 14},
"align": {"value": "left"},
"baseline": {"value": "middle"},
"dx": {"value": 3}
},
"hover": {
"fill": {"value": "firebrick"}
}}}
}, {
"orient": "left",
"scale": "y"
}],
"marks": [{
"type": "group",
"from": {
"facet": {
"name": "series",
"data": "table",
"groupby": "what"
}
},
"marks": [{
"type": "line",
"from": {"data": "series"},
"encode": {
"enter": {
"x": {"scale": "x", "field": "date"},
"y": {"scale": "y", "field": "value"},
"stroke": {"scale": "color", "field": "what"},
"strokeWidth": {"value": 2}
},
"update": {
"interpolate": {"value": "monotone"},
"fillOpacity": {"value": 1}
},
"hover": {
"fillOpacity": {"value": 0.5}
}
}
}]
}]
}
Vega has a property called tickCount that can be added to your axes definitions. Adding this to your y-axis must solve your case:
{
"orient": "left",
"scale": "y",
"tickCount": 4
}
You could use a signal as well if it should be dynamic.
The feature is even more powerful than illustrated. Go check out the docs for other options in below link:
https://vega.github.io/vega/docs/axes/

ng-repeat error: "Duplicates in a repeater are not allowed"

Here is my html,
<tr ng-repeat="val in attribute.format.values">
I am getting,
[Duplicates in a repeater are not allowed. Use 'track by' expression to specify unique keys. Repeater: val in attribute.format.values, Duplicate key: object:07F, Duplicate value: {2}][1]
Here is my JSON,
[{
"name": "Auto",
"weight": "1",
"value": "1",
"count": 0,
"min": 0,
"max": 0,
"children": [],
"id": "06c9f57c-963f-4977-bca5-9226e971a8dc",
"visible": true,
"$$hashKey": "06V"
}, {
"name": "On",
"weight": "1",
"value": "2",
"count": 0,
"min": 0,
"max": 0,
"children": [],
"id": "dc019b87-1da5-4f21-b91f-4ee35ec04eb8",
"visible": true,
"$$hashKey": "06W"
}, {
"name": "Off",
"weight": "1",
"value": "4",
"count": 0,
"min": 0,
"max": 0,
"children": [],
"id": "daf8ef80-a2da-4e02-8960-791b8528905e",
"visible": true,
"$$hashKey": "06X"
}, {
"name": "Redeye Reduction",
"weight": "1",
"value": "5",
"count": 0,
"min": 0,
"max": 0,
"children": [],
"id": "87ccb4ee-39cd-4bd0-9817-7e477af6d5b0",
"visible": true,
"$$hashKey": "06Y"
}, {
"name": "Slow Sync",
"weight": "1",
"value": "6",
"count": 0,
"min": 0,
"max": 0,
"children": [],
"id": "e0b14c8b-af4b-4ab8-a533-32ac4829613f",
"visible": true,
"$$hashKey": "06Z"
}, {
"name": "High Speed Sync",
"weight": "1",
"value": "7",
"count": 0,
"min": 0,
"max": 0,
"children": [],
"id": "622c7ebf-067c-46ed-913a-ba045a0586df",
"visible": true,
"$$hashKey": "070"
}, {
"name": "Front Curtain",
"weight": "1",
"value": "8",
"count": 0,
"min": 0,
"max": 0,
"children": [],
"id": "fe12c21c-e2c3-4702-ae9b-82f2fe248574",
"visible": true,
"$$hashKey": "071"
}, {
"name": "Rear Curtain",
"weight": "1",
"value": "9",
"count": 0,
"min": 0,
"max": 0,
"children": [],
"id": "4a229ebb-d029-4b1e-a13d-246d00215900",
"visible": true,
"$$hashKey": "072"
}, {
"name": "Fill-in",
"weight": "1",
"value": "10",
"count": 0,
"min": 0,
"max": 0,
"children": [],
"id": "a7ed372d-398f-4614-8efa-64a338f0ad20",
"visible": true,
"$$hashKey": "073"
}, {
"name": "Wireless",
"weight": "1",
"value": "11",
"count": 0,
"min": 0,
"max": 0,
"children": [],
"id": "b36ab529-feab-42aa-8863-2a7084ac0aba",
"visible": true,
"$$hashKey": "074"
}, {
"name": "Redeye Reduction with Slow Sync",
"value": "12",
"weight": "1",
"visible": true,
"id": "23ee6ac2-1b8b-41a7-ae80-aa4fcd8134ae",
"$$hashKey": "07F"
}, {
"name": "Slow Rear-Curtain Sync",
"value": "13",
"weight": "1",
"visible": true,
"id": "f5835da6-4eac-4878-a8c0-3f91cd22372f",
"$$hashKey": "07J"
}, {
"name": "Repeating or Strobe",
"value": "14",
"weight": "1",
"visible": true,
"id": "8f3bb252-ae6e-426a-9781-d1232a0a4845",
"$$hashKey": "0CW"
}, {
"name": "Rear Sync",
"value": "15",
"weight": "1",
"visible": true,
"id": "d668aa49-a999-4638-8af2-5e9eaafd6e75",
"$$hashKey": "06L"
}, {
"name": "Fill-Flaw",
"value": "16",
"weight": "1",
"visible": true,
"id": "00f92889-05f9-45fc-b3de-37e224991548",
"$$hashKey": "08D"
}, {
"name": "Advanced Flash",
"value": "17",
"weight": "1",
"visible": true,
"id": "d49c3d25-2bf5-4723-b7d4-c3ae36783097",
"$$hashKey": "079"
}, {
"name": "Fill-Flash",
"value": "18",
"weight": "1",
"visible": true,
"id": "4693db2a-19c7-4839-8e65-875e36416c63",
"$$hashKey": "0ER"
}, {
"name": "Smart Flash",
"value": "19",
"weight": "1",
"visible": true,
"id": "8b04d59b-75cc-46ff-acc0-33f410f64a09",
"$$hashKey": "07D"
}, {
"name": "",
"value": "",
"weight": "",
"visible": true,
"id": "18cec753-48fe-47e6-9e67-1bb36972bee4",
"$$hashKey": "07F"
}, {
"name": "",
"value": "",
"weight": "",
"visible": true,
"id": "a7fbad1d-2a49-40e7-a9b1-520db0f9fc65"
}]
<tr ng-repeat="val in attribute.format.values track by id">
edit like this
id could be the identity of the objects so you can tack though the id property, that will keep one object if you have add two objects that shares same id mistakenly.
Try this:
you can use 'track by $index'
<tr ng-repeat="val in attribute.format.values track by $index">

Categories