prepareBoxplotData.js 3.0 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091
  1. /*
  2. * Licensed to the Apache Software Foundation (ASF) under one
  3. * or more contributor license agreements. See the NOTICE file
  4. * distributed with this work for additional information
  5. * regarding copyright ownership. The ASF licenses this file
  6. * to you under the Apache License, Version 2.0 (the
  7. * "License"); you may not use this file except in compliance
  8. * with the License. You may obtain a copy of the License at
  9. *
  10. * http://www.apache.org/licenses/LICENSE-2.0
  11. *
  12. * Unless required by applicable law or agreed to in writing,
  13. * software distributed under the License is distributed on an
  14. * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  15. * KIND, either express or implied. See the License for the
  16. * specific language governing permissions and limitations
  17. * under the License.
  18. */
  19. import * as numberUtil from '../../src/util/number';
  20. /**
  21. * See:
  22. * <https://en.wikipedia.org/wiki/Box_plot#cite_note-frigge_hoaglin_iglewicz-2>
  23. * <http://stat.ethz.ch/R-manual/R-devel/library/grDevices/html/boxplot.stats.html>
  24. *
  25. * Helper method for preparing data.
  26. *
  27. * @param {Array.<number>} rawData like
  28. * [
  29. * [12,232,443], (raw data set for the first box)
  30. * [3843,5545,1232], (raw datat set for the second box)
  31. * ...
  32. * ]
  33. * @param {Object} [opt]
  34. *
  35. * @param {(number|string)} [opt.boundIQR=1.5] Data less than min bound is outlier.
  36. * default 1.5, means Q1 - 1.5 * (Q3 - Q1).
  37. * If 'none'/0 passed, min bound will not be used.
  38. * @param {(number|string)} [opt.layout='horizontal']
  39. * Box plot layout, can be 'horizontal' or 'vertical'
  40. * @return {Object} {
  41. * boxData: Array.<Array.<number>>
  42. * outliers: Array.<Array.<number>>
  43. * axisData: Array.<string>
  44. * }
  45. */
  46. export default function (rawData, opt) {
  47. opt = opt || [];
  48. var boxData = [];
  49. var outliers = [];
  50. var axisData = [];
  51. var boundIQR = opt.boundIQR;
  52. var useExtreme = boundIQR === 'none' || boundIQR === 0;
  53. for (var i = 0; i < rawData.length; i++) {
  54. axisData.push(i + '');
  55. var ascList = numberUtil.asc(rawData[i].slice());
  56. var Q1 = numberUtil.quantile(ascList, 0.25);
  57. var Q2 = numberUtil.quantile(ascList, 0.5);
  58. var Q3 = numberUtil.quantile(ascList, 0.75);
  59. var min = ascList[0];
  60. var max = ascList[ascList.length - 1];
  61. var bound = (boundIQR == null ? 1.5 : boundIQR) * (Q3 - Q1);
  62. var low = useExtreme
  63. ? min
  64. : Math.max(min, Q1 - bound);
  65. var high = useExtreme
  66. ? max
  67. : Math.min(max, Q3 + bound);
  68. boxData.push([low, Q1, Q2, Q3, high]);
  69. for (var j = 0; j < ascList.length; j++) {
  70. var dataItem = ascList[j];
  71. if (dataItem < low || dataItem > high) {
  72. var outlier = [i, dataItem];
  73. opt.layout === 'vertical' && outlier.reverse();
  74. outliers.push(outlier);
  75. }
  76. }
  77. }
  78. return {
  79. boxData: boxData,
  80. outliers: outliers,
  81. axisData: axisData
  82. };
  83. }