Published
Edited
May 24, 2022
Insert cell
Insert cell
scenario = ({
scenarioId: 1,
outputResultKpis: [
{
anagKpiId: 1,
clusterId: 0, // TOT
kpiValue: 100
},
{
anagKpiId: 1,
clusterId: 1,
kpiValue: 11
},
{
anagKpiId: 1,
clusterId: 2,
kpiValue: 12
},
{
anagKpiId: 1,
clusterId: 3,
kpiValue: 13
},
{
anagKpiId: 1,
clusterId: 4,
kpiValue: 14
},
{
anagKpiId: 2,
clusterId: 0, // TOT
kpiValue: 200
},
{
anagKpiId: 2,
clusterId: 1,
kpiValue: 21
},
{
anagKpiId: 2,
clusterId: 2,
kpiValue: 22
},
{
anagKpiId: 2,
clusterId: 3,
kpiValue: 23
},
{
anagKpiId: 2,
clusterId: 4,
kpiValue: 24
},
]
})
Insert cell
kpis = [
{
anagKpiId: 1,
name: "kpi 1"
},
{
anagKpiId: 2,
name: "kpi 2"
},
]
Insert cell
tableColumns = [
{ primaryLabel: "KPI" },
{ primaryLabel: "Cluster 1", secondaryLabel: "(HR-LC)" },
{ primaryLabel: "Cluster 2", secondaryLabel: "(HR-HC)" },
{ primaryLabel: "Cluster 3", secondaryLabel: "(LR-HC)" },
{ primaryLabel: "Cluster 4", secondaryLabel: "(LR-LC)" },
{ primaryLabel: "TOT" }
]
Insert cell
{
const getKpiClusterValue = (clusterId, kpiClusterValues) => {
return kpiClusterValues.find(kpi => kpi.clusterId === clusterId).kpiValue
}

const scenarioKpis = scenario.outputResultKpis
return kpis.map(kpi => {
const kpiClusterValues = scenarioKpis.filter(scKpi => scKpi.anagKpiId === kpi.anagKpiId)
return [
kpi.name,
getKpiClusterValue(1, kpiClusterValues),
getKpiClusterValue(2, kpiClusterValues),
getKpiClusterValue(3, kpiClusterValues),
getKpiClusterValue(4, kpiClusterValues),
getKpiClusterValue(0, kpiClusterValues) // TOT
]
})
}
Insert cell
{
const scenarioKpis = scenario.outputResultKpis
const groupedKpiValues = scenarioKpis.reduce((acc, kpi) => { // group by anagKpiId
/* step by step to "clarify"
const filteredByKpiId = scenarioKpis.filter(scKpi => scKpi.anagKpiId === kpi.anagKpiId)
const groupedByCluster = filteredByKpiId.reduce((clAcc, cl, i) => {
clAcc[cl.clusterId] = cl.kpiValue
return clAcc
}, {})
acc[kpi.anagKpiId] = groupedByCluster*/
acc[kpi.anagKpiId] = scenarioKpis
.filter(scKpi => scKpi.anagKpiId === kpi.anagKpiId) // filter by anagKpiId
.reduce((clAcc, cl) => { // group by clusterId
clAcc[cl.clusterId] = cl.kpiValue
return clAcc
}, {})
return acc
}, {})

console.log('grouped data', groupedKpiValues)

return kpis.map(kpi => {
return [
kpi.name,
groupedKpiValues[kpi.anagKpiId][1],
groupedKpiValues[kpi.anagKpiId][2],
groupedKpiValues[kpi.anagKpiId][3],
groupedKpiValues[kpi.anagKpiId][4],
groupedKpiValues[kpi.anagKpiId][0] // TOT
]
})
}
Insert cell
tableRows = [
{
checked: true,
data: [
{
primaryValue: "kpi 1"
},
{
primaryValue: 1
},
{
primaryValue: 1
},
{
primaryValue: 1
},
{
primaryValue: 1
},
{
primaryValue: 1
},
]
},
{
checked: false,
data: [
{
primaryValue: "kpi 2"
},
{
primaryValue: 1
},
{
primaryValue: 1
},
{
primaryValue: 1
},
{
primaryValue: 1
},
{
primaryValue: 1
},
]
},
]
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
prepareDataTable = (scenarioId, kpis, scenarios) => {
const baseScenario = scenarios.find(sc => sc.id === scenarioId)
const remainingScenarios = scenarios.filter(scenario => scenario.id !== baseScenario.id)

const cols = [
"KPI",
`${baseScenario.name} (base)`,
...remainingScenarios.flatMap(sc => [sc.name, "delta"])
]
const rows = kpis.map(kpi => {
const baseKpiValue = getKpiValue(kpi.id, baseScenario)
return [
kpi.name,
baseKpiValue,
...remainingScenarios.flatMap(sc => {
const kpiValue = getKpiValue(kpi.id, sc)
return [kpiValue, baseKpiValue - kpiValue]
})
]
})

return { cols, rows };
}
Insert cell
baseScenarioId$ = new Subject()
Insert cell
{
// fake API call
const kpisFromAPI$ = Rx.of([{ id: 1, name: "kp1"}, { id: 2, name: "kp2"}, { id: 3, name: "kp3"}])

// fake API call
const scenariosFromAPI$ = Rx.of([
{ id: 1, name: "scenario 1", kpis: [{ id: 1, value: 42 }, { id: 2, value: 43 }, { id: 3, value: 44 }] },
{ id: 2, name: "scenario 2", kpis: [{ id: 1, value: 23 }, { id: 2, value: 24 }, { id: 3, value: 25 }] },
{ id: 3, name: "scenario 3", kpis: [{ id: 1, value: 666 }, { id: 2, value: 667 }, { id: 3, value: 668 }] },
])
combineLatest([
baseScenarioId$,
kpisFromAPI$,
scenariosFromAPI$
]).pipe(
map(([baseScenarioId, kpis, scenarios]) => prepareDataTable(baseScenarioId, kpis, scenarios))
).subscribe((data) => {
console.log(data)
document.getElementById("resultsContent").innerHTML = hb_table_tpl({
headers: data.cols,
rows: data.rows
})
})
}
Insert cell
Insert cell
{
const test = [
[1, 2],
[3, 4]
];

return test.flat()
}
Insert cell
{
const scenarios = [
{
name: "puppa",
kpiIds: [1, 2, 3]
},
{
name: "fuffa",
kpiIds: [3, 4, 5, 6]
}
];

return [...new Set(scenarios.flatMap(sc => sc.kpiIds))]
}
Insert cell
Insert cell
{
const scenarios = [
{
name: "puppa",
kpiIds: [1, 2, 3]
},
{
name: "fuffa",
kpiIds: [3, 4, 5, 6]
}
];

let sums = [];
for(let i=0; i<scenarios.length; i++) {
sums[i] = 0;
for(let j=0; j<scenarios[i].kpiIds.length; j++){
sums[i] += scenarios[i].kpiIds[j]
}
}

return sums
}
Insert cell
{
const scenarios = [
{
name: "puppa",
kpiIds: [1, 2, 3]
},
{
name: "fuffa",
kpiIds: [3, 4, 5, 6]
}
];

const sum = (arr) => arr.reduce((acc, elem) => acc + elem)
return scenarios.map(sc => sum(sc.kpiIds))
}
Insert cell
{
const okRequest$ = Rx.of('API response').pipe(delay(3000));

/*const errorRequest$ = Rx.interval(1000).pipe(
take(1),
switchMap(() => Rx.throwError('test'))
);*/

const myObs$ = okRequest$.pipe(
takeUntil(Rx.of(null).pipe(delay(2000)))
);

myObs$.subscribe({next: data => console.log('next', data), error: err => console.log('error', err), complete: () => console.log('complete')});
}
Insert cell
{
const callApi = (index) => index < 6 ? Rx.of({status: 'in progress'}) : Rx.of({status: 'completed'});

const timeout$ = Rx.interval(5000).pipe(take(1));
Rx.timer(0, 1000).pipe(
concatMap(i => callApi(i)),
takeWhile(response => response.status === 'in progress', true),
takeUntil(timeout$)
).subscribe({next: data => console.log('next', data), error: err => console.log('error', err), complete: () => console.log('complete')})
}
Insert cell
Insert cell
{
const CLUSTER_1_KEY = '1'

const sortedData = cluster_data[CLUSTER_1_KEY]
.map(elem => ({
...elem,
trueDate: moment(elem.date, 'DD/MM/yyyy').format('yyyy/MM/DD')
}))
.sort((a, b) => a.trueDate === b.trueDate
? 0
: a.trueDate > b.trueDate
? 1
: -1);

const label = sortedData.map(elem => moment(elem.date, 'DD/MM/yyyy').format('MMM yyyy'))

const series = sortedData.map(elem => Number(elem.value))
return { label, series }
}
Insert cell
{
const ALL_CLUSTERS = 'all-clusters'
const CLUSTER_1_KEY = '1'
const CLUSTER_CHART_INFO = {
'1': {
name: 'HR-LC',
color: '#1A73E8'
},
'2': {
name: 'HR-HC',
color: '#1A73E9'
},
'3': {
name: 'LR-HC',
color: '#1A73E5'
},
'4': {
name: 'LR-LC',
color: '#1A73E2'
},
}

const getSeriesAndData = (cluster, data) => {
return {
color: CLUSTER_CHART_INFO[cluster].color,
seriesInfo: {
name: CLUSTER_CHART_INFO[cluster].name,
data: data[cluster].map(elem => Number(elem.value))
}
}
}

const getChartData = (selection, data) => {
if (selection === ALL_CLUSTERS) {
return {
colors: Object.keys(CLUSTER_CHART_INFO).map(clusterKey => getSeriesAndData(clusterKey, data).color),
series: Object.keys(CLUSTER_CHART_INFO).map(clusterKey => getSeriesAndData(clusterKey, data).seriesInfo),
}
} else {
const seriesAndData = getSeriesAndData(selection, data)
return {
colors: [seriesAndData.color],
series: [seriesAndData.seriesInfo]
}
}
}

// Sort cluster data
const sorted_cluster_data = Object.fromEntries(Object.keys(cluster_data).map(clusterKey => {
const sortedSingleClusterData = cluster_data[clusterKey].map(elem => ({
...elem,
trueDate: moment(elem.date, 'DD/MM/yyyy').format('yyyy/MM/DD')
}))
.sort((a, b) => a.trueDate === b.trueDate
? 0
: a.trueDate > b.trueDate
? 1
: -1);

return [clusterKey, sortedSingleClusterData]
}))

return {
categories: sorted_cluster_data[CLUSTER_1_KEY].map(elem => moment(elem.date, 'DD/MM/yyyy').format('MMM yyyy')),
chartsData: getChartData(ALL_CLUSTERS, sorted_cluster_data)
}
}
Insert cell
Insert cell
{
const widths = [155, 155, 155, 155, 155, 155];

return widths.map(
(_, i) => widths
.slice(0, i)
.reduce((acc, curr) => acc + curr, 0)
)
}
Insert cell
Insert cell
{
const HC = 'critical', LC = 'non-critical', HR = 'regular', LR = 'non-regular';
const CLUSTERS = [{
cluster: 1,
criticality: LC,
regularity: HR
}, {
cluster: 2,
criticality: HC,
regularity: HR
}, {
cluster: 3,
criticality: HC,
regularity: LR
}, {
cluster: 4,
criticality: LC,
regularity: LR
}]
const getCriticality = (cluster) => {
return CLUSTERS.find(el => el.cluster === cluster).criticality
}

const getCluster = (previousCluster, criticality) => {
const regularity = CLUSTERS.find(el => el.cluster === previousCluster).regularity
return CLUSTERS.find(el => el.criticality === criticality && el.regularity == regularity).cluster
}

return {
example1: getCriticality(1), // criticality for cluster 1
example2: getCriticality(4), // criticality for cluster 4
example3: getCluster(2, LC), // cluster for low criticality and previous cluster 2
example4: getCluster(4, HC) // cluster for high criticality and prevous cluster 4
}
}
Insert cell
Insert cell
{
const bs$ = new Rx.BehaviorSubject(null);

const apiCall$ = Rx.timer(1000).pipe(
// chiamata API
map(response => 'ciccia')
);

const pageData$ = bs$.pipe(
switchMap(data => data ? Rx.of(data) : apiCall$)
);

setTimeout(() => {
bs$.next('ciccia')
}, 500);

pageData$.subscribe(console.log);
}
Insert cell
{
const getRandomInt = function (max) {
return Math.floor(Math.random() * max);
}
const generateRandomValues = function (fromDay, endDay) {
const dataSeries = [];
while (endDay.isAfter(fromDay)) {
dataSeries.push([
moment(fromDay).valueOf(),
getRandomInt(35)
]);
fromDay.add(getRandomInt(7), 'day');
}
return dataSeries;
}

return JSON.stringify(generateRandomValues(moment('2021-01-01'), moment('2022-04-01')));
}
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
moment = require('moment')
Insert cell

Purpose-built for displays of data

Observable is your go-to platform for exploring data and creating expressive data visualizations. Use reactive JavaScript notebooks for prototyping and a collaborative canvas for visual data exploration and dashboard creation.
Learn more