sample.js 2.1 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364
  1. // @ts-ignore medianIndex exist in d3-array@3.2.0, but @types/d3-array Expired.
  2. import { maxIndex, minIndex, medianIndex } from 'd3-array';
  3. import { createGroups } from './utils/order';
  4. import { columnOf } from './utils/helper';
  5. import { lttb } from './utils/lttb';
  6. function normalizeSample(strategy) {
  7. if (typeof strategy === 'function')
  8. return strategy;
  9. if (strategy === 'lttb')
  10. return lttb;
  11. const strategies = {
  12. first: (f) => [f[0]],
  13. last: (f) => [f[f.length - 1]],
  14. min: (f, X, Y) => [
  15. f[minIndex(f, (i) => Y[i])],
  16. ],
  17. max: (f, X, Y) => [
  18. f[maxIndex(f, (i) => Y[i])],
  19. ],
  20. median: (f, X, Y) => [
  21. f[medianIndex(f, (i) => Y[i])],
  22. ],
  23. };
  24. const sampleFunction = strategies[strategy] || strategies.median;
  25. return (I, X, Y, thresholds) => {
  26. // Sepreate group to frames, then sample each frame.
  27. // Keep more data as possible.
  28. const frameSize = Math.max(1, Math.floor(I.length / thresholds));
  29. const frames = getFrames(I, frameSize);
  30. return frames.flatMap((frame) => sampleFunction(frame, X, Y));
  31. };
  32. }
  33. /**
  34. * Split the array into frame with each frameSize.
  35. */
  36. function getFrames(I, frameSize) {
  37. const size = I.length;
  38. const frames = [];
  39. let i = 0;
  40. while (i < size) {
  41. frames.push(I.slice(i, (i += frameSize)));
  42. }
  43. return frames;
  44. }
  45. /**
  46. * The sample transform groups marks with specified groupBy fields, and
  47. * sample data for each group when data.length >= threshold(default = 2000).
  48. */
  49. export const Sample = (options = {}) => {
  50. const { strategy = 'median', thresholds = 2000, groupBy = ['series', 'color'], } = options;
  51. const sampleFunction = normalizeSample(strategy);
  52. return (I, mark) => {
  53. const { encode } = mark;
  54. const groups = createGroups(groupBy, I, mark);
  55. const [X] = columnOf(encode, 'x');
  56. const [Y] = columnOf(encode, 'y');
  57. return [
  58. groups.flatMap((g) => sampleFunction(g, X, Y, thresholds)),
  59. mark,
  60. ];
  61. };
  62. };
  63. Sample.props = {};
  64. //# sourceMappingURL=sample.js.map