[WIP] gradual merge of Plotly

This commit is contained in:
Alexander Nozik 2024-06-05 09:49:29 +03:00
parent 6fd719b9ee
commit 4f49901351
34 changed files with 92 additions and 123 deletions

View File

@ -7,7 +7,6 @@ plugins {
}
val dataforgeVersion by extra("0.9.0")
val plotlyVersion by extra("2.29.0")
allprojects {
group = "space.kscience"

View File

@ -9,10 +9,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Added
### Changed
- Plotly moved on top of VisionForge (in the VisionForge repository)
- Geo module merged into core
### Deprecated
### Removed
- Own HtmlFragment replaced by VisionForge Html handling
### Fixed

View File

@ -1,6 +1,11 @@
plugins{
id("org.jetbrains.changelog")
}
allprojects {
group = "space.kscience"
version = "0.7.2"
version = "0.8.0-dev-1"
}
readme {

View File

@ -10,7 +10,6 @@ repositories {
dependencies {
implementation(projects.plotly.plotlyktServer)
implementation(projects.plotly.plotlyktJupyter)
implementation(projects.plotly.plotlyktGeo)
implementation(projects.plotly.plotlyktScript)
implementation(kotlin("script-runtime"))
implementation("org.jetbrains.kotlinx:dataframe:0.13.1")

View File

@ -1,5 +1,3 @@
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
plugins {
kotlin("multiplatform")
alias(spclibs.plugins.compose.compiler)
@ -30,10 +28,6 @@ kotlin {
}
}
tasks.withType<KotlinCompile> {
kotlinOptions.freeCompilerArgs += "-Xopt-in=kotlin.RequiresOptIn"
}
compose {
desktop {
application {

View File

@ -1,5 +1,3 @@
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
plugins {
kotlin("jvm")
application
@ -30,6 +28,3 @@ kotlin{
jvmToolchain(11)
}
tasks.withType<KotlinCompile> {
kotlinOptions.freeCompilerArgs = kotlinOptions.freeCompilerArgs +"-Xopt-in=kotlin.RequiresOptIn"
}

View File

@ -20,8 +20,4 @@ kotlin {
}
}
}
}
tasks.withType<org.jetbrains.kotlin.gradle.tasks.KotlinCompile> {
kotlinOptions.freeCompilerArgs += "-Xopt-in=kotlin.RequiresOptIn"
}

View File

@ -1,5 +1,3 @@
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
plugins {
kotlin("multiplatform")
}
@ -23,8 +21,4 @@ kotlin {
}
}
}
}
tasks.withType<KotlinCompile> {
kotlinOptions.freeCompilerArgs = kotlinOptions.freeCompilerArgs +"-Xopt-in=kotlin.RequiresOptIn"
}
}

View File

@ -4,7 +4,7 @@ plugins {
}
val dataforgeVersion: String by rootProject.extra
val plotlyVersion: String by rootProject.extra
val plotlyVersion by extra("2.29.0")
kotlin{
@ -16,10 +16,11 @@ kscience {
native()
wasm()
dependencies {
api("space.kscience:dataforge-meta:$dataforgeVersion")
api(spclibs.kotlinx.html)
// api("org.jetbrains.kotlinx:kotlinx-html:0.11.0")
commonMain {
api(projects.visionforgeCore)
// api("space.kscience:dataforge-meta:$dataforgeVersion")
// api(spclibs.kotlinx.html)
}
jsMain{

View File

@ -2,6 +2,8 @@ package space.kscience.plotly
import kotlinx.html.*
import kotlinx.html.stream.createHTML
import space.kscience.visionforge.html.HtmlFragment
import space.kscience.visionforge.html.appendTo
/**
* A custom HTML fragment including plotly container reference
@ -12,7 +14,7 @@ public class PlotlyFragment(public val render: FlowContent.(renderer: PlotlyRend
* A complete page including headers and title
*/
public data class PlotlyPage(
val headers: Collection<PlotlyHtmlFragment>,
val headers: Collection<HtmlFragment>,
val fragment: PlotlyFragment,
val title: String = "Plotly.kt",
val renderer: PlotlyRenderer = StaticPlotlyRenderer
@ -23,7 +25,7 @@ public data class PlotlyPage(
charset = "utf-8"
}
title(this@PlotlyPage.title)
headers.distinct().forEach { it.visit(consumer) }
headers.distinct().forEach { it.appendTo(consumer) }
}
body {
fragment.render(this, renderer)
@ -37,7 +39,7 @@ public fun Plotly.fragment(content: FlowContent.(renderer: PlotlyRenderer) -> Un
* Create a complete page including plots
*/
public fun Plotly.page(
vararg headers: PlotlyHtmlFragment = arrayOf(cdnPlotlyHeader),
vararg headers: HtmlFragment = arrayOf(cdnPlotlyHeader),
title: String = "Plotly.kt",
renderer: PlotlyRenderer = StaticPlotlyRenderer,
content: FlowContent.(renderer: PlotlyRenderer) -> Unit
@ -47,7 +49,7 @@ public fun Plotly.page(
* Convert an html plot fragment to page
*/
public fun PlotlyFragment.toPage(
vararg headers: PlotlyHtmlFragment = arrayOf(cdnPlotlyHeader),
vararg headers: HtmlFragment = arrayOf(cdnPlotlyHeader),
title: String = "Plotly.kt",
renderer: PlotlyRenderer = StaticPlotlyRenderer
): PlotlyPage = PlotlyPage(headers.toList(), this, title, renderer)
@ -56,7 +58,7 @@ public fun PlotlyFragment.toPage(
* Convert a plot to the sigle-plot page
*/
public fun Plot.toPage(
vararg headers: PlotlyHtmlFragment = arrayOf(cdnPlotlyHeader),
vararg headers: HtmlFragment = arrayOf(cdnPlotlyHeader),
config: PlotlyConfig = PlotlyConfig.empty(),
title: String = "Plotly.kt",
renderer: PlotlyRenderer = StaticPlotlyRenderer

View File

@ -2,20 +2,11 @@ package space.kscience.plotly
import kotlinx.html.*
import kotlinx.html.stream.createHTML
import space.kscience.visionforge.html.HtmlFragment
import space.kscience.visionforge.html.appendTo
public class PlotlyHtmlFragment(public val visit: TagConsumer<*>.() -> Unit) {
override fun toString(): String {
return createHTML().also(visit).finalize()
}
}
public operator fun PlotlyHtmlFragment.plus(other: PlotlyHtmlFragment): PlotlyHtmlFragment = PlotlyHtmlFragment {
this@plus.run { visit() }
other.run { visit() }
}
public val cdnPlotlyHeader: PlotlyHtmlFragment = PlotlyHtmlFragment {
public val cdnPlotlyHeader: HtmlFragment = HtmlFragment{
script {
type = "text/javascript"
src = Plotly.PLOTLY_CDN
@ -26,7 +17,7 @@ public val cdnPlotlyHeader: PlotlyHtmlFragment = PlotlyHtmlFragment {
* Create a html (including headers) string from plot
*/
public fun Plot.toHTML(
vararg headers: PlotlyHtmlFragment = arrayOf(cdnPlotlyHeader),
vararg headers: HtmlFragment = arrayOf(cdnPlotlyHeader),
config: PlotlyConfig = PlotlyConfig(),
): String = createHTML().html {
head {
@ -35,7 +26,7 @@ public fun Plot.toHTML(
}
title(layout.title ?: "Plotly.kt")
headers.forEach {
it.visit(consumer)
it.appendTo(consumer)
}
}
body {
@ -45,7 +36,7 @@ public fun Plot.toHTML(
}
}
public val mathJaxHeader: PlotlyHtmlFragment = PlotlyHtmlFragment {
public val mathJaxHeader: HtmlFragment = HtmlFragment {
script {
type = "text/x-mathjax-config"
unsafe {

View File

@ -2,6 +2,7 @@ package space.kscience.plotly
import kotlinx.html.link
import kotlinx.html.script
import space.kscience.visionforge.html.HtmlFragment
//public fun localBootstrap(basePath: Path) = HtmlFragment {
@ -31,7 +32,7 @@ import kotlinx.html.script
// }
//}
public val cdnBootstrap: PlotlyHtmlFragment = PlotlyHtmlFragment {
public val cdnBootstrap: HtmlFragment = HtmlFragment {
script {
src = "https://code.jquery.com/jquery-3.5.1.slim.min.js"
integrity = "sha384-DfXdz2htPH0lsSSs5nCTpuj/zy4C+OGpamoFVy38MVBnE+IbbVYUew+OrCXaRkfj"

View File

@ -1,6 +1,7 @@
package space.kscience.plotly
import kotlinx.html.FlowContent
import space.kscience.visionforge.html.HtmlFragment
import java.awt.Desktop
import java.nio.file.Files
import java.nio.file.Path
@ -64,7 +65,7 @@ public fun PlotlyFragment.makeFile(
show: Boolean = true,
title: String = "Plotly.kt",
resourceLocation: ResourceLocation = ResourceLocation.LOCAL,
additionalHeaders: List<PlotlyHtmlFragment> = emptyList(),
additionalHeaders: List<HtmlFragment> = emptyList(),
) {
toPage(
title = title,

View File

@ -3,6 +3,7 @@ package space.kscience.plotly
import kotlinx.html.link
import kotlinx.html.script
import kotlinx.html.unsafe
import space.kscience.visionforge.html.HtmlFragment
import java.nio.file.Files
import java.nio.file.Path
import java.nio.file.StandardOpenOption
@ -21,7 +22,7 @@ internal fun checkOrStoreFile(basePath: Path, filePath: Path, resource: String):
} else {
//TODO add logging
val bytes = PlotlyHtmlFragment::class.java.getResourceAsStream(resource)!!.readAllBytes()
val bytes = HtmlFragment::class.java.getResourceAsStream(resource)!!.readAllBytes()
Files.createDirectories(fullPath.parent)
Files.write(fullPath, bytes, StandardOpenOption.CREATE_NEW, StandardOpenOption.WRITE)
}
@ -40,7 +41,7 @@ public fun localScriptHeader(
basePath: Path,
scriptPath: Path,
resource: String,
): PlotlyHtmlFragment = PlotlyHtmlFragment {
): HtmlFragment = HtmlFragment {
val relativePath = checkOrStoreFile(basePath, scriptPath, resource)
script {
type = "text/javascript"
@ -54,7 +55,7 @@ public fun localCssHeader(
basePath: Path,
cssPath: Path,
resource: String,
): PlotlyHtmlFragment = PlotlyHtmlFragment {
): HtmlFragment = HtmlFragment {
val relativePath = checkOrStoreFile(basePath, cssPath, resource)
link {
rel = "stylesheet"
@ -66,7 +67,7 @@ public fun localCssHeader(
internal fun localPlotlyHeader(
path: Path,
relativeScriptPath: String = "$assetsDirectory$PLOTLY_SCRIPT_PATH"
) = PlotlyHtmlFragment {
) = HtmlFragment {
val relativePath = checkOrStoreFile(path, Path.of(relativeScriptPath), PLOTLY_SCRIPT_PATH)
script {
type = "text/javascript"
@ -78,7 +79,7 @@ internal fun localPlotlyHeader(
/**
* A system-wide plotly store location
*/
internal val systemPlotlyHeader = PlotlyHtmlFragment {
internal val systemPlotlyHeader = HtmlFragment {
val relativePath = checkOrStoreFile(
Path.of("."),
Path.of(System.getProperty("user.home")).resolve(".plotly/$assetsDirectory$PLOTLY_SCRIPT_PATH"),
@ -94,10 +95,10 @@ internal val systemPlotlyHeader = PlotlyHtmlFragment {
/**
* embedded plotly script
*/
internal val embededPlotlyHeader = PlotlyHtmlFragment {
internal val embededPlotlyHeader = HtmlFragment {
script {
unsafe {
val bytes = PlotlyHtmlFragment::class.java.getResourceAsStream(PLOTLY_SCRIPT_PATH)!!.readAllBytes()
val bytes = HtmlFragment::class.java.getResourceAsStream(PLOTLY_SCRIPT_PATH)!!.readAllBytes()
+bytes.toString(Charsets.UTF_8)
}
}
@ -107,7 +108,7 @@ internal val embededPlotlyHeader = PlotlyHtmlFragment {
internal fun inferPlotlyHeader(
target: Path?,
resourceLocation: ResourceLocation
): PlotlyHtmlFragment = when (resourceLocation) {
): HtmlFragment = when (resourceLocation) {
ResourceLocation.REMOTE -> cdnPlotlyHeader
ResourceLocation.LOCAL -> if (target != null) {
localPlotlyHeader(target)

View File

@ -1,21 +0,0 @@
# Module plotlykt-geo
## Usage
## Artifact:
The Maven coordinates of this project are `space.kscience:plotlykt-geo:0.7.1`.
**Gradle Kotlin DSL:**
```kotlin
repositories {
maven("https://repo.kotlin.link")
mavenCentral()
}
dependencies {
implementation("space.kscience:plotlykt-geo:0.7.1")
}
```

View File

@ -1,18 +0,0 @@
plugins {
id("space.kscience.gradle.mpp")
`maven-publish`
}
kscience{
jvm()
js()
native()
wasm()
dependencies {
api(projects.plotly.plotlyktCore)
}
}
readme{
maturity = space.kscience.gradle.Maturity.EXPERIMENTAL
}

View File

@ -5,6 +5,7 @@ import kotlinx.html.stream.createHTML
import org.jetbrains.kotlinx.jupyter.api.HTML
import org.jetbrains.kotlinx.jupyter.api.libraries.JupyterIntegration
import org.jetbrains.kotlinx.jupyter.api.libraries.resources
import space.kscience.visionforge.html.HtmlFragment
public object PlotlyJupyterConfiguration {
public var legacyMode: Boolean = false
@ -12,9 +13,9 @@ public object PlotlyJupyterConfiguration {
/**
* Switch plotly renderer to the legacy notebook mode (Jupyter classic)
*/
public fun notebook(): PlotlyHtmlFragment {
public fun notebook(): HtmlFragment {
legacyMode = true
return PlotlyHtmlFragment {
return HtmlFragment {
div {
style = "color: blue;"
+"Plotly notebook integration switched into the notebook mode."
@ -22,9 +23,9 @@ public object PlotlyJupyterConfiguration {
}
}
public fun lab(): PlotlyHtmlFragment {
public fun lab(): HtmlFragment {
legacyMode = false
return PlotlyHtmlFragment {
return HtmlFragment {
div {
style = "color: blue;"
+"Plotly notebook integration switched into the lab mode."
@ -98,7 +99,7 @@ public class PlotlyIntegration : JupyterIntegration(), PlotlyRenderer {
import("space.kscience.plotly.jupyter")
render<PlotlyHtmlFragment> {
render<HtmlFragment> {
HTML(it.toString())
}

View File

@ -4,6 +4,7 @@ import kotlinx.html.FlowContent
import mu.KLogger
import mu.KotlinLogging
import space.kscience.plotly.*
import space.kscience.visionforge.html.HtmlFragment
import java.io.File
import kotlin.script.experimental.api.*
import kotlin.script.experimental.host.toScriptSource
@ -16,7 +17,7 @@ import kotlin.script.experimental.jvmhost.BasicJvmScriptingHost
public fun Plotly.page(
source: SourceCode,
title: String = "Plotly.kt",
headers: Array<PlotlyHtmlFragment> = arrayOf(cdnPlotlyHeader),
headers: Array<HtmlFragment> = arrayOf(cdnPlotlyHeader),
logger: KLogger = KotlinLogging.logger("scripting")
): PlotlyPage {
@ -62,7 +63,7 @@ public fun Plotly.page(
public fun Plotly.page(
file: File,
title: String = "Plotly.kt",
headers: Array<PlotlyHtmlFragment> = arrayOf(cdnPlotlyHeader),
headers: Array<HtmlFragment> = arrayOf(cdnPlotlyHeader),
logger: KLogger = KotlinLogging.logger("scripting")
): PlotlyPage = page(file.toScriptSource(), title, headers, logger)
@ -71,6 +72,6 @@ public fun Plotly.page(
public fun Plotly.page(
string: String,
title: String = "Plotly.kt",
headers: Array<PlotlyHtmlFragment> = arrayOf(cdnPlotlyHeader),
headers: Array<HtmlFragment> = arrayOf(cdnPlotlyHeader),
logger: KLogger = KotlinLogging.logger("scripting")
): PlotlyPage = page(string.toScriptSource(), title, headers, logger)

View File

@ -23,6 +23,8 @@ import space.kscience.dataforge.meta.*
import space.kscience.dataforge.names.Name
import space.kscience.plotly.*
import space.kscience.plotly.server.PlotlyServer.Companion.DEFAULT_PAGE
import space.kscience.visionforge.html.HtmlFragment
import space.kscience.visionforge.html.appendTo
import java.awt.Desktop
import java.net.URI
import kotlin.collections.set
@ -141,10 +143,10 @@ public class PlotlyServer internal constructor(
/**
* a list of headers that should be applied to all pages
*/
private val globalHeaders: ArrayList<PlotlyHtmlFragment> = ArrayList<PlotlyHtmlFragment>()
private val globalHeaders: ArrayList<HtmlFragment> = ArrayList<HtmlFragment>()
public fun header(block: TagConsumer<*>.() -> Unit) {
globalHeaders.add(PlotlyHtmlFragment(block))
globalHeaders.add(HtmlFragment(block))
}
internal fun Route.servePlotData(plots: Map<String, Plot>) {
@ -186,7 +188,7 @@ public class PlotlyServer internal constructor(
plotlyFragment: PlotlyFragment,
route: String = DEFAULT_PAGE,
title: String = "Plotly server page '$route'",
headers: List<PlotlyHtmlFragment> = emptyList(),
headers: List<HtmlFragment> = emptyList(),
) {
root.apply {
val plots = HashMap<String, Plot>()
@ -214,9 +216,9 @@ public class PlotlyServer internal constructor(
meta {
charset = "utf-8"
(globalHeaders + headers).forEach {
it.visit(consumer)
it.appendTo(consumer)
}
plotlyKtHeader.visit(consumer)
plotlyKtHeader.appendTo(consumer)
}
title(title)
}
@ -239,7 +241,7 @@ public class PlotlyServer internal constructor(
public fun page(
route: String = DEFAULT_PAGE,
title: String = "Plotly server page '$route'",
headers: List<PlotlyHtmlFragment> = emptyList(),
headers: List<HtmlFragment> = emptyList(),
content: FlowContent.(renderer: PlotlyRenderer) -> Unit,
) {
page(PlotlyFragment(content), route, title, headers)

View File

@ -14,6 +14,7 @@ import space.kscience.dataforge.meta.Scheme
import space.kscience.dataforge.meta.boolean
import space.kscience.dataforge.meta.int
import space.kscience.plotly.*
import space.kscience.visionforge.html.HtmlFragment
public object PlotlyServerConfiguration : Scheme() {
public var port: Int by int(System.getProperty("space.kscience.plotly.port")?.toInt() ?: 8882)
@ -24,9 +25,9 @@ public object PlotlyServerConfiguration : Scheme() {
/**
* Switch plotly renderer to the legacy notebook mode (Jupyter classic)
*/
public fun notebook(): PlotlyHtmlFragment {
public fun notebook(): HtmlFragment {
legacyMode = true
return PlotlyHtmlFragment {
return HtmlFragment {
div {
style = "color: blue;"
+"Plotly notebook integration switch into the legacy mode."
@ -35,7 +36,7 @@ public object PlotlyServerConfiguration : Scheme() {
}
}
internal val plotlyKtHeader = PlotlyHtmlFragment {
internal val plotlyKtHeader = HtmlFragment {
script {
src = "js/plotly-kt.js"
}
@ -59,15 +60,15 @@ public class PlotlyServerIntegration : JupyterIntegration() {
public val isServerStarted: Boolean get() = server != null
private fun start(): PlotlyHtmlFragment = if (server != null) {
PlotlyHtmlFragment {
private fun start(): HtmlFragment = if (server != null) {
HtmlFragment {
div {
style = "color: blue;"
+"The server is already running on ${Plotly.jupyter.port}. It must be shut down first to be restarted."
}
}
} else {
fun doStart(): PlotlyHtmlFragment {
fun doStart(): HtmlFragment {
server?.stop(1000, 1000)
server = Plotly.serve(host = "0.0.0.0", port = Plotly.jupyter.port) {
root.servePlotData(plots)
@ -80,7 +81,7 @@ public class PlotlyServerIntegration : JupyterIntegration() {
) { plotId, plot ->
plots[plotId] = plot
}
return PlotlyHtmlFragment {
return HtmlFragment {
div {
style = "color: blue;"
+"Started plotly server on ${Plotly.jupyter.port}"
@ -135,7 +136,7 @@ public class PlotlyServerIntegration : JupyterIntegration() {
import("space.kscience.plotly.server.jupyter")
render<PlotlyHtmlFragment> {
render<HtmlFragment> {
HTML(it.toString())
}

View File

@ -62,7 +62,6 @@ include(
":visionforge-jupyter:visionforge-jupyter-common",
":plotly",
":plotly:plotlykt-core",
":plotly:plotlykt-geo",
":plotly:plotlykt-jupyter",
":plotly:plotlykt-server",
":plotly:plotlykt-script",

View File

@ -0,0 +1,21 @@
# Module visionforge-jupyter-common
Jupyter api artifact including all common modules
## Usage
## Artifact:
The Maven coordinates of this project are `space.kscience:visionforge-jupyter-common:0.4.1`.
**Gradle Kotlin DSL:**
```kotlin
repositories {
maven("https://repo.kotlin.link")
mavenCentral()
}
dependencies {
implementation("space.kscience:visionforge-jupyter-common:0.4.1")
}
```

View File

@ -12,6 +12,7 @@ import space.kscience.tables.Table
import space.kscience.visionforge.gdml.toVision
import space.kscience.visionforge.html.HtmlFragment
import space.kscience.visionforge.html.VisionPage
import space.kscience.visionforge.html.appendTo
import space.kscience.visionforge.markup.MarkupPlugin
import space.kscience.visionforge.plotly.PlotlyPlugin
import space.kscience.visionforge.plotly.asVision
@ -63,7 +64,7 @@ public class JupyterCommonIntegration : VisionForgeIntegration(CONTEXT.visionMan
render<PlotlyPage> { plotlyPage ->
val headers = plotlyPage.headers.associate { plotlyFragment ->
plotlyFragment.hashCode().toString(16) to HtmlFragment {
plotlyFragment.visit(this)
plotlyFragment.appendTo(this)
}
}