Skip to content

Instantly share code, notes, and snippets.

@Giammaria
Last active November 6, 2024 13:31
Show Gist options
  • Save Giammaria/ae01f4c8b0088e42f0bd0e95feef7bc0 to your computer and use it in GitHub Desktop.
Save Giammaria/ae01f4c8b0088e42f0bd0e95feef7bc0 to your computer and use it in GitHub Desktop.
20241105_sf_radial_readiness_v2_v
{
"$schema": "https://vega.github.io/schema/vega/v5.json",
"background": {"signal": "backgroundRGB"},
"width": 500,
"padding": 0,
"usermeta": {
"developedBy": "Madison Giammaria",
"LinkedIn": "https://www.linkedin.com/in/madison-giammaria-58463b33",
"email": "[email protected]",
"inspiration": "https://sunny-edi.herokuapp.com/"
},
"signals": [
{"name": "dayInMilliseconds", "value": 86400000},
{
"name": "persistOVLColors",
"init": "showColorIndicatorsConfig.initialValue",
"on": [
{
"events": "@group_showColorIndicatorsToggle:pointerdown",
"update": "!persistOVLColors"
}
]
},
{
"name": "readinessMetric",
"init": "configButtons.initialValue",
"on": [
{
"events": "@readiness_metric_button_background:pointerdown",
"update": "datum.datum.name"
}
]
},
{
"name": "configButtons",
"description": "configurations for the button controls",
"init": "{initialValue: 'cRate', padding: 5, yOffset: 2.5, label: {text: 'Readiness Metric', font: 'Segoe UI', fontSize: 12, fill: mediumColor, fontStyle: 'regular', dy: 15}, outerStroke: '#777', fill: lightColor, selectedFill: '#b5cae1'}"
},
{
"name": "showColorIndicatorsConfig",
"description": "configurations for the show color indicators 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: 'Color Indicators', font: 'Segoe UI', fontSize: 12, fill: mediumColor, fontStyle: 'regular', dy: 7.5}, on: {fill: '#b5cae1', fillOpacity: 1, stroke: '#777', strokeWidth: 1}, tooltip: {text: 'Show/hide indicator colors'}}"
},
{
"name": "xAxisOuterPaddingPercentage",
"description": "percentage of padding between x-axis and day text marks",
"value": 0.015
},
{
"name": "yearAxisRadius",
"description": "radius for the year axis domain",
"init": "min(width,height)/2.3"
},
{
"name": "monthAxisRadius",
"description": "radius for the month axis domain",
"init": "yearAxisRadius-25"
},
{
"name": "dayRadius",
"description": "radius for the day line (text) marks",
"init": "monthAxisRadius-6"
},
{
"name": "outerContentRadius",
"description": "radius for the content marks inside the radial axes",
"init": "dayRadius-50"
},
{
"name": "innerContentRadius",
"description": "radius for the content marks inside the radial axes",
"init": "outerContentRadius/2"
},
{
"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": "#999"
},
{
"name": "backgroundRGB",
"description": "rgb value of the canvas background",
"value": "#000"
},
{"name": "placementNumberOfRows", "value": 4},
{"name": "fleetPlacementRadialOffset", "init": "PI/20"},
{"name": "fleetIconSize", "value": 15},
{
"name": "hoverMonth",
"description": "datum of the currently focused month",
"init": "{FirstOfMonthDate: extent(pluck(data('dataset_exploded'), 'FirstOfMonthDate'))[1]}",
"on": [
{
"events": {
"type": "mouseover",
"markname": "month_axis_hover_interactive"
},
"update": "datum"
}
]
},
{
"name": "hoverUnit",
"description": "datum of the currently focused unit",
"init": "null",
"on": [
{
"events": {
"type": "mouseover",
"markname": "placement_interactive_arcs"
},
"update": "datum"
},
{
"events": {
"type": "mouseout",
"markname": "placement_interactive_arcs"
},
"update": "null"
}
]
},
{
"name": "height",
"description": "height of the canvas to match the width",
"update": "width"
}
],
"marks": [
{
"name": "day_bars",
"description": "colored pipe (|) text marks that serve as a daily indicator",
"from": {"data": "dataset_exploded"},
"interactive": false,
"type": "text",
"encode": {
"update": {
"x": {"signal": "width/2"},
"dx": {"signal": "datum.Day === 1 ? -1 : 0"},
"y": {"signal": "height/2"},
"text": {
"signal": "datum.Day === 1 ? '⯌' : datum.Day === 15 ? '|' : null"
},
"align": {"value": "center"},
"fontfamily": {"value": "consolas"},
"fontSize": {
"signal": "datum.Day === 1 || datum.IsLastDayOfMonth ? 10 : 5"
},
"fontWeight": {"value": 400},
"baseline": {"value": "top"},
"fill": {"signal": "mediumColor"},
"theta": {"scale": "dayAxisScale", "field": "Date"},
"radius": {"signal": "dayRadius"},
"angle": {"signal": "scale('dayAxisScale', datum['Date'])*(180/PI)"}
}
}
},
{
"name": "month_axis_domain",
"description": "month axis domain arcs",
"from": {"data": "day_bars"},
"interactive": false,
"transform": [
{
"type": "formula",
"expr": "datum.datum.datum.FirstOfMonthDate",
"as": "FirstOfMonthDate"
},
{"type": "formula", "expr": "datum['datum']['theta']", "as": "theta"},
{
"type": "joinaggregate",
"fields": ["theta", "theta"],
"ops": ["min", "max"],
"groupby": ["FirstOfMonthDate"],
"as": ["startAngle", "endAngle"]
},
{
"type": "formula",
"expr": "datum['startAngle']+(datum['endAngle']-datum['startAngle'])/2",
"as": "midAngle"
},
{
"type": "formula",
"expr": "datum['midAngle'] < PI/2 || datum['midAngle'] > PI*1.5 ? false : true",
"as": "flipLabel"
},
{
"type": "formula",
"expr": "datum.datum.datum.Day === 1 ? 1 : 0",
"as": "opacity"
},
{
"type": "formula",
"expr": "datum['opacity'] === 1 ? datum['Date'] : null",
"as": "Date"
}
],
"type": "arc",
"encode": {
"update": {
"x": {"signal": "width/2"},
"y": {"signal": "height/2"},
"align": {"value": "center"},
"baseline": {"value": "top"},
"fill": {"signal": "darkColor"},
"startAngle": {"signal": "datum['datum']['startAngle']"},
"endAngle": {"signal": "datum['datum']['endAngle']"},
"innerRadius": {"signal": "monthAxisRadius-1.5"},
"outerRadius": {"signal": "monthAxisRadius"},
"opacity": {"field": "opacity"}
}
}
},
{
"name": "month_axis_hover_interactive",
"description": "month axis domain arcs that are used to capture the month and year",
"from": {"data": "month_axis_domain"},
"interactive": true,
"type": "arc",
"encode": {
"update": {
"x": {"signal": "width/2"},
"y": {"signal": "height/2"},
"align": {"value": "center"},
"baseline": {"value": "top"},
"fill": {"signal": "lightColor"},
"startAngle": {
"signal": "datum['startAngle']-bandwidth('dayAxisScale')/2"
},
"endAngle": {
"signal": "datum['endAngle']+bandwidth('dayAxisScale')/2"
},
"innerRadius": {"signal": "monthAxisRadius-(min(width,height)/2)"},
"outerRadius": {"signal": "width/2"},
"opacity": {"value": 0}
}
}
},
{
"name": "month_axis_hover",
"description": "month axis domain arcs that appear on hover to indicate the currently focused month",
"from": {"data": "month_axis_domain"},
"interactive": false,
"type": "arc",
"encode": {
"update": {
"x": {"signal": "width/2"},
"y": {"signal": "height/2"},
"align": {"value": "center"},
"baseline": {"value": "top"},
"fill": {"signal": "lightColor"},
"startAngle": {
"signal": "datum['startAngle']-bandwidth('dayAxisScale')/2"
},
"endAngle": {
"signal": "datum['endAngle']+bandwidth('dayAxisScale')/2"
},
"innerRadius": {"signal": "monthAxisRadius-(min(width,height)/2)"},
"outerRadius": {"signal": "monthAxisRadius+40"},
"opacity": {
"signal": "isValid(hoverMonth) && datum.FirstOfMonthDate === hoverMonth.FirstOfMonthDate && datum['opacity'] > 0 ? 0.3 : 0"
}
}
}
},
{
"name": "month_axis_label_hover",
"description": "month axis text labels that appear on hover to indicate the currently focused week",
"from": {"data": "month_axis_domain"},
"interactive": false,
"type": "text",
"encode": {
"update": {
"x": {"signal": "width/2"},
"y": {"signal": "height/2"},
"dy": {"signal": "(datum['flipLabel'] ? -1 : 1) *-7.5"},
"fill": {"signal": "lightColor"},
"fontSize": {"value": 14},
"align": {"value": "center"},
"text": {
"signal": "(datum['flipLabel'] ? '⮘ ' : '') + utcFormat(datum.FirstOfMonthDate, '%b %y') + (datum['flipLabel'] ? '' : ' ⮚')"
},
"baseline": {"signal": "datum['flipLabel'] ? 'top': 'bottom'"},
"radius": {"signal": "monthAxisRadius+45"},
"theta": {"signal": "datum['midAngle']"},
"angle": {
"signal": "(datum['flipLabel'] ? (-1*PI/PI*180) : 0) + datum['midAngle']*(180/PI)"
},
"opacity": {
"signal": "isValid(hoverMonth) && datum.FirstOfMonthDate === hoverMonth.FirstOfMonthDate && datum['opacity'] > 0 ? 1 : 0"
}
}
}
},
{
"name": "year_axis_domain",
"description": "year axis domain arcs",
"from": {"data": "day_bars"},
"interactive": false,
"transform": [
{
"type": "formula",
"expr": "datum['datum']['datum']['Year']",
"as": "Year"
},
{"type": "formula", "expr": "datum['datum']['theta']", "as": "theta"},
{
"type": "joinaggregate",
"fields": ["theta", "theta"],
"ops": ["min", "max"],
"groupby": ["Year"],
"as": ["startAngle", "endAngle"]
},
{
"type": "formula",
"expr": "datum['startAngle']+(datum['endAngle']-datum['startAngle'])/2",
"as": "midAngle"
},
{
"type": "formula",
"expr": "datum['midAngle'] < PI/2 || datum['midAngle'] > PI*1.5 ? false : true",
"as": "flipLabel"
},
{
"type": "window",
"ops": ["dense_rank"],
"fields": ["Year"],
"groupby": ["startAngle"],
"as": ["startAngleDR"]
},
{
"type": "formula",
"expr": "datum['startAngleDR'] === 1 ? 1 : 0",
"as": "opacity"
},
{
"type": "formula",
"expr": "datum['opacity'] === 1 ? datum['Date'] : null",
"as": "Date"
}
],
"type": "arc",
"encode": {
"update": {
"x": {"signal": "width/2"},
"y": {"signal": "height/2"},
"align": {"value": "center"},
"baseline": {"value": "top"},
"fill": {"signal": "lightColor"},
"startAngle": {"signal": "datum['datum']['startAngle']"},
"endAngle": {"signal": "datum['datum']['endAngle']"},
"innerRadius": {"signal": "yearAxisRadius-15"},
"outerRadius": {"signal": "yearAxisRadius"},
"opacity": {"field": "opacity"}
},
"hover": {"opacity": {"value": 0}}
}
},
{
"name": "year_axis_start_ticks",
"description": "pipe (|) text mark on the year axis that shows the start of a year",
"from": {"data": "year_axis_domain"},
"interactive": false,
"type": "text",
"encode": {
"update": {
"x": {"signal": "width/2"},
"y": {"signal": "height/2"},
"fill": {"signal": "lightColor"},
"stroke": {"signal": "lightColor"},
"strokeWidth": {"value": 3},
"align": {"value": "left"},
"text": {"value": "▮"},
"fontSize": {"value": 15},
"baseline": {"value": "bottom"},
"radius": {"signal": "yearAxisRadius"},
"theta": {"field": "startAngle", "offset": {"value": -0.001}},
"angle": {"signal": "datum['startAngle']*(180/PI)"}
}
}
},
{
"name": "year_axis_end_ticks",
"description": "pipe (|) text mark on the year axis that shows the end of a year",
"from": {"data": "year_axis_domain"},
"interactive": false,
"type": "text",
"encode": {
"update": {
"x": {"signal": "width/2"},
"y": {"signal": "height/2"},
"fill": {"signal": "lightColor"},
"stroke": {"signal": "lightColor"},
"strokeWidth": {"value": 3},
"align": {"value": "right"},
"text": {"value": "▮"},
"fontSize": {"value": 15},
"baseline": {"value": "bottom"},
"radius": {"signal": "yearAxisRadius"},
"theta": {"field": "endAngle", "offset": {"value": 0.003}},
"angle": {"signal": "datum['endAngle']*(180/PI)"}
}
}
},
{
"name": "year_axis_labels",
"description": "year axis text labels",
"from": {"data": "year_axis_domain"},
"interactive": false,
"type": "text",
"encode": {
"update": {
"x": {"signal": "width/2"},
"y": {"signal": "height/2"},
"dy": {"signal": "(datum['flipLabel'] ? 1 : 0)"},
"fill": {"signal": "'#444'"},
"fontSize": {"value": 15},
"fontWeight": {"value": "500"},
"align": {"value": "center"},
"text": {"signal": "datum.Year"},
"baseline": {"signal": "datum['flipLabel'] ? 'top': 'bottom'"},
"radius": {"signal": "monthAxisRadius+9"},
"theta": {"signal": "datum['midAngle']"},
"angle": {
"signal": "(datum['flipLabel'] ? (-1*PI/PI*180) : 0) + datum['midAngle']*(180/PI)"
},
"opacity": {"signal": "datum['opacity']"}
}
}
},
{
"name": "outer_content_background",
"description": "a filled arc with the same color as the canvas background. This arc prevents the month hover arcs from obsecuring the line graphs",
"interactive": true,
"type": "arc",
"encode": {
"update": {
"x": {"signal": "width/2"},
"y": {"signal": "height/2"},
"startAngle": {"value": 0},
"endAngle": {"signal": "2*PI"},
"innerRadius": {"value": 0},
"outerRadius": {"signal": "outerContentRadius"},
"fill": {"signal": "backgroundRGB"},
"stroke": {"signal": "darkColor"},
"strokeOpacity": {"value": 0.5}
}
}
},
{
"name": "placement_ready_group",
"description": "placement for the ready units",
"type": "group",
"interactive": false,
"encode": {
"update": {
"x": {"signal": "width/2 - outerContentRadius"},
"x2": {"signal": "width/2 + outerContentRadius"},
"y": {"signal": "height/2"},
"y2": {"signal": "height/2-outerContentRadius"},
"fill": {"value": "red"},
"fillOpacity": {"value": 0}
}
},
"marks": [
{
"name": "placement_interactive_arcs",
"from": {"data": "ready_placement"},
"type": "arc",
"interactive": true,
"encode": {
"update": {
"x": {"field": "cx"},
"y": {"field": "cy"},
"startAngle": {"field": "startAngle"},
"endAngle": {"field": "endAngle"},
"outerRadius": {
"field": "rowRadius",
"offset": {"signal": "bandwidth('xScalePlacementRow')/2"}
},
"innerRadius": {
"field": "rowRadius",
"offset": {"signal": "-bandwidth('xScalePlacementRow')/2"}
},
"fill": {"signal": "lightColor"},
"opacity": {"value": 0},
"tooltip": {
"signal": "{title: datum['Reporting Unit'], 'Field Comm': datum['Field Comm'], Delta: datum.Delta, 'C-Rate': isValid(datum.OVL) ? 'C-'+datum.OVL : 'N/A', 'Core Assmt.': datum.Assessment || 'N/A'}"
}
}
}
},
{
"from": {"data": "ready_placement"},
"type": "text",
"interactive": false,
"encode": {
"update": {
"x": {"field": "cx"},
"y": {"field": "cy"},
"dy": {
"signal": "isValid(hoverUnit) && datum['Reporting Unit'] === hoverUnit['Reporting Unit'] ? fleetIconSize/10 : 0"
},
"text": {
"signal": "isValid(hoverUnit) && datum['Reporting Unit'] === hoverUnit['Reporting Unit'] ? '𝅛' : '|'"
},
"theta": {"field": "theta"},
"radius": {"field": "rowRadius"},
"angle": {"field": "angle"},
"fontSize": {
"signal": "isValid(hoverUnit) && datum['Reporting Unit'] === hoverUnit['Reporting Unit'] ? fleetIconSize*1.5 : fleetIconSize"
},
"align": {"value": "center"},
"baseline": {"value": "middle"},
"fill": {
"signal": "persistOVLColors || (isValid(hoverUnit) && datum['Reporting Unit'] === hoverUnit['Reporting Unit']) ? (readinessMetric === 'cRate' ? scale('scaleOVLColor', datum.OVL) : scale('scaleCoreColor', datum.Assessment)) : datum.isReady ? lightColor : darkColor"
}
}
}
}
]
},
{
"name": "placement_not_ready_group",
"description": "placement for the units that are not ready",
"type": "group",
"interactive": false,
"encode": {
"update": {
"x": {"signal": "width/2 - outerContentRadius"},
"x2": {"signal": "width/2 + outerContentRadius"},
"y": {"signal": "height/2"},
"y2": {"signal": "height/2-outerContentRadius"},
"fill": {"value": "red"},
"fillOpacity": {"value": 0}
}
},
"marks": [
{
"name": "placement_interactive_arcs",
"from": {"data": "notReady_placement"},
"type": "arc",
"interactive": true,
"encode": {
"update": {
"x": {"field": "cx"},
"y": {"field": "cy"},
"startAngle": {"field": "startAngle"},
"endAngle": {"field": "endAngle"},
"outerRadius": {
"field": "rowRadius",
"offset": {"signal": "bandwidth('xScalePlacementRow')/2"}
},
"innerRadius": {
"field": "rowRadius",
"offset": {"signal": "-bandwidth('xScalePlacementRow')/2"}
},
"fill": {"signal": "lightColor"},
"opacity": {"value": 0},
"tooltip": {
"signal": "{title: datum['Reporting Unit'], 'Field Comm': datum['Field Comm'], Delta: datum.Delta, 'C-Rate': isValid(datum.OVL) ? 'C-'+datum.OVL : 'N/A', 'Core Assmt.': datum.Assessment || 'N/A'}"
}
}
}
},
{
"from": {"data": "notReady_placement"},
"type": "text",
"interactive": false,
"encode": {
"update": {
"x": {"field": "cx"},
"y": {"field": "cy"},
"dy": {
"signal": "isValid(hoverUnit) && datum['Reporting Unit'] === hoverUnit['Reporting Unit'] ? fleetIconSize/10 : 0"
},
"text": {
"signal": "isValid(hoverUnit) && datum['Reporting Unit'] === hoverUnit['Reporting Unit'] ? '𝅛' : '|'"
},
"theta": {"field": "theta"},
"radius": {"field": "rowRadius"},
"angle": {"field": "angle"},
"fontSize": {
"signal": "isValid(hoverUnit) && datum['Reporting Unit'] === hoverUnit['Reporting Unit'] ? fleetIconSize*1.5 : fleetIconSize"
},
"align": {"value": "center"},
"baseline": {"value": "middle"},
"fill": {
"signal": "persistOVLColors || (isValid(hoverUnit) && datum['Reporting Unit'] === hoverUnit['Reporting Unit']) ? (readinessMetric === 'cRate' ? scale('scaleOVLColor', datum.OVL) : scale('scaleCoreColor', datum.Assessment)) : datum.isReady ? lightColor : darkColor"
}
}
}
}
]
},
{
"name": "group_ready_text",
"type": "group",
"from": {"data": "unit_aggregates"},
"interactive": false,
"encode": {
"update": {
"x": {"signal": "width/2-innerContentRadius/1.5"},
"x2": {"signal": "width/2+innerContentRadius/1.5"},
"y": {"signal": "height/2-innerContentRadius/1.5"},
"y2": {"signal": "height/2+innerContentRadius/1.5"}
}
},
"marks": [
{
"name": "ready_percentage_text",
"type": "text",
"interactive": false,
"encode": {
"update": {
"x": {"signal": "(innerContentRadius/1.5)"},
"y": {"signal": "(innerContentRadius/1.5)"},
"dy": {"signal": "-innerContentRadius/2.15"},
"text": {
"signal": "[format(parent.readyCount/parent.totalCount, '.2%'), '']"
},
"fill": {"value": "#CCC"},
"baseline": {"value": "middle"},
"align": {"value": "center"},
"fontSize": {"value": 19},
"fontWeight": {"value": 500}
}
}
},
{
"name": "ready_readytext",
"type": "text",
"interactive": false,
"encode": {
"update": {
"x": {"signal": "(innerContentRadius/1.5)"},
"y": {"signal": "(innerContentRadius/1.5)"},
"dy": {"signal": "-innerContentRadius/2.15"},
"text": {
"signal": "['', readinessMetric === 'cRate' ? 'Ready (C-Rate)' : 'Ready (Core Assmt.)']"
},
"fill": {"value": "#CCC"},
"baseline": {"value": "middle"},
"align": {"value": "center"},
"lineHeight": {"value": 19},
"fontSize": {"value": 12},
"fontWeight": {"value": 500}
}
}
},
{
"name": "ready_count_text",
"type": "text",
"interactive": false,
"encode": {
"update": {
"x": {"signal": "(innerContentRadius/1.5)"},
"y": {"signal": "(innerContentRadius/1.5)"},
"dy": {"signal": "innerContentRadius/3.5"},
"text": {
"signal": "[parent.readyCount + ' / ' + parent.totalCount, 'Reporting Units']"
},
"fill": {"signal": "mediumColor"},
"baseline": {"value": "middle"},
"align": {"value": "center"},
"fontSize": {"value": 12}
}
}
}
]
},
{
"name": "header_group",
"type": "group",
"encode": {"update": {"x": {"signal": "0"}, "y": {"value": -35}}},
"marks": [
{
"name": "group_readinessMetricButtons",
"type": "group",
"marks": [
{
"name": "labelText",
"type": "text",
"encode": {
"update": {
"text": {"signal": "configButtons.label.text"},
"baseline": {"value": "bottom"},
"font": {"signal": "configButtons.label.font"},
"fontSize": {"signal": "configButtons.label.fontSize"},
"fontStyle": {"signal": "configButtons.label.fontStyle"},
"align": {"value": "left"},
"fill": {"signal": "configButtons.label.fill"}
}
}
},
{
"name": "readiness_metric_dummy_labels",
"description": "text marks that will be used by other button marks for reactive geometry",
"type": "text",
"from": {"data": "readinessMetricConfig"},
"interactive": false,
"encode": {
"enter": {
"x": {"signal": "configButtons.padding+datum.rowNumber*45"},
"y": {
"signal": "configButtons.yOffset+configButtons.label.dy"
},
"text": {"field": "label"},
"fill": {"value": "#666"},
"opacity": {"value": 0}
}
}
},
{
"name": "readiness_metric_button_background",
"description": "the background for the expand/collapse buttons",
"type": "rect",
"from": {"data": "readiness_metric_dummy_labels"},
"interactive": true,
"encode": {
"update": {
"x": {"signal": "datum.bounds.x1-configButtons.padding"},
"x2": {"signal": "datum.bounds.x2+configButtons.padding"},
"y": {"signal": "datum.bounds.y1-configButtons.padding"},
"y2": {"signal": "datum.bounds.y2+configButtons.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},
"stroke": {"signal": "background || '#fff'"},
"strokeWidth": {"value": 1},
"fill": {
"signal": "datum.datum.name === readinessMetric ? configButtons.selectedFill : configButtons.fill"
},
"opacity": {"value": 1},
"cursor": {"value": "pointer"},
"tooltip": {"signal": "datum.datum.tooltip"}
},
"hover": {"opacity": {"value": 0.9}}
}
},
{
"name": "readiness_metric_labels",
"description": "text marks that will be used by other button marks for reactive geometry",
"type": "text",
"from": {"data": "readiness_metric_dummy_labels"},
"interactive": false,
"encode": {
"enter": {
"x": {"signal": "datum.x"},
"y": {"signal": "datum.y"},
"text": {"signal": "datum.datum.label"},
"fill": {"value": "#333"},
"opacity": {"value": 1}
}
}
}
]
},
{
"name": "group_showColorIndicatorsToggle",
"description": "group for the marks that make up the toggle control to hide/show details",
"type": "group",
"from": {"data": "group_readinessMetricButtons"},
"interactive": true,
"clip": false,
"encode": {
"update": {
"y": {"signal": "datum.bounds.y2+10"},
"height": {"signal": "30"},
"x": {"signal": "0"},
"width": {"signal": "showColorIndicatorsConfig.track.width"},
"fill": {"value": "transparent"},
"tooltip": {"signal": "showColorIndicatorsConfig.tooltip.text"},
"cursor": {"value": "pointer"}
}
},
"marks": [
{
"name": "persistOVLColorsToggle_text",
"description": "the title for the toggle control",
"type": "text",
"interactive": false,
"encode": {
"update": {
"text": {
"signal": "showColorIndicatorsConfig.label.text || ''"
},
"baseline": {"value": "top"},
"font": {"signal": "showColorIndicatorsConfig.label.font"},
"fontSize": {
"signal": "showColorIndicatorsConfig.label.fontSize"
},
"fontStyle": {
"signal": "showColorIndicatorsConfig.label.fontStyle"
},
"align": {"value": "left"},
"fill": {"signal": "showColorIndicatorsConfig.label.fill"}
}
}
},
{
"name": "track_rect",
"description": "the track for the toggle control",
"type": "rect",
"from": {"data": "persistOVLColorsToggle_text"},
"interactive": false,
"encode": {
"update": {
"y": {
"signal": "datum.bounds.y2+showColorIndicatorsConfig.label.dy"
},
"height": {
"signal": "showColorIndicatorsConfig.track.height"
},
"x": {"signal": "0"},
"x2": {"signal": "showColorIndicatorsConfig.track.width"},
"cornerRadius": {
"signal": "showColorIndicatorsConfig.track.cornerRadius"
},
"fill": {
"signal": "persistOVLColors ? showColorIndicatorsConfig.on.fill : showColorIndicatorsConfig.track.fill"
},
"stroke": {
"signal": "showColorIndicatorsConfig.track.stroke"
},
"strokeWidth": {
"signal": "showColorIndicatorsConfig.track.strokeWidth"
}
}
}
},
{
"name": "toggle_outer_arc",
"description": "the circle mark that serves as the the 'toggle handle'",
"from": {"data": "persistOVLColorsToggle_text"},
"type": "arc",
"interactive": false,
"encode": {
"enter": {
"y": {
"signal": "datum.bounds.y2+showColorIndicatorsConfig.label.dy+showColorIndicatorsConfig.track.height/2"
},
"innerRadius": {"value": 0},
"outerRadius": {
"signal": "showColorIndicatorsConfig.track.height*0.9"
},
"startAngle": {"signal": "0"},
"endAngle": {"signal": "2*PI"},
"stroke": {
"signal": "showColorIndicatorsConfig.handle.stroke || '#BBB'"
},
"strokeWidth": {
"signal": "showColorIndicatorsConfig.handle.strokeWidth"
},
"fill": {
"signal": "showColorIndicatorsConfig.handle.fill || '#fff'"
}
},
"update": {
"x": {
"signal": "persistOVLColors ? showColorIndicatorsConfig.track.width-showColorIndicatorsConfig.track.cornerRadius : showColorIndicatorsConfig.track.cornerRadius"
}
}
}
},
{
"name": "info_icon",
"type": "symbol",
"from": {"data": "persistOVLColorsToggle_text"},
"encode": {
"update": {
"shape": {
"signal": "'M256 512A256 256 0 1 0 256 0a256 256 0 1 0 0 512zM216 336h24V272H216c-13.3 0-24-10.7-24-24s10.7-24 24-24h48c13.3 0 24 10.7 24 24v88h8c13.3 0 24 10.7 24 24s-10.7 24-24 24H216c-13.3 0-24-10.7-24-24s10.7-24 24-24zm40-208a32 32 0 1 1 0 64 32 32 0 1 1 0-64z'"
},
"fill": {"value": "#b5cae1"},
"size": {"value": 0.0035},
"y": {"signal": "datum.bounds.y2+30"},
"x": {"signal": "-2.5"},
"tooltip": {
"signal": "{title: 'Mouseover the radial timeline to explore readiness', 'By C-Rate': 'C-1 & C-2 considered \"Ready\"', 'By Core Assmt.': 'Y & Q considered \"Ready\"'}"
}
}
}
},
]
}
]
}
],
"legends": [
{
"stroke": "scaleIsReadyColor",
"orient": "none",
"legendX": {"signal": "width/2-75"},
"legendY": {"signal": "height"},
"direction": "horizontal",
"symbolType": "stroke",
"encode": {
"symbols": {
"update": {
"angle": {"value": 90},
"size": {"value": 200},
"opacity": {
"signal": "inrange(hoverMonth.startAngle, [2.6, 3.45]) ? 0 : persistOVLColors ? 0 : 1"
}
}
},
"labels": {
"update": {
"fill": {"signal": "scale('scaleIsReadyColor', datum.value)"},
"text": {"signal": "datum.value ? 'Ready' : 'Not Ready'"},
"fontSize": {"value": 13},
"opacity": {
"signal": "inrange(hoverMonth.startAngle, [2.6, 3.45]) ? 0 : persistOVLColors ? 0 : 1"
}
}
}
}
},
{
"stroke": "scaleOVLColor",
"symbolType": "stroke",
"orient": "none",
"legendX": {"signal": "width/2-120"},
"legendY": {"signal": "height"},
"direction": "horizontal",
"encode": {
"symbols": {
"update": {
"angle": {"value": 90},
"size": {"value": 200},
"opacity": {
"signal": "readinessMetric === 'core' || inrange(hoverMonth.startAngle, [2.6, 3.45]) ? 0 : persistOVLColors ? 1 : 0"
}
}
},
"labels": {
"update": {
"fill": {"signal": "scale('scaleOVLColor', datum.value)"},
"text": {"signal": "'C-'+datum.value"},
"fontSize": {"value": 13},
"opacity": {
"signal": "readinessMetric === 'core' || inrange(hoverMonth.startAngle, [2.6, 3.45]) ? 0 : persistOVLColors ? 1 : 0"
}
}
}
}
},
{
"stroke": "scaleCoreColor",
"symbolType": "stroke",
"orient": "none",
"legendX": {"signal": "width/2-55"},
"legendY": {"signal": "height"},
"direction": "horizontal",
"encode": {
"symbols": {
"update": {
"angle": {"value": 90},
"size": {"value": 200},
"opacity": {
"signal": "readinessMetric === 'cRate' || inrange(hoverMonth.startAngle, [2.6, 3.45]) ? 0 : persistOVLColors ? 1 : 0"
}
}
},
"labels": {
"update": {
"fill": {"signal": "scale('scaleCoreColor', datum.value)"},
"fontSize": {"value": 13},
"opacity": {
"signal": "readinessMetric === 'cRate' || inrange(hoverMonth.startAngle, [2.6, 3.45]) ? 0 : persistOVLColors ? 1 : 0"
}
}
}
}
}
],
"scales": [
{
"name": "dayAxisScale",
"type": "band",
"domain": {
"data": "dataset_exploded",
"field": "Date",
"sort": {"field": "Date"}
},
"range": [0, {"signal": "2*PI"}],
"paddingInner": {"signal": "xAxisOuterPaddingPercentage"},
"paddingOuter": {"signal": "xAxisOuterPaddingPercentage/2"}
},
{
"name": "xScalePlacementRow",
"type": "band",
"domain": {"signal": "sequence(1,placementNumberOfRows+1)"},
"range": {"signal": "[outerContentRadius-innerContentRadius, 0]"},
"padding": 0
},
{
"name": "scaleIsReadyColor",
"type": "ordinal",
"domain": [true, false],
"range": [{"signal": "lightColor"}, "#666"]
},
{
"name": "scaleOVLColor",
"type": "ordinal",
"domain": [1, 2, 3, 4, 5],
"range": [
"#59805C",
"#4CAF50 ",
"#FFEB3B ",
"#F44336",
{"signal": "mediumColor"}
]
},
{
"name": "scaleCoreColor",
"type": "ordinal",
"domain": ["Y", "Q", "N"],
"range": ["#59805C", "#FFEB3B ", "#F44336"]
}
],
"data": [
{
"name": "dataset",
"url": "https://raw.githubusercontent.com/Giammaria/PublicFiles/refs/heads/master/data/sf-notional-dataset.csv",
"format": {
"type": "csv",
"parse": {
"Field Comm": "string",
"Delta": "string",
"Reporting Unit": "string",
"Location": "string",
"Capability": "string",
"Component": "string",
"Squadron Type": "string",
"Mission": "string",
"Date": "date",
"P": "number",
"S": "number",
"R": "number",
"T": "number",
"OVL": "number",
"Override C-Rating": "number",
"Assessment": "string",
"Primary Degraders": "string",
"Secondary Degraders": "string",
"Month Look Back": "number",
"Last Month Lookback Filter": "string",
"Details Max Date": "date"
}
},
"transform": [
{"type": "filter", "expr": "datum.Mission === 'CORE'"},
{
"type": "window",
"ops": ["dense_rank"],
"groupby": ["Date"],
"as": ["dr"]
},
{"type": "filter", "expr": "datum.dr >= 100 && datum.dr < 335"},
{
"type": "project",
"fields": [
"Date",
"Reporting Unit",
"Field Comm",
"Delta",
"OVL",
"Assessment"
],
"as": [
"Date",
"Reporting Unit",
"Field Comm",
"Delta",
"OVL",
"Assessment"
]
}
]
},
{
"name": "dataset_formatted",
"source": "dataset",
"transform": [
{
"type": "formula",
"expr": "+utcFormat(datum.Date, '%Y')",
"as": "Year"
},
{
"type": "formula",
"expr": "+utcFormat(datum.Date, '%m')",
"as": "MonthNumber"
},
{
"type": "formula",
"expr": "utcFormat(datum.Date, '%B')",
"as": "Month"
},
{
"type": "formula",
"expr": "utcFormat(datum.Date, '%b')",
"as": "MonthAbbreviation"
},
{
"type": "formula",
"expr": "toDate(utcFormat(datum.Date, '01-%b-%Y 00:00:00.000'))",
"as": "FirstOfMonthDate"
}
]
},
{
"name": "dataset_exploded",
"source": "dataset_formatted",
"transform": [
{
"type": "formula",
"expr": "toDate(utcFormat(timeOffset('day', timeOffset('month', datum.FirstOfMonthDate, 1), -1), '%d-%b-%Y 00:00:00.000'))",
"as": "LastOfMonthDate"
},
{
"type": "formula",
"expr": "round((datum.LastOfMonthDate-datum.FirstOfMonthDate)/dayInMilliseconds)+1",
"as": "Days"
},
{
"type": "aggregate",
"ops": ["count"],
"groupby": [
"Year",
"Month",
"MonthAbbreviation",
"Days",
"FirstOfMonthDate",
"LastOfMonthDate"
],
"as": ["count"]
},
{"type": "formula", "expr": "sequence(0, datum.Days, 1)", "as": "Day"},
{"type": "flatten", "fields": ["Day"]},
{
"type": "formula",
"expr": "timeOffset('day', datum.FirstOfMonthDate, datum['Day'])",
"as": "Date"
},
{"type": "formula", "expr": "datum.Day + 1", "as": "Day"},
{
"type": "formula",
"expr": "utcFormat(datum.Date, '%b%d') === utcFormat(datum.LastOfMonthDate, '%b%d')",
"as": "IsLastDayOfMonth"
},
{
"type": "project",
"fields": [
"FirstOfMonthDate",
"Date",
"Year",
"Month",
"MonthAbbreviation",
"Day",
"IsLastDayOfMonth"
]
}
]
},
{
"name": "detail_data_crate",
"source": "dataset_formatted",
"transform": [
{
"type": "filter",
"expr": "datum.FirstOfMonthDate === hoverMonth.FirstOfMonthDate"
},
{"type": "formula", "expr": "datum.OVL <= 2", "as": "isReady"},
{
"type": "formula",
"expr": "persistOVLColors || (isValid(datum.hoverUnit) && datum['Reporting Unit'] === datum.hoverUnit['Reporting Unit']) ? scale('scaleOVLColor', datum.OVL) : datum.isReady ? lightColor : darkColor",
"as": "Fill"
},
{"type": "collect", "sort": {"field": "OVL"}},
{
"type": "window",
"ops": ["dense_rank"],
"groupby": ["isReady"],
"as": ["index"]
},
{"type": "formula", "expr": "hoverUnit", "as": "hoverUnit"}
]
},
{
"name": "detail_data_core",
"source": "dataset_formatted",
"transform": [
{
"type": "filter",
"expr": "datum.FirstOfMonthDate === hoverMonth.FirstOfMonthDate"
},
{
"type": "formula",
"expr": "indexof(['Y','Q'], datum.Assessment)>=0",
"as": "isReady"
},
{"type": "collect", "sort": {"field": "OVL"}},
{
"type": "formula",
"expr": "indexof(['Q', 'Y', 'N'], datum.Assessment) || 3",
"as": "AssessmentSort"
},
{"type": "collect", "sort": {"field": "AssessmentSort"}},
{
"type": "window",
"ops": ["dense_rank"],
"groupby": ["isReady"],
"as": ["index"]
},
{"type": "formula", "expr": "hoverUnit", "as": "hoverUnit"}
]
},
{
"name": "detail_data",
"on": [
{
"trigger": "readinessMetric",
"insert": "readinessMetric === 'cRate' ? data('detail_data_crate') : data('detail_data_core')",
"remove": true
}
],
"transform": [
{
"type": "formula",
"expr": "persistOVLColors",
"as": "persistOVLColors"
},
{"type": "collect", "sort": {"field": "index"}}
]
},
{
"name": "unit_aggregates",
"source": "detail_data",
"transform": [
{
"type": "aggregate",
"ops": ["count"],
"groupby": ["isReady"],
"as": ["rowCount"]
},
{"type": "pivot", "field": "isReady", "value": "rowCount"},
{"type": "formula", "expr": "datum.true", "as": "readyCount"},
{"type": "formula", "expr": "datum.false", "as": "notReadyCount"},
{
"type": "formula",
"expr": "(datum.readyCount || 0)+(datum.notReadyCount || 0)",
"as": "totalCount"
},
{
"type": "project",
"fields": ["readyCount", "notReadyCount", "totalCount"]
}
]
},
{
"name": "ready_placement",
"source": "detail_data",
"transform": [
{"type": "filter", "expr": "datum.isReady"},
{
"type": "formula",
"expr": "datum.index%placementNumberOfRows === 0 ? placementNumberOfRows : datum.index%placementNumberOfRows",
"as": "row"
},
{
"type": "formula",
"expr": "scale('xScalePlacementRow', datum.row)",
"as": "rowStartX"
},
{
"type": "formula",
"expr": "(outerContentRadius*2)-scale('xScalePlacementRow', datum.row)-bandwidth('xScalePlacementRow')",
"as": "rowEndX"
},
{
"type": "window",
"ops": ["dense_rank"],
"groupby": ["row"],
"as": ["seat"]
},
{
"type": "joinaggregate",
"ops": ["count"],
"groupby": ["row"],
"as": ["seatCount"]
},
{
"type": "joinaggregate",
"ops": ["max"],
"fields": ["seatCount"],
"as": ["seatCount"]
},
{
"type": "formula",
"expr": "(datum.rowEndX - datum.rowStartX)/2",
"as": "rowRadius"
},
{
"type": "formula",
"expr": "(fleetPlacementRadialOffset/2)+(datum.seat/datum.seatCount)*(PI-fleetPlacementRadialOffset)-PI/2",
"as": "theta"
},
{"type": "formula", "expr": "datum.theta*(180/PI)", "as": "angle"},
{"type": "formula", "expr": "outerContentRadius", "as": "cx"},
{
"type": "formula",
"expr": "(height/2)-(height/2-outerContentRadius)",
"as": "cy"
},
{
"type": "window",
"ops": ["lag", "lead"],
"fields": ["theta", "theta"],
"groupby": ["row", "row"],
"as": ["lagTheta", "leadTheta"]
},
{
"type": "formula",
"expr": "isValid(datum.leadTheta) && isValid(datum.lagTheta) ? (datum.leadTheta - datum.lagTheta)/2 : null",
"as": "thetaBandWidth"
},
{
"type": "joinaggregate",
"ops": ["mean"],
"fields": ["thetaBandWidth"],
"as": ["thetaBandWidth"]
},
{
"type": "formula",
"expr": "datum.theta-(datum.thetaBandWidth/2)",
"as": "startAngle"
},
{
"type": "formula",
"expr": "datum.theta+(datum.thetaBandWidth/2)",
"as": "endAngle"
},
{
"type": "formula",
"expr": "readinessMetric === 'core' ? datum.Fill : persistOVLColors || (isValid(datum.hoverUnit) && datum['Reporting Unit'] === datum.hoverUnit['Reporting Unit']) ? scale('scaleOVLColor', datum.OVL) : datum.isReady ? lightColor : darkColor",
"as": "Fill"
},
{
"type": "formula",
"expr": "readinessMetric === 'cRate' ? datum.Fill : persistOVLColors || (isValid(datum.hoverUnit) && datum['Reporting Unit'] === datum.hoverUnit['Reporting Unit']) ? scale('scaleCoreColor', datum.Assessment) : datum.isReady ? lightColor : darkColor",
"as": "Fill"
}
]
},
{
"name": "notReady_placement",
"source": "detail_data",
"transform": [
{"type": "filter", "expr": "!datum.isReady"},
{
"type": "formula",
"expr": "datum.index%placementNumberOfRows === 0 ? placementNumberOfRows : datum.index%placementNumberOfRows",
"as": "row"
},
{
"type": "formula",
"expr": "scale('xScalePlacementRow', datum.row)",
"as": "rowStartX"
},
{
"type": "formula",
"expr": "(outerContentRadius*2)-scale('xScalePlacementRow', datum.row)-bandwidth('xScalePlacementRow')",
"as": "rowEndX"
},
{
"type": "window",
"ops": ["dense_rank"],
"groupby": ["row"],
"as": ["seat"]
},
{
"type": "joinaggregate",
"ops": ["count"],
"groupby": ["row"],
"as": ["seatCount"]
},
{
"type": "joinaggregate",
"ops": ["max"],
"fields": ["seatCount"],
"as": ["seatCount"]
},
{
"type": "formula",
"expr": "(datum.rowEndX - datum.rowStartX)/2",
"as": "rowRadius"
},
{
"type": "formula",
"expr": "((fleetPlacementRadialOffset/2)+(datum.seat/datum.seatCount)*(PI-fleetPlacementRadialOffset)-PI/2)+PI",
"as": "theta"
},
{"type": "formula", "expr": "datum.theta*(180/PI)", "as": "angle"},
{"type": "formula", "expr": "outerContentRadius", "as": "cx"},
{
"type": "formula",
"expr": "(height/2)-(height/2-outerContentRadius)",
"as": "cy"
},
{
"type": "window",
"ops": ["lag", "lead"],
"fields": ["theta", "theta"],
"groupby": ["row", "row"],
"as": ["lagTheta", "leadTheta"]
},
{
"type": "formula",
"expr": "isValid(datum.leadTheta) && isValid(datum.lagTheta) ? (datum.leadTheta - datum.lagTheta)/2 : null",
"as": "thetaBandWidth"
},
{
"type": "joinaggregate",
"ops": ["mean"],
"fields": ["thetaBandWidth"],
"as": ["thetaBandWidth"]
},
{
"type": "formula",
"expr": "datum.BandWidth || 0.11",
"as": "thetaBandWidth"
},
{
"type": "formula",
"expr": "datum.theta-(datum.thetaBandWidth/2)",
"as": "startAngle"
},
{
"type": "formula",
"expr": "datum.theta+(datum.thetaBandWidth/2)",
"as": "endAngle"
}
]
},
{
"name": "readinessMetricConfig",
"values": [
{
"rowNumber": 0,
"name": "cRate",
"label": "C-Rate",
"tooltip": "Readiness by C-Rate"
},
{
"rowNumber": 1,
"name": "core",
"label": "Core Assmt.",
"tooltip": "Readiness by Core Assessment"
}
]
}
]
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment