Skip to content

Instantly share code, notes, and snippets.

@Giammaria
Last active November 11, 2024 15:02
Show Gist options
  • Save Giammaria/094ee84b221121693da892f852732f57 to your computer and use it in GitHub Desktop.
Save Giammaria/094ee84b221121693da892f852732f57 to your computer and use it in GitHub Desktop.
20241104_MET_Measure_Aggregation_Bar_Chart_v
{
"$schema": "https://vega.github.io/schema/vega/v5.json",
"width": 1100,
"height": 500,
"background": "#000",
"view": {"stroke": "transparent"},
"signals": [
{"name": "yStep", "value": 71},
{"name": "visibleItems", "update": "ceil(height / yStep)"},
{
"name": "asPercentage",
"init": "configAsPercentage.initialValue",
"on": [
{
"events": "@group_asPercentageToggle:pointerdown",
"update": "!asPercentage"
}
]
},
{
"name": "granularityLevel",
"init": "configGranularityButtons.initialValue",
"on": [
{
"events": "@granularity_level_button_background:pointerdown",
"update": "datum.datum.name"
}
]
},
{
"name": "configVerticalScrollbar",
"description": "configurations for the vertical scroll bar",
"update": "{enabled: actualHeight>height,innerPadding: 10, track: {width: 10, height: extent([actualHeight, height])[0], fill: '#232323', stroke: '#444'}, handle: {height: max((height/actualHeight)*extent([actualHeight, height])[0], 30), fill: '#999', hover: {fill: '#CCC'}}}"
},
{
"name": "configGranularityButtons",
"description": "configurations for the granularity level button controls",
"init": "{initialValue: 'MET', padding: 5, yOffset: 2.5, label: {text: 'Granularity', font: 'Segoe UI', fontSize: 12, fill: mediumColor, fontStyle: 'regular', dy: 15}, outerStroke: '#777', fill: lightColor, selectedFill: '#b5cae1'}"
},
{
"name": "sortBy",
"init": "configSortButtons.initialValue",
"on": [
{
"events": "@sort_button_background:pointerdown",
"update": "datum.datum.name"
}
]
},
{
"name": "sortByClickCount",
"init": "0",
"on": [
{
"events": "@sort_button_background:pointerdown",
"update": "sortByClickCount+1"
}
]
},
{
"name": "sortByChange",
"value": false,
"update": "isValid(data('sortByChange')) && length(data('sortByChange')) > 0 ? data('sortByChange')[0]['change'] : sortByChange"
},
{
"name": "sortOrder",
"value": "descending",
"update": "isValid(data('sortByChange')) && length(data('sortByChange')) > 0 ? data('sortByChange')[0].sortOrder : sortOrder"
},
{
"name": "sortDirectionMet",
"value": "descending",
"on": [
{
"events": "@sort_button_background:pointerdown{0, 100}",
"update": "sortByChange ? sortDirectionMet : datum.datum.name === 'Criteria Met' ? sortDirectionMet === 'descending' ? 'ascending' : 'descending' : sortDirectionMet"
}
]
},
{
"name": "sortDirectionNotMet",
"value": "descending",
"on": [
{
"events": "@sort_button_background:pointerdown{0, 100}",
"update": "sortByChange ? sortDirectionNotMet : datum.datum.name === 'Criteria Not Met' ? sortDirectionNotMet === 'descending' ? 'ascending' : 'descending' : sortDirectionNotMet"
}
]
},
{
"name": "configSortButtons",
"description": "configurations for the sort level button controls",
"init": "{initialValue: 'Criteria Not Met', padding: 5, yOffset: 2.5, label: {text: 'Sort', font: 'Segoe UI', fontSize: 12, fill: mediumColor, fontStyle: 'regular', dy: 15}, outerStroke: '#777', fill: lightColor, selectedFill: '#b5cae1'}"
},
{
"name": "configAsPercentage",
"description": "configurations for the 'as percentage' toggle control",
"update": "{enabled: true, initialValue: false, xOffset: 40, track: {height: 7.5, width: 25, cornerRadius: 5, fill: lightColor, stroke: '#777', strokeWidth: 1}, handle: {stroke: '#777', strokeWidth: 1, fill: '#fff'}, label: {text: 'Percentage', font: 'Segoe UI', fontSize: 12, fill: mediumColor, fontStyle: 'regular', dy: 11.5}, on: {fill: '#b5cae1', fillOpacity: 1, stroke: '#777', strokeWidth: 1}, tooltip: {text: 'Toggle between counts and percentages'}}"
},
{
"name": "lightColor",
"description": "light color for theme as hex value",
"value": "#EEE"
},
{
"name": "mediumColor",
"description": "medium color for theme as hex value",
"value": "#AAA"
},
{
"name": "darkColor",
"description": "dark color for theme as hex value",
"value": "#777"
},
{
"name": "backgroundRGB",
"description": "rgb value of the canvas background",
"value": "#000"
},
{
"name": "verticalScrollbarMouseDown",
"description": "boolean indicating whether the vertical scrollbar is currently being clicked",
"value": false,
"on": [
{
"events": "@group_verticalScrollbar:pointerdown",
"update": "configVerticalScrollbar.enabled"
},
{
"events": {
"type": "mouseout",
"scope": "view",
"markname": "group_verticalScrollbar",
"filter": ["!event.pointerdown"]
},
"update": "false"
},
{
"events": {
"type": "mouseover",
"scope": "scope",
"markname": "group_verticalScrollbar",
"filter": ["event.pointerdown"]
},
"update": "true"
},
{"events": {"type": "pointerup"}, "update": "false"}
]
},
{
"name": "verticalScrollbarMouseOver",
"description": "boolean indicating whether the vertical scrollbar is currently being moused over",
"value": false,
"on": [
{
"events": "@group_verticalScrollbar:mouseover",
"update": "configVerticalScrollbar.enabled"
},
{"events": "@group_verticalScrollbar:mouseout", "update": "false"}
]
},
{
"name": "verticalScrollPercent",
"description": "the percentage of the current vertical scroll",
"value": 0,
"on": [
{
"events": {
"type": "wheel",
"consume": true,
"filter": ["!event.ctrlKey", "!event.shiftKey"]
},
"update": "!configVerticalScrollbar.enabled ? 0 : clamp(verticalScrollPercent - (-event.deltaY * pow(3, event.deltaMode) * 0.00015), 0,(actualHeight-height+yStep)/actualHeight)"
},
{
"events": "@group_verticalScrollbar:pointerdown",
"update": "!configVerticalScrollbar.enabled ? 0 : invert('scaleScrollHandleY', y(group()))"
},
{
"events": {
"type": "pointermove",
"source": "scope",
"markname": "group_verticalScrollbar",
"between": [{"type": "pointerdown"}, {"type": "pointerup"}]
},
"update": "!configVerticalScrollbar.enabled ? 0 : verticalScrollbarMouseDown && isValid(group()) ? invert('scaleScrollHandleY', clamp(y(group()), configVerticalScrollbar.handle.height, configVerticalScrollbar.track.height)) : verticalScrollPercent"
},
{
"events": {
"type": "pointermove",
"source": "scope",
"markname": "group_verticalScrollbar",
"between": [{"type": "pointerdown"}, {"type": "mouseout"}]
},
"update": "!configVerticalScrollbar.enabled ? 0 : isValid(group()) ? invert('scaleScrollHandleY', clamp(y(group()), configVerticalScrollbar.handle.height, configVerticalScrollbar.track.height)) : verticalScrollPercent"
},
{
"events": {"signal": "!configVerticalScrollbar.enabled"},
"update": "0"
},
{
"events": "@granularity_level_button_background:pointerdown",
"update": "0"
},
{"events": "@sort_button_background:pointerdown", "update": "0"}
]
},
{
"name": "yHoverDatum",
"init": "null",
"on": [
{
"events": "mouseover",
"update": "isValid(datum) && isValid(datum.yLabel) ? datum : null"
}
]
},
{
"name": "unit",
"value": {},
"on": [
{"events": "pointermove", "update": "isTuple(group()) ? group() : {}"}
]
},
{
"name": "selection",
"update": "vlSelectionResolve('selection_store', 'union', true, true)"
},
{
"name": "selection_tuple",
"on": [
{
"events": [{"source": "scope", "type": "click"}],
"update": "datum && item().mark.marktype !== 'group' && indexof(item().mark.role, 'legend') < 0 ? {_vgsid_: datum['_vgsid_'], datum: datum} : null",
"force": true
},
{
"events": [{"source": "view", "type": "click"}],
"update": "!datum ? null : selection_tuple",
"force": true
}
]
},
{
"name": "selectionCount",
"update": "isValid(selection) && isValid(selection.vlPoint) && isValid(selection.vlPoint.or) ? length(selection.vlPoint.or) : 0"
},
{
"name": "ctrlKey",
"init": "false",
"on": [
{
"events": [{"type": "mousemove", "filter": "event.ctrlKey"}],
"update": "true"
},
{
"events": [{"type": "mousemove", "filter": "!event.ctrlKey"}],
"update": "false"
}
]
},
{
"name": "submitSelections",
"value": false,
"on": [
{
"events": [{"source": "scope", "type": "click"}],
"update": "datum && isValid(datum['_vgsid_']) ? true : false",
"force": true
},
{
"events": [{"source": "view", "type": "click"}],
"update": "!datum ? true : submitSelections",
"force": true
}
]
},
{
"name": "selection_modify",
"on": [
{
"events": {"signal": "selection_tuple"},
"update": "submitSelections ? modify('selection_store', null, (!ctrlKey ? true : null), isValid(selection_tuple) && isValid(selection_tuple['_vgsid_']) && isValid(selection_tuple.datum) ? selection_tuple.datum : null) : null"
}
]
},
{
"name": "highlightIds",
"init": "[]",
"on": [
{
"events": [{"signal": "selection"}],
"update": "isValid(selection) && isValid(selection.vlPoint) && isValid(selection.vlPoint.or) ? pluck(selection.vlPoint.or, '_vgsid_') : []"
}
]
},
{
"name": "horizontalRange",
"description": "the range used in the x-axis scale for the Gantt",
"update": "[0, width-(configVerticalScrollbar.enabled ? configVerticalScrollbar.innerPadding*2 : 0)]"
},
{
"name": "actualHeight",
"description": "height of all rows if not cut off by vertical scrolling",
"update": "(data('preYDomain')[0].rc+visibleItems) * yStep"
}
],
"marks": [
{
"type": "group",
"clip": true,
"marks": [
{
"name": "y_item_hover_rect_Label",
"type": "rect",
"from": {"data": "yDomain"},
"interactive": true,
"encode": {
"update": {
"tooltip": {
"signal": "{'title': granularityLevel + ': ' + datum.yLabel, 'Count': datum.Count + ' reporting units'}"
},
"x": {"value": 0},
"x2": {"signal": "horizontalRange[1]"},
"y": {
"signal": "scale('yScale', datum.ySort) + range('subYAxisScale')[0]"
},
"y2": {
"signal": "scale('yScale', datum.ySort) + range('subYAxisScale')[1]"
},
"fill": {"value": "transparent"},
"cursor": {"value": "pointer"}
}
}
},
{
"name": "y_item_hover_rect",
"type": "rect",
"from": {"data": "yDomain"},
"interactive": true,
"encode": {
"update": {
"tooltip": {
"signal": "{'title': granularityLevel + ': ' + datum.yLabel, 'Count': datum.Count + ' reporting units'}"
},
"x": {"value": 0},
"x2": {"signal": "scale('xScaleCount', datum.Count)"},
"y": {
"signal": "scale('yScale', datum.ySort) + range('subYAxisScale')[0]"
},
"y2": {
"signal": "scale('yScale', datum.ySort) + range('subYAxisScale')[1]"
},
"fill": {"value": "transparent"},
"cursor": {"value": "pointer"}
}
}
},
{
"name": "total_rect",
"type": "rect",
"from": {"data": "yDomain"},
"interactive": false,
"encode": {
"update": {
"tooltip": {"signal": "datum.ySort"},
"x": {"value": 0},
"x2": {"signal": "scale('xScaleCount', datum.Count)"},
"y": {
"signal": "scale('yScale', datum.ySort) + range('subYAxisScale')[0]"
},
"y2": {
"signal": "scale('yScale', datum.ySort) + range('subYAxisScale')[1]"
},
"fill": {"signal": "'#444'"},
"stroke": {
"signal": "isValid(yHoverDatum) && isValid(yHoverDatum.ySort) && yHoverDatum.ySort === datum.ySort ? '#888' : '#666'"
},
"strokeWidth": {
"signal": "isValid(yHoverDatum) && isValid(yHoverDatum.ySort) && yHoverDatum.ySort === datum.ySort ? 2 : 1"
},
"opacity": {
"signal": "asPercentage ? 0 : isValid(highlightIds) ? length(highlightIds) > 0 ? indexof(highlightIds, datum['_vgsid_']) >= 0 ? 1 : 0.5 : 1 : 1"
}
}
}
},
{
"name": "yAxisLabel",
"type": "text",
"from": {"data": "yDomain"},
"encode": {
"update": {
"y": {"scale": "yScale", "field": "ySort"},
"dy": {"value": 2.5},
"text": {"signal": "datum.yLabel"},
"fill": {"signal": "lightColor"},
"fillOpacity": {
"signal": "isValid(yHoverDatum) && isValid(yHoverDatum.ySort) && yHoverDatum.ySort === datum.ySort ? 1 : 0.85"
},
"fontWeight": {
"signal": "isValid(yHoverDatum) && isValid(yHoverDatum.ySort) && yHoverDatum.ySort === datum.ySort ? 600 : 400"
},
"baseline": {"value": "top"},
"limit": {"signal": "horizontalRange[1]"},
"opacity": {
"signal": "length(data('selection_store'))>0 ? indexof(pluck(data('selection_store'), 'yLabel'), datum['yLabel']) >= 0 ? 1 : 0.5 : 1"
}
}
}
},
{
"name": "criteria_met_bars",
"type": "group",
"from": {
"facet": {
"data": "bars",
"groupby": ["yLabel", "ySort", "Count"],
"name": "criteria_met_facet"
}
},
"marks": [
{
"name": "criteria_met_rects",
"type": "rect",
"from": {"data": "criteria_met_facet"},
"encode": {
"update": {
"tooltip": {
"signal": "{'title': granularityLevel + ': ' + datum.yLabel, 'Count': datum['Sub Count'] + ' out of ' + datum.Count + ' reporting units with criteria ' + (datum['Criteria Met'] === 'N' ? 'not' : '') + ' met', '%': format(datum['Percentage'], '.0%')+ ' reporting units with criteria ' + (datum['Criteria Met'] === 'N' ? 'not' : '') + ' met'}"
},
"x": {"value": 0},
"x2": {
"signal": "asPercentage ? scale('xScalePercentage', datum['Percentage']) : scale('xScaleCount', datum['Sub Count'])"
},
"y": {
"signal": "scale('yScale', datum['ySort']) + scale('subYAxisScale', datum['Criteria Met'])"
},
"height": {"signal": "bandwidth('subYAxisScale')"},
"stroke": {"value": "#000"},
"strokeWidth": {
"signal": "isValid(yHoverDatum) && isValid(yHoverDatum.ySort) && yHoverDatum.ySort === datum.ySort ? 2 : 1"
},
"opacity": {
"signal": "isValid(highlightIds) ? length(highlightIds) > 0 ? indexof(highlightIds, datum['_vgsid_']) >= 0 || indexof(highlightIds, datum['parent_vgsid_']) >= 0 ? 1 : 0.5 : 1 : 1"
},
"fill": {"signal": "datum.Fill"},
"cursor": {"value": "pointer"}
}
}
}
]
}
]
},
{
"name": "header_group",
"type": "group",
"encode": {"update": {"x": {"signal": "0"}, "y": {"value": -65}}},
"marks": [
{
"name": "group_granularityLevelButtons",
"type": "group",
"marks": [
{
"name": "labelText",
"type": "text",
"encode": {
"update": {
"text": {"signal": "configGranularityButtons.label.text"},
"baseline": {"value": "bottom"},
"font": {"signal": "configGranularityButtons.label.font"},
"fontSize": {
"signal": "configGranularityButtons.label.fontSize"
},
"fontStyle": {
"signal": "configGranularityButtons.label.fontStyle"
},
"align": {"value": "left"},
"fill": {"signal": "configGranularityButtons.label.fill"}
}
}
},
{
"name": "granularity_level_dummy_labels",
"description": "text marks that will be used by other button marks for reactive geometry",
"type": "text",
"from": {"data": "granularityLevelConfig"},
"interactive": false,
"encode": {
"enter": {
"x": {
"signal": "configGranularityButtons.padding+datum.rowNumber*31.5"
},
"y": {
"signal": "configGranularityButtons.yOffset+configGranularityButtons.label.dy"
},
"fontSize": {
"signal": "configGranularityButtons.label.fontSize-2"
},
"text": {"field": "label"},
"fill": {"value": "#666"},
"opacity": {"value": 0}
}
}
},
{
"name": "granularity_level_button_background",
"description": "the background for the expand/collapse buttons",
"type": "rect",
"from": {"data": "granularity_level_dummy_labels"},
"interactive": true,
"encode": {
"update": {
"x": {
"signal": "datum.bounds.x1-configGranularityButtons.padding"
},
"x2": {
"signal": "datum.bounds.x2+configGranularityButtons.padding"
},
"y": {
"signal": "datum.bounds.y1-configGranularityButtons.padding"
},
"y2": {
"signal": "datum.bounds.y2+configGranularityButtons.padding"
},
"cornerRadiusTopLeft": {
"signal": "datum.datum.rowNumber == 0 ? 5 : 0"
},
"cornerRadiusBottomLeft": {
"signal": "datum.datum.rowNumber == 0 ? 5 : 0"
},
"cornerRadiusTopRight": {
"signal": "datum.datum.rowNumber == 1 ? 5 : 0"
},
"cornerRadiusBottomRight": {
"signal": "datum.datum.rowNumber == 1 ? 5 : 0"
},
"fillOpacity": {"value": 1},
"strokeWidth": {"value": 1},
"fill": {
"signal": "datum.datum.name === granularityLevel ? configGranularityButtons.selectedFill : configGranularityButtons.fill"
},
"opacity": {"value": 1},
"cursor": {"value": "pointer"},
"tooltip": {"signal": "datum.datum.tooltip"}
},
"hover": {"opacity": {"value": 0.9}}
}
},
{
"name": "granularity_level_labels",
"description": "text marks that will be used by other button marks for reactive geometry",
"type": "text",
"from": {"data": "granularity_level_dummy_labels"},
"interactive": false,
"encode": {
"enter": {
"x": {"signal": "datum.x"},
"y": {"signal": "datum.y"},
"text": {"signal": "datum.datum.label"},
"fontSize": {"signal": "datum.fontSize"},
"fill": {"value": "#333"},
"opacity": {"value": 1}
}
}
}
]
},
{
"name": "group_sortLevelButtons",
"type": "group",
"from": {"data": "group_granularityLevelButtons"},
"encode": {"update": {"x": {"signal": "datum.bounds.x2+15"}}},
"marks": [
{
"name": "labelText",
"type": "text",
"encode": {
"update": {
"text": {"signal": "configSortButtons.label.text"},
"baseline": {"value": "bottom"},
"font": {"signal": "configSortButtons.label.font"},
"fontSize": {"signal": "configSortButtons.label.fontSize"},
"fontStyle": {"signal": "configSortButtons.label.fontStyle"},
"align": {"value": "left"},
"fill": {"signal": "configSortButtons.label.fill"}
}
}
},
{
"name": "sort_dummy_labels",
"description": "text marks that will be used by other button marks for reactive geometry",
"type": "text",
"from": {"data": "sortConfig"},
"interactive": false,
"encode": {
"update": {
"x": {
"signal": "configSortButtons.padding+datum.rowNumber*35"
},
"y": {
"signal": "configSortButtons.yOffset+configSortButtons.label.dy"
},
"fontSize": {"signal": "configSortButtons.label.fontSize-2"},
"text": {
"signal": "datum.label + (datum.name === 'Criteria Met' ? (sortDirectionMet === 'descending' ? '▾' : '▴') : (sortDirectionNotMet === 'descending' ? '▾' : '▴'))"
},
"fill": {"value": "#666"},
"opacity": {"value": 0}
}
}
},
{
"name": "sort_button_background",
"description": "the background for the expand/collapse buttons",
"type": "rect",
"from": {"data": "sort_dummy_labels"},
"interactive": true,
"encode": {
"update": {
"x": {"signal": "datum.bounds.x1-configSortButtons.padding"},
"x2": {"signal": "datum.bounds.x2+configSortButtons.padding"},
"y": {"signal": "datum.bounds.y1-configSortButtons.padding"},
"y2": {"signal": "datum.bounds.y2+configSortButtons.padding"},
"cornerRadiusTopLeft": {
"signal": "datum.datum.rowNumber == 0 ? 5 : 0"
},
"cornerRadiusBottomLeft": {
"signal": "datum.datum.rowNumber == 0 ? 5 : 0"
},
"cornerRadiusTopRight": {
"signal": "datum.datum.rowNumber == 1 ? 5 : 0"
},
"cornerRadiusBottomRight": {
"signal": "datum.datum.rowNumber == 1 ? 5 : 0"
},
"fillOpacity": {"value": 1},
"strokeWidth": {"value": 1},
"fill": {
"signal": "datum.datum.name === sortBy ? configSortButtons.selectedFill : configSortButtons.fill"
},
"opacity": {"value": 1},
"cursor": {"value": "pointer"},
"tooltip": {
"signal": "replace(datum.datum.tooltip, 'by criteria','by '+(asPercentage ? 'percentage' : 'count' )+' of criteria')"
}
},
"hover": {"opacity": {"value": 0.9}}
}
},
{
"name": "sort_labels",
"description": "text marks that will be used by other button marks for reactive geometry",
"type": "text",
"from": {"data": "sort_dummy_labels"},
"interactive": false,
"encode": {
"update": {
"x": {"signal": "datum.x"},
"y": {"signal": "datum.y"},
"text": {"signal": "datum.text"},
"fontSize": {"signal": "datum.fontSize"},
"fill": {"value": "#333"},
"opacity": {"value": 1}
}
}
}
]
},
{
"name": "group_asPercentageToggle",
"description": "group for the marks that make up the toggle control to show as percentage vs count percentage",
"type": "group",
"from": {"data": "group_sortLevelButtons"},
"interactive": true,
"clip": false,
"encode": {
"update": {
"x": {"signal": "datum.datum.bounds.x2+120"},
"y": {"signal": "datum.datum.bounds.y1+1"},
"height": {"signal": "30"},
"width": {"signal": "configAsPercentage.track.width"},
"fill": {"value": "transparent"},
"tooltip": {"signal": "configAsPercentage.tooltip.text"},
"cursor": {"value": "pointer"}
}
},
"marks": [
{
"name": "asPercentageToggle_text",
"description": "the title for the toggle control",
"type": "text",
"interactive": false,
"encode": {
"update": {
"text": {"signal": "configAsPercentage.label.text || ''"},
"baseline": {"value": "top"},
"font": {"signal": "configAsPercentage.label.font"},
"fontSize": {"signal": "configAsPercentage.label.fontSize"},
"fontStyle": {"signal": "configAsPercentage.label.fontStyle"},
"align": {"value": "left"},
"fill": {"signal": "configAsPercentage.label.fill"}
}
}
},
{
"name": "track_rect",
"description": "the track for the toggle control",
"type": "rect",
"from": {"data": "asPercentageToggle_text"},
"interactive": false,
"encode": {
"update": {
"y": {
"signal": "datum.bounds.y2+configAsPercentage.label.dy"
},
"height": {"signal": "configAsPercentage.track.height"},
"x": {"signal": "0"},
"x2": {"signal": "configAsPercentage.track.width"},
"cornerRadius": {
"signal": "configAsPercentage.track.cornerRadius"
},
"fill": {
"signal": "asPercentage ? configAsPercentage.on.fill : configAsPercentage.track.fill"
},
"stroke": {"signal": "configAsPercentage.track.stroke"},
"strokeWidth": {
"signal": "configAsPercentage.track.strokeWidth"
}
}
}
},
{
"name": "toggle_outer_arc",
"description": "the circle mark that serves as the the 'toggle handle'",
"from": {"data": "asPercentageToggle_text"},
"type": "arc",
"interactive": false,
"encode": {
"enter": {
"y": {
"signal": "datum.bounds.y2+configAsPercentage.label.dy+configAsPercentage.track.height/2"
},
"innerRadius": {"value": 0},
"outerRadius": {
"signal": "configAsPercentage.track.height*0.9"
},
"startAngle": {"signal": "0"},
"endAngle": {"signal": "2*PI"},
"stroke": {
"signal": "configAsPercentage.handle.stroke || '#BBB'"
},
"strokeWidth": {
"signal": "configAsPercentage.handle.strokeWidth"
},
"fill": {"signal": "configAsPercentage.handle.fill || '#fff'"}
},
"update": {
"x": {
"signal": "asPercentage ? configAsPercentage.track.width-configAsPercentage.track.cornerRadius : configAsPercentage.track.cornerRadius"
}
}
}
}
]
}
]
},
{
"name": "group_verticalScrollbar",
"description": "the group of marks that make up the vertical scrollbar",
"type": "group",
"clip": true,
"encode": {
"update": {
"x": {
"signal": "verticalScrollbarMouseDown ? 0 : width-configVerticalScrollbar.track.width"
},
"width": {
"signal": "configVerticalScrollbar.enabled ? verticalScrollbarMouseDown ? width+configVerticalScrollbar.track.width : configVerticalScrollbar.track.width : 0"
},
"y": {"value": 0},
"height": {
"signal": "configVerticalScrollbar.enabled ? configVerticalScrollbar.track.height : 0"
},
"fill": {"value": "transparent"},
"cursor": {"value": "pointer"}
}
},
"marks": [
{
"name": "rect_verticalScrollbar_track",
"description": "the track for the scrollbar",
"type": "rect",
"interactive": false,
"encode": {
"update": {
"x": {
"signal": "verticalScrollbarMouseDown ? width-configVerticalScrollbar.track.width : 0"
},
"width": {
"signal": "configVerticalScrollbar.enabled ? configVerticalScrollbar.track.width : 0"
},
"y": {"value": 0},
"height": {
"signal": "configVerticalScrollbar.enabled ? configVerticalScrollbar.track.height : 0"
},
"fill": {"signal": "configVerticalScrollbar.track.fill"},
"stroke": {"signal": "configVerticalScrollbar.track.stroke"},
"cursor": {"value": "pointer"}
}
}
},
{
"name": "rect_verticalScrollbar_handle",
"description": "the handle for the scrollbar",
"type": "rect",
"interactive": false,
"encode": {
"update": {
"x": {
"signal": "verticalScrollbarMouseDown ? width-configVerticalScrollbar.track.width : 0"
},
"width": {
"signal": "configVerticalScrollbar.enabled ? configVerticalScrollbar.track.width : 0"
},
"y": {
"signal": "scale('scaleScrollHandleY', verticalScrollPercent)-configVerticalScrollbar.handle.height"
},
"y2": {
"signal": "scale('scaleScrollHandleY', verticalScrollPercent)"
},
"fill": {
"signal": "verticalScrollbarMouseOver ? configVerticalScrollbar.handle.hover.fill : configVerticalScrollbar.handle.fill"
},
"cursor": {"value": "pointer"}
}
}
}
]
}
],
"scales": [
{
"name": "yScale",
"type": "band",
"domain": {"data": "yDomain", "field": "ySort", "sort": true},
"range": {"step": {"signal": "yStep"}},
"paddingInner": 0.15,
"paddingOuter": 0
},
{
"name": "subYAxisScale",
"type": "band",
"domain": {
"data": "bars",
"field": "Criteria Met",
"sort": {"field": "Criteria Met Sub Sort"}
},
"range": {"signal": "[17.5, bandwidth('yScale')]"},
"padding": 0.2
},
{
"name": "scaleScrollHandleY",
"type": "linear",
"domain": [0, {"signal": "(actualHeight-height)/actualHeight"}],
"range": {
"signal": "[configVerticalScrollbar.handle.height, configVerticalScrollbar.track.height]"
},
"clamp": true
},
{
"name": "xScaleCount",
"type": "linear",
"domain": {"data": "dataset_formatted", "fields": ["Count", "Sub Count"]},
"range": {"signal": "horizontalRange"},
"zero": true
},
{
"name": "xScalePercentage",
"type": "linear",
"domain": [0, 1],
"range": {"signal": "horizontalRange"},
"zero": true
},
{
"name": "colorScale",
"type": "ordinal",
"domain": {"signal": "asPercentage ? ['Y', 'N'] : ['Y', 'N', 'Total']"},
"range": {
"signal": "asPercentage ? ['#4CAF50', '#F44336'] : ['#4CAF50', '#F44336', '#242424']"
}
}
],
"axes": [
{
"scale": "xScaleCount",
"orient": "top",
"title": {
"signal": "['Count of Reporting Units', 'with Criteria Met vs. Not Met']"
},
"titleOpacity": {"signal": "(asPercentage ? 0 : 1)"},
"titlePadding": 25,
"titleLineHeight": 20,
"titleFontSize": 14,
"domainOpacity": {"signal": "(asPercentage ? 0 : 1)"},
"domainColor": {"signal": "darkColor"},
"labelColor": {"signal": "mediumColor"},
"labelOpacity": {
"signal": "datum.value%1 === 0 ? (asPercentage ? 0 : 1) : 0"
},
"tickDash": [2, 4],
"tickColor": {"signal": "darkColor"},
"titleColor": {"signal": "mediumColor"},
"tickOpacity": {
"signal": "datum.value%1 === 0 ? (asPercentage ? 0 : 1) : 0"
},
"grid": true,
"gridColor": {"signal": "darkColor"},
"gridDash": [2, 4],
"gridOpacity": {
"signal": "datum.value%1 === 0 ? (asPercentage ? 0 : 1) : 0"
},
"encode": {
"labels": {"update": {"text": {"signal": "format(datum.value, '.0f')"}}}
}
},
{
"scale": "xScalePercentage",
"orient": "top",
"title": {
"signal": "['Percentage of Reporting Units', 'with Criteria Met vs. Not Met']"
},
"titleOpacity": {"signal": "(asPercentage ? 1 : 0)"},
"titlePadding": 25,
"titleLineHeight": 20,
"titleFontSize": 14,
"domainOpacity": {"signal": "(asPercentage ? 1 : 0)"},
"domainColor": {"signal": "darkColor"},
"labelColor": {"signal": "mediumColor"},
"labelOpacity": {"signal": "(asPercentage ? 1 : 0)"},
"tickDash": [2, 4],
"tickColor": {"signal": "darkColor"},
"titleColor": {"signal": "mediumColor"},
"tickOpacity": {"signal": "(asPercentage ? 1 : 0)"},
"grid": true,
"gridColor": {"signal": "darkColor"},
"gridDash": [2, 4],
"gridOpacity": {"signal": "(asPercentage ? 1 : 0)"},
"encode": {
"labels": {"update": {"text": {"signal": "format(datum.value, '.0%')"}}}
}
}
],
"legends": [
{
"fill": "colorScale",
"orient": "none",
"legendX": {"signal": "width -(asPercentage ? 76 : 126)"},
"legendY": {"signal": "-55"},
"symbolType": "square",
"direction": "horizontal",
"labelColor": "#eee",
"encode": {
"symbols": {
"update": {
"stroke": {
"signal": "datum.value === 'Total' ? '#666' : 'transparent'"
}
}
}
}
}
],
"data": [
{
"name": "dataset",
"url": "https://raw.githubusercontent.com/Giammaria/PublicFiles/refs/heads/master/data/sf-notional-MET-standards-dataset.csv",
"format": {
"type": "tsv",
"parse": {
"Field Comm": "string",
"Delta": "string",
"Reporting Unit": "string",
"Location": "string",
"Capability": "string",
"Component": "string",
"Squadron Type": "string",
"Mission": "string",
"Task Number": "string",
"Task Title": "string",
"Task Full Name": "string",
"MET Display Title": "string",
"MET Analytics Series": "string",
"MET Analytics Code": "string",
"MET Analytics Name": "string",
"MET Analytics Sort": "number",
"MET Measure Full Name": "string",
"Measure": "string",
"Criteria Met": "string",
"REMARK": "string"
}
}
},
{
"name": "dataset_formatted",
"source": "dataset",
"transform": [
{
"type": "formula",
"expr": "granularityLevel === 'MET' ? datum['Task Full Name'] : datum['MET Measure Full Name']",
"as": "yLabel"
},
{
"type": "aggregate",
"fields": ["Criteria Met"],
"groupby": ["yLabel", "Criteria Met"],
"as": ["Sub Count"]
},
{
"type": "joinaggregate",
"fields": ["Sub Count"],
"ops": ["sum"],
"groupby": ["yLabel"],
"as": ["Count"]
},
{
"type": "pivot",
"field": "Criteria Met",
"value": "Sub Count",
"groupby": ["yLabel", "Count"]
},
{"type": "formula", "expr": "datum.N || 0", "as": "N"},
{"type": "formula", "expr": "datum.Y || 0", "as": "Y"},
{"type": "formula", "expr": "datum.Y", "as": "Count of Criteria Met"},
{
"type": "formula",
"expr": "datum.N",
"as": "Count of Criteria Not Met"
},
{
"type": "fold",
"fields": ["N", "Y"],
"as": ["Criteria Met", "Sub Count"]
},
{
"type": "formula",
"expr": "(datum['Sub Count'] || 0)/datum.Count",
"as": "Percentage"
},
{
"type": "formula",
"expr": "sortBy === 'Criteria Met' ? indexof(['Y', 'Q', 'N'], datum['Criteria Met']) : indexof(['N', 'Q', 'Y'], datum['Criteria Met'])",
"as": "Criteria Met Sort"
},
{
"type": "formula",
"expr": "['#4CAF50', '#FFEB3B', '#F44336'][indexof(['Y', 'Q', 'N'], datum['Criteria Met'])]",
"as": "Fill"
},
{
"type": "formula",
"expr": "indexof(['Y', 'Q', 'N'], datum['Criteria Met'])",
"as": "Criteria Met Sub Sort"
}
]
},
{
"name": "preYDomain",
"source": "dataset_formatted",
"transform": [
{
"type": "formula",
"expr": "asPercentage ? datum.Percentage : datum['Sub Count']",
"as": "valueForSort"
},
{
"type": "formula",
"expr": "sortBy === 'Criteria Met' ? datum['Criteria Met'] === 'Y' ? datum.valueForSort * (sortOrder === 'descending' ? 1000 : 1) : datum.valueForSort * (sortOrder === 'descending' ? 1 : 1000) : datum['Criteria Met'] === 'N' ? datum.valueForSort * (sortOrder === 'descending' ? 1000 : 1) : datum.valueForSort * (sortOrder === 'descending' ? 1 : 1000) ",
"as": "ySortVal"
},
{
"type": "project",
"fields": [
"yLabel",
"ySortVal",
"Count",
"Count of Criteria Met",
"Count of Criteria Not Met"
]
},
{
"type": "aggregate",
"ops": ["max"],
"fields": ["ySortVal"],
"groupby": [
"yLabel",
"Count",
"Count of Criteria Met",
"Count of Criteria Not Met"
],
"as": ["ySortVal"]
},
{
"type": "window",
"ops": ["row_number"],
"sort": {"field": "ySortVal", "order": {"signal": "sortOrder"}},
"as": ["ySort"]
},
{"type": "collect", "sort": {"field": "ySort"}},
{
"type": "joinaggregate",
"ops": ["distinct"],
"fields": ["yLabel"],
"as": ["rc"]
},
{
"type": "formula",
"expr": "+(granularityLevel === 'MET' ? -1 : 1) * datum.ySort",
"as": "_vgsid_"
},
{"type": "formula", "expr": "'y'", "as": "barType"}
]
},
{
"name": "yDomain",
"source": "preYDomain",
"transform": [
{
"type": "filter",
"expr": "datum.ySort >= floor(verticalScrollPercent * (datum.rc)) && datum.ySort <= ceil((verticalScrollPercent * (datum.rc)) + visibleItems)"
},
{"type": "collect", "sort": {"field": "ySort"}}
]
},
{
"name": "bars",
"source": "dataset_formatted",
"transform": [
{"type": "formula", "expr": "'criteria'", "as": "barType"},
{
"type": "lookup",
"from": "yDomain",
"key": "yLabel",
"fields": ["yLabel"],
"values": ["ySort", "_vgsid_"],
"as": ["ySort", "parent_vgsid_"]
},
{
"type": "filter",
"expr": "indexof(domain('yScale'), datum.ySort) >=0"
},
{
"type": "window",
"ops": ["row_number"],
"sort": {"field": "ySortVal", "order": {"signal": "sortOrder"}},
"as": ["_vgsid_"]
},
{
"type": "formula",
"expr": "(granularityLevel === 'MET' ? -1 : 1) * (datum._vgsid_ + length(data('preYDomain')))",
"as": "_vgsid_"
}
]
},
{
"name": "granularityLevelConfig",
"values": [
{
"rowNumber": 0,
"name": "MET",
"label": "MET",
"tooltip": "Criteria met by MET"
},
{
"rowNumber": 1,
"name": "Measure",
"label": "Measure",
"tooltip": "Criteria met by measure"
}
]
},
{
"name": "sortConfig",
"values": [
{
"rowNumber": 0,
"name": "Criteria Met",
"label": "Met",
"tooltip": "Sort by criteria met"
},
{
"rowNumber": 1,
"name": "Criteria Not Met",
"label": "Not Met",
"tooltip": "Sort by criteria not met"
}
]
},
{
"name": "sortByChange",
"on": [
{
"trigger": "sortByClickCount",
"remove": false,
"insert": "{sortBy: sortBy, timestamp: now(), sortOrder: sortBy === 'Criteria Met' ? (sortDirectionMet === 'descending' ? 'descending' : 'ascending') : sortDirectionNotMet === 'descending' ? 'descending' : 'ascending'}"
}
],
"transform": [
{
"type": "window",
"ops": ["row_number"],
"sort": {"field": "timestamp", "order": "descending"},
"as": ["rn"]
},
{"type": "filter", "expr": "datum.rn<=2"},
{
"type": "window",
"ops": ["lag", "max"],
"fields": ["sortBy", "rn"],
"as": ["lagSortBy", "rowCt"]
},
{
"type": "formula",
"expr": "datum.rowCt === 1 && configSortButtons.initialValue!==datum.sortBy ? true : datum.rn === 1 && datum.rowCt === 2 && isValid(datum.lagSortBy) && datum.sortBy !== datum.lagSortBy",
"as": "change"
},
{
"type": "formula",
"expr": "datum.rn === 1 ? datum.sortOrder : null",
"as": "sortOrder"
},
{
"type": "joinaggregate",
"ops": ["max", "max"],
"fields": ["change", "sortOrder"],
"as": ["change", "sortOrder"]
}
]
},
{"name": "selection_store", "transform": []},
{
"name": "lyra_selections",
"source": "dataset",
"transform": [
{
"type": "formula",
"expr": "pluck(data('selection_store'), 'yLabel')",
"as": "yLabels"
},
{
"type": "formula",
"expr": "granularityLevel === 'MET' ? datum['Task Full Name'] : datum['MET Measure Full Name']",
"as": "yLabel"
},
{"type": "filter", "expr": "indexof(datum.yLabels, datum.yLabel) >=0"},
{
"type": "lookup",
"from": "selection_store",
"key": "yLabel",
"fields": ["yLabel"],
"values": ["barType", "Criteria Met"],
"as": ["barType", "Select Criteria Met"]
},
{
"type": "filter",
"expr": "datum.barType === 'y' ? true : (datum['Select Criteria Met'] === datum['Criteria Met'])"
}
]
},
{
"name": "lyra_self_highlight",
"on": [
{"trigger": "selection", "remove": true},
{
"trigger": "selection",
"insert": "isValid(selection) && isValid(selection.vlPoint) && isValid(selection.vlPoint.or) ? pluck(selection.vlPoint.or, '_vgsid_') : []"
}
]
}
]
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment