IntelliJ IDEA 2024.1 Help

Kotlin Notebook

Kotlin Notebook brings the versatility of notebooks to IntelliJ IDEA.

Notebooks are interactive editors that integrate code, graphics, and text in a single environment. When using a notebook, you can run code cells and immediately see the output, gaining real-time code insights.

Kotlin Notebook is a plugin that allows you to create and edit notebooks smoothly within the IntelliJ IDEA ecosystem while coding with Kotlin.

Kotlin Notebook provides you with a rich set of tools to tackle tasks like:

  • Data analytics and visualization: you can intuitively retrieve, transform, plot, and model your data while getting outputs of your operations as you code.

  • Prototyping: you can run code in small chunks and see the results in real time. This hands-on environment enables rapid experimentation and iteration.

  • Explore and test APIs: Kotlin Notebook offers the ability to call APIs within cells and interact with external services.

  • Code documentation: you can include inline comments within code cells and text annotations within Markdown cells to provide further context, explanations, instructions, and more.

Additionally, you can effortlessly share your work across Kotlin Notebook, Datalore, and Kotlin-Jupyter Notebook without issues. This compatibility is possible because Kotlin Notebook is based on our Kotlin Kernel, ensuring seamless integration among our different Kotlin notebook solutions.

Explore the sections below to learn about the Kotlin Notebook's usage and key features!

Install the plugin

Install the Kotlin Notebook plugin by downloading it from JetBrains Marketplace. Ensure you use the latest version of both the plugin and IntelliJ IDEA Ultimate.

Alternatively, access the Kotlin Notebook plugin from Settings | Plugins | Marketplace within IntelliJ IDEA Ultimate.

Install the Kotlin Notebook plugin

Create a notebook

Once you have installed the plugin in IntelliJ IDEA Ultimate, select File | New | Kotlin Notebook to create a new notebook.

Alternatively, right-click on the directory you want to locate your notebook and select New | Kotlin Notebook.

Create new Kotlin Notebook

A file with a .ipynb extension is created.

Starting from IntelliJ IDEA 2024.1.1, you can also create a Kotlin Notebook as a scratch (temporary) file by selecting File | New | Scratch File. Scratch files allow for testing small pieces of code without creating a new project or modifying an existing one.

Manage your notebook

At the top of your Kotlin Notebook, you can find the notebook toolbar. This toolbar contains buttons for quick cell actions that allow you to dynamically run or modify your code and see the output immediately.

Kotlin Notebook toolbar

The main actions you can perform from the toolbar are:

  • Add cell Add code cell below

  • Cut Cut selection

  • Copy Copy selection

  • Paste Paste selection

  • Move cell up Move cell up

  • Move cell down Move cell down

  • Run cell and select below Run cell and select below

  • Interrupt kernel Interrupt kernel

  • Restart kernel Restart kernel

  • Run all Run all cells

  • Clear outputs Clear outputs

  • Delete cell Delete cell

  • Select type of cell Select type of cell

  • Create gist Create gist

  • Kotlin Notebook settings See Kotlin Notebook settings

When working with notebooks, each cell contributes to the whole state of the notebook, but only after you run the cells. The order of cells in the notebook itself doesn't matter, but the order of running the cells does.

For example, when using a library, although you can run any cell at any time, you need to run the cell that imports the library before running the cells that call the library.

Kotlin Notebook cells

Unlike traditional programming, notebooks allow you to declare multiple variables with the same name within different cells. However, each new declaration of a variable with the same name overrides the previous ones. Only the most recent declaration you run is valid in subsequent cells.

Kotlin Notebook variables

Usually, notebooks have code running under the hood, which may cause unexpected behavior when joining cells. This behavior is because if one of the joined cells contains code that modifies the environment, the changes might not be immediately reflected in the following cell.

Notebooks may have limitations on certain language constructs. Generally, only valid function-level operations are allowed, like working inside a function body.

Access the Kotlin Notebook API

You can access the Kotlin Notebook API directly within cells. The Kotlin Notebook API provides functionality to customize and configure your notebook behavior, such as handling outputs, retrieving information from previously executed code snippets, seamless integration with libraries, and more.

For example, notebook is an entry point for the Kotlin Notebook API. You can use notebook with certain methods to retrieve notebook insights like the executed code cells or declared variables.

Kotlin Notebook API

Add dependencies

You can easily add dynamic dependencies to your notebook from a remote Maven repository or local ones (local JARs). To add dependencies, you have two options: annotations or Gradle-like syntax.

Add dependencies using annotations

There are two annotations to manage dependencies in your Kotlin Notebook:

  • @file:DependsOn(): In this annotation, you need to specify the coordinates of the dependency. This annotation adds artifacts (like JAR files) to the notebook's classpath. It supports absolute and relative paths to class directories or JARs, as well as Ivy and Maven artifacts:

    @file:DependsOn(“io.ktor:ktor-client-core-jvm:$ktorVersion“)
  • @file:Repository(): In this annotation, you need to specify the absolute path of the dependency. This annotation adds a directory or an Ivy or Maven repository to the notebook environment. To specify a Maven local repository, use @file:Repository("*mavenLocal").

Add dependencies using Gradle-like syntax

You can load any library from the Maven repository using Gradle-like syntax in any cell, specifying repositories, locations, and so on:

USE { repositories { maven { url = "https://my.secret.repo/maven/" credentials { username = USER password = TOKEN } } } dependencies { val ktorVersion = "2.0.3" implementation("my.secret:artifact:1.0-beta") implementation("io.ktor:ktor-client-core:$ktorVersion") implementation("io.ktor:ktor-client-apache:$ktorVersion") } }

Utilize line magics

Kotlin Notebook provides special commands, starting with the % character, that interact with the notebook on a per-line basis. These commands, known as line magics, allow you to import libraries, configure output settings, and perform more operations.

Import supported libraries

Kotlin Notebook comes with a set of integrated libraries to perform various tasks, from deep learning to HTTP networking. You can import these integrated libraries just by running the %use line magic before the library's name.

Along with the %use keyword, you can specify a particular library version or include several libraries using a single %use statement.

Kotlin Notebook libraries

Integrate new libraries

You can add and use libraries that are not yet integrated into Kotlin Notebook. There are two ways to integrate a new library: creating a JSON library descriptor or using the Kotlin Notebook API.

Create a JSON library descriptor

To support a new library and make it available via the %use line magic, you need to create a library descriptor. The library descriptor is a .json file defining the most frequent library features, such as properties, renderers, and initial imports:

This example shows the usage of a custom renderer defined within the library descriptor:

USE { render<Int> { "[$it]" } }

Use the Kotlin Notebook API

To add a new library using the Kotlin Notebook API, you need to define an integration class within your library and ensure the integration class name is in the current notebook classpath.

Once you have defined the integration class, you can leverage all available integration features provided by the Kotlin Notebook API. These features facilitate seamless interaction between your library and the Kotlin Notebook environment.

You can use the available integration features directly from the notebook cells employing the USE {} block along with the feature method. Here's an example with the import () method:

USE { import("my.awesome.Clazz") }

Use REPL commands

Use REPL commands to explore your notebook environment, understand the classpath, and inspect the values of variables during execution.

Kotlin Notebook REPL commands

Kotlin Notebook supports the following REPL commands:

:help

Displays help information with details of the notebook version, line magics, and supported libraries.

:classpath

Displays the current classpath of your notebook environment, showing a list of locations where the notebook searches for libraries and resources.

:vars

Displays information about the declared variables and their values.

Render and display rich output

By default, Kotlin Notebook displays return values in text form. However, you can enrich the output by rendering graphics, HTML, or other MIME-encoded data format.

One approach is to send MIME-encoded results to the client using the MIME helper function. Another approach is to use the HTML helper function, which provides a simpler way to display HTML content directly. See samples of these functions in our Kotlin-Jupyter repository on GitHub.

Beyond these functions, Kotlin Notebook supports various features and mechanisms for rendering values:

  • Renderers: Transform values into other representations. Renderers are controlled via the RenderersProcessor method, and you can access it with the notebook API entry point.

  • DisplayResult and Renderable: Objects implementing DisplayResult and Renderable interfaces are rendered to output JSON.

  • Text rendering: Render objects to strings using text renderers. Text renderers are controlled via the TextRenderersProcessor method, and you can access it with the notebook API entry point.

  • Throwables rendering: Throwable renderers behave as regular renderers but handle exceptions and errors generated during cell execution.

Drag and drop data files

Effortlessly retrieve data with simple drag-and-drop functionality, bringing the data from your project directory to the notebook cells.

In a matter of clicks, load CSV, XLS, and JSON files and have them in a data-frame-like structure, ready to be processed. Check the video below to see the drag-and-drop functionality in action.

Export data and graphics

Just as easy as loading data, you can intuitively export both data and graphics from the notebook by clicking on the exporting options in the cells.

Kotlin Notebook exporting

Analyse errors

When something doesn't go as expected in your code, Kotlin Notebook displays error messages and a stack trace in the output cells, providing insights for debugging.

Kotlin Notebook analyse errors

Best practices

Kotlin Notebook is a variant of Jupyter Notebooks and share a similar internal structure.

When you open a notebook and run the first cell, the notebook creates a session under the hood. This session communicates with a kernel, which keeps track of the notebook's runtime state throughout your work.

Working with a notebook has some implications compared to working with regular Kotlin files:

  • When the session is started, the project dependencies that you selected as notebook dependencies are compiled and added to the kernel's classpath. For this reason, if you make changes to your project code, these changes will be available within the notebook only after you restart the kernel.

  • Restarting the kernel is useful when the kernel becomes unresponsive or if you make significant changes to the environment. This action terminates the current running environment, clearing all the declared variables, functions, and objects.

  • The state of a notebook combines aspects of runtime and compile time. For this reason, restarting the kernel clears all previously evaluated variables from the notebook's memory. This can result in unresolved symbol errors if one cell depends on the output of another cell.

    Kotlin Notebook unresolved dependencies
  • Interrupting the kernel only pauses the current running cell without terminating the entire environment. This action is useful when you need to pause and resume the execution, for example, when a cell is taking too long to run.

  • The dependencies you add in cells become available only after you run those cells. This means that if you add a dependency and try to use that dependency in the same cell, the symbols from the dependency are marked as unresolved until you run the cell for the first time.

    Kotlin Notebook unresolved dependencies
  • You can run the cells independently in any order, regardless of their position in the notebook. The notebook's runtime state depends on the order of execution, not the cell's position in the notebook.

  • The cells you run are marked with a number indicating the execution order. On the other hand, those cells that you haven't run are marked with a * symbol. If you restart the kernel and click the Run All button, all the code cells run sequentially. Each cell is marked with a number matching their order of execution. When you run all the cells, the execution starts from the top to the button, so the order naturally aligns with the cells' position in the notebook.

    Kotlin Notebook unresolved dependencies
  • We suggest clicking the Run All button after restarting the kernel. By running all cells, the cells are executed in the correct order, recreating the necessary variables and functions within the memory.

Last modified: 16 May 2024