From 9719f5528bf091aed7acafc105cd7c6c4424536e Mon Sep 17 00:00:00 2001 From: Michael Hudson Nkotagu Date: Thu, 1 Aug 2024 13:42:22 +0300 Subject: [PATCH 1/5] chore: Move LineChartScope to Hurumap-core --- .../hurumap-core/src/Scope/LineChartScope.js | 584 ++++++++++++++++++ packages/hurumap-core/src/Scope/index.js | 2 + 2 files changed, 586 insertions(+) create mode 100644 packages/hurumap-core/src/Scope/LineChartScope.js diff --git a/packages/hurumap-core/src/Scope/LineChartScope.js b/packages/hurumap-core/src/Scope/LineChartScope.js new file mode 100644 index 000000000..74933cc3a --- /dev/null +++ b/packages/hurumap-core/src/Scope/LineChartScope.js @@ -0,0 +1,584 @@ +import merge from "deepmerge"; + +import Scope from "./Scope"; + +export default function LineChartScope( + primaryData, + metadata, + config, + secondaryData, + primaryParentData, + secondaryParentData, + profileNames, + isCompare, + isMobile, + theme, + args, +) { + const { + parentLabel, + xScaleType, + xScaleFormat, + xScaleMobileFormat, + timeUnit, + timeFormat, + } = config; + + const { primary_group: primaryGroup } = metadata; + + const timeTransform = + xScaleType === "time" + ? [ + { + type: "formula", + as: primaryGroup, + expr: "timeParse(datum[mainGroup], timeFormat)", + }, + { + type: "timeunit", + units: timeUnit, + field: primaryGroup, + }, + ] + : undefined; + + return merge( + Scope( + primaryData, + metadata, + config, + secondaryData, + primaryParentData, + secondaryParentData, + "line", + timeTransform, + theme, + args, + ), + { + height: isMobile && isCompare && secondaryData?.length > 1 ? 620 : 310, + signals: [ + { + name: "height", + value: isMobile && isCompare && secondaryData?.length > 1 ? 620 : 310, + }, + { + name: "isMobile", + value: isMobile, + }, + { + name: "isCompare", + value: isCompare, + }, + { + name: "timeFormat", + value: timeFormat || "%b", + }, + ], + scales: [ + { + name: "xscale", + type: xScaleType || "point", + domain: { + data: "primary_formatted", + field: primaryGroup, + }, + range: [ + 15, + { + signal: + "data('secondary').length > 1 && !isMobile ? width/2 - 30 : width", + }, + ], + }, + { + name: "s_xscale", + type: xScaleType || "point", + domain: { + data: "secondary_formatted", + field: primaryGroup, + }, + range: [ + 15, + { + signal: + "!isMobile && data('secondary').length > 1 ? width/2 - 30 : data('secondary').length > 1 ? width : 0", + }, + ], + }, + { + name: "yscale", + type: "linear", + domain: { + data: "primary_formatted", + field: { signal: "datatype[Units]" }, + }, + range: [{ signal: "isCompare && isMobile ? height/2: height" }, 0], + nice: { signal: "primaryYTickCount" }, + zero: false, + clamp: true, + }, + { + name: "s_yscale", + type: "linear", + domain: { + data: "secondary_formatted", + field: { signal: "datatype[Units]" }, + }, + range: [{ signal: "isCompare && isMobile ? height/2: height" }, 0], + nice: { signal: "secondaryYTickCount" }, + zero: false, + clamp: true, + }, + { + name: "color", + type: "ordinal", + range: "category", + domain: { + data: "primary_formatted", + field: primaryGroup, + }, + }, + { + name: "secondary_color", + type: "ordinal", + range: "secondary", + domain: { + data: "secondary_formatted", + field: primaryGroup, + }, + }, + { + name: "parent_color_scale", + type: "ordinal", + range: "category", + domain: [parentLabel], + }, + { + name: "legend_primary_scale", + type: "ordinal", + domain: [profileNames.primary.toUpperCase()], + range: [theme.palette.primary.main], + }, + { + name: "legend_secondary_scale", + type: "ordinal", + domain: [profileNames.secondary.toUpperCase()], + range: [theme.palette.secondary.main], + }, + ], + + marks: [ + { + type: "group", + name: "primary_lines", + encode: { + update: { + x: { value: 0 }, + y: { signal: "chartY" }, + height: { + signal: + "isMobile && isCompare && data('secondary').length > 1 ? height/2: height", + }, + width: { + signal: + "isMobile && data('secondary').length > 1 ? width : width/2", + }, + }, + }, + legends: isCompare + ? [ + { + orient: "top", + fill: "legend_primary_scale", + labelFontWeight: "bold", + labelColor: "#666", + labelFont: theme.typography.fontFamily, + }, + ] + : null, + axes: [ + { + orient: "left", + scale: "yscale", + domain: false, + domainOpacity: 0.5, + tickSize: 0, + tickCount: { signal: "primaryYTickCount" }, + labelPadding: 6, + zindex: 1, + format: { signal: "numberFormat[Units]" }, + }, + { + orient: "bottom", + scale: "xscale", + bandPosition: 0, + domainOpacity: 0.5, + tickSize: 0, + grid: true, + labelPadding: 6, + labelFlush: true, + labelOverlap: true, + formatType: xScaleType, + format: + (isMobile ? xScaleMobileFormat : xScaleFormat) || undefined, + }, + ], + marks: [ + { + name: "line", + from: { data: "primary_formatted" }, + type: "line", + encode: { + enter: { + x: { scale: "xscale", field: { signal: "mainGroup" } }, + stroke: { scale: "color", field: { signal: "mainGroup" } }, + y: { scale: "yscale", field: { signal: "datatype[Units]" } }, + strokeWidth: { value: 2 }, + }, + update: { + x: { scale: "xscale", field: { signal: "mainGroup" } }, + y: { scale: "yscale", field: { signal: "datatype[Units]" } }, + interpolate: { signal: "interpolate" }, + strokeOpacity: { value: 1 }, + }, + }, + }, + { + name: "line symbol", + from: { data: "primary_formatted" }, + type: "symbol", + encode: { + enter: { + x: { scale: "xscale", field: { signal: "mainGroup" } }, + y: { scale: "yscale", field: { signal: "datatype[Units]" } }, + fill: { value: theme.palette.primary.main }, + }, + update: { + x: { scale: "xscale", field: { signal: "mainGroup" } }, + y: { scale: "yscale", field: { signal: "datatype[Units]" } }, + size: { value: 5 }, + tooltip: { + signal: + "{'group': datum[mainGroup], 'count': format(datum.count, numberFormat.value)}", + }, + }, + hover: { + size: { value: 70 }, + }, + }, + }, + ], + }, + { + type: "group", + name: "primary_parent_line", + encode: { + update: { + x: { value: 0 }, + y: { signal: "chartY" }, + height: { + signal: + "isMobile && isCompare && data('secondary').length > 1 ? height/2: height", + }, + }, + }, + legends: + primaryParentData?.length > 1 + ? [ + { + fill: "parent_color_scale", + orient: "none", + legendX: { + signal: + "data('secondary').length > 1 && !isMobile? (width / 2 ) - 100 : width - 85", + }, + legendY: { value: -35 }, + labelFont: theme.typography.fontFamily, + labelColor: theme.palette.chart.text.primary, + encode: { + symbols: { + shape: { value: "stroke" }, + update: { + shape: { value: "stroke" }, + size: { value: 500 }, + stroke: { value: theme.palette.chart.text.primary }, + strokeDash: { value: [2, 2] }, + }, + }, + }, + }, + ] + : null, + marks: [ + { + name: "line", + from: { data: "primary_parent_formatted" }, + type: "line", + encode: { + enter: { + x: { scale: "xscale", field: { signal: "mainGroup" } }, + stroke: { value: theme.palette.chart.text.primary }, + y: { scale: "yscale", field: { signal: "datatype[Units]" } }, + strokeWidth: { value: 2 }, + strokeDash: { value: [2, 2] }, + }, + update: { + x: { scale: "xscale", field: { signal: "mainGroup" } }, + y: { scale: "yscale", field: { signal: "datatype[Units]" } }, + interpolate: { signal: "interpolate" }, + strokeOpacity: { value: 1 }, + }, + }, + }, + { + name: "line symbol", + from: { data: "primary_parent_formatted" }, + type: "symbol", + encode: { + enter: { + x: { scale: "xscale", field: { signal: "mainGroup" } }, + y: { scale: "yscale", field: { signal: "datatype[Units]" } }, + fill: { value: theme.palette.chart.text.primary }, + }, + update: { + x: { scale: "xscale", field: { signal: "mainGroup" } }, + y: { scale: "yscale", field: { signal: "datatype[Units]" } }, + size: { value: 5 }, + tooltip: { + signal: + "{'group': datum[mainGroup], 'count': format(datum.count, numberFormat.value)}", + }, + }, + hover: { + size: { value: 70 }, + }, + }, + }, + ], + }, + { + type: "group", + name: "secondary_lines", + encode: { + update: { + x: { + signal: + "!isMobile && data('secondary').length > 1 ? width / 2 + 30 : 0", + }, + y: { + signal: + "isMobile && data('secondary').length > 1 ? height/2 + 60: data('secondary').length > 1 ? chartY: height + 60", + }, + height: { + signal: + "isMobile && data('secondary').length > 1 ? height/2: data('secondary').length > 1 ? height: 0", + }, + width: { + signal: + "!isMobile && data('secondary').length > 1 ? (width / 2 ) : data('secondary').length > 1 ? width : 0", + }, + }, + }, + legends: isCompare + ? [ + { + orient: "top", + fill: "legend_secondary_scale", + labelFontWeight: "bold", + labelLimit: 400, + labelColor: "#666", + labelFont: theme.typography.fontFamily, + }, + ] + : null, + axes: + secondaryData?.length > 1 + ? [ + { + orient: "left", + scale: "s_yscale", + domain: false, + domainOpacity: 0.5, + tickSize: 0, + tickCount: { signal: "secondaryYTickCount" }, + labelPadding: 6, + zindex: 1, + format: { signal: "numberFormat[Units]" }, + }, + { + orient: "bottom", + scale: "s_xscale", + bandPosition: 0, + domainOpacity: 0.5, + tickSize: 0, + grid: true, + labelPadding: 6, + labelFlush: true, + labelOverlap: true, + formatType: xScaleType, + format: + (isMobile ? xScaleMobileFormat : xScaleFormat) || + undefined, + }, + ] + : null, + marks: [ + { + name: "line", + from: { data: "secondary_formatted" }, + type: "line", + encode: { + enter: { + x: { scale: "s_xscale", field: { signal: "mainGroup" } }, + stroke: { + scale: "secondary_color", + field: { signal: "mainGroup" }, + }, + y: { + scale: "s_yscale", + field: { signal: "datatype[Units]" }, + }, + strokeWidth: { value: 2 }, + }, + update: { + interpolate: { signal: "interpolate" }, + strokeOpacity: { value: 1 }, + }, + }, + }, + { + name: "line symbol", + from: { data: "secondary_formatted" }, + type: "symbol", + encode: { + enter: { + x: { scale: "s_xscale", field: { signal: "mainGroup" } }, + y: { + scale: "s_yscale", + field: { signal: "datatype[Units]" }, + }, + fill: { value: theme.palette.secondary.main }, + }, + update: { + size: { value: 5 }, + tooltip: { + signal: + "{'group': datum[mainGroup], 'count': format(datum.count, numberFormat.value)}", + }, + }, + hover: { + size: { value: 70 }, + }, + }, + }, + ], + }, + { + type: "group", + name: "secondary_parent_line", + encode: { + update: { + x: { + signal: + "!isMobile && data('secondary').length > 1 ? width / 2 + 30 : 0", + }, + y: { + signal: + "isMobile && data('secondary').length > 1 ? height/2 + 30: data('secondary').length > 1 ? chartY: height + 40", + }, + height: { + signal: + "isMobile && data('secondary').length > 1 ? height/2: 0", + }, + }, + }, + legends: + secondaryParentData?.length > 1 + ? [ + { + fill: "parent_color_scale", + offset: 20, + orient: "none", + legendX: { + signal: "isMobile ? width -90: (width / 2 ) - 120", + }, + legendY: { value: isMobile ? -10 : -40 }, + labelFont: theme.typography.fontFamily, + labelColor: theme.palette.chart.text.primary, + encode: { + symbols: { + shape: { value: "stroke" }, + update: { + shape: { value: "stroke" }, + size: { value: 500 }, + stroke: { value: theme.palette.chart.text.primary }, + strokeDash: { value: [2, 2] }, + }, + }, + }, + }, + ] + : null, + marks: + secondaryParentData?.length > 1 + ? [ + { + name: "line", + from: { data: "secondary_parent_formatted" }, + type: "line", + encode: { + enter: { + x: { + scale: "s_xscale", + field: { signal: "mainGroup" }, + }, + stroke: { value: theme.palette.chart.text.primary }, + y: { + scale: "s_yscale", + field: { signal: "datatype[Units]" }, + }, + strokeWidth: { value: 2 }, + strokeDash: { value: [2, 2] }, + }, + update: { + interpolate: { signal: "interpolate" }, + strokeOpacity: { value: 1 }, + }, + }, + }, + { + name: "line symbol", + from: { data: "secondary_parent_formatted" }, + type: "symbol", + encode: { + enter: { + x: { + scale: "s_xscale", + field: { signal: "mainGroup" }, + }, + y: { + scale: "s_yscale", + field: { signal: "datatype[Units]" }, + }, + fill: { value: theme.palette.chart.text.primary }, + }, + update: { + size: { value: 5 }, + tooltip: { + signal: + "{'group': datum[mainGroup], 'count': format(datum.count, numberFormat.value)}", + }, + }, + hover: { + size: { value: 70 }, + }, + }, + }, + ] + : null, + }, + ], + }, + ); +} diff --git a/packages/hurumap-core/src/Scope/index.js b/packages/hurumap-core/src/Scope/index.js index 9cbb70f75..ac6929c26 100644 --- a/packages/hurumap-core/src/Scope/index.js +++ b/packages/hurumap-core/src/Scope/index.js @@ -1,7 +1,9 @@ import BarChartScope from "./BarChartScope"; +import LineChartScope from "./LineChartScope"; import Scope from "./Scope"; export default { Scope, BarChartScope, + LineChartScope, }; From a8631f613e9125a0df20930afe95eb666683cb9b Mon Sep 17 00:00:00 2001 From: Michael Hudson Nkotagu Date: Thu, 1 Aug 2024 19:35:09 +0300 Subject: [PATCH 2/5] fix: Fix breaking chart due to nice property --- .../hurumap-core/src/Scope/LineChartScope.js | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/packages/hurumap-core/src/Scope/LineChartScope.js b/packages/hurumap-core/src/Scope/LineChartScope.js index 74933cc3a..7311718a7 100644 --- a/packages/hurumap-core/src/Scope/LineChartScope.js +++ b/packages/hurumap-core/src/Scope/LineChartScope.js @@ -2,7 +2,7 @@ import merge from "deepmerge"; import Scope from "./Scope"; -export default function LineChartScope( +export default function LineChartScope({ primaryData, metadata, config, @@ -14,7 +14,7 @@ export default function LineChartScope( isMobile, theme, args, -) { +}) { const { parentLabel, xScaleType, @@ -23,7 +23,6 @@ export default function LineChartScope( timeUnit, timeFormat, } = config; - const { primary_group: primaryGroup } = metadata; const timeTransform = @@ -43,18 +42,18 @@ export default function LineChartScope( : undefined; return merge( - Scope( + Scope({ primaryData, metadata, config, secondaryData, primaryParentData, secondaryParentData, - "line", + chartType: "line", timeTransform, theme, args, - ), + }), { height: isMobile && isCompare && secondaryData?.length > 1 ? 620 : 310, signals: [ @@ -114,7 +113,8 @@ export default function LineChartScope( field: { signal: "datatype[Units]" }, }, range: [{ signal: "isCompare && isMobile ? height/2: height" }, 0], - nice: { signal: "primaryYTickCount" }, + // TODO: explore why adding nice breaks the chart with error: Error: Cycle detected in dataflow graph. + // nice: { signal: "primaryYTickCount" }, zero: false, clamp: true, }, @@ -126,7 +126,8 @@ export default function LineChartScope( field: { signal: "datatype[Units]" }, }, range: [{ signal: "isCompare && isMobile ? height/2: height" }, 0], - nice: { signal: "secondaryYTickCount" }, + // TODO: explore why adding nice breaks the chart with error: Error: Cycle detected in dataflow graph. + // nice: { signal: "secondaryYTickCount" }, zero: false, clamp: true, }, From 2028d9606026c63b7a6aeac357977b143707e647 Mon Sep 17 00:00:00 2001 From: Michael Hudson Nkotagu Date: Thu, 1 Aug 2024 19:39:34 +0300 Subject: [PATCH 3/5] feat: Import Line Chart from Hurumap package in Climate Mapped Africa --- .../HURUmap/Chart/LineChartScope.js | 582 ------------------ .../HURUmap/Chart/configureScope.js | 35 +- 2 files changed, 28 insertions(+), 589 deletions(-) delete mode 100644 apps/climatemappedafrica/src/components/HURUmap/Chart/LineChartScope.js diff --git a/apps/climatemappedafrica/src/components/HURUmap/Chart/LineChartScope.js b/apps/climatemappedafrica/src/components/HURUmap/Chart/LineChartScope.js deleted file mode 100644 index a40eb11dc..000000000 --- a/apps/climatemappedafrica/src/components/HURUmap/Chart/LineChartScope.js +++ /dev/null @@ -1,582 +0,0 @@ -import merge from "deepmerge"; - -import Scope from "./Scope"; - -import theme from "@/climatemappedafrica/theme"; - -export default function LineChartScope( - primaryData, - metadata, - config, - secondaryData, - primaryParentData, - secondaryParentData, - profileNames, - isCompare, - isMobile, -) { - const { - parentLabel, - xScaleType, - xScaleFormat, - xScaleMobileFormat, - timeUnit, - timeFormat, - } = config; - - const { primary_group: primaryGroup } = metadata; - - const timeTransform = - xScaleType === "time" - ? [ - { - type: "formula", - as: primaryGroup, - expr: "timeParse(datum[mainGroup], timeFormat)", - }, - { - type: "timeunit", - units: timeUnit, - field: primaryGroup, - }, - ] - : undefined; - - return merge( - Scope( - primaryData, - metadata, - config, - secondaryData, - primaryParentData, - secondaryParentData, - "line", - timeTransform, - ), - { - height: isMobile && isCompare && secondaryData?.length > 1 ? 620 : 310, - signals: [ - { - name: "height", - value: isMobile && isCompare && secondaryData?.length > 1 ? 620 : 310, - }, - { - name: "isMobile", - value: isMobile, - }, - { - name: "isCompare", - value: isCompare, - }, - { - name: "timeFormat", - value: timeFormat || "%b", - }, - ], - scales: [ - { - name: "xscale", - type: xScaleType || "point", - domain: { - data: "primary_formatted", - field: primaryGroup, - }, - range: [ - 15, - { - signal: - "data('secondary').length > 1 && !isMobile ? width/2 - 30 : width", - }, - ], - }, - { - name: "s_xscale", - type: xScaleType || "point", - domain: { - data: "secondary_formatted", - field: primaryGroup, - }, - range: [ - 15, - { - signal: - "!isMobile && data('secondary').length > 1 ? width/2 - 30 : data('secondary').length > 1 ? width : 0", - }, - ], - }, - { - name: "yscale", - type: "linear", - domain: { - data: "primary_formatted", - field: { signal: "datatype[Units]" }, - }, - range: [{ signal: "isCompare && isMobile ? height/2: height" }, 0], - // nice: { signal: "primaryYTickCount" }, - zero: false, - clamp: true, - }, - { - name: "s_yscale", - type: "linear", - domain: { - data: "secondary_formatted", - field: { signal: "datatype[Units]" }, - }, - range: [{ signal: "isCompare && isMobile ? height/2: height" }, 0], - // nice: { signal: "secondaryYTickCount" }, - zero: false, - clamp: true, - }, - { - name: "color", - type: "ordinal", - range: "category", - domain: { - data: "primary_formatted", - field: primaryGroup, - }, - }, - { - name: "secondary_color", - type: "ordinal", - range: "secondary", - domain: { - data: "secondary_formatted", - field: primaryGroup, - }, - }, - { - name: "parent_color_scale", - type: "ordinal", - range: "category", - domain: [parentLabel], - }, - { - name: "legend_primary_scale", - type: "ordinal", - domain: [profileNames.primary.toUpperCase()], - range: [theme.palette.primary.main], - }, - { - name: "legend_secondary_scale", - type: "ordinal", - domain: [profileNames.secondary.toUpperCase()], - range: [theme.palette.secondary.main], - }, - ], - - marks: [ - { - type: "group", - name: "primary_lines", - encode: { - update: { - x: { value: 0 }, - y: { signal: "chartY" }, - height: { - signal: - "isMobile && isCompare && data('secondary').length > 1 ? height/2: height", - }, - width: { - signal: - "isMobile && data('secondary').length > 1 ? width : width/2", - }, - }, - }, - legends: isCompare - ? [ - { - orient: "top", - fill: "legend_primary_scale", - labelFontWeight: "bold", - labelColor: "#666", - labelFont: theme.typography.fontFamily, - }, - ] - : null, - axes: [ - { - orient: "left", - scale: "yscale", - domain: false, - domainOpacity: 0.5, - tickSize: 0, - tickCount: { signal: "primaryYTickCount" }, - labelPadding: 6, - zindex: 1, - format: { signal: "numberFormat[Units]" }, - }, - { - orient: "bottom", - scale: "xscale", - bandPosition: 0, - domainOpacity: 0.5, - tickSize: 0, - grid: true, - labelPadding: 6, - labelFlush: true, - labelOverlap: true, - formatType: xScaleType, - format: - (isMobile ? xScaleMobileFormat : xScaleFormat) || undefined, - }, - ], - marks: [ - { - name: "line", - from: { data: "primary_formatted" }, - type: "line", - encode: { - enter: { - x: { scale: "xscale", field: { signal: "mainGroup" } }, - stroke: { scale: "color", field: { signal: "mainGroup" } }, - y: { scale: "yscale", field: { signal: "datatype[Units]" } }, - strokeWidth: { value: 2 }, - }, - update: { - x: { scale: "xscale", field: { signal: "mainGroup" } }, - y: { scale: "yscale", field: { signal: "datatype[Units]" } }, - interpolate: { signal: "interpolate" }, - strokeOpacity: { value: 1 }, - }, - }, - }, - { - name: "line symbol", - from: { data: "primary_formatted" }, - type: "symbol", - encode: { - enter: { - x: { scale: "xscale", field: { signal: "mainGroup" } }, - y: { scale: "yscale", field: { signal: "datatype[Units]" } }, - fill: { value: theme.palette.primary.main }, - }, - update: { - x: { scale: "xscale", field: { signal: "mainGroup" } }, - y: { scale: "yscale", field: { signal: "datatype[Units]" } }, - size: { value: 5 }, - tooltip: { - signal: - "{'group': datum[mainGroup], 'count': format(datum.count, numberFormat.value)}", - }, - }, - hover: { - size: { value: 70 }, - }, - }, - }, - ], - }, - { - type: "group", - name: "primary_parent_line", - encode: { - update: { - x: { value: 0 }, - y: { signal: "chartY" }, - height: { - signal: - "isMobile && isCompare && data('secondary').length > 1 ? height/2: height", - }, - }, - }, - legends: - primaryParentData?.length > 1 - ? [ - { - fill: "parent_color_scale", - orient: "none", - legendX: { - signal: - "data('secondary').length > 1 && !isMobile? (width / 2 ) - 100 : width - 85", - }, - legendY: { value: -35 }, - labelFont: theme.typography.fontFamily, - labelColor: theme.palette.chart.text.primary, - encode: { - symbols: { - shape: { value: "stroke" }, - update: { - shape: { value: "stroke" }, - size: { value: 500 }, - stroke: { value: theme.palette.chart.text.primary }, - strokeDash: { value: [2, 2] }, - }, - }, - }, - }, - ] - : null, - marks: [ - { - name: "line", - from: { data: "primary_parent_formatted" }, - type: "line", - encode: { - enter: { - x: { scale: "xscale", field: { signal: "mainGroup" } }, - stroke: { value: theme.palette.chart.text.primary }, - y: { scale: "yscale", field: { signal: "datatype[Units]" } }, - strokeWidth: { value: 2 }, - strokeDash: { value: [2, 2] }, - }, - update: { - x: { scale: "xscale", field: { signal: "mainGroup" } }, - y: { scale: "yscale", field: { signal: "datatype[Units]" } }, - interpolate: { signal: "interpolate" }, - strokeOpacity: { value: 1 }, - }, - }, - }, - { - name: "line symbol", - from: { data: "primary_parent_formatted" }, - type: "symbol", - encode: { - enter: { - x: { scale: "xscale", field: { signal: "mainGroup" } }, - y: { scale: "yscale", field: { signal: "datatype[Units]" } }, - fill: { value: theme.palette.chart.text.primary }, - }, - update: { - x: { scale: "xscale", field: { signal: "mainGroup" } }, - y: { scale: "yscale", field: { signal: "datatype[Units]" } }, - size: { value: 5 }, - tooltip: { - signal: - "{'group': datum[mainGroup], 'count': format(datum.count, numberFormat.value)}", - }, - }, - hover: { - size: { value: 70 }, - }, - }, - }, - ], - }, - { - type: "group", - name: "secondary_lines", - encode: { - update: { - x: { - signal: - "!isMobile && data('secondary').length > 1 ? width / 2 + 30 : 0", - }, - y: { - signal: - "isMobile && data('secondary').length > 1 ? height/2 + 60: data('secondary').length > 1 ? chartY: height + 60", - }, - height: { - signal: - "isMobile && data('secondary').length > 1 ? height/2: data('secondary').length > 1 ? height: 0", - }, - width: { - signal: - "!isMobile && data('secondary').length > 1 ? (width / 2 ) : data('secondary').length > 1 ? width : 0", - }, - }, - }, - legends: isCompare - ? [ - { - orient: "top", - fill: "legend_secondary_scale", - labelFontWeight: "bold", - labelLimit: 400, - labelColor: "#666", - labelFont: theme.typography.fontFamily, - }, - ] - : null, - axes: - secondaryData?.length > 1 - ? [ - { - orient: "left", - scale: "s_yscale", - domain: false, - domainOpacity: 0.5, - tickSize: 0, - tickCount: { signal: "secondaryYTickCount" }, - labelPadding: 6, - zindex: 1, - format: { signal: "numberFormat[Units]" }, - }, - { - orient: "bottom", - scale: "s_xscale", - bandPosition: 0, - domainOpacity: 0.5, - tickSize: 0, - grid: true, - labelPadding: 6, - labelFlush: true, - labelOverlap: true, - formatType: xScaleType, - format: - (isMobile ? xScaleMobileFormat : xScaleFormat) || - undefined, - }, - ] - : null, - marks: [ - { - name: "line", - from: { data: "secondary_formatted" }, - type: "line", - encode: { - enter: { - x: { scale: "s_xscale", field: { signal: "mainGroup" } }, - stroke: { - scale: "secondary_color", - field: { signal: "mainGroup" }, - }, - y: { - scale: "s_yscale", - field: { signal: "datatype[Units]" }, - }, - strokeWidth: { value: 2 }, - }, - update: { - interpolate: { signal: "interpolate" }, - strokeOpacity: { value: 1 }, - }, - }, - }, - { - name: "line symbol", - from: { data: "secondary_formatted" }, - type: "symbol", - encode: { - enter: { - x: { scale: "s_xscale", field: { signal: "mainGroup" } }, - y: { - scale: "s_yscale", - field: { signal: "datatype[Units]" }, - }, - fill: { value: theme.palette.secondary.main }, - }, - update: { - size: { value: 5 }, - tooltip: { - signal: - "{'group': datum[mainGroup], 'count': format(datum.count, numberFormat.value)}", - }, - }, - hover: { - size: { value: 70 }, - }, - }, - }, - ], - }, - { - type: "group", - name: "secondary_parent_line", - encode: { - update: { - x: { - signal: - "!isMobile && data('secondary').length > 1 ? width / 2 + 30 : 0", - }, - y: { - signal: - "isMobile && data('secondary').length > 1 ? height/2 + 30: data('secondary').length > 1 ? chartY: height + 40", - }, - height: { - signal: - "isMobile && data('secondary').length > 1 ? height/2: 0", - }, - }, - }, - legends: - secondaryParentData?.length > 1 - ? [ - { - fill: "parent_color_scale", - offset: 20, - orient: "none", - legendX: { - signal: "isMobile ? width -90: (width / 2 ) - 120", - }, - legendY: { value: isMobile ? -10 : -40 }, - labelFont: theme.typography.fontFamily, - labelColor: theme.palette.chart.text.primary, - encode: { - symbols: { - shape: { value: "stroke" }, - update: { - shape: { value: "stroke" }, - size: { value: 500 }, - stroke: { value: theme.palette.chart.text.primary }, - strokeDash: { value: [2, 2] }, - }, - }, - }, - }, - ] - : null, - marks: - secondaryParentData?.length > 1 - ? [ - { - name: "line", - from: { data: "secondary_parent_formatted" }, - type: "line", - encode: { - enter: { - x: { - scale: "s_xscale", - field: { signal: "mainGroup" }, - }, - stroke: { value: theme.palette.chart.text.primary }, - y: { - scale: "s_yscale", - field: { signal: "datatype[Units]" }, - }, - strokeWidth: { value: 2 }, - strokeDash: { value: [2, 2] }, - }, - update: { - interpolate: { signal: "interpolate" }, - strokeOpacity: { value: 1 }, - }, - }, - }, - { - name: "line symbol", - from: { data: "secondary_parent_formatted" }, - type: "symbol", - encode: { - enter: { - x: { - scale: "s_xscale", - field: { signal: "mainGroup" }, - }, - y: { - scale: "s_yscale", - field: { signal: "datatype[Units]" }, - }, - fill: { value: theme.palette.chart.text.primary }, - }, - update: { - size: { value: 5 }, - tooltip: { - signal: - "{'group': datum[mainGroup], 'count': format(datum.count, numberFormat.value)}", - }, - }, - hover: { - size: { value: 70 }, - }, - }, - }, - ] - : null, - }, - ], - }, - ); -} diff --git a/apps/climatemappedafrica/src/components/HURUmap/Chart/configureScope.js b/apps/climatemappedafrica/src/components/HURUmap/Chart/configureScope.js index 1c8376c72..457a5fa97 100644 --- a/apps/climatemappedafrica/src/components/HURUmap/Chart/configureScope.js +++ b/apps/climatemappedafrica/src/components/HURUmap/Chart/configureScope.js @@ -1,7 +1,6 @@ import { Scope } from "@hurumap/core"; import DonutChartScope from "./DonutChartScope"; -import LineChartScope from "./LineChartScope"; import MultiLineChartScope from "./MultiLineChartScope"; import StackedChartScope from "./StackedChartScope"; import TreemapChartScope from "./TreemapChartScope"; @@ -11,7 +10,7 @@ import VerticalStackedChartScope from "./VerticalStackedChartScope"; import { hurumapArgs } from "@/climatemappedafrica/config"; import theme from "@/climatemappedafrica/theme"; -const { BarChartScope } = Scope; +const { BarChartScope, LineChartScope } = Scope; export default function configureScope( indicator, @@ -31,7 +30,14 @@ export default function configureScope( let vegaSpec; const chartType = configuration?.chart_type?.toLowerCase(); - const scopeOptions = [ + + /** + * @deprecated Use scopeOptions for implementing new charts + * This will be completely removed once all charts scopes + * are moved to Hurumap package + */ + // eslint-disable-next-line no-underscore-dangle + const _scopeOptions = [ indicator?.data, indicator?.metadata, configuration, @@ -42,19 +48,34 @@ export default function configureScope( isCompare, isMobile, ]; + + const scopeOptions = { + primaryData: indicator?.data, + metadata: indicator?.metadata, + config: configuration, + secondaryData: secondaryIndicator?.data ?? null, + primaryParentData: showParent ? indicator?.parentData : [{}], + secondaryParentData: showParent ? secondaryIndicator?.parentData : [{}], + profileNames, + isCompare, + isMobile, + theme, + args: hurumapArgs, + }; + switch (chartType) { case "line": if (configuration?.stacked_field) { - vegaSpec = MultiLineChartScope(...scopeOptions); + vegaSpec = MultiLineChartScope(..._scopeOptions); } else { - vegaSpec = LineChartScope(...scopeOptions); + vegaSpec = LineChartScope(scopeOptions); } break; case "donut": - vegaSpec = DonutChartScope(...scopeOptions); + vegaSpec = DonutChartScope(..._scopeOptions); break; case "treemap": - vegaSpec = TreemapChartScope(...scopeOptions); + vegaSpec = TreemapChartScope(..._scopeOptions); break; case "stacked": if (isMobile) { From 1e003bfeba77b63a87904addcb3f80c864a23648 Mon Sep 17 00:00:00 2001 From: Michael Hudson Nkotagu Date: Thu, 1 Aug 2024 20:04:44 +0300 Subject: [PATCH 4/5] feat: Import LineChart Scope from Hurumap package --- .../HURUmap/Chart/configureScope.js | 51 +++++++++++-------- 1 file changed, 29 insertions(+), 22 deletions(-) diff --git a/apps/pesayetu/src/components/HURUmap/Chart/configureScope.js b/apps/pesayetu/src/components/HURUmap/Chart/configureScope.js index cc0be0067..be2bc7332 100644 --- a/apps/pesayetu/src/components/HURUmap/Chart/configureScope.js +++ b/apps/pesayetu/src/components/HURUmap/Chart/configureScope.js @@ -1,7 +1,6 @@ import { Scope } from "@hurumap/core"; import DonutChartScope from "./DonutChartScope"; -import LineChartScope from "./LineChartScope"; import MultiLineChartScope from "./MultiLineChartScope"; import StackedChartScope from "./StackedChartScope"; import TreemapChartScope from "./TreemapChartScope"; @@ -11,7 +10,7 @@ import VerticalStackedChartScope from "./VerticalStackedChartScope"; import { hurumapArgs } from "@/pesayetu/config"; import theme from "@/pesayetu/theme"; -const { BarChartScope } = Scope; +const { BarChartScope, LineChartScope } = Scope; export default function configureScope( indicator, @@ -31,7 +30,14 @@ export default function configureScope( let vegaSpec; const chartType = configuration?.chart_type?.toLowerCase(); - const scopeOptions = [ + + /** + * @deprecated Use scopeOptions for implementing new charts + * This will be completely removed once all charts scopes + * are moved to Hurumap package + */ + // eslint-disable-next-line no-underscore-dangle + const _scopeOptions = [ indicator?.data, indicator?.metadata, configuration, @@ -42,19 +48,34 @@ export default function configureScope( isCompare, isMobile, ]; + + const scopeOptions = { + primaryData: indicator?.data, + metadata: indicator?.metadata, + config: configuration, + secondaryData: secondaryIndicator?.data ?? null, + primaryParentData: showParent ? indicator?.parentData : [{}], + secondaryParentData: showParent ? secondaryIndicator?.parentData : [{}], + profileNames, + isCompare, + isMobile, + theme, + args: hurumapArgs, + }; + switch (chartType) { case "line": if (configuration?.stacked_field) { - vegaSpec = MultiLineChartScope(...scopeOptions); + vegaSpec = MultiLineChartScope(..._scopeOptions); } else { - vegaSpec = LineChartScope(...scopeOptions); + vegaSpec = LineChartScope(scopeOptions); } break; case "donut": - vegaSpec = DonutChartScope(...scopeOptions); + vegaSpec = DonutChartScope(..._scopeOptions); break; case "treemap": - vegaSpec = TreemapChartScope(...scopeOptions); + vegaSpec = TreemapChartScope(..._scopeOptions); break; case "stacked": if (isMobile) { @@ -93,21 +114,7 @@ export default function configureScope( isCompare, ); } else { - const barChartArgs = { - primaryData: indicator?.data, - metadata: indicator?.metadata, - config: configuration, - secondaryData: secondaryIndicator?.data ?? null, - primaryParentData: showParent ? indicator?.parentData : [{}], - secondaryParentData: showParent - ? secondaryIndicator?.parentData - : [{}], - profileNames, - isCompare, - theme, - args: hurumapArgs, - }; - vegaSpec = BarChartScope(barChartArgs); + vegaSpec = BarChartScope(scopeOptions); } break; } From b5c5fb0bbd1cd6e46e8acfec30526c9e806f62c2 Mon Sep 17 00:00:00 2001 From: Michael Hudson Nkotagu Date: Fri, 2 Aug 2024 11:39:11 +0300 Subject: [PATCH 5/5] chore: Remove unused LineChartScope from PesaYetu --- .../HURUmap/Chart/LineChartScope.js | 582 ------------------ 1 file changed, 582 deletions(-) delete mode 100644 apps/pesayetu/src/components/HURUmap/Chart/LineChartScope.js diff --git a/apps/pesayetu/src/components/HURUmap/Chart/LineChartScope.js b/apps/pesayetu/src/components/HURUmap/Chart/LineChartScope.js deleted file mode 100644 index 5781d1e7b..000000000 --- a/apps/pesayetu/src/components/HURUmap/Chart/LineChartScope.js +++ /dev/null @@ -1,582 +0,0 @@ -import merge from "deepmerge"; - -import Scope from "./Scope"; - -import theme from "@/pesayetu/theme"; - -export default function LineChartScope( - primaryData, - metadata, - config, - secondaryData, - primaryParentData, - secondaryParentData, - profileNames, - isCompare, - isMobile, -) { - const { - parentLabel, - xScaleType, - xScaleFormat, - xScaleMobileFormat, - timeUnit, - timeFormat, - } = config; - - const { primary_group: primaryGroup } = metadata; - - const timeTransform = - xScaleType === "time" - ? [ - { - type: "formula", - as: primaryGroup, - expr: "timeParse(datum[mainGroup], timeFormat)", - }, - { - type: "timeunit", - units: timeUnit, - field: primaryGroup, - }, - ] - : undefined; - - return merge( - Scope( - primaryData, - metadata, - config, - secondaryData, - primaryParentData, - secondaryParentData, - "line", - timeTransform, - ), - { - height: isMobile && isCompare && secondaryData?.length > 1 ? 620 : 310, - signals: [ - { - name: "height", - value: isMobile && isCompare && secondaryData?.length > 1 ? 620 : 310, - }, - { - name: "isMobile", - value: isMobile, - }, - { - name: "isCompare", - value: isCompare, - }, - { - name: "timeFormat", - value: timeFormat || "%b", - }, - ], - scales: [ - { - name: "xscale", - type: xScaleType || "point", - domain: { - data: "primary_formatted", - field: primaryGroup, - }, - range: [ - 15, - { - signal: - "data('secondary').length > 1 && !isMobile ? width/2 - 30 : width", - }, - ], - }, - { - name: "s_xscale", - type: xScaleType || "point", - domain: { - data: "secondary_formatted", - field: primaryGroup, - }, - range: [ - 15, - { - signal: - "!isMobile && data('secondary').length > 1 ? width/2 - 30 : data('secondary').length > 1 ? width : 0", - }, - ], - }, - { - name: "yscale", - type: "linear", - domain: { - data: "primary_formatted", - field: { signal: "datatype[Units]" }, - }, - range: [{ signal: "isCompare && isMobile ? height/2: height" }, 0], - nice: { signal: "primaryYTickCount" }, - zero: false, - clamp: true, - }, - { - name: "s_yscale", - type: "linear", - domain: { - data: "secondary_formatted", - field: { signal: "datatype[Units]" }, - }, - range: [{ signal: "isCompare && isMobile ? height/2: height" }, 0], - nice: { signal: "secondaryYTickCount" }, - zero: false, - clamp: true, - }, - { - name: "color", - type: "ordinal", - range: "category", - domain: { - data: "primary_formatted", - field: primaryGroup, - }, - }, - { - name: "secondary_color", - type: "ordinal", - range: "secondary", - domain: { - data: "secondary_formatted", - field: primaryGroup, - }, - }, - { - name: "parent_color_scale", - type: "ordinal", - range: "category", - domain: [parentLabel], - }, - { - name: "legend_primary_scale", - type: "ordinal", - domain: [profileNames.primary.toUpperCase()], - range: [theme.palette.primary.main], - }, - { - name: "legend_secondary_scale", - type: "ordinal", - domain: [profileNames.secondary.toUpperCase()], - range: [theme.palette.secondary.main], - }, - ], - - marks: [ - { - type: "group", - name: "primary_lines", - encode: { - update: { - x: { value: 0 }, - y: { signal: "chartY" }, - height: { - signal: - "isMobile && isCompare && data('secondary').length > 1 ? height/2: height", - }, - width: { - signal: - "isMobile && data('secondary').length > 1 ? width : width/2", - }, - }, - }, - legends: isCompare - ? [ - { - orient: "top", - fill: "legend_primary_scale", - labelFontWeight: "bold", - labelColor: "#666", - labelFont: theme.typography.fontFamily, - }, - ] - : null, - axes: [ - { - orient: "left", - scale: "yscale", - domain: false, - domainOpacity: 0.5, - tickSize: 0, - tickCount: { signal: "primaryYTickCount" }, - labelPadding: 6, - zindex: 1, - format: { signal: "numberFormat[Units]" }, - }, - { - orient: "bottom", - scale: "xscale", - bandPosition: 0, - domainOpacity: 0.5, - tickSize: 0, - grid: true, - labelPadding: 6, - labelFlush: true, - labelOverlap: true, - formatType: xScaleType, - format: - (isMobile ? xScaleMobileFormat : xScaleFormat) || undefined, - }, - ], - marks: [ - { - name: "line", - from: { data: "primary_formatted" }, - type: "line", - encode: { - enter: { - x: { scale: "xscale", field: { signal: "mainGroup" } }, - stroke: { scale: "color", field: { signal: "mainGroup" } }, - y: { scale: "yscale", field: { signal: "datatype[Units]" } }, - strokeWidth: { value: 2 }, - }, - update: { - x: { scale: "xscale", field: { signal: "mainGroup" } }, - y: { scale: "yscale", field: { signal: "datatype[Units]" } }, - interpolate: { signal: "interpolate" }, - strokeOpacity: { value: 1 }, - }, - }, - }, - { - name: "line symbol", - from: { data: "primary_formatted" }, - type: "symbol", - encode: { - enter: { - x: { scale: "xscale", field: { signal: "mainGroup" } }, - y: { scale: "yscale", field: { signal: "datatype[Units]" } }, - fill: { value: theme.palette.primary.main }, - }, - update: { - x: { scale: "xscale", field: { signal: "mainGroup" } }, - y: { scale: "yscale", field: { signal: "datatype[Units]" } }, - size: { value: 5 }, - tooltip: { - signal: - "{'group': datum[mainGroup], 'count': format(datum.count, numberFormat.value)}", - }, - }, - hover: { - size: { value: 70 }, - }, - }, - }, - ], - }, - { - type: "group", - name: "primary_parent_line", - encode: { - update: { - x: { value: 0 }, - y: { signal: "chartY" }, - height: { - signal: - "isMobile && isCompare && data('secondary').length > 1 ? height/2: height", - }, - }, - }, - legends: - primaryParentData?.length > 1 - ? [ - { - fill: "parent_color_scale", - orient: "none", - legendX: { - signal: - "data('secondary').length > 1 && !isMobile? (width / 2 ) - 100 : width - 85", - }, - legendY: { value: -35 }, - labelFont: theme.typography.fontFamily, - labelColor: theme.palette.chart.text.primary, - encode: { - symbols: { - shape: { value: "stroke" }, - update: { - shape: { value: "stroke" }, - size: { value: 500 }, - stroke: { value: theme.palette.chart.text.primary }, - strokeDash: { value: [2, 2] }, - }, - }, - }, - }, - ] - : null, - marks: [ - { - name: "line", - from: { data: "primary_parent_formatted" }, - type: "line", - encode: { - enter: { - x: { scale: "xscale", field: { signal: "mainGroup" } }, - stroke: { value: theme.palette.chart.text.primary }, - y: { scale: "yscale", field: { signal: "datatype[Units]" } }, - strokeWidth: { value: 2 }, - strokeDash: { value: [2, 2] }, - }, - update: { - x: { scale: "xscale", field: { signal: "mainGroup" } }, - y: { scale: "yscale", field: { signal: "datatype[Units]" } }, - interpolate: { signal: "interpolate" }, - strokeOpacity: { value: 1 }, - }, - }, - }, - { - name: "line symbol", - from: { data: "primary_parent_formatted" }, - type: "symbol", - encode: { - enter: { - x: { scale: "xscale", field: { signal: "mainGroup" } }, - y: { scale: "yscale", field: { signal: "datatype[Units]" } }, - fill: { value: theme.palette.chart.text.primary }, - }, - update: { - x: { scale: "xscale", field: { signal: "mainGroup" } }, - y: { scale: "yscale", field: { signal: "datatype[Units]" } }, - size: { value: 5 }, - tooltip: { - signal: - "{'group': datum[mainGroup], 'count': format(datum.count, numberFormat.value)}", - }, - }, - hover: { - size: { value: 70 }, - }, - }, - }, - ], - }, - { - type: "group", - name: "secondary_lines", - encode: { - update: { - x: { - signal: - "!isMobile && data('secondary').length > 1 ? width / 2 + 30 : 0", - }, - y: { - signal: - "isMobile && data('secondary').length > 1 ? height/2 + 60: data('secondary').length > 1 ? chartY: height + 60", - }, - height: { - signal: - "isMobile && data('secondary').length > 1 ? height/2: data('secondary').length > 1 ? height: 0", - }, - width: { - signal: - "!isMobile && data('secondary').length > 1 ? (width / 2 ) : data('secondary').length > 1 ? width : 0", - }, - }, - }, - legends: isCompare - ? [ - { - orient: "top", - fill: "legend_secondary_scale", - labelFontWeight: "bold", - labelLimit: 400, - labelColor: "#666", - labelFont: theme.typography.fontFamily, - }, - ] - : null, - axes: - secondaryData?.length > 1 - ? [ - { - orient: "left", - scale: "s_yscale", - domain: false, - domainOpacity: 0.5, - tickSize: 0, - tickCount: { signal: "secondaryYTickCount" }, - labelPadding: 6, - zindex: 1, - format: { signal: "numberFormat[Units]" }, - }, - { - orient: "bottom", - scale: "s_xscale", - bandPosition: 0, - domainOpacity: 0.5, - tickSize: 0, - grid: true, - labelPadding: 6, - labelFlush: true, - labelOverlap: true, - formatType: xScaleType, - format: - (isMobile ? xScaleMobileFormat : xScaleFormat) || - undefined, - }, - ] - : null, - marks: [ - { - name: "line", - from: { data: "secondary_formatted" }, - type: "line", - encode: { - enter: { - x: { scale: "s_xscale", field: { signal: "mainGroup" } }, - stroke: { - scale: "secondary_color", - field: { signal: "mainGroup" }, - }, - y: { - scale: "s_yscale", - field: { signal: "datatype[Units]" }, - }, - strokeWidth: { value: 2 }, - }, - update: { - interpolate: { signal: "interpolate" }, - strokeOpacity: { value: 1 }, - }, - }, - }, - { - name: "line symbol", - from: { data: "secondary_formatted" }, - type: "symbol", - encode: { - enter: { - x: { scale: "s_xscale", field: { signal: "mainGroup" } }, - y: { - scale: "s_yscale", - field: { signal: "datatype[Units]" }, - }, - fill: { value: theme.palette.secondary.main }, - }, - update: { - size: { value: 5 }, - tooltip: { - signal: - "{'group': datum[mainGroup], 'count': format(datum.count, numberFormat.value)}", - }, - }, - hover: { - size: { value: 70 }, - }, - }, - }, - ], - }, - { - type: "group", - name: "secondary_parent_line", - encode: { - update: { - x: { - signal: - "!isMobile && data('secondary').length > 1 ? width / 2 + 30 : 0", - }, - y: { - signal: - "isMobile && data('secondary').length > 1 ? height/2 + 30: data('secondary').length > 1 ? chartY: height + 40", - }, - height: { - signal: - "isMobile && data('secondary').length > 1 ? height/2: 0", - }, - }, - }, - legends: - secondaryParentData?.length > 1 - ? [ - { - fill: "parent_color_scale", - offset: 20, - orient: "none", - legendX: { - signal: "isMobile ? width -90: (width / 2 ) - 120", - }, - legendY: { value: isMobile ? -10 : -40 }, - labelFont: theme.typography.fontFamily, - labelColor: theme.palette.chart.text.primary, - encode: { - symbols: { - shape: { value: "stroke" }, - update: { - shape: { value: "stroke" }, - size: { value: 500 }, - stroke: { value: theme.palette.chart.text.primary }, - strokeDash: { value: [2, 2] }, - }, - }, - }, - }, - ] - : null, - marks: - secondaryParentData?.length > 1 - ? [ - { - name: "line", - from: { data: "secondary_parent_formatted" }, - type: "line", - encode: { - enter: { - x: { - scale: "s_xscale", - field: { signal: "mainGroup" }, - }, - stroke: { value: theme.palette.chart.text.primary }, - y: { - scale: "s_yscale", - field: { signal: "datatype[Units]" }, - }, - strokeWidth: { value: 2 }, - strokeDash: { value: [2, 2] }, - }, - update: { - interpolate: { signal: "interpolate" }, - strokeOpacity: { value: 1 }, - }, - }, - }, - { - name: "line symbol", - from: { data: "secondary_parent_formatted" }, - type: "symbol", - encode: { - enter: { - x: { - scale: "s_xscale", - field: { signal: "mainGroup" }, - }, - y: { - scale: "s_yscale", - field: { signal: "datatype[Units]" }, - }, - fill: { value: theme.palette.chart.text.primary }, - }, - update: { - size: { value: 5 }, - tooltip: { - signal: - "{'group': datum[mainGroup], 'count': format(datum.count, numberFormat.value)}", - }, - }, - hover: { - size: { value: 70 }, - }, - }, - }, - ] - : null, - }, - ], - }, - ); -}