override fun apply()

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()
    }