commonMain.jetbrains.datalore.plot.MonolithicCommon.kt Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of lets-plot-common Show documentation
Show all versions of lets-plot-common Show documentation
Lets-Plot JVM package without rendering part
/*
* Copyright (c) 2020. JetBrains s.r.o.
* Use of this source code is governed by the MIT license that can be found in the LICENSE file.
*/
package jetbrains.datalore.plot
import jetbrains.datalore.base.geometry.DoubleRectangle
import jetbrains.datalore.base.geometry.DoubleVector
import jetbrains.datalore.plot.builder.PlotContainerPortable
import jetbrains.datalore.plot.builder.assemble.PlotAssembler
import jetbrains.datalore.plot.config.BunchConfig
import jetbrains.datalore.plot.config.PlotConfig
import jetbrains.datalore.plot.config.PlotConfigClientSide
import jetbrains.datalore.plot.config.PlotConfigClientSideUtil
import jetbrains.datalore.plot.server.config.PlotConfigServerSide
import jetbrains.datalore.vis.svgToString.SvgToString
object MonolithicCommon {
/**
* Static SVG export
*/
fun buildSvgImagesFromRawSpecs(
plotSpec: MutableMap,
plotSize: DoubleVector?,
svgToString: SvgToString,
computationMessagesHandler: ((List) -> Unit)
): List {
@Suppress("NAME_SHADOWING")
val plotSpec = processRawSpecs(plotSpec, frontendOnly = false)
val buildResult = buildPlotsFromProcessedSpecs(plotSpec, plotSize, plotMaxWidth = null)
if (buildResult.isError) {
val errorMessage = (buildResult as PlotsBuildResult.Error).error
throw RuntimeException(errorMessage)
}
val success = buildResult as PlotsBuildResult.Success
val computationMessages = success.buildInfos.flatMap { it.computationMessages }
if (computationMessages.isNotEmpty()) {
computationMessagesHandler(computationMessages)
}
return success.buildInfos.map {
val assembler = it.plotAssembler
val plot = assembler.createPlot()
val plotContainer = PlotContainerPortable(plot, it.size)
plotContainer.ensureContentBuilt()
plotContainer.svg
}.map { svgToString.render(it) }
}
fun buildPlotsFromProcessedSpecs(
plotSpec: MutableMap,
plotSize: DoubleVector?,
plotMaxWidth: Double?
): PlotsBuildResult {
throwTestingErrors() // noop
PlotConfig.assertPlotSpecOrErrorMessage(plotSpec)
if (PlotConfig.isFailure(plotSpec)) {
val errorMessage = PlotConfig.getErrorMessage(plotSpec)
return PlotsBuildResult.Error(errorMessage)
}
return when {
PlotConfig.isPlotSpec(plotSpec) -> {
PlotsBuildResult.Success(
listOf(
buildSinglePlotFromProcessedSpecs(
plotSpec,
plotSize,
plotMaxWidth
)
)
)
}
PlotConfig.isGGBunchSpec(plotSpec) -> buildGGBunchFromProcessedSpecs(plotSpec)
else -> throw RuntimeException("Unexpected plot spec kind: " + PlotConfig.specKind(plotSpec))
}
}
private fun buildGGBunchFromProcessedSpecs(
bunchSpec: MutableMap
): PlotsBuildResult {
val bunchConfig = BunchConfig(bunchSpec)
if (bunchConfig.bunchItems.isEmpty()) return PlotsBuildResult.Error(
"No plots in the bunch"
)
val buildInfos = ArrayList()
for (bunchItem in bunchConfig.bunchItems) {
val plotSpec = bunchItem.featureSpec as MutableMap
var buildInfo =
buildSinglePlotFromProcessedSpecs(
plotSpec,
PlotSizeHelper.bunchItemSize(bunchItem),
plotMaxWidth = null
)
buildInfo = PlotBuildInfo(
buildInfo.plotAssembler,
buildInfo.processedPlotSpec,
DoubleVector(bunchItem.x, bunchItem.y), // true origin
buildInfo.size,
buildInfo.computationMessages
)
buildInfos.add(buildInfo)
}
return PlotsBuildResult.Success(buildInfos)
}
private fun buildSinglePlotFromProcessedSpecs(
plotSpec: MutableMap,
plotSize: DoubleVector?,
plotMaxWidth: Double?
): PlotBuildInfo {
val computationMessages = ArrayList()
val config = PlotConfigClientSide.create(plotSpec) {
computationMessages.addAll(it)
}
val preferredSize = PlotSizeHelper.singlePlotSize(
plotSpec,
plotSize,
plotMaxWidth,
config.facets,
config.containsLiveMap
)
val assembler = createPlotAssembler(config)
return PlotBuildInfo(
assembler,
plotSpec,
DoubleVector.ZERO,
preferredSize,
computationMessages
)
}
private fun createPlotAssembler(
config: PlotConfigClientSide
): PlotAssembler {
return PlotConfigClientSideUtil.createPlotAssembler(config)
}
private fun throwTestingErrors() {
// testing errors
// throw RuntimeException()
// throw RuntimeException("My sudden crush")
// throw IllegalArgumentException("User configuration error")
// throw IllegalStateException("User configuration error")
// throw IllegalStateException() // Huh?
}
/**
* Applies all transformations to plot specifications.
* @param plotSpec: raw specifications of a single plot or GGBunch
*/
@Suppress("DuplicatedCode")
fun processRawSpecs(plotSpec: MutableMap, frontendOnly: Boolean): MutableMap {
PlotConfig.assertPlotSpecOrErrorMessage(plotSpec)
if (PlotConfig.isFailure(plotSpec)) {
return plotSpec
}
// Only "portable" transforms (not supported: raster image, any async transforms)
// Backend transforms
@Suppress("NAME_SHADOWING")
val plotSpec =
if (frontendOnly) {
plotSpec
} else {
PlotConfigServerSide.processTransform(plotSpec)
}
if (PlotConfig.isFailure(plotSpec)) {
return plotSpec
}
// Frontend transforms
return PlotConfigClientSide.processTransform(plotSpec)
}
sealed class PlotsBuildResult {
val isError: Boolean = this is Error
class Error(val error: String) : PlotsBuildResult()
class Success(
val buildInfos: List
) : PlotsBuildResult()
}
class PlotBuildInfo constructor(
val plotAssembler: PlotAssembler,
val processedPlotSpec: MutableMap,
val origin: DoubleVector,
val size: DoubleVector,
val computationMessages: List
) {
fun bounds(): DoubleRectangle {
return DoubleRectangle(origin, size)
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy