Vega-lite: How do you customize legend labels? - javascript

I have this bar chart that's made with Vega-lite (code and pic below).
But I want to customize the legend labels so that instead of videoGame it's Video Game and instead of tv its TV. Is there anyway to do this?
lineChart = vegalite ({
"$schema": "https://vega.github.io/schema/vega-lite/v5.json",
"width": 560,
"height": 200,
"data": {"values": chartData},
"mark": {"type": "bar"},
"encoding": {
"x": {"field": "year_reference", "type": "temporal", "axis": {"title": "Year", "grid": true}},
"y": {"field": "reference_count_total", "type": "quantitative", "axis": {"title": "References", "grid": true}},
"color": {
"field": "title_type",
"scale": {
"domain": [
"tv",
"movie",
"video",
"videoGame"
],
"range": [
"#9e9ac8",
"#74c476",
"#a6761d",
"#6baed6"
]
},
"legend": true,
"title": "Reference Type"
},
}
})

Just provide labelExpr in legend, where you can conditionally give the labels depending on your fields data.
Refer the below code or the chart in editor
{
"$schema": "https://vega.github.io/schema/vega-lite/v5.json",
"width": 560,
"height": 200,
"data": {
"values": [
{
"title_type": "tv",
"year_reference": "10-12-2012",
"reference_count_total": 10
},
{
"title_type": "movie",
"year_reference": "10-12-2012",
"reference_count_total": 10
},
{
"title_type": "video",
"year_reference": "10-12-2012",
"reference_count_total": 10
},
{
"title_type": "videoGame",
"year_reference": "10-12-2012",
"reference_count_total": 10
}
]
},
"mark": {"type": "bar"},
"encoding": {
"x": {
"field": "year_reference",
"type": "temporal",
"axis": {"title": "Year", "grid": true}
},
"y": {
"field": "reference_count_total",
"type": "quantitative",
"axis": {"title": "References", "grid": true}
},
"color": {
"field": "title_type",
"scale": {
"domain": ["tv", "movie", "video", "videoGame"],
"range": ["#9e9ac8", "#74c476", "#a6761d", "#6baed6"]
},
"legend": {
"labelExpr": "datum.label == 'tv' ? 'Tv' : datum.label == 'movie' ? 'Movie' :datum.label == 'video' ? 'Video' : 'Video Game'"
},
"title": "Reference Type"
}
}
}

Related

Is there a way in Vega lite to use different color encodings on a choropleth map, the map has a drop down menu

As stated the map has a drop down menu that changes the display of the map, it selects different columns in the dataset. Ideally I would like to show a different "scheme" for input one and input two or what would also work in my case is to use "reverse" the "scale" encoding to reverse the color scheme for one of the two data columns being loaded
Code extract:
{"$schema": "https://vega.github.io/schema/vega-lite/v5.json",
"config": {
"background":"white",
"view": {"stroke": "trasparent"}},
"width": 700,
"height": 500,
"data": {
"url": "https://unpkg.com/world-atlas#1.1.4/world/110m.json",
"format": {
"type": "topojson",
"feature": "countries"}
},
"projection": {
"type": "naturalEarth2"},
"mark": {
"type": "geoshape",
"stroke": "rgb(50, 50, 50)",
"strokeWidth":0.3},
"transform": [
{"calculate":"parseInt(datum.id)", "as":"id_N"},
{
"lookup": "id_N",
"from": {
"key": "id",
"fields": ["alpha3", "name"],
"data": {"url": "data1"}}
},
{"lookup": "alpha3",
"from":{
"data":{
"url":"data2"},
"key": "ISO3",
"fields":["Vulnerability", "Gain"]
}
},
{"calculate": "datum.Vulnerability", "as": "Climate Vulnerability"},
{"calculate": "datum.Gain", "as": "Overall Vulnerability Index"},
{"calculate": "datum[Select]","as": "varSelected"},
],
"params": [
{"name": "Select",
"value": "Vulnerability",
"bind": {
"input": "select",
"options": [
"Climate Vulnerability",
"Overall Vulnerability Index"]}}],
"encoding": {
"color":{
"field":"varSelected",
"type":"quantitative",
"title": null,
"scale":{
"scheme": {"name": "turbo", "count":5}
}
},
"tooltip":[
{"field":"name", "title":"Country"},
{"field":"varSelected","title":"Score","type":"quantitative"}],
}

Sorting a chart axis based on the dynamically updated axis order in another chart

In this VegaLite spec the y-axis order of the bottom-most barplot is updated as the data of that plot is filtered based on the selection in the scatter plot. How can I achieve the same resorting behavior for both the blue and orange bars in the top-most bar plot where I have layered the same barplot together with another chart?
I have tried toggling the axis between shared and independent and switching the order of the layer, but that didn't do it. Conceptually I can imagine using a calculate transform to define a new field that is based on the selection and used as the sort order key, but I can't figure out how to write this vega expression string.
Here is that Altair code if anyone prefers to solve it that way:
import altair as alt
import pandas as pd
data={
'Term': ['algorithm','learning','learning','algorithm','algorithm','learning'],
'Freq_x': [1330,1153,504.42,296.69,177.59,140.35],
'Total': [1330, 1353,1353.7,1330.47,1330.47,1353.7],
'Category': ['Default', 'Default', 'Topic1', 'Topic1', 'Topic2', 'Topic2'],
'logprob': [30.0, 27.0, -5.116, -5.1418, -5.4112, -5.5271],
'loglift': [30.0, 27.0, 0.0975, 0.0891, -0.1803, -0.3135],
'saliency_ind': [0, 3, 76, 77, 181, 186],
'x': [None,None,-0.0080,-0.0080,-0.0053,-0.0053],
'y': [None,None,-0.0056,-0.0056, 0.0003,0.0003],
'topics': [None,None, 1.0, 1.0, 2.0, 2.0],
'cluster': [None,None, 1.0, 1.0, 1.0, 1.0],
'Freq_y': [None,None,20.39,20.39,14.18,14.18]}
df=pd.DataFrame(data)
pts = alt.selection(type="single", fields=['Category'], empty='none')
points = alt.Chart(df).mark_circle().encode(
x='mean(x)',
y='mean(y)',
size='Freq_y',
detail='Category',
color=alt.condition(pts, alt.value('#F28E2B'), alt.value('#4E79A7'))
).add_selection(pts)
bars = alt.Chart(df).mark_bar().encode(
x='Freq_x',
y=alt.Y('Term'),
)
bars2 = alt.Chart(df).mark_bar(color='#F28E2B').encode(
x='Freq_x',
y=alt.Y('Term', sort='-x'),
).transform_filter(
pts
)
(points | (bars + bars2) & bars2)
The issue with your spec was that in layers you performed filter transform which created a separate data for each layers. Sorting was working at each level of layer but since both the layers data were separate so each layer was getting sorted inpendently.
So instead of having a filter transform, I tried to manual filter using calculate transform and created a filtered_freq_x field which is later used on 2nd layer and performed sorting using this on window. So with this my data becomes same for both layers, just few fields were added and used.
Let me know if this works for you not. Below is the spec config and editor:
{
"config": {"view": {"continuousWidth": 200, "continuousHeight": 300}},
"hconcat": [
{
"mark": "circle",
"encoding": {
"color": {
"condition": {"value": "#F28E2B", "selection": "selector046"},
"value": "#4E79A7"
},
"detail": {"type": "nominal", "field": "Category"},
"size": {"type": "quantitative", "field": "Freq_y"},
"x": {"type": "quantitative", "aggregate": "mean", "field": "x"},
"y": {"type": "quantitative", "aggregate": "mean", "field": "y"}
},
"selection": {
"selector046": {
"type": "single",
"fields": ["Category"],
"empty": "none"
}
}
},
{
"vconcat": [
{
"transform": [
{
"joinaggregate": [
{"field": "Freq_x", "op": "max", "as": "max_Fx"}
]
},
{
"calculate": "selector046['Category'] ? selector046['Category'] : []",
"as": "filterCategory"
},
{
"calculate": "indexof(datum.filterCategory,datum['Category']) > -1 ? datum['Freq_x'] : null",
"as": "filtered_Freq_x"
},
{
"sort": [{"field": "filtered_Freq_x", "order": "descending"}],
"window": [{"op": "rank", "as": "Sorted"}]
}
],
"height": 50,
"layer": [
{
"mark": "bar",
"encoding": {
"x": {"type": "quantitative", "field": "Freq_x"},
"y": {
"type": "nominal",
"field": "Term",
"sort": {"field": "Sorted"}
}
}
},
{
"mark": {"type": "bar", "color": "#F28E2B"},
"encoding": {
"x": {"type": "quantitative", "field": "filtered_Freq_x"},
"y": {
"type": "nominal",
"field": "Term",
"sort": {"field": "Sorted"}
}
}
}
]
},
{
"mark": {"type": "bar", "color": "#F28E2B"},
"encoding": {
"x": {"type": "quantitative", "field": "Freq_x"},
"y": {"type": "nominal", "field": "Term", "sort": "-x"}
},
"transform": [{"filter": {"selection": "selector046"}}]
}
]
}
],
"data": {"name": "data-d807cd22b94d04d6f1543201cfe5f45e"},
"$schema": "https://vega.github.io/schema/vega-lite/v4.8.1.json",
"datasets": {
"data-d807cd22b94d04d6f1543201cfe5f45e": [
{
"Term": "algorithm",
"Freq_x": 1330,
"Total": 1330,
"Category": "Default",
"logprob": 30,
"loglift": 30,
"saliency_ind": 0,
"x": null,
"y": null,
"topics": null,
"cluster": null,
"Freq_y": null
},
{
"Term": "learning",
"Freq_x": 1153,
"Total": 1353,
"Category": "Default",
"logprob": 27,
"loglift": 27,
"saliency_ind": 3,
"x": null,
"y": null,
"topics": null,
"cluster": null,
"Freq_y": null
},
{
"Term": "learning",
"Freq_x": 504.42,
"Total": 1353.7,
"Category": "Topic1",
"logprob": -5.116,
"loglift": 0.0975,
"saliency_ind": 76,
"x": -0.008,
"y": -0.0056,
"topics": 1,
"cluster": 1,
"Freq_y": 20.39
},
{
"Term": "algorithm",
"Freq_x": 296.69,
"Total": 1330.47,
"Category": "Topic1",
"logprob": -5.1418,
"loglift": 0.0891,
"saliency_ind": 77,
"x": -0.008,
"y": -0.0056,
"topics": 1,
"cluster": 1,
"Freq_y": 20.39
},
{
"Term": "algorithm",
"Freq_x": 177.59,
"Total": 1330.47,
"Category": "Topic2",
"logprob": -5.4112,
"loglift": -0.1803,
"saliency_ind": 181,
"x": -0.0053,
"y": 0.0003,
"topics": 2,
"cluster": 1,
"Freq_y": 14.18
},
{
"Term": "learning",
"Freq_x": 140.35,
"Total": 1353.7,
"Category": "Topic2",
"logprob": -5.5271,
"loglift": -0.3135,
"saliency_ind": 186,
"x": -0.0053,
"y": 0.0003,
"topics": 2,
"cluster": 1,
"Freq_y": 14.18
}
]
}
}

Vega editor "table is empty"

I am trying to build an elementary plot showing proportion of energy source by continent. I've already cleaned up the data and uploaded a .csv file here : https://raw.githubusercontent.com/mkeutgen/dataviz_energy/main/prop_source_by_continent_2015
Yet when I try to import it in vega lite editor, it states that my csv is empty.
Here is the code I've written :
{
"data": {"url": "raw.githubusercontent.com/mkeutgen/dataviz_energy/main/prop_source_by_continent_2015"},
"mark": "bar",
"encoding": {
"x": {
"field": "continent",
"type": "nominal",
"domain":["Africa","Europe","Asia","North America","South America","Asia"],
"title": "Continent"
},
"y": {
"field":"prop",
"aggregate":"sum",
"type": "quantitative",
"stack": "normalize"
},
"color": {
"field": "share energy",
"type": "nominal",
"scale": {
"domain": ["coal_share_energy","gas_share_energy","nuclear_share_energy", "hydro_share_energy","renewables_share_energy","oil_share_energy"],
"range": ["#e7ba52", "#c7c7c7", "#aec7e8", "#1f77b4", "#9467bd"]
},
"title": "Weather type"
}
}
}
If you look in the Javascript console, you'll see the issue:
loader.js:175 GET https://vega.github.io/editor/raw.githubusercontent.com/mkeutgen/dataviz_energy/main/prop_source_by_continent_2015 404
You are attempting to load the dataset with a relative rather than absolute URL, which is returning a 404; you can fix this by adding https:// to the front of your URL.
Additionally, since your URL does not include a file extension, you must tell Vega-Lite that the data is CSV-formatted using a format specification. With these two changes, your chart works (open in editor):
{
"data": {
"url": "https://raw.githubusercontent.com/mkeutgen/dataviz_energy/master/prop_source_by_continent_2015",
"format": {"type": "csv"}
},
"mark": "bar",
"encoding": {
"x": {
"field": "continent",
"type": "nominal",
"domain":["Africa","Europe","Asia","North America","South America","Asia"],
"title": "Continent"
},
"y": {
"field":"prop",
"aggregate":"sum",
"type": "quantitative",
"stack": "normalize"
},
"color": {
"field": "share energy",
"type": "nominal",
"scale": {
"domain": ["coal_share_energy","gas_share_energy","nuclear_share_energy",
"hydro_share_energy","renewables_share_energy","oil_share_energy"],
"range": ["#e7ba52", "#c7c7c7", "#aec7e8", "#1f77b4", "#9467bd"]
},
"title": "Weather type"
}
}
}
The Url you have provided in your data config should also contain https:// and then need to specify the format of data. Refer the below config or try fiddle:
{
"data": {
"url": "https://raw.githubusercontent.com/mkeutgen/dataviz_energy/main/prop_source_by_continent_2015",
"format": {"type": "csv"}
},
"$schema": "https://vega.github.io/schema/vega-lite/v5.json",
"mark": "bar",
"encoding": {
"x": {
"field": "continent",
"type": "nominal",
"domain": [
"Africa",
"Europe",
"Asia",
"North America",
"South America",
"Asia"
],
"title": "Continent"
},
"y": {
"field": "prop",
"aggregate": "sum",
"type": "quantitative",
"stack": "normalize"
},
"color": {
"field": "share energy",
"type": "nominal",
"scale": {
"domain": [
"coal_share_energy",
"gas_share_energy",
"nuclear_share_energy",
"hydro_share_energy",
"renewables_share_energy",
"oil_share_energy"
],
"range": ["#e7ba52", "#c7c7c7", "#aec7e8", "#1f77b4", "#9467bd"]
},
"title": "Weather type"
}
}
}

How to render class/org/flow/state chart/diagrams with Vega / Vega-lite

I can't find an example of a state/class/flow chart/org chart diagram with Vega. Are there any out there?
It feels like Vega is perfectly suited for this (if a bit overpowered), but without an example to start from it's a rather steep learning curve. There are some examples on a "How Vega Works" page, but no links to how they're built:
There's also the tree layout example, but it's not clear how one would begin converting this into blocks suitable for a flow-chart style diagram.
Here's some examples of the sort of output desired (plus other shapes e.g. diamonds/triangles) from e.g. mermaid.js
Suppose you're able to represent your chart as follows:
"values": [
{"id": "1", "parent": null, "title": "Animal"},
{"id": "2", "parent": "1", "title": "Duck"},
{"id": "3", "parent": "1", "title": "Fish"},
{"id": "4", "parent": "1", "title": "Zebra"}
]
What you can then do is to lay the nodes out in a tree-like shape (stratify does the job):
"transform": [
{
"type": "stratify",
"key": "id",
"parentKey": "parent"
},
{
"type": "tree",
"method": "tidy",
"separation": true,
"size": [{"signal": "width"}, {"signal": "height"}]
}
]
having laid out the nodes, you need to generate connecting lines, treelinks + linkpath combo does exactly that:
{
"name": "links",
"source": "tree", // take datasource "tree" as input
"transform": [
{ "type": "treelinks" }, // apply transform 1
{ "type": "linkpath", // follow up with next transform
"shape": "diagonal"
}
]
}
now that you've got your data sources, you want to draw actual objects. in Vega these are called marks. I guess this is where I'm going to deviate from your desired output as I'm only drawing one rectangle with a title for each data point and some basic lines to connect:
"marks": [
{
"type": "path",
"from": {"data": "links"}, // dataset we defined above
"encode": {
"enter": {
"path": {"field": "path"} // linkpath generated a dataset with "path" field in it - we just grab it here
}
}
},
{
"type": "rect",
"from": {"data": "tree"},
"encode": {
"enter": {
"stroke": {"value": "black"},
"width": {"value": 100},
"height": {"value": 20},
"x": {"field": "x"},
"y": {"field": "y"}
}
}
},
{
"type": "text",
"from": {"data": "tree"}, // use data set we defined earlier
"encode": {
"enter": {
"stroke": {"value": "black"},
"text": {"field": "title"}, // we can use data fields to display actual values
"x": {"field": "x"}, // use data fields to draw values from
"y": {"field": "y"},
"dx": {"value":50}, // offset the mark to appear in rectangle center
"dy": {"value":13},
"align": {"value": "center"}
}
}
}
]
All in all I arrived at a very basic approximation of your target state. It's definitely not an exact match: the rectangles there should probably be replaced with groups and connection paths will need some work too. You will notice I'm not using any signalsto feed dynamic user inputs and update/exit/hover instructions - again, for simplicity.
{
"$schema": "https://vega.github.io/schema/vega/v5.json",
"width": 800,
"height": 300,
"padding": 5,
"data": [
{
"name": "tree",
"values": [
{"id": "1", "parent": null, "title": "Animal"},
{"id": "2", "parent": "1", "title": "Duck"},
{"id": "3", "parent": "1", "title": "Fish"},
{"id": "4", "parent": "1", "title": "Zebra"}
],
"transform": [
{
"type": "stratify",
"key": "id",
"parentKey": "parent"
},
{
"type": "tree",
"method": "tidy",
"separation": true,
"size": [{"signal": "width"}, {"signal": "height"}]
}
]
},
{
"name": "links",
"source": "tree",
"transform": [
{ "type": "treelinks" },
{ "type": "linkpath",
"shape": "diagonal"
}
]
},
{
"name": "tree-boxes",
"source": "tree",
"transform": [
{
"type": "filter",
"expr": "datum.parent == null"
}
]
},
{
"name": "tree-circles",
"source": "tree",
"transform": [
{
"type": "filter",
"expr": "datum.parent != null"
}
]
}
],
"marks": [
{
"type": "path",
"from": {"data": "links"},
"encode": {
"enter": {
"path": {"field": "path"}
}
}
},
{
"type": "rect",
"from": {"data": "tree-boxes"},
"encode": {
"enter": {
"stroke": {"value": "black"},
"width": {"value": 100},
"height": {"value": 20},
"x": {"field": "x"},
"y": {"field": "y"}
}
}
},
{
"type": "symbol",
"from": {"data": "tree-circles"},
"encode": {
"enter": {
"stroke": {"value": "black"},
"width": {"value": 100},
"height": {"value": 20},
"x": {"field": "x"},
"y": {"field": "y"}
}
}
},
{
"type": "rect",
"from": {"data": "tree"},
"encode": {
"enter": {
"stroke": {"value": "black"},
"width": {"value": 100},
"height": {"value": 20},
"x": {"field": "x"},
"y": {"field": "y"}
}
}
},
{
"type": "text",
"from": {"data": "tree"},
"encode": {
"enter": {
"stroke": {"value": "black"},
"text": {"field": "title"},
"x": {"field": "x"},
"y": {"field": "y"},
"dx": {"value":50},
"dy": {"value":13},
"align": {"value": "center"}
}
}
}
]
}
UPD: suppose, you would like to render different shapes for root and leaf nodes of your chart.
One way to achieve this will be to add two filter transformations based on your tree dataset and filter them accordingly:
{
"name": "tree-boxes",
"source": "tree", // grab the existing data
"transform": [
{
"type": "filter",
"expr": "datum.parent == null" // run it through a filter defined by expression
}
]
},
{
"name": "tree-circles",
"source": "tree",
"transform": [
{
"type": "filter",
"expr": "datum.parent != null"
}
]
}
then instead of rendering all marks as rect you'd want two different shapes for respective transformed datasets:
{
"type": "rect",
"from": {"data": "tree-boxes"},
"encode": {
"enter": {
"stroke": {"value": "black"},
"width": {"value": 100},
"height": {"value": 20},
"x": {"field": "x"},
"y": {"field": "y"}
}
}
},
{
"type": "symbol",
"from": {"data": "tree-circles"},
"encode": {
"enter": {
"stroke": {"value": "black"},
"width": {"value": 100},
"height": {"value": 20},
"x": {"field": "x"},
"y": {"field": "y"}
}
}
}
You can refer to this solution - Working with trees which covers
Step 1 - Extracting Nodes from Tabular Data
Step 2 - Extracting Links from Stratified Node Data
Step 3 - How to bring them together
Step 4 - Add labels
Step 5 - Add Color
I have built an example which is the closest so far to what is described in this question. I based my solution on the accepted answer here, thanks to #timur.
Click here to view it in the Vega Editor.
It displays tree nodes as groups with multiple texts inside. It supports expanding & collapsing of nodes as well as switching between horizontal and vertical layout (which you can control by setting the default value of horizontal signal).
There are a few limitations I faced though:
Switching between horizontal & vertical layouts doesn't re-render all marks properly (raised an issue here). It works only if you manually change the default value of horizontal signal in the code
I couldn't find a way to properly collapse the root-node of the tree without manually collapsing nested nodes (posted a relevant question here)
Anyway, it should be useful to anyone looking for a way to build Org Chart kind of visualization with Vega - without having closer examples, I had to spend many hours to figure out all the caveats and fix almost all the issues.

Unable to Implement angular-schema-form-signature

I'm unsure as to why an input field shows on the form when implementing this code.(ref: https://github.com/JamesGuthrie/angular-schema-form-signature)
This is my Schema:
{ "type": "object", "properties": { "signature": { "type": "string" } } }
This is my Form:
[
"name",
{
"type": "tabs",
"tabs": [
{
"title": "Tab1",
"tabType": "top",
"items": [
{
"title": "Signature",
"key": "signature",
"type": "signature",
"width": 500,
"height": 100,
"resetButtonText": "Clear signature"
}
]
}
]
}
]

Categories

Resources