Skip to content

Commit 5126e08

Browse files
Merge pull request #448 from Kotlin/with_data
Add `withData`
2 parents f11d660 + 4ac5394 commit 5126e08

File tree

11 files changed

+216
-6
lines changed

11 files changed

+216
-6
lines changed

docs/kd.tree

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@
5757
<toc-element topic="API.md">
5858
<toc-element topic="Plot-API.md"/>
5959
<toc-element toc-title="Data Manipulation">
60+
<toc-element topic="WithData-API.md"/>
6061
<toc-element topic="GroupBy-API.md"/>
6162
<toc-element toc-title="statistics">
6263
<toc-element topic="StatBin-API.md"/>

docs/topics/API.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
[layout](Layout-API.md)
1818
[tooltips](Tooltips-API.md)
1919
## Data manipulation
20+
[withData](WithData-API.md)
2021
[groupBy](GroupBy-API.md)
2122
### Statistics
2223
[statBin](StatBin-API.md)

docs/topics/Getting-Started.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,7 @@ providing a quick reference to assist you in building your visualizations.
161161
<list>
162162
<li>Data Manipulation
163163
<list>
164+
<li><a href="WithData-API.md">groupBy</a></li>
164165
<li><a href="GroupBy-API.md">groupBy</a></li>
165166
<li><a href="StatBin-API.md">statBin</a></li>
166167
<li><a href="StatDensity-API.md">statDensity</a></li>

docs/topics/apiRef/WithData-API.md

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
# withData
2+
3+
<tldr>
4+
<p><format style="bold" color="GoldenRod">
5+
withData&lt;<a href="#t"><format color="Blue">T</format></a>></format>(
6+
<a href="#dataset"><format style="bold" color="CadetBlue">dataset</format></a>:
7+
<emphasis>DataFrame&lt;T> | Map&lt;String, List&lt;*>></emphasis>) <format style="italic">{ this: DataFrameScope&lt;T> -></format></p>
8+
9+
<format style="italic">}</format>
10+
</tldr>
11+
12+
The `withData` function creates a new plotting context with a new provided [dataset](#dataset).
13+
All layers created in this context use this dataset.
14+
If `DataFrame` is provided as a dataset, you can access its columns in this context.
15+
16+
## Arguments
17+
18+
### T
19+
20+
<p>Type of DataFrame</p>
21+
22+
### dataset
23+
24+
<p>
25+
<format style="superscript" color="Red">Required</format>
26+
</p>
27+
<p>
28+
<format style="superscript" color="#E8488B">DataFrame&lt;T></format>
29+
<format style="superscript" color="#E8488B">Map&lt;String, List&lt;*>></format>
30+
</p>
31+
32+
<p>
33+
New dataset used for layers created in a new context.
34+
</p>

gradle/libs.versions.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ dataframe = "0.14.1"
1111
serialization = "1.6.3"
1212
datetime = "0.6.0"
1313
html = "0.11.0"
14-
statistics = "0.4.0-dev-7"
14+
statistics = "0.4.0-dev-8"
1515
letsPlot = "4.7.3"
1616
letsPlotImage = "4.3.3"
1717
mockk = "1.13.10"

kandy-api/src/main/kotlin/org/jetbrains/kotlinx/kandy/dsl/internal/MultiLayerPlotBuilder.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ public abstract class MultiLayerPlotBuilder internal constructor() : LayerCreato
5555
*
5656
* @return new dataset builder index in [datasetBuilders].
5757
*/
58+
@PublishedApi
5859
internal abstract fun addDataset(dataset: TableData, initialBuilder: DatasetBuilder? = null): Int
5960
internal abstract fun addEmptyDataset(): Int
60-
6161
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package org.jetbrains.kotlinx.kandy.dsl.internal
2+
3+
/**
4+
* Marks the DSL for creating and configuring plots within the Kandy library.
5+
*
6+
* The `PlotDslMarker` annotation is used to restrict the scope of DSL functions to prevent unintentional
7+
* interference between different DSL builders. By applying this marker, we ensure a clear and structured
8+
* separation of concerns within the DSL context, leading to safer and more predictable DSL designs.
9+
*
10+
* Now only works for `DataFramePlotBuilder.withData {}`
11+
*/
12+
@DslMarker
13+
internal annotation class PlotDslMarker

kandy-api/src/main/kotlin/org/jetbrains/kotlinx/kandy/dsl/internal/dataframe/DataFramePlotBuilder.kt

Lines changed: 33 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,10 @@ import org.jetbrains.kotlinx.dataframe.*
44
import org.jetbrains.kotlinx.dataframe.api.GroupBy
55
import org.jetbrains.kotlinx.dataframe.api.getColumns
66
import org.jetbrains.kotlinx.dataframe.api.groupBy
7+
import org.jetbrains.kotlinx.dataframe.api.toDataFrame
78
import org.jetbrains.kotlinx.dataframe.columns.ColumnReference
89
import org.jetbrains.kotlinx.kandy.dsl.internal.DatasetBuilder
10+
import org.jetbrains.kotlinx.kandy.dsl.internal.PlotDslMarker
911

1012
/**
1113
* Represents a standard plotting context initialized with a [DataFrame] as its primary dataset.
@@ -17,6 +19,7 @@ import org.jetbrains.kotlinx.kandy.dsl.internal.DatasetBuilder
1719
*
1820
* @param T the type of the DataFrame.
1921
*/
22+
@PlotDslMarker
2023
public class DataFramePlotBuilder<T> @PublishedApi internal constructor(
2124
@PublishedApi
2225
internal val dataFrame: DataFrame<T>,
@@ -39,11 +42,37 @@ public class DataFramePlotBuilder<T> @PublishedApi internal constructor(
3942
*/
4043
public fun <C> columns(vararg columns: String): List<AnyCol> = dataFrame.getColumns(*columns)
4144

45+
/**
46+
* Creates and initializes a new layer creator scope with the given dataframe as a dataset.
47+
*
48+
* @param dataFrame The DataFrame to be used as a dataset within the scope.
49+
* @param block layer creator scope with a new dataset.
50+
*/
51+
public inline fun <T> withData(
52+
dataFrame: DataFrame<T>,
53+
block: DataFrameScope<T>.() -> Unit
54+
) {
55+
DataFrameScope(dataFrame, this, addDataset(NamedData(dataFrame), null)).apply(block)
56+
}
57+
58+
/**
59+
* Creates and initializes a new layer creator scope with the given map as a dataset.
60+
*
61+
* @param map The map to be used as a dataset within the scope.
62+
* @param block layer creator scope with a new dataset.
63+
*/
64+
public inline fun withData(
65+
map: Map<String, List<*>>,
66+
block: DataFrameScope<*>.() -> Unit
67+
) {
68+
withData(map.toDataFrame(), block)
69+
}
70+
4271
/**
4372
* Creates and initializes a new context with the dataframe grouped by the specified column names.
4473
*
4574
* @param columns the column names to group the dataframe by.
46-
* @param block a lambda with receiver block that configures the new grouped context.
75+
* @param block layer creator scope with a new dataset.
4776
*/
4877
public inline fun groupBy(
4978
columns: Iterable<String>,
@@ -61,7 +90,7 @@ public class DataFramePlotBuilder<T> @PublishedApi internal constructor(
6190
* Creates and initializes a new context with the dataframe grouped by the specified column names.
6291
*
6392
* @param columns the column names to group the dataframe by.
64-
* @param block a lambda with receiver block that configures the new grouped context.
93+
* @param block layer creator scope with a new dataset.
6594
*/
6695
public inline fun groupBy(
6796
vararg columns: String,
@@ -72,7 +101,7 @@ public class DataFramePlotBuilder<T> @PublishedApi internal constructor(
72101
* Creates and initializes a new context with the dataframe grouped by the given column references.
73102
*
74103
* @param columnReferences references to the columns to group by.
75-
* @param block a lambda with receiver block that configures the new grouped context.
104+
* @param block layer creator scope with a new dataset.
76105
*/
77106
public inline fun groupBy(
78107
vararg columnReferences: ColumnReference<*>,
@@ -83,7 +112,7 @@ public class DataFramePlotBuilder<T> @PublishedApi internal constructor(
83112
* Creates and initializes a new context with the dataframe grouped by the given column references.
84113
*
85114
* @param columnReferences a list of references to the columns to group by.
86-
* @param block a lambda with receiver block that configures the new grouped context.
115+
* @param block layer creator scope with a new dataset.
87116
*/
88117
public inline fun groupBy(
89118
columnReferences: List<ColumnReference<*>>,
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
package org.jetbrains.kotlinx.kandy.dsl.internal.dataframe
2+
3+
import org.jetbrains.kotlinx.dataframe.ColumnsContainer
4+
import org.jetbrains.kotlinx.dataframe.DataFrame
5+
import org.jetbrains.kotlinx.kandy.dsl.internal.LayerCreatorScope
6+
import org.jetbrains.kotlinx.kandy.dsl.internal.MultiLayerPlotBuilder
7+
import org.jetbrains.kotlinx.kandy.dsl.internal.PlotDslMarker
8+
9+
/**
10+
* Represents a plot builder data scope with grouped dataset
11+
* created by [DataFramePlotBuilder.withData].
12+
*
13+
* @param T The type of the DataFrame.
14+
*/
15+
@PlotDslMarker
16+
public class DataFrameScope<T> @PublishedApi internal constructor(
17+
dataFrame: DataFrame<T>,
18+
override val plotBuilder: MultiLayerPlotBuilder,
19+
override val datasetIndex: Int,
20+
) : LayerCreatorScope(), ColumnsContainer<T> by dataFrame {
21+
override val layersInheritMappings: Boolean = false
22+
}

kandy-api/src/main/kotlin/org/jetbrains/kotlinx/kandy/dsl/internal/dataframe/MultiLayerPlotBuilderImpl.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import org.jetbrains.kotlinx.kandy.dsl.internal.MultiLayerPlotBuilder
66
import org.jetbrains.kotlinx.kandy.ir.data.TableData
77

88
public abstract class MultiLayerPlotBuilderImpl : MultiLayerPlotBuilder() {
9+
@PublishedApi
910
override fun addDataset(dataset: TableData, initialBuilder: DatasetBuilder?): Int {
1011
datasetBuilders.add(DatasetBuilderImpl(dataset, initialBuilder as DatasetBuilderImpl?))
1112
return datasetBuilders.lastIndex
Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
/*
2+
* Copyright 2020-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
3+
*/
4+
5+
package org.jetbrains.kotlinx.kandy.dsl
6+
7+
import org.jetbrains.kotlinx.dataframe.api.column
8+
import org.jetbrains.kotlinx.dataframe.api.toDataFrame
9+
import org.jetbrains.kotlinx.kandy.dsl.impl.*
10+
import org.jetbrains.kotlinx.kandy.dsl.internal.dataframe.NamedData
11+
import org.jetbrains.kotlinx.kandy.ir.Layer
12+
import org.jetbrains.kotlinx.kandy.ir.Plot
13+
import org.jetbrains.kotlinx.kandy.ir.bindings.NonPositionalMapping
14+
import org.jetbrains.kotlinx.kandy.ir.bindings.PositionalMapping
15+
import org.jetbrains.kotlinx.kandy.ir.scale.PositionalContinuousScale
16+
import org.jetbrains.kotlinx.kandy.util.color.Color
17+
import kotlin.test.Test
18+
import kotlin.test.assertEquals
19+
20+
class WithDataTest {
21+
22+
@Test
23+
fun withDataTest() {
24+
val datasetMain = mapOf(
25+
"x" to listOf(1.0, 2.0, 3.0),
26+
"y" to listOf(3F, 12F, 5.5F),
27+
).toDataFrame()
28+
val srcX = column<Double>("x")
29+
val srcY = column<Float>("y")
30+
31+
val datasetSecondary = mapOf(
32+
"width" to listOf(1.0, 2.0, 3.0, 3.0),
33+
"height" to listOf(3F, 12F, 5.5F, 8F),
34+
"type" to listOf("A", "B", "A", "B"),
35+
).toDataFrame()
36+
37+
val width = column<Double>("width")
38+
val height = column<Float>("height")
39+
val type = column<String>("type")
40+
41+
val plot = datasetMain.plot {
42+
x(srcX)
43+
points {
44+
y(srcY)
45+
}
46+
withData(datasetSecondary) {
47+
line {
48+
x(width)
49+
y(height) {
50+
scale = continuous(1f..15f)
51+
}
52+
color(type)
53+
}
54+
}
55+
}
56+
57+
assertEquals(
58+
Plot(
59+
listOf(NamedData(datasetMain), NamedData(datasetSecondary)),
60+
listOf(
61+
Layer(
62+
0,
63+
POINT,
64+
mappings = mapOf(
65+
Y to PositionalMapping<Float>(
66+
Y, srcY.name(), CommonPositionalMappingParametersContinuous()
67+
),
68+
),
69+
settings = emptyMap(),
70+
emptyMap(),
71+
emptyMap(),
72+
),
73+
Layer(
74+
1,
75+
LINE,
76+
mappings = mapOf(
77+
X to PositionalMapping<Double>(
78+
X, width.name(), CommonPositionalMappingParametersContinuous()
79+
),
80+
Y to PositionalMapping(
81+
Y, height.name(), CommonPositionalMappingParametersContinuous(
82+
PositionalContinuousScale(1f, 15f, null, null)
83+
)
84+
),
85+
COLOR to NonPositionalMapping<String, Color>(
86+
COLOR, type.name(), CommonNonPositionalMappingParametersContinuous()
87+
),
88+
),
89+
emptyMap(),
90+
emptyMap(),
91+
emptyMap(),
92+
inheritsBindings = false
93+
)
94+
),
95+
mapOf(
96+
X to PositionalMapping<Float>(
97+
X, srcX.name(), CommonPositionalMappingParametersContinuous()
98+
),
99+
),
100+
emptyMap(),
101+
emptyMap(),
102+
emptyMap()
103+
),
104+
plot
105+
)
106+
}
107+
}
108+

0 commit comments

Comments
 (0)