/** * Copyright (C) 2010-14 diirt developers. See COPYRIGHT.TXT * All rights reserved. Use is subject to license terms. See LICENSE.TXT */ package org.diirt.datasource.formula.array; import static org.diirt.vtype.ValueFactory.*; import java.util.Arrays; import java.util.List; import org.diirt.datasource.formula.StatefulFormulaFunction; import org.diirt.util.array.ArrayInt; import org.diirt.util.array.IteratorNumber; import org.diirt.util.array.ListNumber; import org.diirt.util.array.ListNumbers; import org.diirt.util.stats.Range; import org.diirt.util.stats.Ranges; import org.diirt.util.stats.Statistics; import org.diirt.util.stats.StatisticsUtil; import org.diirt.util.text.NumberFormats; import org.diirt.vtype.VNumber; import org.diirt.vtype.VNumberArray; /** * @author shroffk * */ public class HistogramOfFormulaFunction extends StatefulFormulaFunction { @Override public boolean isVarArgs() { return false; } @Override public String getName() { return "histogramOf"; } @Override public String getDescription() { return "Returns a histograms of the elements in the array."; } @Override public List<Class<?>> getArgumentTypes() { return Arrays.<Class<?>> asList(VNumberArray.class); } @Override public List<String> getArgumentNames() { return Arrays.asList("Array", "index"); } @Override public Class<?> getReturnType() { return VNumber.class; } private VNumberArray previousValue; private VNumberArray previousResult; private double previousMaxCount; private Range previousXRange; @Override public Object calculate(List<Object> args) { VNumberArray numberArray = (VNumberArray) args.get(0); if (numberArray == null) { return null; } // If no change, return previous if (previousValue == numberArray) { return previousResult; } Statistics stats = StatisticsUtil.statisticsOf(numberArray.getData()); int nBins = 100; Range aggregatedRange = Ranges.aggregateRange(stats.getRange(), previousXRange); Range xRange; if (Ranges.overlap(aggregatedRange, stats.getRange()) >= 0.75) { xRange = aggregatedRange; } else { xRange = stats.getRange(); } IteratorNumber newValues = numberArray.getData().iterator(); double minValueRange = xRange.getMinimum(); double maxValueRange = xRange.getMaximum(); ListNumber xBoundaries = ListNumbers.linearListFromRange(minValueRange, maxValueRange, nBins + 1); String unit = numberArray.getUnits(); int[] binData = new int[nBins]; double maxCount = 0; while (newValues.hasNext()) { double value = newValues.nextDouble(); // Check value in range if (xRange.contains(value)) { int bin = (int) Math.floor(xRange.normalize( value) * nBins); if (bin == nBins) { bin--; } binData[bin]++; if (binData[bin] > maxCount) { maxCount = binData[bin]; } } } if (previousMaxCount > maxCount && previousMaxCount < maxCount * 2.0) { maxCount = previousMaxCount; } previousMaxCount = maxCount; previousXRange = xRange; previousValue = numberArray; previousResult = newVNumberArray(new ArrayInt(binData), new ArrayInt(nBins), Arrays.asList(newDisplay(xBoundaries, unit)), numberArray, numberArray, newDisplay(0.0, 0.0, 0.0, "count", NumberFormats.format(0), maxCount, maxCount, maxCount, Double.NaN, Double.NaN)); return previousResult; } }