Years Not Formatting to Correct Date Format - vega-lite

Fairly new to vega/vega-lite and javascript in general so trying my hand at this and it is not working the way I'd like.
My main issue at the moment is that my years are whole numbers as primitive values. I've tried parsing them to show as temporal units in the format of %Y but I just keep getting decimal places which doesn't work.
{
"data": {"name": "dataset"},
"width": 500,
"height": 500,
"layer": [
{
"mark": {
"type": "line",
"point": true
},
"encoding": {
"y": {"aggregate": "mean","field": "Index Score", "type": "quantitative", "axis": {"format": ".1e"}, "title": "Economic Exposure Score"},
"x": {"field": "Year","type": "quantitative", "title": "Years"},
"color": {"field": "Country", "type": "nominal", "legend": null}
}
},
{
"mark": {"type": "text", "align": "center", "dy": 15, "fontWeight": "bold", "fontSize": 14},
"encoding": {
"x": {
"field": "Year",
"type": "quantitative"
},
"y": {
"field": "Index Score",
"type": "quantitative"
},
"text": {"field": "Event Name", "type": "nominal"},
"color": {"value": "black"}
}
}
]
}
Here is where I'm at right now: v1 index score over years. Yes there are a lot of lines. I have a dynamic card that will show the chart only once a country has been selected from a slicer in the dashboard so no worries there. I plan on adding labels to the lines.
Summary of troubleshooting:
have tried formatting this at the "Data" level as well as within the mark/line/encoding/y but I either get a whole number representation or a decimal...

Option 1: Create the date in Power Query
As you say in the comments, you can easily create the date on the Power BI side and pass it in. I would have your month and year columns as text and concatenate them like this:
let
Source = Excel.CurrentWorkbook(){[Name="Table1"]}[Content],
#"Changed Type" = Table.TransformColumnTypes(Source,{{"Country", type text}, {"Index Score", type number}, {"Month", type text}, {"Event Name", type any}, {"Year", type text}}),
#"Added Custom" = Table.AddColumn(#"Changed Type", "Date", each [Month] & " 1, " & [Year], type text),
#"Changed Type1" = Table.TransformColumnTypes(#"Added Custom",{{"Date", type date}}),
#"Calculated End of Month" = Table.TransformColumns(#"Changed Type1",{{"Date", Date.EndOfMonth, type date}})
in
#"Calculated End of Month"
If you want start of month, remove the #"Calculated End of Month" step.
Option 2: Formatting in Vega-lite
You could also leave the year as you have it, and simply add formatting in the x-axis encoding in Vega:
"encoding": {
"x": {
...
"axis": {"format": "0000"}
},
Open the Chart in the Vega Editor

Related

Force vega-lite to show label when number is 0

I'm still very much a beginner in vega-lite but I'm trying to create a stacked bar chart with different sales channels. Sometimes a sales channel has a 0 and doesn't show up, how can I still show the label?
{
"layer": [
{
"mark": {
"type": "bar",
"cornerRadius": 50,
"color": "#90C290",
"tooltip": true
},
"encoding": {
"x": {
"field": "Number of customers"
}
}
},
{
"mark": {
"type": "text",
"tooltip": true,
"align": "left",
"baseline": "middle",
"x": 10,
"color": "white"
},
"encoding": {
"text": {
"field": "Number of customers",
"type": "text"
}
}
}
],
"encoding": {
"y": {
"field": "Sales channel",
"type": "nominal",
"sort": "descending",
"title": null
},
"x": {
"type": "quantitative",
"title": null,
"axis": null
}
}
}
I tried the code above and looked through documentation but couldn't exactly find what I was looking for
I added sample data to your spec, and there are a few changes I would make.
Around line 29 you have "type": "text" which should be "type": "quantitative".
I think your problem is that the text color is white and the background color is white, so the text is there but you can't see it. A simple fix would be to set the text color to black, or change the background color to something other than white (add "background": "lightgray", before "layer").
It's also possible you don't see the channel at all depending on how you are passing data from Power BI. Check the data tab in the Deneb window to make sure the Channel is there.
If the channel is not there, you'll have to adjust something on the Power BI side. A good practice is to put the data in a table in Power BI first so you know what you are sending into Deneb. If you use an aggregation like SUM on the data field in Power BI, nulls will drop out, but zeros should stay. If you use "Don't summarize" then nulls or errors (text in a number field) will pass in as nulls to Deneb, but you may need to add an "aggregate": "sum" to your encoding.
In any case, here's the spec the way I would write it.
{
"data": {"name": "dataset"},
"layer": [
{
"mark": {
"type": "bar",
"cornerRadius": 50,
"color": "#90C290",
"tooltip": true
}
},
{
"mark": {
"type": "text",
"tooltip": true,
"align": "left",
"baseline": "middle",
"dx": 5,
"color": "black"
},
"encoding": {
"text": {
"field": "Number of customers",
"type": "quantitative"
}
}
}
],
"encoding": {
"y": {
"field": "Sales channel",
"type": "nominal",
"sort": "descending",
"title": null
},
"x": {
"field": "Number of customers",
"type": "quantitative",
"title": null,
"axis": null
}
}
}
Link to sample data in Vega Editor

Vega-Lite v4 - Pivot example (and my code) throwing errors

So I am working with vega-lite-v4 (that's the version our businesses airtable extension uses) and the answer to my previous post was that I need to use the pivot transform
But any time I try and use it as it is explained in the v4 documentation (https://vega.github.io/vega-lite-v4/docs/pivot.html) it throws an error as if the pivoted field does not exist
I've used the following test data:
Airtable test data
With the following test code:
{
"$schema": "https://vega.github.io/schema/vega-lite/v4.json",
"title": "Table 2",
"transform": [{
"pivot": "type",
"value": "calls",
"groupby": ["Month"]
}],
"mark": "bar",
"encoding": {
"x": {"field": "Month", "type": "nominal"},
"y": {"field": "Total", "type": "quantitative"}
}
}
And I still get the same error:
Total is not a valid transform name, inline data name, or field name from the Table 2 table:
"y": {
"field": "Total",
------------^
"type": "quantitative"
}
Even when I copy and paste the examples from the above documentation into the widget, it comes up with this error like pivot isn't making these fields
Can anyone help me figure out why this isn't working, or what to use instead?
EDIT:
So, a weird solution/workaround I found is to calculate the field as itself:
{
"$schema": "https://vega.github.io/schema/vega-lite/v4.json",
"title": "Table 2",
"transform": [{
"pivot": "type",
"value": "calls",
"groupby": ["Month"]
},
{"calculate" : "datum.Total", "as" : "newTotal"}
],
"mark": "bar",
"encoding": {
"x": {"field": "Month", "type": "nominal"},
"y": {"field": "newTotal", "type": "quantitative"}
}
}
This makes the graph behave completely as normal. I can use this for now, but it means I have to hard code each field name with a calculate transform, does this help anyone understand what's going on with this transform?
First of all, Vega and Vega-lite field names are case-sensitive, so "Month" is not the same as "month".
In your first code sample, "month" is incorrect and should be "Month":
"x": {"field": "month", "type": "nominal"},
but in the second code sample that was changed to "Month" which is correct:
"x": {"field": "Month", "type": "nominal"},
Try just correcting field name "Month" in the first code sample without calculating "newTotal":
{
"$schema": "https://vega.github.io/schema/vega-lite/v4.json",
"title": "Table 2",
"transform": [{
"pivot": "type",
"value": "calls",
"groupby": ["Month"]
}],
"mark": "bar",
"encoding": {
"x": {"field": "Month", "type": "nominal"},
"y": {"field": "Total", "type": "quantitative"}
}
}
[EDIT: added following]
Here is a working example using your example data with pivot transform and rendered as bar chart by Vega-lite v5.2.0 with no errors.
Try using Vega-lite v5.2.0 instead of v4.
View in Vega on-line editor

visualize the duration of events

I want to visualize durations of events as a bar, my input value is a decimal value where the integer part represents days and the decimal part a fraction of a day. I can convert the input value to any value needed.
An event can span multiple days.
The code below contains data for two events, the duration of event a is 36 hours and the duration of event b is 12 hours. Of course, it's possible that an event can be over after just some minutes or take 3hours 14minutes 24seconds.
I want the x-axis have ticks every 30minutes, from the sample data I need 36 hours, an axis label can look like 0d 0:00.
{
"$schema": "https://vega.github.io/schema/vega-lite/v5.json",
"height": "container",
"width": "container",
"data": {
"values": [
{
"event": "a",
"durationdecimal": 1.5
},
{
"event": "b",
"durationdecimal": 0.5
}
]
},
"mark": {"type": "bar"},
"encoding": {
"x": {
"field": "durationdecimal",
"type": "temporal",
"axis": {"grid": false},
"timeUnit": "utchoursminutes"
},
"y": {"field": "event", "type": "nominal", "title": null}
,
"tooltip": [{"field": "durationdecimal"}]
}
}
I appreciate any help.
I don't think your durationdecimal should be temporal as there is no date/month/year provided. I tried recreating your sample using quantitative type and have done conversions on labels using labelExpr and some expressions. It mostly covers all your mentioned requirements. The only remaining part seems to be of ticks for 30 mins.
Below is the config or refer editor:
{
"$schema": "https://vega.github.io/schema/vega-lite/v5.json",
"height": "container",
"width": "container",
"data": {
"values": [
{"event": "a", "durationdecimal": 1.5},
{"event": "c", "durationdecimal": 2.1},
{"event": "b", "durationdecimal": 0.5}
]
},
"mark": {"type": "bar"},
"transform": [
{
"calculate": "split(toString(datum.durationdecimal),'.')[0] + 'd ' + (split(toString(datum.durationdecimal),'.')[1] ? floor(('0.'+split(toString(datum.durationdecimal),'.')[1])*24) + ':00': '0:00')",
"as": "x_dateLabelTooltip"
}
],
"encoding": {
"x": {
"field": "durationdecimal",
"type": "quantitative",
"axis": {
"grid": false,
"labelExpr": "split(toString(datum.label),'.')[0] + 'd ' + (split(toString(datum.label),'.')[1] ? floor(('0.'+split(toString(datum.label),'.')[1])*24) + ':00': '0:00')"
}
},
"y": {"field": "event", "type": "nominal", "title": null},
"tooltip": [{"field": "x_dateLabelTooltip"}]
}
}
Let me know if this works for you.

how to control the order of groups in a vega-lite stacked bar chart

Given a stacked bar chart such as in this example: https://vega.github.io/editor/?#/examples/vega-lite/stacked_bar_weather
I want to control the order of the items in the aggregation so that, for example, 'fog' comes at the bottom, with 'sun' next etc. Is that possible?
The reason for this is I have one type that is much larger than the others. I want this to appear at the bottom, then control the domain to 'cut off' most of that section.
Thanks
You can control the stack order via the order encoding: see https://vega.github.io/vega-lite/docs/stack.html#sorting-stack-order
Unfortunately, this only allows sorting by field value, rather than by an explicit order as you want here. The workaround is to use a calculate transform to turn your explicit order into a field (view in editor):
{
"$schema": "https://vega.github.io/schema/vega-lite/v4.json",
"data": {"url": "data/seattle-weather.csv"},
"transform": [
{
"calculate": "indexof(['sun', 'fog', 'drizzle', 'rain', 'snow'], datum.weather)",
"as": "order"
}
],
"mark": "bar",
"encoding": {
"x": {
"timeUnit": "month",
"field": "date",
"type": "ordinal",
"axis": {"title": "Month of the year"}
},
"y": {"aggregate": "count", "type": "quantitative"},
"color": {
"field": "weather",
"type": "nominal",
"scale": {
"domain": ["sun", "fog", "drizzle", "rain", "snow"],
"range": ["#e7ba52", "#c7c7c7", "#aec7e8", "#1f77b4", "#9467bd"]
},
"legend": {"title": "Weather type"}
},
"order": {"field": "order", "type": "ordinal"}
}
}

issues transforming string to date vega lite

I am trying to display some data in a line graph. However, my "Harvest_Year" data, which is a date in years, like 2017 or 2018, is being displayed as what I believe is a string
I imported by data from a .csv file, and the following are the steps I took to change the string to a date formate. I tired to do:
"Harvest_Year": "year"
But that did not work as it made all my values null. So I thought first I will make it into a int and then transform it into year. However in Vega-Lite all my years re displayed correctly in the table but when I display it on the line graph I only see 1970 which I am sure I don't have in the dataset, and it only displays that single year.
Where as in the image below, you can see I have all the years in my data:
{
"$schema": "https://vega.github.io/schema/vega-lite/v4.json",
"data": {
"url": "https://raw.githubusercontent.com/DanStein91/Info-vis/master/CoffeeRobN.csv",
"format": {
"type": "csv",
"parse": {
"Number_of_Bags": "number",
"Bag_weight": "number",
"Harvest_Year": "number"
}
}
},
"transform": [
{
"timeUnit": "year",
"field": "Harvest_Year",
"as": "Year"
},
{
"calculate": "datum.Number_of_Bags * datum.Bag_Weight ",
"as": "Total_Export"
}
],
"width": 300,
"height": 200,
"mark": "line",
"encoding": {
"y": {
"field": "Total_Export",
"type": "quantitative"
},
"x": {
"field": "Harvest_Year",
"type": "temporal"
}
},
"config": {}
}
When you tell vega-lite to interpret numbers as dates, it treats them as unix timestamps, i.e. milliseconds after January 1 1970. Each of your resulting dates is in the year 1970, which leads to the chart you are seeing.
Your dates appear to be in a non-standard format (e.g. "2017.0" means the year 2017) so you'll have to use vega expressions to manually parse them into date objects. Here is an example of this (view in editor):
{
"data": {
"url": "https://raw.githubusercontent.com/DanStein91/Info-vis/master/CoffeeRobN.csv",
"format": {
"type": "csv",
"parse": {
"Number_of_Bags": "number",
"Bag_weight": "number",
"Harvest_Year": "number"
}
}
},
"transform": [
{"filter": "isValid(datum.Harvest_Year)"},
{"calculate": "datetime(datum.Harvest_Year, 1)", "as": "Harvest_Year"},
{
"calculate": "datum.Number_of_Bags * datum.Bag_Weight ",
"as": "Total_Export"
}
],
"mark": "point",
"encoding": {
"y": {"field": "Total_Export", "type": "quantitative"},
"x": {"field": "Harvest_Year", "type": "ordinal", "timeUnit": "year"}
},
"width": 300,
"height": 200
}
Another option is to avoid datetime and timeUnit logic altogether (since your data does not actually contain any dates), and just use the year numbers directly in your encoding; e.g.
{
"data": {
"url": "https://raw.githubusercontent.com/DanStein91/Info-vis/master/CoffeeRobN.csv",
"format": {
"type": "csv",
"parse": {
"Number_of_Bags": "number",
"Bag_weight": "number",
"Harvest_Year": "number"
}
}
},
"transform": [
{"filter": "isValid(datum.Harvest_Year)"},
{
"calculate": "datum.Number_of_Bags * datum.Bag_Weight ",
"as": "Total_Export"
}
],
"mark": "point",
"encoding": {
"y": {"field": "Total_Export", "type": "quantitative"},
"x": {"field": "Harvest_Year", "type": "ordinal"}
},
"width": 300,
"height": 200
}