Skip to content

Commit fae804e

Browse files
Merge pull request #98 from Kotlin/jupyter_swing
new jupyter render
2 parents a97b11d + d96a06c commit fae804e

File tree

9 files changed

+205
-7
lines changed

9 files changed

+205
-7
lines changed

build.gradle.kts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,14 @@ allprojects {
4747
}
4848

4949

50-
val published = listOf("ggdsl-api", "ggdsl-dataframe", "ggdsl-dataframe-lets-plot", "ggdsl-echarts", "ggdsl-lets-plot")
50+
val published = listOf(
51+
"ggdsl-api",
52+
"ggdsl-dataframe",
53+
"ggdsl-dataframe-lets-plot",
54+
"ggdsl-echarts",
55+
"ggdsl-lets-plot",
56+
"ggdsl-util"
57+
)
5158

5259
configure(subprojects.filter { it.name in published }) {
5360
apply(from = project.rootProject.file("gradle/publish.gradle"))

ggdsl-echarts/src/test/kotlin/org/jetbrains/kotlinx/ggdsl/echarts/jupyter/MonoIntegrationTest.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,6 @@ class MonoIntegrationTest : JupyterReplTestCase() {
4242
val resourcePath = "testData/jupyter/${testName.methodName}.out"
4343
val resource = classLoader.getResource(resourcePath)
4444
assertNotNull(resource)
45-
assertEquals(resource.readText(), actualOutputText)
45+
assertEquals(resource.readText().replace("\r\n", "\n"), actualOutputText)
4646
}
4747
}

ggdsl-lets-plot/build.gradle.kts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ val html_version: String by project
1212
val datetime_version: String by project
1313
val lets_plot_kotlin_version: String by project
1414
val lets_plot_image_version: String by project
15+
val serialization_version: String by project
1516

1617
dependencies {
1718
implementation(kotlin("stdlib"))
@@ -20,7 +21,9 @@ dependencies {
2021
implementation("org.jetbrains.kotlinx:kotlinx-datetime-jvm:$datetime_version")
2122
implementation("org.jetbrains.lets-plot:lets-plot-kotlin-jvm:$lets_plot_kotlin_version")
2223
implementation("org.jetbrains.lets-plot:lets-plot-image-export:$lets_plot_image_version")
24+
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:$serialization_version")
2325
api(project(":ggdsl-api"))
26+
implementation(project(":ggdsl-util"))
2427
}
2528

2629
tasks {

ggdsl-lets-plot/src/main/kotlin/org/jetbrains/kotlinx/ggdsl/letsplot/Integration.kt

Lines changed: 31 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,16 +4,23 @@
44

55
package org.jetbrains.kotlinx.ggdsl.letsplot
66

7+
import kotlinx.serialization.json.JsonPrimitive
8+
import kotlinx.serialization.json.buildJsonObject
79
import org.jetbrains.kotlinx.ggdsl.ir.Plot
810
import org.jetbrains.kotlinx.ggdsl.letsplot.multiplot.model.PlotBunch
911
import org.jetbrains.kotlinx.ggdsl.letsplot.multiplot.model.PlotGrid
1012
import org.jetbrains.kotlinx.ggdsl.letsplot.translator.toLetsPlot
1113
import org.jetbrains.kotlinx.ggdsl.letsplot.translator.wrap
14+
import org.jetbrains.kotlinx.ggdsl.util.serialization.serializeSpec
1215
import org.jetbrains.kotlinx.jupyter.api.HTML
16+
import org.jetbrains.kotlinx.jupyter.api.MimeTypedResultEx
1317
import org.jetbrains.kotlinx.jupyter.api.annotations.JupyterLibrary
1418
import org.jetbrains.kotlinx.jupyter.api.libraries.JupyterIntegration
19+
import org.jetbrains.letsPlot.Figure
20+
import org.jetbrains.letsPlot.GGBunch
1521
import org.jetbrains.letsPlot.LetsPlot
1622
import org.jetbrains.letsPlot.frontend.NotebookFrontendContext
23+
import org.jetbrains.letsPlot.intern.toSpec
1724

1825
@JupyterLibrary
1926
internal class Integration : JupyterIntegration() {
@@ -51,11 +58,31 @@ internal class Integration : JupyterIntegration() {
5158
import("org.jetbrains.kotlinx.ggdsl.letsplot.util.font.*")
5259
// import("org.jetbrains.kotlinx.ggdsl.letsplot.util.statParameters.*")
5360

54-
render<Plot> { HTML(frontendContext.getHtml(it.toLetsPlot())) }
55-
render<PlotBunch> { HTML(frontendContext.getHtml(it.wrap())) }
56-
render<PlotGrid> { HTML(frontendContext.getHtml(it.wrap())) }
61+
render<Plot> { it.toLetsPlot().toMimeResult() }
62+
render<PlotBunch> { it.wrap().toMimeResult() }
63+
render<PlotGrid> { it.wrap().toMimeResult() }
5764
}
5865

59-
}
66+
internal fun Figure.toHTML(): String {
67+
return when(this) {
68+
is org.jetbrains.letsPlot.intern.Plot -> frontendContext.getHtml(this)
69+
is GGBunch -> frontendContext.getHtml(this)
70+
else -> error("Unsupported Figure")
71+
}
72+
}
6073

74+
internal fun Figure.toMimeResult(): MimeTypedResultEx {
75+
val spec = toSpec()
76+
val html = toHTML()
77+
return MimeTypedResultEx(
78+
buildJsonObject {
79+
put("text/html", JsonPrimitive(html))
80+
put("application/plot", buildJsonObject {
81+
put("output_type", JsonPrimitive("lets_plot_spec"))
82+
put("output", serializeSpec(spec))
83+
})
84+
}
85+
)
86+
}
6187

88+
}

ggdsl-util/build.gradle.kts

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
plugins {
2+
kotlin("jvm")
3+
kotlin("plugin.serialization")
4+
}
5+
6+
repositories {
7+
mavenCentral()
8+
}
9+
10+
val serialization_version: String by project
11+
val lets_plot_kotlin_version: String by project
12+
13+
dependencies {
14+
implementation(kotlin("stdlib"))
15+
testImplementation(kotlin("test"))
16+
api("org.jetbrains.kotlinx:kotlinx-serialization-json:$serialization_version")
17+
testImplementation("org.jetbrains.lets-plot:lets-plot-kotlin-jvm:$lets_plot_kotlin_version")
18+
testImplementation(project(":ggdsl-lets-plot"))
19+
}
20+
21+
22+
tasks {
23+
compileKotlin {
24+
kotlinOptions.jvmTarget = "1.8"
25+
}
26+
compileTestKotlin {
27+
kotlinOptions.jvmTarget = "1.8"
28+
}
29+
}
30+
31+
tasks.withType<JavaCompile> {
32+
sourceCompatibility = JavaVersion.VERSION_1_8.toString()
33+
targetCompatibility = JavaVersion.VERSION_1_8.toString()
34+
}
35+
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
package org.jetbrains.kotlinx.ggdsl.util.serialization
2+
3+
import kotlinx.serialization.json.*
4+
5+
public typealias LetsPlotSpec = Map<String, Any>
6+
7+
public fun serializeSpec(spec: LetsPlotSpec): JsonElement {
8+
return serialize(spec)
9+
}
10+
11+
private fun serializeAny(obj: Any?): JsonElement {
12+
return when(obj) {
13+
null -> JsonNull
14+
is Map<*, *> -> serialize(obj)
15+
is List<*> -> serialize(obj)
16+
is String -> JsonPrimitive(obj)
17+
is Boolean -> JsonPrimitive(obj)
18+
is Number -> JsonPrimitive(obj)
19+
else -> error("Don't know how to parse object [$obj] of class ${obj::class}")
20+
}
21+
}
22+
23+
private fun serialize(map: Map<*, *>): JsonObject {
24+
return buildJsonObject {
25+
for ((key, value) in map) {
26+
if (key !is String) error("Map key [$key] is of type ${key?.let { it::class }}. Don't know how to serialize it.")
27+
put(key, serializeAny(value))
28+
}
29+
}
30+
}
31+
32+
private fun serialize(list: List<*>): JsonArray {
33+
return buildJsonArray {
34+
for (value in list) {
35+
add(serializeAny(value))
36+
}
37+
}
38+
}
39+
40+
public fun deserializeSpec(json: JsonElement): LetsPlotSpec {
41+
if (json !is JsonObject) error("LetsPlot spec should be a key-value object, but it's $json")
42+
val map = deserializeMap(json)
43+
44+
for (value in map.values) {
45+
if (value == null) error("LetsPlot spec shouldn't have null values on the top level")
46+
}
47+
48+
@Suppress("UNCHECKED_CAST")
49+
return map as LetsPlotSpec
50+
}
51+
52+
private fun deserializeAny(json: JsonElement): Any? {
53+
return when(json) {
54+
is JsonObject -> deserializeMap(json)
55+
is JsonArray -> deserializeList(json)
56+
is JsonPrimitive -> deserializePrimitive(json)
57+
}
58+
}
59+
60+
private fun deserializePrimitive(json: JsonPrimitive): Any? {
61+
return when {
62+
json is JsonNull -> null
63+
json.isString -> json.content
64+
else -> {
65+
json.booleanOrNull ?:
66+
json.intOrNull ?:
67+
json.longOrNull ?:
68+
json.doubleOrNull ?:
69+
error("Unknown JSON primitive type: [$json]")
70+
}
71+
}
72+
}
73+
74+
private fun deserializeMap(json: JsonObject): Map<String, Any?> {
75+
return buildMap {
76+
for ((key, value) in json) {
77+
put(key, deserializeAny(value))
78+
}
79+
}
80+
}
81+
82+
private fun deserializeList(jsonArray: JsonArray): List<Any?> {
83+
return buildList {
84+
for (el in jsonArray) {
85+
add(deserializeAny(el))
86+
}
87+
}
88+
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
package org.jetbrains.kotlinx.ggdsl.util.serialization
2+
3+
import org.jetbrains.kotlinx.ggdsl.dsl.*
4+
import org.jetbrains.kotlinx.ggdsl.dsl.column.columnPointer
5+
import org.jetbrains.kotlinx.ggdsl.ir.Plot
6+
import org.jetbrains.kotlinx.ggdsl.letsplot.layers.points
7+
import org.jetbrains.kotlinx.ggdsl.letsplot.translator.toLetsPlot
8+
import org.jetbrains.kotlinx.ggdsl.letsplot.util.symbol.Symbol
9+
import org.jetbrains.kotlinx.ggdsl.letsplot.x
10+
import org.jetbrains.kotlinx.ggdsl.util.color.Color
11+
import org.jetbrains.letsPlot.intern.toSpec
12+
import kotlin.test.Test
13+
import kotlin.test.assertEquals
14+
15+
internal class SpecSerializationTest {
16+
@Test
17+
fun testSimpleCase() = doTest(
18+
plot(dataOf {
19+
"origin" to listOf("x", "y", "z")
20+
"mpg" to listOf(1.3, 8.1, 5.0)
21+
}) {
22+
x(columnPointer<String>("origin"))
23+
points {
24+
y(columnPointer<Double>("mpg").scaled(continuousPos(limits = 1.0 to 5.0)))
25+
symbol(Symbol.CIRCLE_FILLED)
26+
fillColor(Color.RED)
27+
}
28+
}
29+
)
30+
31+
private fun doTest(plot: Plot) {
32+
val spec = plot.toLetsPlot().toSpec()
33+
val serializedSpec = serializeSpec(spec)
34+
val deserializedSpec = deserializeSpec(serializedSpec)
35+
assertEquals(spec, deserializedSpec)
36+
}
37+
}

gradle.properties

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ systemProp.dokka_version=1.7.20
1010

1111
## Plugins
1212
systemProp.nexus_version=1.1.0
13-
systemProp.jupyter_api_version=0.11.0-218
13+
systemProp.jupyter_api_version=0.11.0-225
1414

1515

1616
## Libraries

settings.gradle.kts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ include("ggdsl-lets-plot")
44
include("ggdsl-echarts")
55
include("ggdsl-dataframe")
66
include("ggdsl-dataframe-lets-plot")
7+
include("ggdsl-util")
78

89
include("examples:idea-examples:lets-plot-simple")
910
include("examples:idea-examples:lets-plot-dataframe-simple")

0 commit comments

Comments
 (0)