bin.js 3.3 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182
  1. var __rest = (this && this.__rest) || function (s, e) {
  2. var t = {};
  3. for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
  4. t[p] = s[p];
  5. if (s != null && typeof Object.getOwnPropertySymbols === "function")
  6. for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
  7. if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
  8. t[p[i]] = s[p[i]];
  9. }
  10. return t;
  11. };
  12. import { bin as d3Bin, group, thresholdScott, extent } from 'd3-array';
  13. import { defined, subObject } from '../utils/helper';
  14. import { GroupN } from './groupN';
  15. import { columnOf } from './utils/helper';
  16. const THRESHOLD = 'thresholds';
  17. /**
  18. * @see https://github.com/observablehq/plot/blob/main/src/transforms/bin.js
  19. */
  20. function thresholdAuto(values) {
  21. const [min, max] = extent(values);
  22. return Math.min(200, thresholdScott(values, min, max));
  23. }
  24. /**
  25. * The Bin aggregate data.
  26. * @todo More threshold method.
  27. * @todo Performance.
  28. */
  29. export const Bin = (options = {}) => {
  30. const { groupChannels = ['color'], binChannels = ['x', 'y'] } = options, rest = __rest(options, ["groupChannels", "binChannels"]);
  31. const channelIndexKey = {};
  32. // Group indexes and update channelIndexKey.
  33. const groupBy = (I, mark) => {
  34. const { encode } = mark;
  35. const binValues = binChannels.map((channel) => {
  36. const [V] = columnOf(encode, channel);
  37. return V;
  38. });
  39. const thresholds = subObject(rest, THRESHOLD);
  40. const DI = I.filter((i) => binValues.every((V) => defined(V[i])));
  41. // Group indexes by both discrete and quantitative channels.
  42. const groupKeys = [
  43. // For discrete channels, use value as group key.
  44. ...groupChannels
  45. .map((d) => {
  46. const [V] = columnOf(encode, d);
  47. return V;
  48. })
  49. .filter(defined)
  50. .map((V) => (i) => V[i]),
  51. // For quantitative channels, use extent of bin as group key.
  52. ...binChannels.map((d, i) => {
  53. const V = binValues[i];
  54. const t = thresholds[d] || thresholdAuto(V);
  55. const bins = d3Bin()
  56. .thresholds(t)
  57. .value((i) => +V[i])(DI);
  58. const indexKey = new Map(bins.flatMap((bin) => {
  59. const { x0, x1 } = bin;
  60. const key = `${x0},${x1}`;
  61. return bin.map((i) => [i, key]);
  62. }));
  63. channelIndexKey[d] = indexKey;
  64. return (i) => indexKey.get(i);
  65. }),
  66. ];
  67. // Group by indexes by channel keys.
  68. const key = (i) => groupKeys.map((key) => key(i)).join('-');
  69. return Array.from(group(DI, key).values());
  70. };
  71. return GroupN(Object.assign(Object.assign(Object.assign({}, Object.fromEntries(Object.entries(rest).filter(([k]) => !k.startsWith(THRESHOLD)))), Object.fromEntries(binChannels.flatMap((channel) => {
  72. const start = ([i]) => +channelIndexKey[channel].get(i).split(',')[0];
  73. const end = ([i]) => +channelIndexKey[channel].get(i).split(',')[1];
  74. end.from = channel;
  75. return [
  76. [channel, start],
  77. [`${channel}1`, end],
  78. ];
  79. }))), { groupBy }));
  80. };
  81. Bin.props = {};
  82. //# sourceMappingURL=bin.js.map