fun createLegends()

in plot-builder/src/commonMain/kotlin/org/jetbrains/letsPlot/core/plot/builder/assemble/PlotAssemblerUtil.kt [21:157]


    fun createLegends(
        ctx: PlotContext,
        geomTiles: PlotGeomTiles,
        scaleMappersNP: Map<Aes<*>, ScaleMapper<*>>,
        guideOptionsMap: Map<GuideKey, GuideOptionsList>,
        legendTheme: LegendTheme,
        panelTheme: PanelTheme
    ): List<LegendBoxInfo> {

        val legendAssemblerByTitle = LinkedHashMap<String, LegendAssembler>()
        val colorBarAssemblerByTitle = LinkedHashMap<String, ColorBarAssembler>()

        for ((layerIndex, layerInfo) in geomTiles.layerInfos().withIndex()) {
            val layerConstantByAes = HashMap<Aes<*>, Any>()
            for (aes in layerInfo.renderedAes()) {
                if (layerInfo.hasConstant(aes)) {
                    layerConstantByAes[aes] = layerInfo.getConstant(aes)!!
                }
            }

            val aesListByScaleName = LinkedHashMap<String, MutableList<Aes<*>>>()
            val aesList = mappedRenderedAesToCreateGuides(layerInfo, guideOptionsMap)
            for (aes in aesList) {
                val scale = ctx.getScale(aes)

                val colorBarOptions: ColorBarOptions? = guideOptionsMap[GuideKey.fromAes(aes)]
                    ?.getColorBarOptions()
                    ?.also { checkFitsColorBar(aes, scale) }

                if (colorBarOptions != null || fitsColorBar(aes, scale)) {
                    // Colorbar
                    @Suppress("UNCHECKED_CAST")
                    val colorBarAssembler = createColorBarAssembler(
                        scale.name,
                        ctx.overallTransformedDomain(aes),
                        scale,
                        scaleMappersNP.getValue(aes) as ScaleMapper<Color>,
                        colorBarOptions,
                        legendTheme
                    )

                    val colorbarName = colorBarAssemblerByTitle[scale.name]?.let { existingAssembler ->
                        if (colorBarAssembler.equalScalesAndOptions(existingAssembler)) {
                            scale.name
                        } else {
                            // Don't just replace an existing colorbar (see LP-760: ggmarginal(): broken coloring)
                            // Add under another key
                            "${scale.name} (${aes.name})"
                        }
                    } ?: scale.name

                    colorBarAssemblerByTitle[colorbarName] = colorBarAssembler.withTitle(colorbarName)

                } else {
                    // Legend
                    aesListByScaleName.getOrPut(scale.name) { ArrayList() }.add(aes)
                }
            }

            for ((scaleName, aesListForScaleName) in aesListByScaleName) {
                val legendAssembler = legendAssemblerByTitle.getOrPut(scaleName) {
                    LegendAssembler(
                        scaleName,
                        guideOptionsMap,
                        scaleMappersNP,
                        legendTheme,
                        panelTheme
                    )
                }

                val guideKeysForScaleName = aesListForScaleName.map(GuideKey.Companion::fromAes)
                val allOverrideAesValues = guideOptionsMap
                    .filterKeys { it in guideKeysForScaleName }
                    .values
                    .mapNotNull { it.getLegendOptions()?.overrideAesValues }
                    .flatMap { it.entries }
                    .associate { it.key to it.value }

                legendAssembler.addLayer(
                    keyFactory = layerInfo.legendKeyElementFactory,
                    aesList = aesListForScaleName,
                    overrideAesValues = allOverrideAesValues,
                    constantByAes = layerConstantByAes,
                    aestheticsDefaults = layerInfo.aestheticsDefaults,
                    colorByAes = layerInfo.colorByAes,
                    fillByAes = layerInfo.fillByAes,
                    isMarginal = layerInfo.isMarginal,
                    ctx = ctx
                )
            }

            // custom legend
            layerInfo.customLegendOptions?.let { legendOptions ->
                val guideKey = GuideKey.fromName(legendOptions.group)
                if (guideOptionsMap[guideKey]?.hasNone() == true) return@let

                val legendTitle = guideOptionsMap[guideKey]?.getTitle() ?: legendOptions.group

                val customLegendAssembler = legendAssemblerByTitle.getOrPut(legendTitle) {
                    LegendAssembler(
                        legendTitle,
                        guideOptionsMap,
                        scaleMappersNP,
                        legendTheme,
                        panelTheme
                    )
                }
                val allOverrideAesValues = processOverrideAesValues(
                    guideOptionsMap[guideKey]?.getLegendOptions()?.overrideAesValues,
                    legendOptions.index ?: layerIndex
                )

                customLegendAssembler.addCustomLayer(
                    customLegendOptions = legendOptions,
                    keyFactory = layerInfo.legendKeyElementFactory,
                    overrideAesValues = allOverrideAesValues,
                    constantByAes = layerConstantByAes,
                    aestheticsDefaults = layerInfo.aestheticsDefaults,
                    colorByAes = layerInfo.colorByAes,
                    fillByAes = layerInfo.fillByAes,
                    isMarginal = layerInfo.isMarginal
                )
            }
        }

        val legendBoxInfos = ArrayList<LegendBoxInfo>()
        for (legendTitle in colorBarAssemblerByTitle.keys) {
            val boxInfo = colorBarAssemblerByTitle.getValue(legendTitle).createColorBar()
            boxInfo?.let { legendBoxInfos.add(it) }
        }

        for (legendTitle in legendAssemblerByTitle.keys) {
            val boxInfo = legendAssemblerByTitle.getValue(legendTitle).createLegend()
            boxInfo?.let { legendBoxInfos.add(it) }
        }
        return legendBoxInfos
    }