diff --git a/frontend/js/helpers/charts.js b/frontend/js/helpers/charts.js index bca3a3492..1a550ad74 100644 --- a/frontend/js/helpers/charts.js +++ b/frontend/js/helpers/charts.js @@ -1,3 +1,9 @@ +const calculateStatistics = (data) => { + const mean = data.reduce((sum, value) => sum + value.value, 0) / data.length; + const stddev = Math.sqrt(data.reduce((sum, value) => sum + Math.pow(value.value - mean, 2), 0) / data.length); + return { mean, stddev }; +} + const getCompareChartOptions = (legend, series, chart_type='line', x_axis='time', y_axis_name, mark_area=null, graphic=null) => { let tooltip_trigger = (chart_type=='line') ? 'axis' : 'item'; @@ -106,7 +112,7 @@ const calculateMA = (series, factor) => { return result; } -const getLineBarChartOptions = (legend, labels, series, x_axis_name=null, y_axis_name='', x_axis='time', mark_area=null, no_toolbox=false, graphic=null, moving_average=false, show_x_axis_label=true) => { +const getLineBarChartOptions = (legend, labels, series, x_axis_name=null, y_axis_name='', x_axis='time', mark_area=null, no_toolbox=false, graphic=null, moving_average=false, show_x_axis_label=true, stddev=false) => { if(Object.keys(series).length == 0) { return {graphic: getChartGraphic("No energy reporter active")}; @@ -128,6 +134,31 @@ const getLineBarChartOptions = (legend, labels, series, x_axis_name=null, y_axis }) } + if(stddev) { + const { mean, stddev } = calculateStatistics(series[0].data); + + legend.push('Stddev') + series.push({ + name: 'Stddev', + type: 'line', + markArea: { + label: { + show: true, + name: "MarkArea", + position: 'top' + }, + data: [ + [ + { yAxis: mean + stddev, name: `StdDev: ${(stddev/mean * 100).toFixed(2)} %`}, + { yAxis: mean - stddev}, + ] + + ], + } + }); + } + + let options = { tooltip: { trigger: tooltip_trigger }, grid: { diff --git a/frontend/js/timeline.js b/frontend/js/timeline.js index 045b670dd..69d5974fd 100644 --- a/frontend/js/timeline.js +++ b/frontend/js/timeline.js @@ -218,12 +218,12 @@ const loadCharts = async () => { } }] - let options = getLineBarChartOptions([], series[my_series].labels, data_series, 'Time', series[my_series].unit, 'category', null, false, null, true, false); + let options = getLineBarChartOptions([], series[my_series].labels, data_series, 'Time', series[my_series].unit, 'category', null, false, null, true, false, true); options.tooltip = { trigger: 'item', formatter: function (params, ticket, callback) { - if(params.componentType != 'series') return; // no notes for the MovingAverage + if(series[params.seriesName]?.notes == null) return; // no notes for the MovingAverage return `${series[params.seriesName].notes[params.dataIndex].run_name}
date: ${series[params.seriesName].notes[params.dataIndex].created_at}
metric_name: ${params.seriesName}
@@ -243,9 +243,31 @@ const loadCharts = async () => { }); + options.dataZoom = { + show: false, + start: 0, + end: 100, + }; + chart_instance.setOption(options); chart_instances.push(chart_instance); + chart_instance.on('datazoom', function(e, f) { + const data = chart_instance.getOption().series[0].data + const dataZoomOption = chart_instance.getOption().dataZoom[0]; + const startPercent = dataZoomOption.start; + const endPercent = dataZoomOption.end; + const totalDataPoints = data.length; + const startIndex = Math.floor(startPercent / 100 * totalDataPoints); + const endIndex = Math.ceil(endPercent / 100 * totalDataPoints) - 1; + const { mean, stddev } = calculateStatistics(data.slice(startIndex, endIndex+1)); + + let options = chart_instance.getOption() + options.series[2].markArea.data[0][0].name = `StdDev: ${(stddev/mean * 100).toFixed(2)} %` + options.series[2].markArea.data[0][0].yAxis = mean + stddev + options.series[2].markArea.data[0][1].yAxis = mean - stddev; + chart_instance.setOption(options) + }); }