in plot-base/src/commonMain/kotlin/org/jetbrains/letsPlot/core/plot/base/stat/BinStat.kt [44:111]
override fun apply(data: DataFrame, statCtx: StatContext, messageConsumer: (s: String) -> Unit): DataFrame {
if (!hasRequiredValues(data, Aes.X)) {
return withEmptyStatValues()
}
val statX = ArrayList<Double>()
val statCount = ArrayList<Double>()
val statDensity = ArrayList<Double>()
val statSumProp = ArrayList<Double>()
val statSumPct = ArrayList<Double>()
val rangeX = statCtx.overallXRange()
val filteredBreaks = breaks.filter(Double::isFinite).distinct().sorted()
when {
filteredBreaks.isNotEmpty() -> {
BinStatUtil.computeHistogramBins(
data.getNumeric(TransformVar.X),
filteredBreaks,
BinStatUtil.weightAtIndex(data)
)
}
rangeX != null -> BinStatUtil.computeHistogramStatSeries(
data,
rangeX,
data.getNumeric(TransformVar.X),
xPosKind,
xPos,
binOptions
)
else -> null // null means all input values are null
}?.let { binsData ->
statX.addAll(binsData.x)
statCount.addAll(binsData.count)
statDensity.addAll(binsData.density)
statSumProp.addAll(binsData.sumProp)
statSumPct.addAll(binsData.sumPct)
}
if (threshold != null) {
val leftDropPart = statCount.withIndex().takeWhile { it.value <= threshold }.map { it.index }
val rightDropPart = statCount.withIndex().reversed().takeWhile { it.value <= threshold }.map { it.index }
val dropList = leftDropPart + rightDropPart
dropList.forEach {
statCount[it] = Double.NaN
statDensity[it] = Double.NaN
statSumProp[it] = Double.NaN
statSumPct[it] = Double.NaN
}
// resolution hack - need at least two consecutive X values, or width of the bin will be incorrect
when {
statX.size - dropList.size > 1 -> dropList // already have at least two consecutive X values
leftDropPart.isNotEmpty() -> leftDropPart.dropLast(1) + rightDropPart
rightDropPart.isNotEmpty() -> leftDropPart + rightDropPart.dropLast(1) // dropLast b/c reversed
else -> emptyList()
}.forEach { statX[it] = Double.NaN }
}
return DataFrame.Builder()
.putNumeric(Stats.X, statX)
.putNumeric(Stats.COUNT, statCount)
.putNumeric(Stats.DENSITY, statDensity)
.putNumeric(Stats.SUMPROP, statSumProp)
.putNumeric(Stats.SUMPCT, statSumPct)
.build()
}