Align multiple series to the same interval with interpolation, fix #1211
This commit is contained in:
@@ -1,10 +1,11 @@
|
|||||||
package datasource
|
package datasource
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/alexanderzobnin/grafana-zabbix/pkg/timeseries"
|
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/alexanderzobnin/grafana-zabbix/pkg/timeseries"
|
||||||
|
|
||||||
"github.com/alexanderzobnin/grafana-zabbix/pkg/zabbix"
|
"github.com/alexanderzobnin/grafana-zabbix/pkg/zabbix"
|
||||||
"github.com/grafana/grafana-plugin-sdk-go/backend"
|
"github.com/grafana/grafana-plugin-sdk-go/backend"
|
||||||
"github.com/grafana/grafana-plugin-sdk-go/data"
|
"github.com/grafana/grafana-plugin-sdk-go/data"
|
||||||
@@ -123,6 +124,10 @@ func (ds *ZabbixDatasourceInstance) applyDataProcessing(ctx context.Context, que
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if len(series) > 1 {
|
||||||
|
series = timeseries.AlignSeriesIntervals(series)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
series, err := applyFunctions(series, query.Functions)
|
series, err := applyFunctions(series, query.Functions)
|
||||||
|
|||||||
@@ -80,3 +80,64 @@ func (ts TimeSeries) DetectInterval() time.Duration {
|
|||||||
midIndex := int(math.Floor(float64(len(deltas)) * 0.5))
|
midIndex := int(math.Floor(float64(len(deltas)) * 0.5))
|
||||||
return time.Duration(deltas[midIndex]) * time.Millisecond
|
return time.Duration(deltas[midIndex]) * time.Millisecond
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// AlignSeriesIntervals aligns series to the same time interval
|
||||||
|
func AlignSeriesIntervals(series []*TimeSeriesData) []*TimeSeriesData {
|
||||||
|
if len(series) == 0 {
|
||||||
|
return series
|
||||||
|
}
|
||||||
|
|
||||||
|
minInterval := *series[0].Meta.Interval
|
||||||
|
for _, s := range series {
|
||||||
|
if *s.Meta.Interval < minInterval {
|
||||||
|
minInterval = *s.Meta.Interval
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 0 interval means series is not aligned, so it's tricky to align multiple series
|
||||||
|
if minInterval == 0 {
|
||||||
|
return series
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, s := range series {
|
||||||
|
if s.Len() < 2 || *s.Meta.Interval == minInterval {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
s.TS = s.TS.Interpolate(minInterval)
|
||||||
|
}
|
||||||
|
|
||||||
|
return series
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ts TimeSeries) Interpolate(interval time.Duration) TimeSeries {
|
||||||
|
if interval <= 0 || ts.Len() < 2 {
|
||||||
|
return ts
|
||||||
|
}
|
||||||
|
|
||||||
|
alignedTs := NewTimeSeries()
|
||||||
|
var frameTs = ts[0].Time
|
||||||
|
var pointFrameTs time.Time
|
||||||
|
var point TimePoint
|
||||||
|
var nextPoint TimePoint
|
||||||
|
|
||||||
|
for i := 0; i < ts.Len()-1; i++ {
|
||||||
|
point = ts[i]
|
||||||
|
nextPoint = ts[i+1]
|
||||||
|
pointFrameTs = point.Time
|
||||||
|
|
||||||
|
if point.Value != nil && nextPoint.Value != nil {
|
||||||
|
frameTs = pointFrameTs.Add(interval)
|
||||||
|
for frameTs.Before(nextPoint.Time) {
|
||||||
|
pointValue := linearInterpolation(frameTs, point, nextPoint)
|
||||||
|
alignedTs = append(alignedTs, TimePoint{Time: frameTs, Value: &pointValue})
|
||||||
|
frameTs = frameTs.Add(interval)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
alignedTs = append(alignedTs, TimePoint{Time: pointFrameTs, Value: point.Value})
|
||||||
|
frameTs = frameTs.Add(interval)
|
||||||
|
}
|
||||||
|
|
||||||
|
return alignedTs
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user