Skip to content

Commit

Permalink
feat(sample): add demo to compare samples
Browse files Browse the repository at this point in the history
  • Loading branch information
SnailSword committed Sep 22, 2020
1 parent 7dcce2c commit e916453
Show file tree
Hide file tree
Showing 4 changed files with 198 additions and 25 deletions.
38 changes: 14 additions & 24 deletions src/data/List.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1694,15 +1694,15 @@ class List<

/**
* Large data down sampling using largest-triangle-three-buckets
* copied from https://github.com/pingec/downsample-lttb with some modifications
* https://github.com/pingec/downsample-lttb
* @param {string} baseDimension
* @param {string} valueDimension
* @param {number} threshold target counts
*/
lttbDownSample(
baseDimension: DimensionName,
valueDimension: DimensionName,
threshold: number
baseDimension: DimensionName,
valueDimension: DimensionName,
threshold: number
) {
const list = cloneListForMapAndSample(this, [baseDimension, valueDimension]);
const targetStorage = list._storage;
Expand All @@ -1721,38 +1721,31 @@ class List<
valueDimStore[originalChunkIndex][originalChunkOffset]
];
};
if (threshold >= len || threshold === 0) {
return list; // Nothing to do
}

// let sampled = [],
let sampledIndex = 0;

// Bucket size. Leave room for start and end data points
const every = (len - 2) / (threshold - 2);

let a = 0; // Initially a is the first point in the triangle
// maxAreaPoint,
let maxArea;
let area;
let nextA;
let a = 0;
let maxArea;
let area;
let nextA;

newIndices[sampledIndex++] = a;
// sampled[ sampledIndex++ ] = getPair(0); // Always add the first point
for (let i = 0; i < threshold - 2; i++) {

// Calculate point average for next bucket (containing c)
let avgX = 0;
let avgY = 0;
let avgRangeStart = mathFloor((i + 1) * every) + 1;
let avgRangeEnd = mathFloor((i + 2) * every) + 1;
let avgY = 0;
let avgRangeStart = mathFloor((i + 1) * every) + 1;
let avgRangeEnd = mathFloor((i + 2) * every) + 1;

avgRangeEnd = avgRangeEnd < len ? avgRangeEnd : len;

const avgRangeLength = avgRangeEnd - avgRangeStart;

for (; avgRangeStart < avgRangeEnd; avgRangeStart++) {
avgX += getPair(avgRangeStart)[0] * 1; // * 1 enforces Number (value may be Date)
avgY += getPair(avgRangeStart)[1] * 1;
avgX += getPair(avgRangeStart)[0] * 1; // * 1 enforces Number (value may be Date)
avgY += getPair(avgRangeStart)[1] * 1;
}
avgX /= avgRangeLength;
avgY /= avgRangeLength;
Expand All @@ -1774,19 +1767,16 @@ class List<
) * 0.5;
if (area > maxArea) {
maxArea = area;
// maxAreaPoint = getPair(rangeOffs);
nextA = rangeOffs; // Next a is this b
}
}

newIndices[sampledIndex++] = nextA;
// sampled[ sampledIndex++ ] = maxAreaPoint; // Pick this point from the bucket

a = nextA; // This a is the next a (chosen b)
}

newIndices[sampledIndex++] = len - 1;
// sampled[ sampledIndex++ ] = getPair(len - 1); // Always add last
list._count = sampledIndex;
list._indices = newIndices;

Expand Down
2 changes: 1 addition & 1 deletion src/processor/dataSample.ts
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ export default function (seriesType: string): StageHandler {
const valueAxis = coordSys.getOtherAxis(baseAxis);
const extent = baseAxis.getExtent();
// Coordinste system has been resized
const size = extent[1] - extent[0];
const size = Math.abs(extent[1] - extent[0]);
const rate = Math.round(data.count() / size);

if (rate > 1) {
Expand Down
1 change: 1 addition & 0 deletions test/data/large-data.json

Large diffs are not rendered by default.

182 changes: 182 additions & 0 deletions test/sample-compare.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,182 @@

<!--
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
-->
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>ECharts Demo</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
<h2 id="wait">Loading lib....</h2>

<div id="container" style="height: 600px; width: 100%;"></div>

<script src="lib/esl.js"></script>
<script src="lib/config.js"></script>
<script>
require([
'echarts'
// 'echarts/chart/sankey',
// 'echarts/component/tooltip'
], function (echarts) {
function round2(val) {
return Math.round(val * 100) / 100;
}

function round3(val) {
return Math.round(val * 1000) / 1000;
}

function prepData(packed) {
// console.time('prep');

// epoch,idl,recv,send,read,writ,used,free

const numFields = packed[0];
packed = packed.slice(numFields + 1);

var cpu = Array(packed.length/numFields);

for (let i = 0, j = 0; i < packed.length; i += numFields, j++) {
let date = packed[i] * 60 * 1000;
cpu[j] = [date, round3(100 - packed[i+1])];
}

// console.timeEnd('prep');

return [cpu];
}

function makeChart(data) {
console.time('chart');

var dom = document.getElementById("container");
var myChart = echarts.init(dom);

let opts = {
grid: {
left: 40,
top: 0,
right: 0,
bottom: 30,
},
xAxis: {
type: 'time',
splitLine: {
show: false
},
data: data[0],
},
yAxis: {
type: 'value'
},
legend: {
},
series: [
{
name: 'none',
type: 'line',
showSymbol: false,
hoverAnimation: false,
data: data[0],
lineStyle: {
normal: {
opacity: 0.5,
width: 1
}
}
},
{
name: 'lttb',
type: 'line',
showSymbol: false,
hoverAnimation: false,
data: data[0],
sampling: 'lttb',
lineStyle: {
normal: {
opacity: 0.5,
width: 1
}
}
},
{
name: 'average',
type: 'line',
showSymbol: false,
hoverAnimation: false,
data: data[0],
sampling: 'average',
lineStyle: {
normal: {
opacity: 0.5,
width: 1
}
}
},
{
name: 'max',
type: 'line',
showSymbol: false,
hoverAnimation: false,
data: data[0],
sampling: 'max',
lineStyle: {
normal: {
opacity: 0.5,
width: 1
}
}
},
{
name: 'min',
type: 'line',
showSymbol: false,
hoverAnimation: false,
data: data[0],
sampling: 'min',
lineStyle: {
normal: {
opacity: 0.5,
width: 1
}
}
},
]
};

myChart.setOption(opts, true);

wait.textContent = "Done!";
console.timeEnd('chart');
}

let wait = document.getElementById("wait");
wait.textContent = "Fetching data.json (2.07MB)....";
fetch("./data/large-data.json").then(r => r.json()).then(packed => {
wait.textContent = "Rendering...";
let data = prepData(packed);
setTimeout(() => makeChart(data), 0);
});
});
</script>
</body>
</html>

0 comments on commit e916453

Please sign in to comment.