Giter VIP home page Giter VIP logo

koalaplot-core's People

Contributors

gsteckman avatar jakepurple13 avatar kentvu avatar maltsev-gorskij avatar ralfhartmann avatar ruyut avatar vitalyperyatin avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar

koalaplot-core's Issues

Stairs for XYChart

Hi there,
I stumbled across your lib when searching for a plot lib for Compose Multiplatform.
There is one question that arises: is there any chance to plot stairs for XY values?

Thanks in advance.

Feature Request: Implement mouse tracking lines on chart

I want to implement vertical and horizontal lines tracking the mouse cursor on the chart.

To do this, a feature that converts the mouse cursor's absolute coordinates into relative coordinates on the chart is needed.

And for this, an API that can determine the size of the chart is necessary.

IOS supported or not?

Hello! I've added lib to commonMain dependencies and it seems works well on Android app.
When I'm trying to build an app via Xcode - it says Build Failed with error:

Could not find "org.jetbrains.kotlin.native.platform.Symbols" in [/Users/vdcast/111/DEV/Projects/MoneyWorksPersonal, /Users/vdcast/.konan/klib, /Users/vdcast/.konan/kotlin-native-prebuilt-macos-x86_64-1.9.10/klib/common, /Users/vdcast/.konan/kotlin-native-prebuilt-macos-x86_64-1.9.10/klib/platform/ios_arm64]

Do I need to add in in Xcode libraries? If yes - how to do it?
Please, help me add it to IOS target correctly, ty!

Here is my build.gradle shared module:

`plugins {
kotlin("multiplatform")
id("com.android.library")
id("org.jetbrains.compose")
id("com.squareup.sqldelight")
}

kotlin {
androidTarget {
compilations.all {
kotlinOptions {
jvmTarget = "17"
}
}
}

targets.withType(org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeTarget::class.java).all {
    binaries.withType(org.jetbrains.kotlin.gradle.plugin.mpp.Framework::class.java).all {
        export("dev.icerock.moko:mvvm-core:0.16.1")
    }
}

listOf(
    iosX64(),
    iosArm64(),
    iosSimulatorArm64()
).forEach { iosTarget ->
    iosTarget.binaries.framework {
        baseName = "shared"
        isStatic = true
    }
}

sourceSets {
    val commonMain by getting {
        dependencies {
            implementation(compose.runtime)
            implementation(compose.foundation)
            implementation(compose.material3)
            @OptIn(org.jetbrains.compose.ExperimentalComposeLibrary::class)
            implementation(compose.components.resources)

            implementation("androidx.datastore:datastore-preferences-core:1.1.0-dev01")

            implementation("com.squareup.sqldelight:runtime:1.5.5")
            implementation("com.squareup.sqldelight:coroutines-extensions:1.5.5")
            implementation("org.jetbrains.kotlinx:kotlinx-datetime:0.4.0")

            implementation("org.jetbrains.kotlinx:atomicfu:0.17.3")

            implementation("org.jetbrains.kotlinx:kotlinx-datetime:0.4.0")

            implementation("io.github.koalaplot:koalaplot-core:0.5.2")
        }
    }
    val androidMain by getting {
        dependencies {
            api("androidx.activity:activity-compose:1.8.0")
            api("androidx.appcompat:appcompat:1.6.1")
            api("androidx.core:core-ktx:1.12.0")

            implementation("com.squareup.sqldelight:android-driver:1.5.5")
        }
    }
    val iosX64Main by getting
    val iosArm64Main by getting
    val iosSimulatorArm64Main by getting
    val iosMain by creating {
        dependencies {
            implementation("com.squareup.sqldelight:native-driver:1.5.5")
        }
        dependsOn(commonMain)
        iosX64Main.dependsOn(this)
        iosArm64Main.dependsOn(this)
        iosSimulatorArm64Main.dependsOn(this)
    }
}

}

android {
compileSdk = (findProperty("android.compileSdk") as String).toInt()
namespace = "com.vdcast.moneyworkspersonal"

sourceSets["main"].manifest.srcFile("src/androidMain/AndroidManifest.xml")
sourceSets["main"].res.srcDirs("src/androidMain/res")
sourceSets["main"].resources.srcDirs("src/commonMain/resources")

defaultConfig {
    minSdk = (findProperty("android.minSdk") as String).toInt()
}
compileOptions {
    sourceCompatibility = JavaVersion.VERSION_17
    targetCompatibility = JavaVersion.VERSION_17
}
kotlin {
    jvmToolchain(17)
}

}

sqldelight {
database("AppDatabase") {
packageName = "com.vdcast.moneyworkspersonal.data.database"
sourceFolders = listOf("sqldelight")
}
}

dependencies {
implementation("androidx.compose.material3:material3:1.1.2")
implementation("androidx.core:core:1.10.1")
commonMainApi("dev.icerock.moko:mvvm-core:0.16.1")
commonMainApi("dev.icerock.moko:mvvm-compose:0.16.1")
commonMainApi("dev.icerock.moko:mvvm-flow:0.16.1")
commonMainApi("dev.icerock.moko:mvvm-flow-compose:0.16.1")
}`

and build.gradle project:

buildscript {
dependencies {
classpath("com.android.tools.build:gradle:8.1.2")
classpath("com.squareup.sqldelight:gradle-plugin:1.5.5")
classpath("org.jetbrains.kotlinx:atomicfu-gradle-plugin:0.17.3")
}
}
plugins {
kotlin("multiplatform").apply(false)
id("com.android.application").apply(false)
id("com.android.library").apply(false)
id("org.jetbrains.compose").apply(false)
}

allprojects {
apply(plugin = "kotlinx-atomicfu")
}

repositories {
mavenCentral()
maven("https://maven.pkg.jetbrains.space/public/p/compose/dev")
}

Limit the display of labels if there is no space for labels for pie chart.

Hello.

I get poor display when there are a lot of pieces of the pie and not enough space to display the labels. For example, 40%, 40% and 1%, 1%, 1%, 1%, 1%, 1%, 1%, 1%, 1%, 1%, 1%, 1%, 1%, 1%, 1%, 1%, 1%, 1%, 1%, 1%, 1%, 1%, 1%, 1%, 1%, 1%, 1%, 1%, 1%, 1%, 1% , 1%, 1%, 1%, 1%, 1%, 1%, 1%, 1%, 1%, 1%, 1%, 1%,

image

NoSuchElementException thrown on calling autoScaleXRange()

Reproducer:

XYGraph(
                xAxisModel = LongLinearAxisModel(
                    points.autoScaleXRange(),
                    minorTickCount = 0,
                    minimumMajorTickIncrement = 100,
                ),
// ...

where points is an empty list.

Stacktrace:

Exception in thread "main" java.util.NoSuchElementException
	at kotlin.collections.CollectionsKt___CollectionsKt.maxOrThrow(_Collections.kt:1920)
	at io.github.koalaplot.core.xygraph.LongLinearAxisModelKt.autoScaleRange(LongLinearAxisModel.kt:262)
	at io.github.koalaplot.core.xygraph.LongLinearAxisModelKt.autoScaleXRange(LongLinearAxisModel.kt:302)
	at MainKt$App$1$2.invoke(Main.kt:79)
	at MainKt$App$1$2.invoke(Main.kt:62)
	at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jb.kt:107)
	at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jb.kt:33)
	at io.github.koalaplot.core.ChartLayoutKt.ChartLayout(ChartLayout.kt:56)
	at MainKt.App(Main.kt:62)
	at ComposableSingletons$MainKt$lambda-5$1.invoke(Main.kt:130)
	at ComposableSingletons$MainKt$lambda-5$1.invoke(Main.kt:129)
	at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jb.kt:116)
	at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jb.kt:33)
	at androidx.compose.ui.awt.ComposeWindow$setContent$5.invoke(ComposeWindow.desktop.kt:156)
	at androidx.compose.ui.awt.ComposeWindow$setContent$5.invoke(ComposeWindow.desktop.kt:155)
	at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jb.kt:107)
	at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jb.kt:33)
	at androidx.compose.ui.awt.WindowContentLayout_desktopKt.WindowContentLayout(WindowContentLayout.desktop.kt:103)
	at androidx.compose.ui.awt.ComposeWindowPanel$setContent$3$1.invoke(ComposeWindowPanel.desktop.kt:171)
	at androidx.compose.ui.awt.ComposeWindowPanel$setContent$3$1.invoke(ComposeWindowPanel.desktop.kt:170)
	at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jb.kt:107)
	at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jb.kt:33)
	at androidx.compose.runtime.CompositionLocalKt.CompositionLocalProvider(CompositionLocal.kt:248)
	at androidx.compose.ui.awt.ComposeWindowPanel$setContent$3.invoke(ComposeWindowPanel.desktop.kt:168)
	at androidx.compose.ui.awt.ComposeWindowPanel$setContent$3.invoke(ComposeWindowPanel.desktop.kt:167)
	at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jb.kt:107)
	at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jb.kt:33)
	at androidx.compose.ui.scene.ComposeContainer$setContent$1$1.invoke(ComposeContainer.desktop.kt:231)
	at androidx.compose.ui.scene.ComposeContainer$setContent$1$1.invoke(ComposeContainer.desktop.kt:230)
	at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jb.kt:107)
	at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jb.kt:33)
	at androidx.compose.runtime.CompositionLocalKt.CompositionLocalProvider(CompositionLocal.kt:248)
	at androidx.compose.ui.scene.ComposeContainer_desktopKt.ProvideContainerCompositionLocals(ComposeContainer.desktop.kt:335)
	at androidx.compose.ui.scene.ComposeContainer_desktopKt.access$ProvideContainerCompositionLocals(ComposeContainer.desktop.kt:1)
	at androidx.compose.ui.scene.ComposeContainer$setContent$1.invoke(ComposeContainer.desktop.kt:230)
	at androidx.compose.ui.scene.ComposeContainer$setContent$1.invoke(ComposeContainer.desktop.kt:229)
	at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jb.kt:107)
	at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jb.kt:33)
	at androidx.compose.runtime.CompositionLocalKt.CompositionLocalProvider(CompositionLocal.kt:248)
	at androidx.compose.ui.scene.BaseComposeScene$setContent$1$2.invoke(BaseComposeScene.skiko.kt:139)
	at androidx.compose.ui.scene.BaseComposeScene$setContent$1$2.invoke(BaseComposeScene.skiko.kt:138)
	at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jb.kt:107)
	at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jb.kt:33)
	at androidx.compose.runtime.CompositionLocalKt.CompositionLocalProvider(CompositionLocal.kt:228)
	at androidx.compose.ui.platform.CompositionLocalsKt.ProvideCommonCompositionLocals(CompositionLocals.kt:186)
	at androidx.compose.ui.platform.Wrapper_skikoKt$setContent$2$1.invoke(Wrapper.skiko.kt:49)
	at androidx.compose.ui.platform.Wrapper_skikoKt$setContent$2$1.invoke(Wrapper.skiko.kt:48)
	at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jb.kt:107)
	at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jb.kt:33)
	at androidx.compose.runtime.CompositionLocalKt.CompositionLocalProvider(CompositionLocal.kt:228)
	at androidx.compose.runtime.CompositionLocalKt.CompositionLocalProvider(CompositionLocal.kt:266)
	at androidx.compose.ui.platform.Wrapper_skikoKt.provide(Wrapper.skiko.kt:62)
	at androidx.compose.ui.platform.Wrapper_skikoKt.access$provide(Wrapper.skiko.kt:1)
	at androidx.compose.ui.platform.Wrapper_skikoKt$setContent$2.invoke(Wrapper.skiko.kt:48)
	at androidx.compose.ui.platform.Wrapper_skikoKt$setContent$2.invoke(Wrapper.skiko.kt:47)
	at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jb.kt:107)
	at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jb.kt:33)
	at androidx.compose.runtime.ActualJvm_jvmKt.invokeComposable(ActualJvm.jvm.kt:33)
	at androidx.compose.runtime.ComposerImpl.doCompose(Composer.kt:3303)
	at androidx.compose.runtime.ComposerImpl.composeContent$runtime(Composer.kt:3236)
	at androidx.compose.runtime.CompositionImpl.composeContent(Composition.kt:725)
	at androidx.compose.runtime.Recomposer.composeInitial$runtime(Recomposer.kt:1071)
	at androidx.compose.runtime.CompositionImpl.composeInitial(Composition.kt:633)
	at androidx.compose.runtime.CompositionImpl.setContent(Composition.kt:619)
	at androidx.compose.ui.platform.Wrapper_skikoKt.setContent(Wrapper.skiko.kt:47)
	at androidx.compose.ui.scene.MultiLayerComposeSceneImpl.createComposition(MultiLayerComposeScene.skiko.kt:203)
	at androidx.compose.ui.scene.BaseComposeScene.setContent(BaseComposeScene.skiko.kt:138)
	at androidx.compose.ui.scene.ComposeSceneMediator$setContent$1.invoke(ComposeSceneMediator.desktop.kt:457)
	at androidx.compose.ui.scene.ComposeSceneMediator$setContent$1.invoke(ComposeSceneMediator.desktop.kt:455)
	at androidx.compose.ui.scene.ComposeSceneMediator.onComponentAttached(ComposeSceneMediator.desktop.kt:410)
	at androidx.compose.ui.scene.ComposeContainer.addNotify(ComposeContainer.desktop.kt:186)
	at androidx.compose.ui.awt.ComposeWindowPanel.addNotify(ComposeWindowPanel.desktop.kt:148)
	at java.desktop/java.awt.Container.addNotify(Container.java:2804)
	at java.desktop/javax.swing.JComponent.addNotify(JComponent.java:4839)
	at java.desktop/java.awt.Container.addNotify(Container.java:2804)
	at java.desktop/javax.swing.JComponent.addNotify(JComponent.java:4839)
	at java.desktop/java.awt.Container.addNotify(Container.java:2804)
	at java.desktop/javax.swing.JComponent.addNotify(JComponent.java:4839)
	at java.desktop/javax.swing.JRootPane.addNotify(JRootPane.java:729)
	at java.desktop/java.awt.Container.addNotify(Container.java:2804)
	at java.desktop/java.awt.Window.addNotify(Window.java:791)
	at java.desktop/java.awt.Frame.addNotify(Frame.java:495)
	at java.desktop/java.awt.Window.pack(Window.java:829)
	at androidx.compose.ui.util.Windows_desktopKt.setSizeImpl-6HolHcs(Windows.desktop.kt:116)
	at androidx.compose.ui.util.Windows_desktopKt.setSizeSafely-hQcJfNw(Windows.desktop.kt:55)
	at androidx.compose.ui.window.Window_desktopKt$Window$5.invoke(Window.desktop.kt:239)
	at androidx.compose.ui.window.Window_desktopKt$Window$5.invoke(Window.desktop.kt:176)
	at androidx.compose.ui.window.Window_desktopKt$Window$12$1.invoke(Window.desktop.kt:426)
	at androidx.compose.ui.window.Window_desktopKt$Window$12$1.invoke(Window.desktop.kt:419)
	at androidx.compose.ui.window.AwtWindow_desktopKt$AwtWindow$3.invoke(AwtWindow.desktop.kt:78)
	at androidx.compose.ui.window.AwtWindow_desktopKt$AwtWindow$3.invoke(AwtWindow.desktop.kt:76)
	at androidx.compose.ui.util.UpdateEffect_desktopKt$UpdateEffect$2$performUpdate$1.invoke(UpdateEffect.desktop.kt:59)
	at androidx.compose.ui.util.UpdateEffect_desktopKt$UpdateEffect$2$performUpdate$1.invoke(UpdateEffect.desktop.kt:55)
	at androidx.compose.runtime.snapshots.Snapshot$Companion.observe(Snapshot.kt:2304)
	at androidx.compose.runtime.snapshots.SnapshotStateObserver$ObservedScopeMap.observe(SnapshotStateObserver.kt:504)
	at androidx.compose.runtime.snapshots.SnapshotStateObserver.observeReads(SnapshotStateObserver.kt:260)
	at androidx.compose.ui.util.UpdateEffect_desktopKt$UpdateEffect$2.invoke$performUpdate(UpdateEffect.desktop.kt:55)
	at androidx.compose.ui.util.UpdateEffect_desktopKt$UpdateEffect$2.invoke(UpdateEffect.desktop.kt:64)
	at androidx.compose.ui.util.UpdateEffect_desktopKt$UpdateEffect$2.invoke(UpdateEffect.desktop.kt:47)
	at androidx.compose.runtime.DisposableEffectImpl.onRemembered(Effects.kt:82)
	at androidx.compose.runtime.CompositionImpl$RememberEventDispatcher.dispatchRememberObservers(Composition.kt:1295)
	at androidx.compose.runtime.CompositionImpl.applyChangesInLocked(Composition.kt:984)
	at androidx.compose.runtime.CompositionImpl.applyChanges(Composition.kt:1005)
	at androidx.compose.runtime.Recomposer.composeInitial$runtime(Recomposer.kt:1099)
	at androidx.compose.runtime.CompositionImpl.composeInitial(Composition.kt:633)
	at androidx.compose.runtime.CompositionImpl.setContent(Composition.kt:619)
	at androidx.compose.ui.window.Application_desktopKt$awaitApplication$2$1$2.invokeSuspend(Application.desktop.kt:219)
	at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
	at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:108)
	at java.desktop/java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:318)
	at java.desktop/java.awt.EventQueue.dispatchEventImpl(EventQueue.java:771)
	at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:722)
	at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:716)
	at java.base/java.security.AccessController.doPrivileged(AccessController.java:399)
	at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:86)
	at java.desktop/java.awt.EventQueue.dispatchEvent(EventQueue.java:741)
	at java.desktop/java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:203)
	at java.desktop/java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:124)
	at java.desktop/java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:113)
	at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:109)
	at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:101)
	at java.desktop/java.awt.EventDispatchThread.run(EventDispatchThread.java:90)

LineChart: cornerPathEffect results in area-line inconsistencies

Id like to smoothen out the lines of my chart. Unfortunately, this happens when I use cornerPathEffect, which makes sense given that its only applied to the lineStyle. Would it be possible to incorporate it in the AreaStyle as well?

LineStyle(
    brush = SolidColor(color),
    strokeWidth = 2.dp,
    pathEffect = cornerPathEffect(/* 40.dp in the screenshot */),
)
image

Feature Request: Allow disabling of all input (Bar Chart)

My charts are in a scrollable column, and currently, they swallow all input events even with enabled = false.

This means I can't scroll my column when my finger is passing over the chat. it makes for some very awkward scrolling.

So far this is happening for me with BarChart, but not PieChart.

XYGraph Axis annotations

XYAnnotation places a composable within the XYGraph plot area. This feature is to enable placing a Composable as an annotation along the x-axis/y-axis.

Please vote for this issue by adding a ๐Ÿ‘ to help prioritize new features.

Crash when mutating data in PieChart

When rapidly changing chart data size, the app crashes. I think generateHueColorPalette gets called too late.

Sample

Spam-click Toggle list button to reproduce:

fun main() {
    application {
        Window(
            onCloseRequest = this::exitApplication,
            title = "Demo app"
        ) {
            Column {
                var showBigList by remember { mutableStateOf(false) }

                val data = remember(showBigList) {
                    List(size = if (showBigList) 100 else 5) { it.toFloat() }
                }

                Button(
                    onClick = { showBigList = !showBigList }
                ) {
                    Text("Toggle list")
                }

                PieChart(
                    values = data
                )
            }
        }
    }
}

Logs:

Exception in thread "AWT-EventQueue-0" java.lang.IndexOutOfBoundsException: index: 5, size: 5
	at kotlin.collections.AbstractList$Companion.checkElementIndex$kotlin_stdlib(AbstractList.kt:108)
	at kotlin.collections.builders.ListBuilder.get(ListBuilder.kt:39)
	at io.github.koalaplot.core.pie.PieChartKt$PieChart$7.invoke(PieChart.kt:339)
	at io.github.koalaplot.core.pie.PieChartKt$PieChart$7.invoke(PieChart.kt:337)
	at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jb.kt:137)
	at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jb.kt:33)
	at io.github.koalaplot.core.pie.PieChartKt$Pie$1$1.invoke(PieChart.kt:397)
	at io.github.koalaplot.core.pie.PieChartKt$Pie$1$1.invoke(PieChart.kt:390)
	at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jb.kt:116)
	at androidx.compose.runtime.internal.ComposableLambdaImpl$invoke$2.invoke(ComposableLambda.jb.kt:128)
	at androidx.compose.runtime.internal.ComposableLambdaImpl$invoke$2.invoke(ComposableLambda.jb.kt:127)
	at androidx.compose.runtime.RecomposeScopeImpl.compose(RecomposeScopeImpl.kt:192)
	at androidx.compose.runtime.ComposerImpl.recomposeToGroupEnd(Composer.kt:2557)
	at androidx.compose.runtime.ComposerImpl.skipCurrentGroup(Composer.kt:2828)
	at androidx.compose.runtime.ComposerImpl.doCompose(Composer.kt:3315)
	at androidx.compose.runtime.ComposerImpl.recompose$runtime(Composer.kt:3266)
	at androidx.compose.runtime.CompositionImpl.recompose(Composition.kt:940)
	at androidx.compose.runtime.Recomposer.performRecompose(Recomposer.kt:1155)
	at androidx.compose.runtime.Recomposer.access$performRecompose(Recomposer.kt:127)
	at androidx.compose.runtime.Recomposer$runRecomposeAndApplyChanges$2$1.invoke(Recomposer.kt:583)
	at androidx.compose.runtime.Recomposer$runRecomposeAndApplyChanges$2$1.invoke(Recomposer.kt:551)
	at androidx.compose.runtime.BroadcastFrameClock$FrameAwaiter.resume(BroadcastFrameClock.kt:42)
	at androidx.compose.runtime.BroadcastFrameClock.sendFrame(BroadcastFrameClock.kt:71)
	at androidx.compose.ui.scene.BaseComposeScene.render(BaseComposeScene.skiko.kt:163)
	at androidx.compose.ui.scene.ComposeSceneMediator$DesktopSkikoView.onRender(ComposeSceneMediator.desktop.kt:523)
	at org.jetbrains.skiko.SkiaLayer.update$skiko(SkiaLayer.awt.kt:548)
	at org.jetbrains.skiko.redrawer.AWTRedrawer.update(AWTRedrawer.kt:54)
	at org.jetbrains.skiko.redrawer.Direct3DRedrawer$frameDispatcher$1.invokeSuspend(Direct3DRedrawer.kt:49)
	at org.jetbrains.skiko.redrawer.Direct3DRedrawer$frameDispatcher$1.invoke(Direct3DRedrawer.kt)
	at org.jetbrains.skiko.redrawer.Direct3DRedrawer$frameDispatcher$1.invoke(Direct3DRedrawer.kt)
	at org.jetbrains.skiko.FrameDispatcher$job$1.invokeSuspend(FrameDispatcher.kt:33)
	at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
	at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:104)
	at java.desktop/java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:318)
	at java.desktop/java.awt.EventQueue.dispatchEventImpl(EventQueue.java:773)
	at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:720)
	at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:714)
	at java.base/java.security.AccessController.doPrivileged(AccessController.java:400)
	at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:87)
	at java.desktop/java.awt.EventQueue.dispatchEvent(EventQueue.java:742)
	at java.desktop/java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:203)
	at java.desktop/java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:124)
	at java.desktop/java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:113)
	at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:109)
	at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:101)
	at java.desktop/java.awt.EventDispatchThread.run(EventDispatchThread.java:90)
	Suppressed: kotlinx.coroutines.internal.DiagnosticCoroutineContextException: [androidx.compose.ui.scene.ComposeContainer$DesktopCoroutineExceptionHandler@2b52488f, androidx.compose.runtime.BroadcastFrameClock@5bc6f3a2, StandaloneCoroutine{Cancelling}@7d783f0a, FlushCoroutineDispatcher@635857e4]

Info

I managed to fix this by adding nullability when getting slice color. I found no issues with this workaround:

fun main() {
    application {
        Window(
            onCloseRequest = this::exitApplication,
            title = "Demo app"
        ) {
            Column {
                var showBigList by remember { mutableStateOf(false) }

                val data = remember(showBigList) {
                    List(size = if (showBigList) 100 else 5) { it.toFloat() }
                }

                Button(
                    onClick = { showBigList = !showBigList }
                ) {
                    Text("Toggle list")
                }

                PieChart(
                    values = data
                    slice = {
                        val colors = remember(data.size) { generateHueColorPalette(data.size) }
                        DefaultSlice(colors.getOrNull(it) ?: Color.Transparent) // Can be null here
                    }
                )
            }
        }
    }
}

Library version: 0.6.0
Compose: 1.6.2 (Multiplatform)
Platform: Windows 10

Scatter plot with error bars

A scatter plot can be created by using LinePlot with symbols. This feature adds a variant that is a scatter plot with error bars plotted at each point.

Please vote for this issue by adding a ๐Ÿ‘ to help prioritize new features.

VerticalBarChart Crash: When I have only one bar

I'm not sure of the exact cause yet.

Exception in thread "AWT-EventQueue-0" java.lang.IndexOutOfBoundsException: Index -1 out of bounds for length 1
	at java.base/jdk.internal.util.Preconditions.outOfBounds(Preconditions.java:64)
	at java.base/jdk.internal.util.Preconditions.outOfBoundsCheckIndex(Preconditions.java:70)
	at java.base/jdk.internal.util.Preconditions.checkIndex(Preconditions.java:266)
	at java.base/java.util.Objects.checkIndex(Objects.java:359)
	at java.base/java.util.ArrayList.get(ArrayList.java:427)
	at io.github.koalaplot.core.bar.VerticalBarChartKt$VerticalBarChart$4.measure-3p2s80s(VerticalBarChart.kt:144)
	at androidx.compose.ui.node.InnerNodeCoordinator.measure-BRTryo0(InnerNodeCoordinator.kt:103)
	at androidx.compose.ui.node.LayoutNodeLayoutDelegate$performMeasure$2.invoke(LayoutNodeLayoutDelegate.kt:1090)
	at androidx.compose.ui.node.LayoutNodeLayoutDelegate$performMeasure$2.invoke(LayoutNodeLayoutDelegate.kt:1086)
	at androidx.compose.runtime.snapshots.Snapshot$Companion.observe(Snapshot.kt:2201)
	at androidx.compose.runtime.snapshots.SnapshotStateObserver$observeReads$1$1.invoke(SnapshotStateObserver.kt:238)
	at androidx.compose.runtime.snapshots.SnapshotStateObserver$observeReads$1$1.invoke(SnapshotStateObserver.kt:234)
	at androidx.compose.runtime.SnapshotStateKt__DerivedStateKt.observeDerivedStateRecalculations(DerivedState.kt:341)
	at androidx.compose.runtime.SnapshotStateKt.observeDerivedStateRecalculations(Unknown Source)

Plot area shrinks when x axis labels are too long

When I do not provide any labels to x axis it fills up the space correctly. But when I try to add some long labels (for example dates) it seems to shrink the plot area and it does no fill the space fully anymore. I post pictures of that behavior
image

Time-based axis

For dynamic data it is important to have time-based axis (preferably based on Kotlinx-datetime Instant. It requires #63 to work properly.

xAxis not shown with 500 Points

I use the LineChartSample with a data set of 500 data points instead of the RainData set. This leads to the x-axis not being displayed correctly. If the number for the label reaches two digits, it is no longer displayed.

`@OptIn(ExperimentalKoalaPlotApi::class)
@composable
@Suppress("MagicNumber")
private fun Chart(title: String) {
ChartLayout(
modifier = paddingMod,
title = { ChartTitle(title) },
legend = { Legend() },
legendLocation = LegendLocation.BOTTOM
) {
syncGraphList()

    XYGraph(
        xAxisModel = CategoryAxisModel(
            GraphData.labels
        ),
        yAxisModel = LinearAxisModel(
            -128f..128f,
            minimumMajorTickSpacing = 20.dp,
        ),
        xAxisStyle = rememberAxisStyle(
            color = Color.White,
            majorTickSize = 0.dp,
            minorTickSize = 0.dp,
            tickPosition = TickPosition.None,
            lineWidth = 1.dp,
            labelRotation = 0
        ),
        xAxisLabels = { AxisLabel(it, Modifier.absolutePadding(right = 2.dp)) },
        xAxisTitle = {
            Box(
                modifier = Modifier.fillMaxWidth(),
                contentAlignment = Alignment.BottomCenter
            ) {
                AxisTitle("Lรคnge [m]",
                    modifier = Modifier
                        .padding(20.dp)
                )
            }

        },
        yAxisStyle = rememberAxisStyle(
            color = Color.White,
            majorTickSize = 0.dp,
            minorTickSize = 0.dp,
            tickPosition = TickPosition.None,
            lineWidth = 1.dp,
            labelRotation = 0
        ),
        yAxisLabels = {
            AxisLabel(it.toString(), Modifier.absolutePadding(right = 2.dp))
        },
        yAxisTitle = {
            Box(
                modifier = Modifier.fillMaxHeight(),
                contentAlignment = Alignment.TopStart
            ) {
                AxisTitle(
                    "Einheit (?)",
                    modifier = Modifier.rotateVertically(VerticalRotation.COUNTER_CLOCKWISE)
                        .padding(bottom = padding)
                )
            }

        },
        horizontalMajorGridLineStyle = KoalaPlotTheme.axis.majorGridlineStyle,
        horizontalMinorGridLineStyle = KoalaPlotTheme.axis.minorGridlineStyle,
        verticalMajorGridLineStyle = KoalaPlotTheme.axis.majorGridlineStyle,
        verticalMinorGridLineStyle = KoalaPlotTheme.axis.minorGridlineStyle,

        ) {
        GraphData.data.entries.sortedBy { it.key }.forEach { (channel, labels) ->
            var points = labels.mapIndexed { index, d ->
                DefaultPoint(GraphData.labels[index], d.toFloat())
            }

            chart(
                channel,
                points,
            )
        }
    }
}

}

@OptIn(ExperimentalKoalaPlotApi::class)
@composable
private fun XYGraphScope<String, Float>.chart(
channel: String,
data: List<DefaultPoint<String, Float>>,
) {
LinePlot(
data = data,
lineStyle = LineStyle(
brush = SolidColor(colorMap[channel] ?: Color.Black),
strokeWidth = 2.dp
),
symbol = { point ->
Symbol(
shape = CircleShape,
size = 2.dp,
fillBrush = SolidColor(colorMap[channel] ?: Color.Black),
modifier = Modifier.then(
Modifier.hoverableElement {
HoverSurface { Text(point.y.toString()) }
}
)
)
}
)
}`

Vertical Bullet Graph

Please vote for this issue by adding a ๐Ÿ‘ to help prioritize new features.

Secondary Y-axis

Add the capability to add a secondary Y-axis to an XYGraph, displayed on the right side of the plot area.

Please vote for this issue by adding a ๐Ÿ‘ to help prioritize new features.

XYChart issues with long x-axis labels

First thanks a lot for this great library.
I am struggling a bit to show a VerticalBarChart with long labels on the x-axis. Spread sheet applications like Excel or Google Sheets offer to show the labels in an rotated angle so that the labels do not overlap. It would be a quite nice enhancement for this library as well. I tried to achieve this on my own without changing the source code of this library but failed. While i was able to rotate and position the labels correctly, i did not achieve change the inner dimensions of the Text composable itself, so that the text wraps even there would be enough space to render the labels without soft wrap.
This screenshot shows how my intended chart is shown in google sheets.
Screenshot 2023-04-23 at 17 42 29

ArithmeticException: / by zero

Version: 0.6.0-dev2

I still got ArithmeticException, not sure where it comes from. The exception is not always throwing.

Exception in thread "AWT-EventQueue-0" java.lang.ArithmeticException: / by zero
	at io.github.koalaplot.core.xygraph.ChartAreas.xTickSpacing(XYGraph.kt:292)
	at io.github.koalaplot.core.xygraph.ChartAreas.withComputedXAxisLabelAreas(XYGraph.kt:303)
	at io.github.koalaplot.core.xygraph.XYGraphKt.optimizeGraphSize-m8Kt_7k(XYGraph.kt:422)
	at io.github.koalaplot.core.xygraph.XYGraphKt.access$optimizeGraphSize-m8Kt_7k(XYGraph.kt:1)
	at io.github.koalaplot.core.xygraph.XYAxisMeasurePolicy.measure-3p2s80s(XYGraph.kt:441)
	at io.github.koalaplot.core.xygraph.XYGraphKt$XYGraph$1$1.invoke-0kLqBqw(XYGraph.kt:169)
	at io.github.koalaplot.core.xygraph.XYGraphKt$XYGraph$1$1.invoke(XYGraph.kt:98)
	at androidx.compose.ui.layout.LayoutNodeSubcompositionsState$createMeasurePolicy$1.measure-3p2s80s(SubcomposeLayout.kt:709)
	at androidx.compose.ui.node.InnerNodeCoordinator.measure-BRTryo0(InnerNodeCoordinator.kt:126)
	at androidx.compose.ui.node.LayoutNodeLayoutDelegate$performMeasureBlock$1.invoke(LayoutNodeLayoutDelegate.kt:252)
	at androidx.compose.ui.node.LayoutNodeLayoutDelegate$performMeasureBlock$1.invoke(LayoutNodeLayoutDelegate.kt:251)
	at androidx.compose.runtime.snapshots.Snapshot$Companion.observe(Snapshot.kt:2304)
	at androidx.compose.runtime.snapshots.SnapshotStateObserver$ObservedScopeMap.observe(SnapshotStateObserver.kt:504)
	at androidx.compose.runtime.snapshots.SnapshotStateObserver.observeReads(SnapshotStateObserver.kt:260)
	at androidx.compose.ui.node.OwnerSnapshotObserver.observeReads$ui(OwnerSnapshotObserver.kt:133)
	at androidx.compose.ui.node.OwnerSnapshotObserver.observeMeasureSnapshotReads$ui(OwnerSnapshotObserver.kt:113)
	at androidx.compose.ui.node.LayoutNodeLayoutDelegate.performMeasure-BRTryo0(LayoutNodeLayoutDelegate.kt:1617)
	at androidx.compose.ui.node.LayoutNodeLayoutDelegate.access$performMeasure-BRTryo0(LayoutNodeLayoutDelegate.kt:36)
	at androidx.compose.ui.node.LayoutNodeLayoutDelegate$MeasurePassDelegate.remeasure-BRTryo0(LayoutNodeLayoutDelegate.kt:620)
	at androidx.compose.ui.node.LayoutNodeLayoutDelegate$MeasurePassDelegate.measure-BRTryo0(LayoutNodeLayoutDelegate.kt:596)
	at androidx.compose.foundation.layout.BoxMeasurePolicy.measure-3p2s80s(Box.kt:122)
	at androidx.compose.ui.node.InnerNodeCoordinator.measure-BRTryo0(InnerNodeCoordinator.kt:126)
	at androidx.compose.ui.node.LayoutNodeLayoutDelegate$performMeasureBlock$1.invoke(LayoutNodeLayoutDelegate.kt:252)
	at androidx.compose.ui.node.LayoutNodeLayoutDelegate$performMeasureBlock$1.invoke(LayoutNodeLayoutDelegate.kt:251)
	at androidx.compose.runtime.snapshots.Snapshot$Companion.observe(Snapshot.kt:2304)
	at androidx.compose.runtime.snapshots.SnapshotStateObserver$ObservedScopeMap.observe(SnapshotStateObserver.kt:504)
	at androidx.compose.runtime.snapshots.SnapshotStateObserver.observeReads(SnapshotStateObserver.kt:260)
	at androidx.compose.ui.node.OwnerSnapshotObserver.observeReads$ui(OwnerSnapshotObserver.kt:133)
	at androidx.compose.ui.node.OwnerSnapshotObserver.observeMeasureSnapshotReads$ui(OwnerSnapshotObserver.kt:113)
	at androidx.compose.ui.node.LayoutNodeLayoutDelegate.performMeasure-BRTryo0(LayoutNodeLayoutDelegate.kt:1617)
	at androidx.compose.ui.node.LayoutNodeLayoutDelegate.access$performMeasure-BRTryo0(LayoutNodeLayoutDelegate.kt:36)
	at androidx.compose.ui.node.LayoutNodeLayoutDelegate$MeasurePassDelegate.remeasure-BRTryo0(LayoutNodeLayoutDelegate.kt:620)
	at androidx.compose.ui.node.LayoutNodeLayoutDelegate$MeasurePassDelegate.measure-BRTryo0(LayoutNodeLayoutDelegate.kt:596)
	at io.github.koalaplot.core.util.HoverableElementAreaKt$HoverableElementArea$2$1.measure-3p2s80s(HoverableElementArea.kt:85)
	at androidx.compose.ui.node.InnerNodeCoordinator.measure-BRTryo0(InnerNodeCoordinator.kt:126)
	at androidx.compose.ui.node.LayoutNodeLayoutDelegate$performMeasureBlock$1.invoke(LayoutNodeLayoutDelegate.kt:252)
	at androidx.compose.ui.node.LayoutNodeLayoutDelegate$performMeasureBlock$1.invoke(LayoutNodeLayoutDelegate.kt:251)
	at androidx.compose.runtime.snapshots.Snapshot$Companion.observe(Snapshot.kt:2304)
	at androidx.compose.runtime.snapshots.SnapshotStateObserver$ObservedScopeMap.observe(SnapshotStateObserver.kt:504)
	at androidx.compose.runtime.snapshots.SnapshotStateObserver.observeReads(SnapshotStateObserver.kt:260)
	at androidx.compose.ui.node.OwnerSnapshotObserver.observeReads$ui(OwnerSnapshotObserver.kt:133)
	at androidx.compose.ui.node.OwnerSnapshotObserver.observeMeasureSnapshotReads$ui(OwnerSnapshotObserver.kt:113)
	at androidx.compose.ui.node.LayoutNodeLayoutDelegate.performMeasure-BRTryo0(LayoutNodeLayoutDelegate.kt:1617)
	at androidx.compose.ui.node.LayoutNodeLayoutDelegate.access$performMeasure-BRTryo0(LayoutNodeLayoutDelegate.kt:36)
	at androidx.compose.ui.node.LayoutNodeLayoutDelegate$MeasurePassDelegate.remeasure-BRTryo0(LayoutNodeLayoutDelegate.kt:620)
	at androidx.compose.ui.node.LayoutNodeLayoutDelegate$MeasurePassDelegate.measure-BRTryo0(LayoutNodeLayoutDelegate.kt:596)
	at androidx.compose.foundation.layout.BoxMeasurePolicy.measure-3p2s80s(Box.kt:122)
	at androidx.compose.ui.node.InnerNodeCoordinator.measure-BRTryo0(InnerNodeCoordinator.kt:126)
	at androidx.compose.ui.node.LayoutNodeLayoutDelegate$performMeasureBlock$1.invoke(LayoutNodeLayoutDelegate.kt:252)
	at androidx.compose.ui.node.LayoutNodeLayoutDelegate$performMeasureBlock$1.invoke(LayoutNodeLayoutDelegate.kt:251)
	at androidx.compose.runtime.snapshots.Snapshot$Companion.observe(Snapshot.kt:2304)
	at androidx.compose.runtime.snapshots.SnapshotStateObserver$ObservedScopeMap.observe(SnapshotStateObserver.kt:504)
	at androidx.compose.runtime.snapshots.SnapshotStateObserver.observeReads(SnapshotStateObserver.kt:260)
	at androidx.compose.ui.node.OwnerSnapshotObserver.observeReads$ui(OwnerSnapshotObserver.kt:133)
	at androidx.compose.ui.node.OwnerSnapshotObserver.observeMeasureSnapshotReads$ui(OwnerSnapshotObserver.kt:113)
	at androidx.compose.ui.node.LayoutNodeLayoutDelegate.performMeasure-BRTryo0(LayoutNodeLayoutDelegate.kt:1617)
	at androidx.compose.ui.node.LayoutNodeLayoutDelegate.access$performMeasure-BRTryo0(LayoutNodeLayoutDelegate.kt:36)
	at androidx.compose.ui.node.LayoutNodeLayoutDelegate$MeasurePassDelegate.remeasure-BRTryo0(LayoutNodeLayoutDelegate.kt:620)
	at androidx.compose.ui.node.LayoutNodeLayoutDelegate$MeasurePassDelegate.measure-BRTryo0(LayoutNodeLayoutDelegate.kt:596)
	at androidx.compose.foundation.layout.RowColumnMeasurementHelper.measureWithoutPlacing-_EkL_-Y(RowColumnMeasurementHelper.kt:172)
	at androidx.compose.foundation.layout.RowColumnMeasurePolicy.measure-3p2s80s(RowColumnImpl.kt:73)
	at androidx.compose.ui.node.InnerNodeCoordinator.measure-BRTryo0(InnerNodeCoordinator.kt:126)
	at androidx.compose.ui.node.LayoutNodeLayoutDelegate$performMeasureBlock$1.invoke(LayoutNodeLayoutDelegate.kt:252)
	at androidx.compose.ui.node.LayoutNodeLayoutDelegate$performMeasureBlock$1.invoke(LayoutNodeLayoutDelegate.kt:251)
	at androidx.compose.runtime.snapshots.Snapshot$Companion.observe(Snapshot.kt:2304)
	at androidx.compose.runtime.snapshots.SnapshotStateObserver$ObservedScopeMap.observe(SnapshotStateObserver.kt:504)
	at androidx.compose.runtime.snapshots.SnapshotStateObserver.observeReads(SnapshotStateObserver.kt:260)
	at androidx.compose.ui.node.OwnerSnapshotObserver.observeReads$ui(OwnerSnapshotObserver.kt:133)
	at androidx.compose.ui.node.OwnerSnapshotObserver.observeMeasureSnapshotReads$ui(OwnerSnapshotObserver.kt:113)
	at androidx.compose.ui.node.LayoutNodeLayoutDelegate.performMeasure-BRTryo0(LayoutNodeLayoutDelegate.kt:1617)
	at androidx.compose.ui.node.LayoutNodeLayoutDelegate.access$performMeasure-BRTryo0(LayoutNodeLayoutDelegate.kt:36)
	at androidx.compose.ui.node.LayoutNodeLayoutDelegate$MeasurePassDelegate.remeasure-BRTryo0(LayoutNodeLayoutDelegate.kt:620)
	at androidx.compose.ui.node.LayoutNodeLayoutDelegate$MeasurePassDelegate.measure-BRTryo0(LayoutNodeLayoutDelegate.kt:596)
	at androidx.compose.foundation.layout.RowColumnMeasurementHelper.measureWithoutPlacing-_EkL_-Y(RowColumnMeasurementHelper.kt:112)
	at androidx.compose.foundation.layout.RowColumnMeasurePolicy.measure-3p2s80s(RowColumnImpl.kt:73)
	at androidx.compose.ui.node.InnerNodeCoordinator.measure-BRTryo0(InnerNodeCoordinator.kt:126)
	at androidx.compose.foundation.layout.SizeNode.measure-3p2s80s(Size.kt:838)
	at androidx.compose.ui.node.LayoutModifierNodeCoordinator.measure-BRTryo0(LayoutModifierNodeCoordinator.kt:116)
	at androidx.compose.ui.node.LayoutNodeLayoutDelegate$performMeasureBlock$1.invoke(LayoutNodeLayoutDelegate.kt:252)
	at androidx.compose.ui.node.LayoutNodeLayoutDelegate$performMeasureBlock$1.invoke(LayoutNodeLayoutDelegate.kt:251)
	at androidx.compose.runtime.snapshots.Snapshot$Companion.observe(Snapshot.kt:2304)
	at androidx.compose.runtime.snapshots.SnapshotStateObserver$ObservedScopeMap.observe(SnapshotStateObserver.kt:504)
	at androidx.compose.runtime.snapshots.SnapshotStateObserver.observeReads(SnapshotStateObserver.kt:260)
	at androidx.compose.ui.node.OwnerSnapshotObserver.observeReads$ui(OwnerSnapshotObserver.kt:133)
	at androidx.compose.ui.node.OwnerSnapshotObserver.observeMeasureSnapshotReads$ui(OwnerSnapshotObserver.kt:113)
	at androidx.compose.ui.node.LayoutNodeLayoutDelegate.performMeasure-BRTryo0(LayoutNodeLayoutDelegate.kt:1617)
	at androidx.compose.ui.node.LayoutNodeLayoutDelegate.access$performMeasure-BRTryo0(LayoutNodeLayoutDelegate.kt:36)
	at androidx.compose.ui.node.LayoutNodeLayoutDelegate$MeasurePassDelegate.remeasure-BRTryo0(LayoutNodeLayoutDelegate.kt:620)
	at androidx.compose.ui.node.LayoutNodeLayoutDelegate$MeasurePassDelegate.measure-BRTryo0(LayoutNodeLayoutDelegate.kt:596)
	at androidx.compose.foundation.layout.RowColumnMeasurementHelper.measureWithoutPlacing-_EkL_-Y(RowColumnMeasurementHelper.kt:112)
	at androidx.compose.foundation.layout.RowColumnMeasurePolicy.measure-3p2s80s(RowColumnImpl.kt:73)
	at androidx.compose.ui.node.InnerNodeCoordinator.measure-BRTryo0(InnerNodeCoordinator.kt:126)
	at androidx.compose.foundation.ScrollingLayoutNode.measure-3p2s80s(Scroll.kt:394)
	at androidx.compose.ui.node.LayoutModifierNodeCoordinator.measure-BRTryo0(LayoutModifierNodeCoordinator.kt:116)
	at androidx.compose.ui.graphics.SimpleGraphicsLayerModifier.measure-3p2s80s(GraphicsLayerModifier.kt:646)
	at androidx.compose.ui.node.LayoutModifierNodeCoordinator.measure-BRTryo0(LayoutModifierNodeCoordinator.kt:116)
	at androidx.compose.ui.node.LayoutNodeLayoutDelegate$performMeasureBlock$1.invoke(LayoutNodeLayoutDelegate.kt:252)
	at androidx.compose.ui.node.LayoutNodeLayoutDelegate$performMeasureBlock$1.invoke(LayoutNodeLayoutDelegate.kt:251)
	at androidx.compose.runtime.snapshots.Snapshot$Companion.observe(Snapshot.kt:2304)
	at androidx.compose.runtime.snapshots.SnapshotStateObserver$ObservedScopeMap.observe(SnapshotStateObserver.kt:504)
	at androidx.compose.runtime.snapshots.SnapshotStateObserver.observeReads(SnapshotStateObserver.kt:260)
	at androidx.compose.ui.node.OwnerSnapshotObserver.observeReads$ui(OwnerSnapshotObserver.kt:133)
	at androidx.compose.ui.node.OwnerSnapshotObserver.observeMeasureSnapshotReads$ui(OwnerSnapshotObserver.kt:113)
	at androidx.compose.ui.node.LayoutNodeLayoutDelegate.performMeasure-BRTryo0(LayoutNodeLayoutDelegate.kt:1617)
	at androidx.compose.ui.node.LayoutNodeLayoutDelegate.access$performMeasure-BRTryo0(LayoutNodeLayoutDelegate.kt:36)
	at androidx.compose.ui.node.LayoutNodeLayoutDelegate$MeasurePassDelegate.remeasure-BRTryo0(LayoutNodeLayoutDelegate.kt:620)
	at androidx.compose.ui.node.LayoutNodeLayoutDelegate$MeasurePassDelegate.measure-BRTryo0(LayoutNodeLayoutDelegate.kt:596)
	at androidx.compose.foundation.layout.BoxMeasurePolicy.measure-3p2s80s(Box.kt:122)
	at androidx.compose.ui.node.InnerNodeCoordinator.measure-BRTryo0(InnerNodeCoordinator.kt:126)
	at androidx.compose.foundation.layout.FillNode.measure-3p2s80s(Size.kt:699)
	at androidx.compose.ui.node.LayoutModifierNodeCoordinator.measure-BRTryo0(LayoutModifierNodeCoordinator.kt:116)
	at androidx.compose.ui.node.LayoutNodeLayoutDelegate$performMeasureBlock$1.invoke(LayoutNodeLayoutDelegate.kt:252)
	at androidx.compose.ui.node.LayoutNodeLayoutDelegate$performMeasureBlock$1.invoke(LayoutNodeLayoutDelegate.kt:251)
	at androidx.compose.runtime.snapshots.Snapshot$Companion.observe(Snapshot.kt:2304)
	at androidx.compose.runtime.snapshots.SnapshotStateObserver$ObservedScopeMap.observe(SnapshotStateObserver.kt:504)
	at androidx.compose.runtime.snapshots.SnapshotStateObserver.observeReads(SnapshotStateObserver.kt:260)
	at androidx.compose.ui.node.OwnerSnapshotObserver.observeReads$ui(OwnerSnapshotObserver.kt:133)
	at androidx.compose.ui.node.OwnerSnapshotObserver.observeMeasureSnapshotReads$ui(OwnerSnapshotObserver.kt:113)
	at androidx.compose.ui.node.LayoutNodeLayoutDelegate.performMeasure-BRTryo0(LayoutNodeLayoutDelegate.kt:1617)
	at androidx.compose.ui.node.LayoutNodeLayoutDelegate.access$performMeasure-BRTryo0(LayoutNodeLayoutDelegate.kt:36)
	at androidx.compose.ui.node.LayoutNodeLayoutDelegate$MeasurePassDelegate.remeasure-BRTryo0(LayoutNodeLayoutDelegate.kt:620)
	at androidx.compose.ui.node.LayoutNode.remeasure-_Sx5XlM$ui(LayoutNode.kt:1145)
	at androidx.compose.ui.node.LayoutNode.remeasure-_Sx5XlM$ui$default(LayoutNode.kt:1136)
	at androidx.compose.ui.node.MeasureAndLayoutDelegate.doRemeasure-sdFAvZA(MeasureAndLayoutDelegate.kt:356)
	at androidx.compose.ui.node.MeasureAndLayoutDelegate.remeasureAndRelayoutIfNeeded(MeasureAndLayoutDelegate.kt:514)
	at androidx.compose.ui.node.MeasureAndLayoutDelegate.onlyRemeasureIfScheduled(MeasureAndLayoutDelegate.kt:598)
	at androidx.compose.ui.node.MeasureAndLayoutDelegate.forceMeasureTheSubtreeInternal(MeasureAndLayoutDelegate.kt:624)
	at androidx.compose.ui.node.MeasureAndLayoutDelegate.forceMeasureTheSubtreeInternal(MeasureAndLayoutDelegate.kt:631)
	at androidx.compose.ui.node.MeasureAndLayoutDelegate.forceMeasureTheSubtree(MeasureAndLayoutDelegate.kt:587)
	at androidx.compose.ui.node.RootNodeOwner$OwnerImpl.forceMeasureTheSubtree(RootNodeOwner.skiko.kt:308)
	at androidx.compose.ui.node.Owner.forceMeasureTheSubtree$default(Owner.kt:239)
	at androidx.compose.ui.node.LayoutNodeLayoutDelegate$MeasurePassDelegate.remeasure-BRTryo0(LayoutNodeLayoutDelegate.kt:632)
	at androidx.compose.ui.node.LayoutNodeLayoutDelegate$MeasurePassDelegate.measure-BRTryo0(LayoutNodeLayoutDelegate.kt:596)
	at org.jetbrains.compose.splitpane.DesktopSplitPaneKt$SplitPane$5.measure-3p2s80s(DesktopSplitPane.kt:100)
	at androidx.compose.ui.node.InnerNodeCoordinator.measure-BRTryo0(InnerNodeCoordinator.kt:126)
	at androidx.compose.ui.node.LayoutNodeLayoutDelegate$performMeasureBlock$1.invoke(LayoutNodeLayoutDelegate.kt:252)
	at androidx.compose.ui.node.LayoutNodeLayoutDelegate$performMeasureBlock$1.invoke(LayoutNodeLayoutDelegate.kt:251)
	at androidx.compose.runtime.snapshots.Snapshot$Companion.observe(Snapshot.kt:2304)
	at androidx.compose.runtime.snapshots.SnapshotStateObserver$ObservedScopeMap.observe(SnapshotStateObserver.kt:504)
	at androidx.compose.runtime.snapshots.SnapshotStateObserver.observeReads(SnapshotStateObserver.kt:260)
	at androidx.compose.ui.node.OwnerSnapshotObserver.observeReads$ui(OwnerSnapshotObserver.kt:133)
	at androidx.compose.ui.node.OwnerSnapshotObserver.observeMeasureSnapshotReads$ui(OwnerSnapshotObserver.kt:113)
	at androidx.compose.ui.node.LayoutNodeLayoutDelegate.performMeasure-BRTryo0(LayoutNodeLayoutDelegate.kt:1617)
	at androidx.compose.ui.node.LayoutNodeLayoutDelegate.access$performMeasure-BRTryo0(LayoutNodeLayoutDelegate.kt:36)
	at androidx.compose.ui.node.LayoutNodeLayoutDelegate$MeasurePassDelegate.remeasure-BRTryo0(LayoutNodeLayoutDelegate.kt:620)
	at androidx.compose.ui.node.LayoutNode.remeasure-_Sx5XlM$ui(LayoutNode.kt:1145)
	at androidx.compose.ui.node.LayoutNode.remeasure-_Sx5XlM$ui$default(LayoutNode.kt:1136)
	at androidx.compose.ui.node.MeasureAndLayoutDelegate.doRemeasure-sdFAvZA(MeasureAndLayoutDelegate.kt:356)
	at androidx.compose.ui.node.MeasureAndLayoutDelegate.remeasureAndRelayoutIfNeeded(MeasureAndLayoutDelegate.kt:514)
	at androidx.compose.ui.node.MeasureAndLayoutDelegate.onlyRemeasureIfScheduled(MeasureAndLayoutDelegate.kt:598)
	at androidx.compose.ui.node.MeasureAndLayoutDelegate.forceMeasureTheSubtreeInternal(MeasureAndLayoutDelegate.kt:624)
	at androidx.compose.ui.node.MeasureAndLayoutDelegate.forceMeasureTheSubtree(MeasureAndLayoutDelegate.kt:587)
	at androidx.compose.ui.node.RootNodeOwner$OwnerImpl.forceMeasureTheSubtree(RootNodeOwner.skiko.kt:308)
	at androidx.compose.ui.node.Owner.forceMeasureTheSubtree$default(Owner.kt:239)
	at androidx.compose.ui.node.LayoutNodeLayoutDelegate$MeasurePassDelegate.remeasure-BRTryo0(LayoutNodeLayoutDelegate.kt:632)
	at androidx.compose.ui.node.LayoutNodeLayoutDelegate$MeasurePassDelegate.measure-BRTryo0(LayoutNodeLayoutDelegate.kt:596)
	at org.jetbrains.compose.splitpane.DesktopSplitPaneKt$SplitPane$5.measure-3p2s80s(DesktopSplitPane.kt:100)
	at androidx.compose.ui.node.InnerNodeCoordinator.measure-BRTryo0(InnerNodeCoordinator.kt:126)
	at androidx.compose.ui.node.LayoutNodeLayoutDelegate$performMeasureBlock$1.invoke(LayoutNodeLayoutDelegate.kt:252)
	at androidx.compose.ui.node.LayoutNodeLayoutDelegate$performMeasureBlock$1.invoke(LayoutNodeLayoutDelegate.kt:251)
	at androidx.compose.runtime.snapshots.Snapshot$Companion.observe(Snapshot.kt:2304)
	at androidx.compose.runtime.snapshots.SnapshotStateObserver$ObservedScopeMap.observe(SnapshotStateObserver.kt:504)
	at androidx.compose.runtime.snapshots.SnapshotStateObserver.observeReads(SnapshotStateObserver.kt:260)
	at androidx.compose.ui.node.OwnerSnapshotObserver.observeReads$ui(OwnerSnapshotObserver.kt:133)
	at androidx.compose.ui.node.OwnerSnapshotObserver.observeMeasureSnapshotReads$ui(OwnerSnapshotObserver.kt:113)
	at androidx.compose.ui.node.LayoutNodeLayoutDelegate.performMeasure-BRTryo0(LayoutNodeLayoutDelegate.kt:1617)
	at androidx.compose.ui.node.LayoutNodeLayoutDelegate.access$performMeasure-BRTryo0(LayoutNodeLayoutDelegate.kt:36)
	at androidx.compose.ui.node.LayoutNodeLayoutDelegate$MeasurePassDelegate.remeasure-BRTryo0(LayoutNodeLayoutDelegate.kt:620)
	at androidx.compose.ui.node.LayoutNode.remeasure-_Sx5XlM$ui(LayoutNode.kt:1145)
	at androidx.compose.ui.node.LayoutNode.remeasure-_Sx5XlM$ui$default(LayoutNode.kt:1136)
	at androidx.compose.ui.node.MeasureAndLayoutDelegate.doRemeasure-sdFAvZA(MeasureAndLayoutDelegate.kt:356)
	at androidx.compose.ui.node.MeasureAndLayoutDelegate.remeasureAndRelayoutIfNeeded(MeasureAndLayoutDelegate.kt:514)
	at androidx.compose.ui.node.MeasureAndLayoutDelegate.remeasureAndRelayoutIfNeeded$default(MeasureAndLayoutDelegate.kt:491)
	at androidx.compose.ui.node.MeasureAndLayoutDelegate.measureAndLayout(MeasureAndLayoutDelegate.kt:377)
	at androidx.compose.ui.node.RootNodeOwner$OwnerImpl.measureAndLayout(RootNodeOwner.skiko.kt:290)
	at androidx.compose.ui.node.RootNodeOwner.measureAndLayout(RootNodeOwner.skiko.kt:187)
	at androidx.compose.ui.scene.MultiLayerComposeSceneImpl.measureAndLayout(MultiLayerComposeScene.skiko.kt:247)
	at androidx.compose.ui.scene.BaseComposeScene.doLayout(BaseComposeScene.skiko.kt:225)
	at androidx.compose.ui.scene.BaseComposeScene.access$doLayout(BaseComposeScene.skiko.kt:51)
	at androidx.compose.ui.scene.BaseComposeScene.render(BaseComposeScene.skiko.kt:164)
	at androidx.compose.ui.scene.ComposeSceneMediator$DesktopSkikoView.onRender(ComposeSceneMediator.desktop.kt:522)
	at org.jetbrains.skiko.SkiaLayer.update$skiko(SkiaLayer.awt.kt:548)
	at org.jetbrains.skiko.redrawer.AWTRedrawer.update(AWTRedrawer.kt:54)
	at org.jetbrains.skiko.redrawer.MetalRedrawer$frameDispatcher$1.invokeSuspend(MetalRedrawer.kt:82)
	at org.jetbrains.skiko.redrawer.MetalRedrawer$frameDispatcher$1.invoke(MetalRedrawer.kt)
	at org.jetbrains.skiko.redrawer.MetalRedrawer$frameDispatcher$1.invoke(MetalRedrawer.kt)
	at org.jetbrains.skiko.FrameDispatcher$job$1.invokeSuspend(FrameDispatcher.kt:33)
	at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
	at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:108)
	at java.desktop/java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:318)
	at java.desktop/java.awt.EventQueue.dispatchEventImpl(EventQueue.java:773)
	at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:720)
	at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:714)
	at java.base/java.security.AccessController.doPrivileged(AccessController.java:399)
	at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:86)
	at java.desktop/java.awt.EventQueue.dispatchEvent(EventQueue.java:742)
	at java.desktop/java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:203)
	at java.desktop/java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:124)
	at java.desktop/java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:113)
	at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:109)
	at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:101)
	at java.desktop/java.awt.EventDispatchThread.run(EventDispatchThread.java:90)
	Suppressed: kotlinx.coroutines.internal.DiagnosticCoroutineContextException: [StandaloneCoroutine{Cancelling}@3a24894b, SwingDispatcher@773f7baa]

material Snackbar only showed once when Koalaplot is added to project

First of all thanks for the great work on Koalaplot, i love it!.

i've had this wiered behaviour with snackbar when koalaplot library is added to the project, the snackbar showes only once and cannot be shown the second time calling 'showsnackbar' function.

effected targets:

  • iOS (Material 2 & 3)
  • Desktop (Material 3)

here are the steps to reproduce the issue:

  1. Create a new compose multiplatform project using: https://kmp.jetbrains.com/
  2. Replace the code in App.kt in 'commonmain'
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.material.*
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import kotlinx.coroutines.launch

@Composable
fun App() {
    MaterialTheme {
        val snackbarHostState = remember { SnackbarHostState() }
        val scope = rememberCoroutineScope()
        var x by remember { mutableStateOf(1) }
        Scaffold(modifier = Modifier,
            snackbarHost = { SnackbarHost(snackbarHostState) }) {
            Column(Modifier.fillMaxWidth(), horizontalAlignment = Alignment.CenterHorizontally) {
                Button(onClick = {
                    scope.launch {
                        snackbarHostState.showSnackbar("Snackbar shown this many times: $x")
                        x++
                    }
                }) {
                    Text("Show snackbar!")
                }
            }
        }
    }
}
  1. Add Koalaplot library to build.gradle.kts and sync
  2. If you run the app on one of the effected targets snackbar will only be shown the first time.

if you remove the koalaplot library and sync then run the snackbar will be shown normally.

Migrate to material 3

Right now MaterialTheme references material 2, would probably be a good idea to switch to material 3.

Horizontal bar chart

Please vote for this issue by adding a ๐Ÿ‘ to help prioritize new features.

Crash with intrinsic measurements

I'm assuming inside the chart library you use Subcompose? Is there a recommended way to use the charts inside of a widget that grows to match its parent? (Flow layouts, lists, etc).

Using it inside a flow layout produces the following:

java.lang.IllegalStateException: Asking for intrinsic measurements of SubcomposeLayout layouts is not supported. This includes components that are built on top of SubcomposeLayout, such as lazy lists, BoxWithConstraints, TabRow, etc

VerticalBarPlot does not update if xData / yData lists change

Hi! And thanks for your Compose Multiplatform graph library, it's been great for rendering graphs on my Android/iOS app!

I have a view where the user can cycle through different periods, and I update the rendered data directly from old data to new data, retaining the same composable renderers. I noticed that while updating data, the graph would just keep on showing the old values. I traced the problem to the file io.github.koalaplot.core.bar.VerticalBarPlot.kt, line 113:

@Composable
public fun <X, Y, E : VerticalBarPlotEntry<X, Y>> XYGraphScope<X, Y>.VerticalBarPlot(
    data: List<E>,
    modifier: Modifier = Modifier,
    bar: @Composable BarScope.(index: Int) -> Unit,
    barWidth: Float = 0.9f,
    animationSpec: AnimationSpec<Float> = KoalaPlotTheme.animationSpec
) {
    val dataAdapter = remember {
        EntryToGroupedEntryListAdapter(data)
    }

    // Delegate to the GroupedVerticalBarPlot - non-grouped is like grouped but with only 1 group per x-axis position
    GroupedVerticalBarPlot(
    ...
    )
}

There, the dataAdapter initialization should be changed to val dataAdapter = remember(data) { ... } so that it is updated when the underlying data changes. Or at least by duplicating your code structure and changing that fixed the issue for me...

Support Scroll Axis

I have tried several chart libraries on android but I didn't find the horizontal scroll axis feature like in the video, really appreciate if there is such a feature in this library

RPReplay_Final1666345044.MP4

Data in plot is not displayed in Compose preview

code:

    XYGraph(
        rememberLinearAxisModel(data.autoScaleXRange()),
        rememberLinearAxisModel(data.autoScaleYRange())
    ) {
        LinePlot(
            data,
            lineStyle = LineStyle(SolidColor(Color.Blue))
        )
    }

Desktop app:

image

Desktop @Preview:
image

Request for in repository samples

It would be valuable to have snippets & tiny samples directly available in the repository and help on the features discoverability

Exception thrown for XYGraph: Minimum tick spacing must be greater than 0 and less than or equal to 1

I got an exception when trying to display a XYGraph. I thought it was related to empty data, so I ensure there are some data but still in vain. How to avoid errors to display the chart correctly?

Version: 0.5.2
Target Platform: Desktop

Stacktrace:

Exception in thread "AWT-EventQueue-0" java.lang.IllegalArgumentException: Minimum tick spacing must be greater than 0 and less than or equal to 1
	at io.github.koalaplot.core.xygraph.LinearAxisModel.computeMajorTickSpacing(LinearAxisModel.kt:104)
	at io.github.koalaplot.core.xygraph.LinearAxisModel.computeMajorTickValues(LinearAxisModel.kt:74)
	at io.github.koalaplot.core.xygraph.LinearAxisModel.computeTickValues-0680j_4(LinearAxisModel.kt:92)
	at io.github.koalaplot.core.xygraph.AxisDelegate$Companion.createAxis-eqLRuRQ(AxisDelegate.kt:95)
	at io.github.koalaplot.core.xygraph.AxisDelegate$Companion.createVerticalAxis-wH6b6FI(AxisDelegate.kt:82)
	at io.github.koalaplot.core.xygraph.XYGraphKt$XYGraph$1$1.invoke-0kLqBqw(XYGraph.kt:119)
	at io.github.koalaplot.core.xygraph.XYGraphKt$XYGraph$1$1.invoke(XYGraph.kt:98)
	at androidx.compose.ui.layout.LayoutNodeSubcompositionsState$createMeasurePolicy$1.measure-3p2s80s(SubcomposeLayout.kt:709)
	at androidx.compose.ui.node.InnerNodeCoordinator.measure-BRTryo0(InnerNodeCoordinator.kt:126)
	at androidx.compose.ui.node.LayoutNodeLayoutDelegate$performMeasureBlock$1.invoke(LayoutNodeLayoutDelegate.kt:252)
	at androidx.compose.ui.node.LayoutNodeLayoutDelegate$performMeasureBlock$1.invoke(LayoutNodeLayoutDelegate.kt:251)
	at androidx.compose.runtime.snapshots.Snapshot$Companion.observe(Snapshot.kt:2304)
	at androidx.compose.runtime.snapshots.SnapshotStateObserver$ObservedScopeMap.observe(SnapshotStateObserver.kt:504)
	at androidx.compose.runtime.snapshots.SnapshotStateObserver.observeReads(SnapshotStateObserver.kt:260)
	at androidx.compose.ui.node.OwnerSnapshotObserver.observeReads$ui(OwnerSnapshotObserver.kt:133)
	at androidx.compose.ui.node.OwnerSnapshotObserver.observeMeasureSnapshotReads$ui(OwnerSnapshotObserver.kt:113)
	at androidx.compose.ui.node.LayoutNodeLayoutDelegate.performMeasure-BRTryo0(LayoutNodeLayoutDelegate.kt:1617)
	at androidx.compose.ui.node.LayoutNodeLayoutDelegate.access$performMeasure-BRTryo0(LayoutNodeLayoutDelegate.kt:36)
	at androidx.compose.ui.node.LayoutNodeLayoutDelegate$MeasurePassDelegate.remeasure-BRTryo0(LayoutNodeLayoutDelegate.kt:620)
	at androidx.compose.ui.node.LayoutNodeLayoutDelegate$MeasurePassDelegate.measure-BRTryo0(LayoutNodeLayoutDelegate.kt:596)
	at androidx.compose.foundation.layout.BoxMeasurePolicy.measure-3p2s80s(Box.kt:122)
	at androidx.compose.ui.node.InnerNodeCoordinator.measure-BRTryo0(InnerNodeCoordinator.kt:126)
	at androidx.compose.ui.node.LayoutNodeLayoutDelegate$performMeasureBlock$1.invoke(LayoutNodeLayoutDelegate.kt:252)
	at androidx.compose.ui.node.LayoutNodeLayoutDelegate$performMeasureBlock$1.invoke(LayoutNodeLayoutDelegate.kt:251)
	at androidx.compose.runtime.snapshots.Snapshot$Companion.observe(Snapshot.kt:2304)
	at androidx.compose.runtime.snapshots.SnapshotStateObserver$ObservedScopeMap.observe(SnapshotStateObserver.kt:504)
	at androidx.compose.runtime.snapshots.SnapshotStateObserver.observeReads(SnapshotStateObserver.kt:260)
	at androidx.compose.ui.node.OwnerSnapshotObserver.observeReads$ui(OwnerSnapshotObserver.kt:133)
	at androidx.compose.ui.node.OwnerSnapshotObserver.observeMeasureSnapshotReads$ui(OwnerSnapshotObserver.kt:113)
	at androidx.compose.ui.node.LayoutNodeLayoutDelegate.performMeasure-BRTryo0(LayoutNodeLayoutDelegate.kt:1617)
	at androidx.compose.ui.node.LayoutNodeLayoutDelegate.access$performMeasure-BRTryo0(LayoutNodeLayoutDelegate.kt:36)
	at androidx.compose.ui.node.LayoutNodeLayoutDelegate$MeasurePassDelegate.remeasure-BRTryo0(LayoutNodeLayoutDelegate.kt:620)
	at androidx.compose.ui.node.LayoutNodeLayoutDelegate$MeasurePassDelegate.measure-BRTryo0(LayoutNodeLayoutDelegate.kt:596)
	at io.github.koalaplot.core.util.HoverableElementAreaKt$HoverableElementArea$2$1.measure-3p2s80s(HoverableElementArea.kt:85)
	at androidx.compose.ui.node.InnerNodeCoordinator.measure-BRTryo0(InnerNodeCoordinator.kt:126)
	at androidx.compose.ui.node.LayoutNodeLayoutDelegate$performMeasureBlock$1.invoke(LayoutNodeLayoutDelegate.kt:252)
	at androidx.compose.ui.node.LayoutNodeLayoutDelegate$performMeasureBlock$1.invoke(LayoutNodeLayoutDelegate.kt:251)
	at androidx.compose.runtime.snapshots.Snapshot$Companion.observe(Snapshot.kt:2304)
	at androidx.compose.runtime.snapshots.SnapshotStateObserver$ObservedScopeMap.observe(SnapshotStateObserver.kt:504)
	at androidx.compose.runtime.snapshots.SnapshotStateObserver.observeReads(SnapshotStateObserver.kt:260)
	at androidx.compose.ui.node.OwnerSnapshotObserver.observeReads$ui(OwnerSnapshotObserver.kt:133)
	at androidx.compose.ui.node.OwnerSnapshotObserver.observeMeasureSnapshotReads$ui(OwnerSnapshotObserver.kt:113)
	at androidx.compose.ui.node.LayoutNodeLayoutDelegate.performMeasure-BRTryo0(LayoutNodeLayoutDelegate.kt:1617)
	at androidx.compose.ui.node.LayoutNodeLayoutDelegate.access$performMeasure-BRTryo0(LayoutNodeLayoutDelegate.kt:36)
	at androidx.compose.ui.node.LayoutNodeLayoutDelegate$MeasurePassDelegate.remeasure-BRTryo0(LayoutNodeLayoutDelegate.kt:620)
	at androidx.compose.ui.node.LayoutNodeLayoutDelegate$MeasurePassDelegate.measure-BRTryo0(LayoutNodeLayoutDelegate.kt:596)
	at androidx.compose.foundation.layout.BoxMeasurePolicy.measure-3p2s80s(Box.kt:122)
	at androidx.compose.ui.node.InnerNodeCoordinator.measure-BRTryo0(InnerNodeCoordinator.kt:126)
	at androidx.compose.ui.node.LayoutNodeLayoutDelegate$performMeasureBlock$1.invoke(LayoutNodeLayoutDelegate.kt:252)
	at androidx.compose.ui.node.LayoutNodeLayoutDelegate$performMeasureBlock$1.invoke(LayoutNodeLayoutDelegate.kt:251)
	at androidx.compose.runtime.snapshots.Snapshot$Companion.observe(Snapshot.kt:2304)
	at androidx.compose.runtime.snapshots.SnapshotStateObserver$ObservedScopeMap.observe(SnapshotStateObserver.kt:504)
	at androidx.compose.runtime.snapshots.SnapshotStateObserver.observeReads(SnapshotStateObserver.kt:260)
	at androidx.compose.ui.node.OwnerSnapshotObserver.observeReads$ui(OwnerSnapshotObserver.kt:133)
	at androidx.compose.ui.node.OwnerSnapshotObserver.observeMeasureSnapshotReads$ui(OwnerSnapshotObserver.kt:113)
	at androidx.compose.ui.node.LayoutNodeLayoutDelegate.performMeasure-BRTryo0(LayoutNodeLayoutDelegate.kt:1617)
	at androidx.compose.ui.node.LayoutNodeLayoutDelegate.access$performMeasure-BRTryo0(LayoutNodeLayoutDelegate.kt:36)
	at androidx.compose.ui.node.LayoutNodeLayoutDelegate$MeasurePassDelegate.remeasure-BRTryo0(LayoutNodeLayoutDelegate.kt:620)
	at androidx.compose.ui.node.LayoutNode.remeasure-_Sx5XlM$ui(LayoutNode.kt:1145)
	at androidx.compose.ui.node.LayoutNode.remeasure-_Sx5XlM$ui$default(LayoutNode.kt:1136)
	at androidx.compose.ui.node.MeasureAndLayoutDelegate.doRemeasure-sdFAvZA(MeasureAndLayoutDelegate.kt:356)
	at androidx.compose.ui.node.MeasureAndLayoutDelegate.remeasureAndRelayoutIfNeeded(MeasureAndLayoutDelegate.kt:514)
	at androidx.compose.ui.node.MeasureAndLayoutDelegate.onlyRemeasureIfScheduled(MeasureAndLayoutDelegate.kt:598)
	at androidx.compose.ui.node.MeasureAndLayoutDelegate.forceMeasureTheSubtreeInternal(MeasureAndLayoutDelegate.kt:624)
	at androidx.compose.ui.node.MeasureAndLayoutDelegate.forceMeasureTheSubtreeInternal(MeasureAndLayoutDelegate.kt:631)
	at androidx.compose.ui.node.MeasureAndLayoutDelegate.forceMeasureTheSubtreeInternal(MeasureAndLayoutDelegate.kt:631)
	at androidx.compose.ui.node.MeasureAndLayoutDelegate.forceMeasureTheSubtreeInternal(MeasureAndLayoutDelegate.kt:631)
	at androidx.compose.ui.node.MeasureAndLayoutDelegate.forceMeasureTheSubtreeInternal(MeasureAndLayoutDelegate.kt:631)
	at androidx.compose.ui.node.MeasureAndLayoutDelegate.forceMeasureTheSubtreeInternal(MeasureAndLayoutDelegate.kt:631)
	at androidx.compose.ui.node.MeasureAndLayoutDelegate.forceMeasureTheSubtree(MeasureAndLayoutDelegate.kt:587)
	at androidx.compose.ui.node.RootNodeOwner$OwnerImpl.forceMeasureTheSubtree(RootNodeOwner.skiko.kt:308)
	at androidx.compose.ui.node.Owner.forceMeasureTheSubtree$default(Owner.kt:239)
	at androidx.compose.ui.node.LayoutNodeLayoutDelegate$MeasurePassDelegate.remeasure-BRTryo0(LayoutNodeLayoutDelegate.kt:632)
	at androidx.compose.ui.node.LayoutNodeLayoutDelegate$MeasurePassDelegate.measure-BRTryo0(LayoutNodeLayoutDelegate.kt:596)
	at org.jetbrains.compose.splitpane.DesktopSplitPaneKt$SplitPane$5.measure-3p2s80s(DesktopSplitPane.kt:100)
	at androidx.compose.ui.node.InnerNodeCoordinator.measure-BRTryo0(InnerNodeCoordinator.kt:126)
	at androidx.compose.ui.node.LayoutNodeLayoutDelegate$performMeasureBlock$1.invoke(LayoutNodeLayoutDelegate.kt:252)
	at androidx.compose.ui.node.LayoutNodeLayoutDelegate$performMeasureBlock$1.invoke(LayoutNodeLayoutDelegate.kt:251)
	at androidx.compose.runtime.snapshots.Snapshot$Companion.observe(Snapshot.kt:2304)
	at androidx.compose.runtime.snapshots.SnapshotStateObserver$ObservedScopeMap.observe(SnapshotStateObserver.kt:504)
	at androidx.compose.runtime.snapshots.SnapshotStateObserver.observeReads(SnapshotStateObserver.kt:260)
	at androidx.compose.ui.node.OwnerSnapshotObserver.observeReads$ui(OwnerSnapshotObserver.kt:133)
	at androidx.compose.ui.node.OwnerSnapshotObserver.observeMeasureSnapshotReads$ui(OwnerSnapshotObserver.kt:113)
	at androidx.compose.ui.node.LayoutNodeLayoutDelegate.performMeasure-BRTryo0(LayoutNodeLayoutDelegate.kt:1617)
	at androidx.compose.ui.node.LayoutNodeLayoutDelegate.access$performMeasure-BRTryo0(LayoutNodeLayoutDelegate.kt:36)
	at androidx.compose.ui.node.LayoutNodeLayoutDelegate$MeasurePassDelegate.remeasure-BRTryo0(LayoutNodeLayoutDelegate.kt:620)
	at androidx.compose.ui.node.LayoutNode.remeasure-_Sx5XlM$ui(LayoutNode.kt:1145)
	at androidx.compose.ui.node.LayoutNode.remeasure-_Sx5XlM$ui$default(LayoutNode.kt:1136)
	at androidx.compose.ui.node.MeasureAndLayoutDelegate.doRemeasure-sdFAvZA(MeasureAndLayoutDelegate.kt:356)
	at androidx.compose.ui.node.MeasureAndLayoutDelegate.remeasureAndRelayoutIfNeeded(MeasureAndLayoutDelegate.kt:514)
	at androidx.compose.ui.node.MeasureAndLayoutDelegate.onlyRemeasureIfScheduled(MeasureAndLayoutDelegate.kt:598)
	at androidx.compose.ui.node.MeasureAndLayoutDelegate.forceMeasureTheSubtreeInternal(MeasureAndLayoutDelegate.kt:624)
	at androidx.compose.ui.node.MeasureAndLayoutDelegate.forceMeasureTheSubtree(MeasureAndLayoutDelegate.kt:587)
	at androidx.compose.ui.node.RootNodeOwner$OwnerImpl.forceMeasureTheSubtree(RootNodeOwner.skiko.kt:308)
	at androidx.compose.ui.node.Owner.forceMeasureTheSubtree$default(Owner.kt:239)
	at androidx.compose.ui.node.LayoutNodeLayoutDelegate$MeasurePassDelegate.remeasure-BRTryo0(LayoutNodeLayoutDelegate.kt:632)
	at androidx.compose.ui.node.LayoutNodeLayoutDelegate$MeasurePassDelegate.measure-BRTryo0(LayoutNodeLayoutDelegate.kt:596)
	at org.jetbrains.compose.splitpane.DesktopSplitPaneKt$SplitPane$5.measure-3p2s80s(DesktopSplitPane.kt:100)
	at androidx.compose.ui.node.InnerNodeCoordinator.measure-BRTryo0(InnerNodeCoordinator.kt:126)
	at androidx.compose.ui.node.LayoutNodeLayoutDelegate$performMeasureBlock$1.invoke(LayoutNodeLayoutDelegate.kt:252)
	at androidx.compose.ui.node.LayoutNodeLayoutDelegate$performMeasureBlock$1.invoke(LayoutNodeLayoutDelegate.kt:251)
	at androidx.compose.runtime.snapshots.Snapshot$Companion.observe(Snapshot.kt:2304)
	at androidx.compose.runtime.snapshots.SnapshotStateObserver$ObservedScopeMap.observe(SnapshotStateObserver.kt:504)
	at androidx.compose.runtime.snapshots.SnapshotStateObserver.observeReads(SnapshotStateObserver.kt:260)
	at androidx.compose.ui.node.OwnerSnapshotObserver.observeReads$ui(OwnerSnapshotObserver.kt:133)
	at androidx.compose.ui.node.OwnerSnapshotObserver.observeMeasureSnapshotReads$ui(OwnerSnapshotObserver.kt:113)
	at androidx.compose.ui.node.LayoutNodeLayoutDelegate.performMeasure-BRTryo0(LayoutNodeLayoutDelegate.kt:1617)
	at androidx.compose.ui.node.LayoutNodeLayoutDelegate.access$performMeasure-BRTryo0(LayoutNodeLayoutDelegate.kt:36)
	at androidx.compose.ui.node.LayoutNodeLayoutDelegate$MeasurePassDelegate.remeasure-BRTryo0(LayoutNodeLayoutDelegate.kt:620)
	at androidx.compose.ui.node.LayoutNode.remeasure-_Sx5XlM$ui(LayoutNode.kt:1145)
	at androidx.compose.ui.node.LayoutNode.remeasure-_Sx5XlM$ui$default(LayoutNode.kt:1136)
	at androidx.compose.ui.node.MeasureAndLayoutDelegate.doRemeasure-sdFAvZA(MeasureAndLayoutDelegate.kt:356)
	at androidx.compose.ui.node.MeasureAndLayoutDelegate.remeasureAndRelayoutIfNeeded(MeasureAndLayoutDelegate.kt:514)
	at androidx.compose.ui.node.MeasureAndLayoutDelegate.remeasureAndRelayoutIfNeeded$default(MeasureAndLayoutDelegate.kt:491)
	at androidx.compose.ui.node.MeasureAndLayoutDelegate.measureAndLayout(MeasureAndLayoutDelegate.kt:377)
	at androidx.compose.ui.node.RootNodeOwner$OwnerImpl.measureAndLayout(RootNodeOwner.skiko.kt:290)
	at androidx.compose.ui.node.RootNodeOwner.measureAndLayout(RootNodeOwner.skiko.kt:187)
	at androidx.compose.ui.scene.MultiLayerComposeSceneImpl.measureAndLayout(MultiLayerComposeScene.skiko.kt:247)
	at androidx.compose.ui.scene.BaseComposeScene.doLayout(BaseComposeScene.skiko.kt:225)
	at androidx.compose.ui.scene.BaseComposeScene.access$doLayout(BaseComposeScene.skiko.kt:51)
	at androidx.compose.ui.scene.BaseComposeScene.render(BaseComposeScene.skiko.kt:164)
	at androidx.compose.ui.scene.ComposeSceneMediator$DesktopSkikoView.onRender(ComposeSceneMediator.desktop.kt:490)
	at org.jetbrains.skiko.SkiaLayer.update$skiko(SkiaLayer.awt.kt:548)
	at org.jetbrains.skiko.redrawer.AWTRedrawer.update(AWTRedrawer.kt:54)
	at org.jetbrains.skiko.redrawer.MetalRedrawer$frameDispatcher$1.invokeSuspend(MetalRedrawer.kt:82)
	at org.jetbrains.skiko.redrawer.MetalRedrawer$frameDispatcher$1.invoke(MetalRedrawer.kt)
	at org.jetbrains.skiko.redrawer.MetalRedrawer$frameDispatcher$1.invoke(MetalRedrawer.kt)
	at org.jetbrains.skiko.FrameDispatcher$job$1.invokeSuspend(FrameDispatcher.kt:33)
	at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
	at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:108)
	at java.desktop/java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:318)
	at java.desktop/java.awt.EventQueue.dispatchEventImpl(EventQueue.java:773)
	at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:720)
	at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:714)
	at java.base/java.security.AccessController.doPrivileged(AccessController.java:399)
	at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:86)
	at java.desktop/java.awt.EventQueue.dispatchEvent(EventQueue.java:742)
	at java.desktop/java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:203)
	at java.desktop/java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:124)
	at java.desktop/java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:113)
	at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:109)
	at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:101)
	at java.desktop/java.awt.EventDispatchThread.run(EventDispatchThread.java:90)
	Suppressed: kotlinx.coroutines.internal.DiagnosticCoroutineContextException: [StandaloneCoroutine{Cancelling}@570805d2, SwingDispatcher@6d583e10]

Reproducer:

ChartLayout(title = { AppText("Latencies over Time (95%)") }) {
    latenciesMsOverTime.takeIf { it.size >= 2 }?.let { latenciesMsOverTime ->
        XYGraph(
            xAxisModel = CategoryAxisModel(
                latenciesMsOverTime.keys.toList().ifEmpty { listOf(KInstant.now().toMilliseconds()) }),
            yAxisModel = LinearAxisModel(
                range = 0f..6000f,
            ),
            xAxisLabels = { KZonedInstant(it, KZoneOffset.local()).format("HH:mm:ss") },
            xAxisTitle = "Time",
            yAxisTitle = "Latency (ms)",
        ) {
            latenciesMsOverTime.forEach { (timestamp, result) ->
                DefaultPoint(timestamp, result.at95Percent)
            }
        }
    }
}

Boxplot

Please vote for this issue by adding a ๐Ÿ‘ to help prioritize new features.

Bar Plot graph generation animation from middle/zero

The graph generation animation in the bar plots currently always starts from the bottom of the graph.

This looks weird if the Y axis zero point is not at the bottom of the graph. For example if you want to show positive and negative values, with the bars attaching to 0.

It would be great if we could set the Y position the bars are built up/down from.

Support "hoverable" for mobile targets as well

I really dig the hoverable functionality on desktop. It would be sweet if something similar was available for Android and iOS.

Im not sure which approach is most fitting for mobile, but I do love the tactile feeling of scrubbing through a graph and immediately seeing the closest value highlighted - either just above my finger, or at the TopCenter of the graph.

VerticalBarChart Crash: Cannot round NaN value.

This seems to happen when I have bars with very low values, like 0 or 1? not sure, trying to narrow it down.

Exception in thread "AWT-EventQueue-0" java.lang.IllegalArgumentException: Cannot round NaN value.
	at kotlin.math.MathKt__MathJVMKt.roundToInt(MathJVM.kt:1165)
	at io.github.koalaplot.core.bar.VerticalBarChartKt$VerticalBarChart$4$measure$1.invoke(VerticalBarChart.kt:183)
	at io.github.koalaplot.core.bar.VerticalBarChartKt$VerticalBarChart$4$measure$1.invoke(VerticalBarChart.kt:164)
	at androidx.compose.ui.layout.MeasureScope$layout$1.placeChildren(MeasureScope.kt:70)

Pie chart crash

If you have a pie chart where every item has a value of zero, it will crash.

Can't find a lot of new classes

I'm seeing a bunch of ReplaceWith though the class it wants me to change to doesn't seem to exist

Example:

@Deprecated("Use BarPlotEntry", ReplaceWith("BarPlotEntry"))

However if I search the codebase for BarPlotEntry (https://github.com/search?q=repo%3AKoalaPlot%2Fkoalaplot-core%20BarPlotEntry&type=code) it doesn't exist. There is VerticalBarPlotEntry which seems to the right one?

Theres a lot of these such as FloatStackedAreaPlotEntry (

* Floating point values, use [FloatStackedAreaPlotEntry].
) Search Results so i'm not sure if there are just some missing commits or what is happening here

There is also no implementation of StackedAreaPlotEntry, Float or otherwise

scrollable XYLine chart questionaire

Hi, i have pulled the sample and check on my android device. It seems great. The rainfall data looks great.

Also I want to know if there is any features of scrolling horizontally LineChart so when there is more data says for like 30 days. The ui may not look congested. Jan feb mar... seems congested. User will scroll horizontally and gap will be maintained to view full month.

also say if i have market price of 30 days which gives 30 data (not scrollable)
i want to show the month horizontally say jan1 jan5 feb15 feb30 (fixed) and load the plotting line in the middle for that 30 days price. Can we do this? Please provide the hint.

i mean to say the months can load like jan,apr,sep,dec (only 4 with the gap)and all plotting will be done inbetween.

val months =
listOf("Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec")

// if i change months to only size of 5 it crases array out of bound.

val rainfall = buildMap {
    put(
        "New York City",
        listOf(83.6, 78.8, 98.5, 93.4, 106.0, 84.5, 105.0, 104.3, 91.2, 83.5, 106.6, 92.3)
    )

Also, i wonder if there is official api documentation and features. Please provide the link.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.