Skip to content

Commit 3194e30

Browse files
committed
Merge branch 'master' into unsupported-data-sources-examples
# Conflicts: # settings.gradle.kts
2 parents 2327777 + 521840e commit 3194e30

File tree

13 files changed

+215
-10
lines changed

13 files changed

+215
-10
lines changed

core/generated-sources/src/main/kotlin/org/jetbrains/kotlinx/dataframe/io/html.kt

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,14 @@ internal val formatter = DataFrameFormatter(
7777
internal fun getResources(vararg resource: String) = resource.joinToString(separator = "\n") { getResourceText(it) }
7878

7979
internal fun getResourceText(resource: String, vararg replacement: Pair<String, Any>): String {
80-
val res = DataFrame::class.java.getResourceAsStream(resource) ?: error("Resource '$resource' not found")
80+
/**
81+
* The choice of loader is crucial here: it should always be a class loaded by the same class loader as the resource we load.
82+
* I.e. [DataFrame] isn't a good fit because it might be loaded by Kotlin IDEA plugin (because Kotlin plugin
83+
* loads DataFrame compiler plugin), and plugin's classloader knows nothing about the resources.
84+
*/
85+
val loader = HtmlContent::class.java
86+
val res = loader.getResourceAsStream(resource)
87+
?: error("Resource '$resource' not found. Load was attempted by $loader, loaded by ${loader.classLoader}")
8188
var template = InputStreamReader(res).readText()
8289
replacement.forEach {
8390
template = template.replace(it.first, it.second.toString())

core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/io/html.kt

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,14 @@ internal val formatter = DataFrameFormatter(
7777
internal fun getResources(vararg resource: String) = resource.joinToString(separator = "\n") { getResourceText(it) }
7878

7979
internal fun getResourceText(resource: String, vararg replacement: Pair<String, Any>): String {
80-
val res = DataFrame::class.java.getResourceAsStream(resource) ?: error("Resource '$resource' not found")
80+
/**
81+
* The choice of loader is crucial here: it should always be a class loaded by the same class loader as the resource we load.
82+
* I.e. [DataFrame] isn't a good fit because it might be loaded by Kotlin IDEA plugin (because Kotlin plugin
83+
* loads DataFrame compiler plugin), and plugin's classloader knows nothing about the resources.
84+
*/
85+
val loader = HtmlContent::class.java
86+
val res = loader.getResourceAsStream(resource)
87+
?: error("Resource '$resource' not found. Load was attempted by $loader, loaded by ${loader.classLoader}")
8188
var template = InputStreamReader(res).readText()
8289
replacement.forEach {
8390
template = template.replace(it.first, it.second.toString())

docs/StardustDocs/topics/Compiler-Plugin.md

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,34 @@
11
# Kotlin DataFrame Compiler Plugin
22

3-
Kotlin DataFrame compiler plugin: available in Gradle projects, is coming to Kotlin Notebook and Maven projects soon.
3+
<web-summary>
4+
Explore the Kotlin DataFrame Compiler Plugin —
5+
a powerful tool providing on-the-fly type-safe column-accessors for dataframes.
6+
</web-summary>
47

5-
Check out this video that shows how expressions update the schema of a dataframe:
8+
<card-summary>
9+
Explore the Kotlin DataFrame Compiler Plugin —
10+
a powerful tool providing on-the-fly type-safe column-accessors for dataframes.
11+
</card-summary>
12+
13+
<link-summary>
14+
Explore the Kotlin DataFrame Compiler Plugin —
15+
a powerful tool providing on-the-fly type-safe column-accessors for dataframes.
16+
</link-summary>
17+
18+
19+
> Now available in Gradle projects, is coming soon to Kotlin Notebook and Maven projects.
20+
21+
**Kotlin DataFrame Compiler Plugin** is a Kotlin compiler plugin that automatically generates
22+
**[type-safe extension properties](extensionPropertiesApi.md)** for your dataframes,
23+
allowing you to access columns and row values in a type-safe way and avoid mistakes in column names.
624

25+
## Why use it?
26+
27+
- Access columns as regular properties: `df.name` instead of `df["name"]`.
28+
- Get full IDE and compiler support: autocompletion, refactoring, and type checking.
29+
- Improve code readability and safety when working with DataFrame.
30+
31+
Check out this video that shows how expressions update the schema of a dataframe:
732

833
<video src="compiler_plugin.mp4" controls=""/>
934

@@ -113,3 +138,9 @@ fun main() {
113138
```
114139

115140
[Learn more](dataSchema.md) about data schema declarations
141+
142+
## Examples
143+
144+
* [Kotlin DataFrame in the IntelliJ IDEA project example](https://github.com/Kotlin/dataframe/blob/master/examples/kotlin-dataframe-plugin-example)
145+
— an IntelliJ IDEA project showcasing simple DataFrame expressions using the Compiler Plugin.
146+
* [](compilerPluginExamples.md) — few examples of Compiler Plugin usages.

docs/StardustDocs/topics/Home.topic

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
<secondary>
2929
<title>Featured topics</title>
3030
<a href="Kotlin-DataFrame-Features-in-Kotlin-Notebook.md"/>
31+
<a href="Compiler-Plugin.md"/>
3132
<a href="readSqlDatabases.md"/>
3233
</secondary>
3334

docs/StardustDocs/topics/compilerPluginExamples.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@
33
This page provides a few examples that you can copy directly to your project.
44
[Schema info](staticInterpretation.md#schema-info) will be a convenient way to observe the result of different operations.
55

6+
> See also an [IntelliJ IDEA project example](https://github.com/Kotlin/dataframe/blob/master/examples/kotlin-dataframe-plugin-example),
7+
> showcasing simple DataFrame expressions using the Compiler Plugin.
8+
69
### Example 1
710

811
```kotlin

docs/StardustDocs/topics/guides/Guides-And-Examples.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,11 @@ Explore our structured, in-depth guides to steadily improve your Kotlin DataFram
5656

5757
Explore our extensive collection of practical examples and real-world analytics workflows.
5858

59+
* [Kotlin DataFrame Compiler Plugin Example](https://github.com/Kotlin/dataframe/blob/master/examples/kotlin-dataframe-plugin-example)
60+
— a simple project demonstrating the usage of the [compiler plugin](Compiler-Plugin.md),
61+
showcasing DataFrame expressions with [extension properties](extensionPropertiesApi.md)
62+
that are generated on-the-fly in the IDEA project.
63+
5964
* [Titanic Example](https://github.com/Kotlin/dataframe/blob/master/examples/notebooks/titanic/Titanic.ipynb)
6065
— discover the famous "Titanic"
6166
dataset with the Kotlin DataFrame analysis toolkit

examples/README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
# Examples of Kotlin Dataframe
22

33
### Idea examples
4+
* [plugin example](kotlin-dataframe-plugin-example) IDEA project with a
5+
[Kotlin DataFrame Compiler Plugin](https://kotlin.github.io/dataframe/compiler-plugin.html) example.
46
* [movies](idea-examples/movies) Using extension properties [Access API](https://kotlin.github.io/dataframe/apilevels.html) to perform a data cleaning task
57
* [titanic](idea-examples/titanic)
68
* [youtube](idea-examples/youtube)
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
# Kotlin DataFrame Compiler Plugin Example
2+
3+
An IntelliJ IDEA project demonstrating the use of the
4+
[Kotlin DataFrame Compiler Plugin](https://kotlin.github.io/dataframe/compiler-plugin.html).
5+
6+
> **Note:** This project uses **dev versions** of the Kotlin and the Kotlin DataFrame plugin.
7+
> See [build.gradle.kts](build.gradle.kts) for details.
8+
9+
For proper functionality in IntelliJ IDEA requires version 2025.2 or higher
10+
(Currently available only in [IntelliJ IDEA EAP](https://www.jetbrains.com/idea/nextversion/?_gl=1*1ojxffu*_gcl_au*MTk5NzUwODYzOS4xNzQ2NzkxMDMz*_ga*MTE0ODQ1MzY3OS4xNzM4OTY1NzM3*_ga_9J976DJZ68*czE3NDkyMTM4MzkkbzE5OCRnMSR0MTc0OTIxMzg0MSRqNTgkbDAkaDA.)).
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import org.jlleitschuh.gradle.ktlint.KtlintExtension
2+
3+
plugins {
4+
id("org.jlleitschuh.gradle.ktlint") version "12.3.0"
5+
kotlin("jvm") version "2.2.20-dev-3524"
6+
kotlin("plugin.dataframe") version "2.2.20-dev-3524"
7+
}
8+
9+
group = "org.example"
10+
version = "1.0-SNAPSHOT"
11+
12+
repositories {
13+
maven("https://packages.jetbrains.team/maven/p/kt/dev/")
14+
mavenCentral()
15+
}
16+
17+
dependencies {
18+
implementation("org.jetbrains.kotlinx:dataframe:1.0.0-Beta2")
19+
testImplementation(kotlin("test"))
20+
}
21+
22+
tasks.test {
23+
useJUnitPlatform()
24+
}
25+
kotlin {
26+
jvmToolchain(11)
27+
}
28+
29+
configure<KtlintExtension> {
30+
version = "1.6.0"
31+
// rules are set up through .editorconfig
32+
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
kotlin.code.style=official
2+
# Disabling incremental compilation will no longer be necessary
3+
# when https://youtrack.jetbrains.com/issue/KT-66735 is resolved.
4+
kotlin.incremental=false
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
pluginManagement {
2+
repositories {
3+
maven("https://packages.jetbrains.team/maven/p/kt/dev/")
4+
mavenCentral()
5+
gradlePluginPortal()
6+
}
7+
}
8+
plugins {
9+
id("org.gradle.toolchains.foojay-resolver-convention") version "0.8.0"
10+
}
11+
rootProject.name = "kotlin-dataframe-plugin-example"
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
package org.jetbrains.kotlinx.dataframe.examples.plugin
2+
3+
import org.jetbrains.kotlinx.dataframe.DataFrame
4+
import org.jetbrains.kotlinx.dataframe.annotations.DataSchema
5+
import org.jetbrains.kotlinx.dataframe.api.add
6+
import org.jetbrains.kotlinx.dataframe.api.convert
7+
import org.jetbrains.kotlinx.dataframe.api.convertTo
8+
import org.jetbrains.kotlinx.dataframe.api.filter
9+
import org.jetbrains.kotlinx.dataframe.api.into
10+
import org.jetbrains.kotlinx.dataframe.api.rename
11+
import org.jetbrains.kotlinx.dataframe.api.renameToCamelCase
12+
import org.jetbrains.kotlinx.dataframe.api.with
13+
import org.jetbrains.kotlinx.dataframe.io.readCsv
14+
import org.jetbrains.kotlinx.dataframe.io.writeCsv
15+
import java.net.URL
16+
17+
// Declare data schema for the DataFrame from jetbrains_repositories.csv.
18+
@DataSchema
19+
data class Repositories(
20+
val full_name: String,
21+
val html_url: URL,
22+
val stargazers_count: Int,
23+
val topics: String,
24+
val watchers: Int,
25+
)
26+
27+
// Define kinds of repositories.
28+
enum class RepoKind {
29+
Kotlin,
30+
IntelliJ,
31+
Other,
32+
}
33+
34+
// A rule for determining the kind of repository based on its name and topics.
35+
fun getKind(fullName: String, topics: List<String>): RepoKind {
36+
fun checkContains(name: String) = name in topics || fullName.lowercase().contains(name)
37+
38+
return when {
39+
checkContains("kotlin") -> RepoKind.Kotlin
40+
checkContains("idea") || checkContains("intellij") -> RepoKind.IntelliJ
41+
else -> RepoKind.Other
42+
}
43+
}
44+
45+
fun main() {
46+
val repos = DataFrame
47+
// Read DataFrame from the CSV file.
48+
.readCsv("https://raw.githubusercontent.com/Kotlin/dataframe/master/data/jetbrains_repositories.csv")
49+
// And convert it to match the `Repositories` schema.
50+
.convertTo<Repositories>()
51+
52+
// With Compiler Plugin, the DataFrame schema changes immediately after each operation:
53+
// For example, if a new column is added or the old one is renamed (or its type is changed)
54+
// during the operation, you can use the new name immediately in the following operations:
55+
repos
56+
// Add a new "name" column...
57+
.add("name") { full_name.substringAfterLast("/") }
58+
// ... and now we can use "name" extension in DataFrame operations, such as `filter`.
59+
.filter { name.lowercase().contains("kotlin") }
60+
61+
// Let's update the DataFrame with some operations using these features.
62+
val reposUpdated = repos
63+
// Rename columns to CamelCase.
64+
// Note that after that, in the following operations, extension properties will have
65+
// new names corresponding to the column names.
66+
.renameToCamelCase()
67+
// Rename "stargazersCount" column to "stars".
68+
.rename { stargazersCount }.into("stars")
69+
// And we can immediately use the updated name in the filtering.
70+
.filter { stars > 50 }
71+
// Convert values in the "topic" column (which were `String` initially)
72+
// to the list of topics.
73+
.convert { topics }.with {
74+
val inner = it.removeSurrounding("[", "]")
75+
if (inner.isEmpty()) emptyList() else inner.split(',').map(String::trim)
76+
}
77+
// Now "topics" is a `List<String>` column.
78+
// Add a new column with the number of topics.
79+
.add("topicCount") { topics.size }
80+
// Add a new column with the kind of repository.
81+
.add("kind") { getKind(fullName, topics) }
82+
83+
// Write the updated DataFrame to a CSV file.
84+
reposUpdated.writeCsv("jetbrains_repositories_new.csv")
85+
86+
// TODO: Add Kandy Plot
87+
// reposUpdated.groupBy { kind }.max { stargazersCount }.plot {
88+
// bars {
89+
// x(kind)
90+
// y(stargazersCount)
91+
// }
92+
// }
93+
}

settings.gradle.kts

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ include("plugins:dataframe-gradle-plugin")
1111
include("plugins:symbol-processor")
1212
include("plugins:expressions-converter")
1313
include("plugins:kotlin-dataframe")
14+
include("plugins:public-api-modifier")
1415
include("tests")
1516
include("dataframe-json")
1617
include("dataframe-arrow")
@@ -19,13 +20,17 @@ include("dataframe-excel")
1920
include("dataframe-jdbc")
2021
include("dataframe-csv")
2122
include("dataframe-jupyter")
23+
include("dataframe-geo")
24+
include("dataframe-openapi-generator")
2225
include("core")
26+
include("dataframe-compiler-plugin-core")
2327

2428
include("examples:idea-examples:titanic")
2529
include("examples:idea-examples:movies")
2630
include("examples:idea-examples:youtube")
2731
include("examples:idea-examples:json")
2832
include("examples:idea-examples:unsupported-data-sources")
33+
includeBuild("examples/kotlin-dataframe-plugin-example")
2934

3035
val jupyterApiTCRepo: String by settings
3136

@@ -45,9 +50,3 @@ pluginManagement {
4550
plugins {
4651
id("org.gradle.toolchains.foojay-resolver-convention") version "0.5.0"
4752
}
48-
include("dataframe-excel")
49-
include("core")
50-
include("dataframe-openapi-generator")
51-
include("dataframe-geo")
52-
include("plugins:public-api-modifier")
53-
include("dataframe-compiler-plugin-core")

0 commit comments

Comments
 (0)