Skip to content

Instantly share code, notes, and snippets.

@dm-p
Last active September 26, 2022 19:54
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save dm-p/7976dc964437124ecf6830a74d9b2e03 to your computer and use it in GitHub Desktop.
Save dm-p/7976dc964437124ecf6830a74d9b2e03 to your computer and use it in GitHub Desktop.
Hill and Valley Chart Starting Point - A shaded area chart that shows actual vs. target. Includes linear interpolation to ensure that if lines intersect between points on the x-axis, then they are masked accordingly. If Actual does not meet target, then the area is shaded red, if Actual exceeds Target, this is shaded green.
{
"$schema": "https://vega.github.io/schema/vega-lite/v5.json",
"usermeta": {
"deneb": {
"build": "1.3.0.0",
"metaVersion": 1,
"provider": "vegaLite",
"providerVersion": "5.2.0"
},
"interactivity": {
"tooltip": false,
"contextMenu": false,
"selection": false,
"highlight": false,
"dataPointLimit": 50
},
"information": {
"name": "Hill and Valley Chart Starting Point",
"description": "A shaded area chart that shows actual vs. target. Includes linear interpolation to ensure that if lines intersect between points on the x-axis, then they are masked accordingly. If Actual does not meet target, then the area is shaded red, if Actual exceeds Target, this is shaded green.",
"author": "Daniel Marsh-Patrick",
"uuid": "c310368f-4a62-40f2-8ebf-653c031d853e",
"generated": "2022-08-23T08:52:56.436Z",
"previewImageBase64PNG": "data:image/png;base64,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"
},
"dataset": [
{
"key": "__0__",
"name": "Month Start",
"description": "Date field representing the start of each month in the dataset.",
"type": "dateTime",
"kind": "column"
},
{
"key": "__1__",
"name": "Actual",
"description": "The primary measure.",
"type": "numeric",
"kind": "measure"
},
{
"key": "__2__",
"name": "Target",
"description": "Our target measure, that Actual should achieve or exceed in order for the area to be shaded positive.",
"type": "numeric",
"kind": "measure"
}
]
},
"config": {
"view": {"stroke": "transparent"},
"font": "Segoe UI",
"axis": {
"title": null,
"grid": false,
"ticks": false,
"labelPadding": 10,
"labelFontSize": 12
},
"axisY": {"domain": false},
"style": {
"delta_negative": {
"color": "#8D1D1C"
},
"delta_positive": {
"color": "#83C79B"
},
"mask_foreground": {
"color": "#ffffff",
"stroke": "#ffffff"
},
"target_line": {
"color": "#939393",
"strokeWidth": 2
},
"actual_line": {
"color": "#000000",
"strokeWidth": 3
}
}
},
"data": {"name": "dataset"},
"encoding": {
"x": {
"field": "__0__",
"type": "temporal",
"axis": {
"zindex": 1,
"format": "%b"
}
},
"y": {
"type": "quantitative",
"axis": {"tickCount": 5}
}
},
"layer": [
{
"description": "Target area - background",
"mark": {
"type": "area",
"style": "delta_negative"
},
"encoding": {
"y": {"field": "__2__"}
}
},
{
"description": "Actual area - masks out target where necessary",
"mark": {
"type": "area",
"style": "delta_positive"
},
"encoding": {
"y": {"field": "__1__"}
}
},
{
"description": "Masking layer (with interpolated points)",
"transform": [
{
"calculate": "min(datum['__2__'], datum['__1__'])",
"as": "lowest_value"
},
{
"window": [
{
"op": "lead",
"field": "__0__",
"as": "month_following"
},
{
"op": "lead",
"field": "__1__",
"as": "actual_following"
},
{
"op": "lead",
"field": "__2__",
"as": "target_following"
}
]
},
{
"calculate": "(datum['actual_following'] - datum['__1__']) / (datum['month_following'] - datum['__0__'])",
"as": "actual_slope"
},
{
"calculate": "(datum['target_following'] - datum['__2__']) / (datum['month_following'] - datum['__0__'])",
"as": "target_slope"
},
{
"calculate": "datum['__1__'] - (datum['actual_slope'] * datum['__0__'])",
"as": "actual_y_intercept"
},
{
"calculate": "datum['__2__'] - (datum['target_slope'] * datum['__0__'])",
"as": "target_y_intercept"
},
{
"calculate": "(datum['target_y_intercept'] - datum['actual_y_intercept']) / (datum['actual_slope'] - datum['target_slope'])",
"as": "intersect_base"
},
{
"calculate": "datum['intersect_base'] > datum['__0__'] && datum['intersect_base'] < datum['month_following']",
"as": "intersect_before_following"
},
{
"calculate": "datum['intersect_before_following'] ? datetime(datum['intersect_base']) : null",
"as": "intersect_x"
},
{
"calculate": "datum['intersect_before_following'] ? (datum['actual_slope'] * datum['intersect_base']) + datum['actual_y_intercept'] : null",
"as": "intersect_y"
},
{
"fold": [
"__0__",
"intersect_x"
]
},
{
"filter": "datum['value'] !== null"
},
{
"calculate": "datum['key'] === '__0__' ? datum['__0__'] : datum['intersect_x']",
"as": "x"
},
{
"calculate": "datum['key'] === '__0__' ? datum['lowest_value'] : datum['intersect_y']",
"as": "y"
}
],
"mark": {
"type": "area",
"style": "mask_foreground"
},
"encoding": {
"x": {"field": "x"},
"y": {"field": "y"}
}
},
{
"description": "Target line",
"mark": {
"type": "line",
"style": "target_line"
},
"encoding": {
"y": {"field": "__2__"}
}
},
{
"description": "Actual line",
"mark": {
"type": "line",
"style": "actual_line"
},
"encoding": {
"y": {"field": "__1__"}
}
}
]
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment