Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

0.7.0-dev-1 #103

Merged
merged 4 commits into from
Feb 4, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,15 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## Unreleased

### Added
- Compose demo

### Changed
- Migrated to DF 0.8

### Deprecated

### Removed
- Grid view

### Fixed

Expand Down
6 changes: 3 additions & 3 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,12 @@ plugins {
id("space.kscience.gradle.project")
}

val dataforgeVersion by extra("0.7.1")
val plotlyVersion by extra("2.24.1")
val dataforgeVersion by extra("0.8.0")
val plotlyVersion by extra("2.29.0")

allprojects {
group = "space.kscience"
version = "0.6.1"
version = "0.7.0-dev-1"
}

apiValidation {
Expand Down
42 changes: 42 additions & 0 deletions examples/compose-demo/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile

plugins {
kotlin("multiplatform")
id("org.jetbrains.compose") version "1.5.12"
}

repositories {
mavenCentral()
maven("https://repo.kotlin.link")
maven("https://jogamp.org/deployment/maven")
}

kotlin{
jvm()
jvmToolchain(17)
sourceSets{
jvmMain{
dependencies {
implementation(compose.runtime)
implementation(compose.foundation)
implementation(compose.material)
implementation(compose.desktop.currentOs)
implementation("io.github.kevinnzou:compose-webview-multiplatform:1.8.6")
implementation(projects.plotlyktServer)
implementation(spclibs.logback.classic)
}
}
}
}

tasks.withType<KotlinCompile> {
kotlinOptions.freeCompilerArgs += "-Xopt-in=kotlin.RequiresOptIn"
}

compose {
desktop {
application {
mainClass = "space.kscience.plotly.compose.AppKt"
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
package space.kscience.plotly.compose

import androidx.compose.foundation.layout.*
import androidx.compose.material.*
import androidx.compose.runtime.*
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import androidx.compose.ui.window.Window
import androidx.compose.ui.window.application
import com.multiplatform.webview.web.LoadingState
import com.multiplatform.webview.web.WebView
import com.multiplatform.webview.web.rememberWebViewNavigator
import com.multiplatform.webview.web.rememberWebViewStateWithHTMLData
import dev.datlag.kcef.KCEF
import kotlinx.coroutines.flow.MutableStateFlow

private val allowedPages = listOf(
"Static",
"Dynamic"
)

@Composable
fun App() {
val scaleFlow = remember { MutableStateFlow(1f) }
val scale by scaleFlow.collectAsState()
val scope = rememberCoroutineScope()
val server = remember {
scope.servePlots(scaleFlow)
}

val state = rememberWebViewStateWithHTMLData(staticPlot())

val navigator = rememberWebViewNavigator()

val loadingState = state.loadingState
if (loadingState is LoadingState.Loading) {
LinearProgressIndicator(
progress = loadingState.progress,
modifier = Modifier.fillMaxWidth()
)
}

Row(Modifier.fillMaxSize()) {
Column(Modifier.width(300.dp)) {
Button({ navigator.loadHtml(staticPlot()) }, modifier = Modifier.fillMaxWidth()) {
Text("Static")
}
Button({ navigator.loadUrl("http://localhost:7778/Dynamic") }, modifier = Modifier.fillMaxWidth()) {
Text("Dynamic")
}

Slider(
scale,
{ scaleFlow.value = it },
valueRange = 0.1f..10f,
modifier = Modifier.fillMaxWidth()
)
}
Column(Modifier.fillMaxSize()) {

WebView(
state = state,
navigator = navigator,
modifier = Modifier.fillMaxSize()
)
}
}
}

fun main() = application {
KCEF.initBlocking(
builder = {
progress {
onDownloading {
println("Download progress: $it%")
}
}
release(true)
}
)
Window(onCloseRequest = ::exitApplication) {
MaterialTheme {
App()
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
package space.kscience.plotly.compose

import io.ktor.server.engine.ApplicationEngine
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.isActive
import kotlinx.coroutines.launch
import space.kscience.plotly.*
import space.kscience.plotly.models.Scatter
import space.kscience.plotly.models.invoke
import space.kscience.plotly.server.pushUpdates
import space.kscience.plotly.server.serve
import kotlin.math.PI
import kotlin.math.cos
import kotlin.math.sin

fun staticPlot(): String = Plotly.page {
val x = (0..100).map { it.toDouble() / 100.0 }.toDoubleArray()
val y1 = x.map { sin(2.0 * PI * it) }.toDoubleArray()
val y2 = x.map { cos(2.0 * PI * it) }.toDoubleArray()
val trace1 = Scatter(x, y1) {
name = "sin"
}
val trace2 = Scatter(x, y2) {
name = "cos"
}
plot(config = PlotlyConfig { responsive = true }) {//static plot
traces(trace1, trace2)
layout {
title = "First graph, row: 1, size: 8/12"
xaxis.title = "x axis name"
yaxis { title = "y axis name" }
}
}
}.render()

fun CoroutineScope.servePlots(scale: StateFlow<Number>): ApplicationEngine = Plotly.serve(this, port = 7778) {
page("Static") { container ->
val x = (0..100).map { it.toDouble() / 100.0 }.toDoubleArray()
val y1 = x.map { sin(2.0 * PI * it) }.toDoubleArray()
val y2 = x.map { cos(2.0 * PI * it) }.toDoubleArray()
val trace1 = Scatter(x, y1) {
name = "sin"
}
val trace2 = Scatter(x, y2) {
name = "cos"
}
plot(renderer = container) {//static plot
traces(trace1, trace2)
layout {
title = "First graph, row: 1, size: 8/12"
xaxis.title = "x axis name"
yaxis { title = "y axis name" }
}
}
}

page("Dynamic") { container ->
val x = (0..100).map { it.toDouble() / 100.0 }
val y = x.map { sin(2.0 * PI * it) }

val trace = Scatter(x, y) { name = "sin" }

val plot = plot("dynamic", config = PlotlyConfig { responsive = true }, renderer = container) {
traces(trace)
layout {
title = "Dynamic plot"
xaxis.title = "x axis name"
yaxis.title = "y axis name"
}
}

launch {
var time: Long = 0
while (isActive) {
delay(10)
time += 10
val frequency = scale.value.toDouble()
val dynamicY = x.map { sin(2.0 * PI * frequency * (it + time.toDouble() / 1000.0)) }
//trace.y.numbers = dynamicY
plot.data[0].y.numbers = dynamicY
plot.layout {
xaxis.title = "x axis name (t = $time)"
}
}
}
}
pushUpdates(100)
}


Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ import kotlinx.serialization.json.Json
import org.w3c.dom.HTMLElement
import org.w3c.dom.events.Event
import space.kscience.dataforge.meta.MetaSerializer
import space.kscience.dataforge.meta.toMutableMeta
import space.kscience.plotly.*
import space.kscience.plotly.events.PlotlyEventListenerType
import space.kscience.plotly.models.ScatterMode
Expand Down Expand Up @@ -133,7 +132,7 @@ fun main(): Unit = withCanvas {
}
val serialized = plot.toJsonString()
console.log(serialized)
val deserialized = Plot(Json.decodeFromString(MetaSerializer, serialized).toMutableMeta())
val deserialized = Plot(Json.decodeFromString(MetaSerializer, serialized))
plotDiv(plot = deserialized).on(PlotlyEventListenerType.CLICK){
console.info(it.toString())
}
Expand Down
14 changes: 3 additions & 11 deletions examples/native-demo/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -10,20 +10,12 @@ repositories {
}

kotlin {
val hostOs = System.getProperty("os.name")
val isMingwX64 = hostOs.startsWith("Windows")
val nativeTarget = when {
hostOs == "Mac OS X" -> macosX64("native")
hostOs == "Linux" -> linuxX64("native")
isMingwX64 -> mingwX64("native")
else -> throw GradleException("Host OS is not supported in Kotlin/Native.")
}

nativeTarget.apply {
binaries {
linuxX64{
binaries{
executable()
}
}

sourceSets{
commonMain {
dependencies {
Expand Down
73 changes: 71 additions & 2 deletions examples/src/main/kotlin/gridPageLayout.kt
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import kotlinx.html.div
import space.kscience.plotly.*
import space.kscience.plotly.models.Trace
import space.kscience.plotly.models.invoke
Expand All @@ -6,8 +7,76 @@ import kotlin.math.PI
import kotlin.math.cos
import kotlin.math.sin

@Suppress("DEPRECATION")
@UnstablePlotlyAPI

private class PlotGrid {
public data class PlotCell(val id: String, val plot: Plot, val row: Int, val col: Int, val width: Int = 1)

private val cells = HashMap<String, PlotCell>()

/**
* @return Columns in ascending order, grouped by rows in ascending order.
* */
public val grid: List<List<PlotCell>>
get() = cells.values.groupBy { it.row }.toSortedMap().values.map {
it.sortedBy { cell -> cell.col }
}.toList()

public operator fun get(id: String): PlotCell? = cells[id]

private var currentRow = 0
private var currentCol = 0

public fun plot(
plot: Plot,
id: String = plot.toString(),
width: Int = 6,
row: Int? = null,
col: Int? = null,
): Plot {
val actualRow = if (row != null) {
row
} else {
currentCol = 0
currentRow++
}

val actualColumn = col ?: currentCol++

cells[id] = PlotCell(id, plot, actualRow, actualColumn, width)

return plot
}

public fun plot(
row: Int? = null,
col: Int? = null,
id: String? = null,
width: Int = 6,
block: Plot.() -> Unit,
): Plot {
val plot = Plotly.plot(block)
return plot(plot, id ?: plot.toString(), width, row, col)
}
}


private fun Plotly.grid(block: PlotGrid.() -> Unit): PlotlyPage {
val grid = PlotGrid().apply(block)
return page(cdnBootstrap, cdnPlotlyHeader) { container ->
div("col") {
grid.grid.forEach { row ->
div("row") {
row.forEach { cell ->
div("col-${cell.width}") {
plot(cell.plot, cell.id, renderer = container)
}
}
}
}
}
}
}

fun main() {

val x = (0..100).map { it.toDouble() / 100.0 }
Expand Down
1 change: 1 addition & 0 deletions plotlykt-core/api/plotlykt-core.api
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,7 @@ public final class space/kscience/plotly/PlotGridKt {
}

public final class space/kscience/plotly/PlotKt {
public static final fun Plot (Lspace/kscience/dataforge/meta/Meta;)Lspace/kscience/plotly/Plot;
public static final fun layout (Lspace/kscience/plotly/Plot;Lkotlin/jvm/functions/Function1;)V
public static final fun toJsonString (Lspace/kscience/plotly/Plot;)Ljava/lang/String;
public static final fun trace (Lspace/kscience/plotly/Plot;Lkotlin/jvm/functions/Function1;)Lspace/kscience/plotly/models/Trace;
Expand Down
Loading
Loading