Smoothing in Neptune charts
How smoothing and downsampling works in Neptune charts
Neptune applies two smoothing functions to data displayed in charts:
  • Neptune servers: Downsampling algorithm when fetching data
  • Neptune UI: Smoothing function controlled by the user

Neptune servers downsampling

If there are more than 1024 data points in the fetched data, the Neptune servers automatically downsample the values by taking the average of each consecutive value pair and forming a new value series out of the averages. The length of the new series is thus half of the original series.
This downsampling continues as long as the resulting series contains more than 1024 values.
The function also returns a margin of error or uncertainty, which is displayed as a shaded area in the chart:
Visualized error margin in downsampled values
If you zoom in on a specific region with less than 1024 data points, the chart updates to show the actual logged values.

Neptune UI smoothing

This function is manually controlled with the smoothing slider on the right of a chart. The values range from a minimum of 1 to a maximum of 100 and increase in increments of 9.
Manual smoothing in Neptune
When you move the smoothing slider, Neptune applies a low-pass filter to the y values in the chart. Additionally, the function takes as input the margin of error (the minimum and maximum y values) of the values returned by the downsampling algorithm.
The following example shows how the smoothing function works underneath the hood.
1
import math
2
3
4
def smooth(last, value):
5
# Weighted average if last value is known, else just return the value
6
return weight * last + (1 - weight) * value if math.isfinite(last) else value
7
8
9
def lowPassFilter(val):
10
if val == 0 or val[1] == 0:
11
return 0
12
13
low = smooth(0, val[0])
14
mid = smooth(0, val[1])
15
high = smooth(0, val[2])
16
17
return [low, mid, high]
18
19
20
def smoothData(data, smoothingValue):
21
22
if len(data) == 0:
23
return data
24
25
global weight
26
weight = 1 if smoothingValue > 100 else (smoothingValue - 1) / 100
27
28
colCount = len(data[0])
29
30
newData = dict()
31
for i in range(len(data)):
32
for k in range(1, colCount):
33
newData[data[i][0]] = lowPassFilter(data[i][k])
34
35
return newData
Copied!
The input shape is [x, [minY, Y, maxY]], where
  • x is the x value
  • Y is the y value
  • minY and maxY represent the margin of error after downsampling.
1
data = smoothData(
2
data=[
3
[0, [1, 1, 1]],
4
[1, [2, 2, 2]],
5
[2, [3, 3, 3]],
6
[3, [4, 4, 4]],
7
[4, [5, 5, 5]],
8
[5, [6, 6, 6]],
9
[6, [7, 7, 7]],
10
[7, [8, 8, 8]],
11
[8, [9, 9, 9]],
12
[9, [10, 10, 10]],
13
[10, [11, 11, 11]],
14
],
15
smoothingValue=100,
16
)
17
18
print(data)
Copied!