πŸ“– Book of jnotebook

jnotebook is a modern notebook system for Java
jnotebook interprets Java JShell files and render them as notebooks.

βš–οΈ Rationale

Computational notebooks allow arguing from evidence by mixing prose with executable code. For a good overview of problems users encounter in traditional notebooks like Jupyter, see I don't like notebooks and What’s Wrong with Computational Notebooks? Pain Points, Needs, and Design Opportunities.

jnotebook tries to address the following problems:

  • notebook editors are less helpful than IDE editors
  • notebook code is hard to reuse
  • out-of-order execution causes reproducibility issues
  • notebook code is hard to version control
  • the Java ecosystem does not provide a great experience for visualization and document formatting

jnotebook is a notebook library for Java that address these problems by doing less, namely:

  • no editing environment: you can keep the code editor you know and love
  • (almost) no new format: jnotebook interprets JShell files and renders them as notebook.
    Because jnotebook is not required to run JShell files, it does not introduce a dependency if you wish to run the JShell file in production.
  • no out-of-order execution: jnotebook always evaluates from top to bottom. jnotebook builds a dependency graph of Java statements and only recomputes the needed changes to keep the feedback loop fast.
  • cells outputs are interpreted as html. This gives access to great visualization libraries and standard html for formatting.

πŸš€ Getting Started

Quickstart

jnotebook requires Java 17 or higher.
jnotebook is distributed in a single portable binary. Download it.

curl -Ls https://get.jnotebook.catheu.tech -o jnotebook
chmod +x jnotebook

Launch it.

./jnotebook server

# or
java -jar jnotebook server

Then go to http://localhost:5002.
By default, the notebook folder is notebooks. If it does not exist, it will be created with an example notebook.
jnotebook automatically detects when a .jsh file in the notebooks folder is edited
and renders it in the web app.
Once your notebook is ready to be published, render it in a single html file with:

./jnotebook render notebooks/my_notebook.jsh

A my_notebook.html file will be generated.

Install

See detailed installation instruction for different platforms in the github project.

🀹 Demo notebooks

Coming soon.

πŸ”Œ In an Existing Project

Maven

When launched within a maven project, jnotebook automatically injects the project
dependencies in the classpath. If launched in a submodule, only the submodule
dependencies are injected.

Manual

Dependencies can be injected manually with the -cp=<CLASSPATH> parameter.

IDE integration

IntelliJ

Enable IntelliSense highlighting and code utilities for JShell .jsh files:

  1. Go to Settings | Editor | File Types
  2. Click on JShell snippet
  3. In file name patterns, click + (add)
  4. Add *.jsh.

πŸ’‘ Editor principle

Cells are delimited by blank lines

String s1 = "Hello";
"Hello"
String s2 = "World";
"World"

for multi-statements cells, only the last value or method result is returned.

String s3 = "!"; String s4 = "!"; String message = s1 + " " + s2 + s3 + s4;
"Hello World!!"

but everything sent to System.out is returned.

System.out.println("Hello John"); System.out.println("Hello Jane"); String s5 = "Hello Alex";
Hello John
Hello Jane
"Hello Alex"

html in return values is interpreted. (see custom html for more html manipulation)

String sayHello() { return "<b>Hello John!</b>"; } sayHello();
"Hello John!"

while System.out is not interpreted as html.

System.out.println("<b>Hello Jane!</b>");
<b>Hello Jane!</b>

By default, the java environment imports common classes. The exact list can be found here.

List.of(1,2,3); Map.of("key", "value"); Thread.sleep(1);

Mistakes happen! jnotebook tries its best to give helpful error messages.

invalidJava();
Error: 
cannot find symbol
  symbol:   method invalidJava()
  location: class 
invalidJava();
^^^^^^^^^^^^

Exceptions happen too!

throw new RuntimeException("Panic!");
jdk.jshell.EvalException: Panic!

Markdown

Comments are interpreted as markdown.

// #### example title
// my text with [a link](example.com)

Is rendered as

example title

my text with a link

You can also use multiline comments.

Latex

Latex is supported inline:

$`a^2+b^2=c^2`$
β†’ will render as a2+b2=c2a^2+b^2=c^2.
and as block:

```math
a^2+b^2=c^2
```
a2+b2=c2 a^2+b^2=c^2

Mermaid

Mermaid graphs are supported

AliceJohnHello John, how are you?John, can you hear me?Hi Alice, I can hear you!I feel great!AliceJohn

using

```mermaid
[MERMAID GRAPH CODE]
```

See mermaid documentation for examples.

πŸ” Viewers

jnotebook provides viewers and utils for data, tables, plots, flamegraphs etc.
These utils are packaged in a separate dependency jnotebook-utils. By default, jnotebook-utils is in the classpath.
All utils are available as static method in tech.catheu.jnotebook.Nb.

import tech.catheu.jnotebook.Nb;

πŸ”’ Tables

coming soon

πŸ“Š Plotly

jnotebook has built-in support for Plotly's low-ceremony plotting. See Plotly's JavaScript docs for more examples and options.

Nb.plotly(List.of( Map.of("z", List.of(List.of(1, 2, 3), List.of(3, 2, 1)), "type", "surface")), Map.of(), Map.of());

πŸ—Ί Vega Lite

jnotebook also supports Vega Lite.

Nb.vega(Map.of( "data", Map.of("url", "https://vega.github.io/vega-lite/data/seattle-weather.csv"), "mark", "bar", "encoding", Map.of( "x", Map.of("timeUnit", "month", "field", "date", "type", "ordinal"), "y", Map.of("aggregate", "mean", "field", "precipitation") ) ));

🏞 Images

coming soon

πŸ”  Grid Layouts

Layouts can be composed via rows, columns and grids

Nb.row(1, 2, 3, 4);
1
2
3
4
Nb.col(1, 2, 3, 4);
1
2
3
4
Nb.col(Nb.row("John", "Jane", "Alex"), Nb.row(1, 2, 3), Nb.row(4, 5, 6));
John
Jane
Alex
1
2
3
4
5
6
int numCols = 4; Nb.grid(numCols, 1, 2, 3, 4, 5, 6, 7);
1
2
3
4
5
6
7

βš™οΈ Custom html

You can use the j2html library directly to generate html easily.
Values inheriting j2html.tags.DomContent are rendered as html.

import static j2html.TagCreator.*; // import all html tags b("Hello red!").withStyle("color: red");
Hello red!

This makes it easy to create custom viewers

import j2html.tags.DomContent; DomContent title(String text) { return p(text).withStyle("font-weight:bold; font-size: x-large; display: block;margin-left: auto; margin-right: auto"); }; title("A big title.");

A big title.

All Nb viewers output are of class j2html.tags.DomContent. This makes is easy to combine viewers

var graph1 = Nb.vega(Map.of( "data", Map.of("url", "https://vega.github.io/vega-lite/data/seattle-weather.csv"), "mark", "bar", "encoding", Map.of( "x", Map.of("timeUnit", "month", "field", "date", "type", "ordinal"), "y", Map.of("aggregate", "mean", "field", "precipitation") ) )); var graph2 = Nb.vega(Map.of( "data", Map.of("url", "https://vega.github.io/vega-lite/data/seattle-weather.csv"), "mark", "bar", "encoding", Map.of( "x", Map.of("timeUnit", "month", "field", "date", "type", "ordinal"), "y", Map.of("aggregate", "mean", "field", "precipitation") ) )); Nb.row(title("My awesome analysis"), Nb.col(graph1, graph2));

My awesome analysis

πŸ”₯ Flamegraphs

You can profile methods and generate flamegraphs.

Runnable arrayFilling = () -> { List<Integer> a = new ArrayList<>(); for (int i = 0; i < 10000000; i++) { a.add(i); } }; var profilePath = Nb.profile(arrayFilling); Nb.flame(profilePath);

Credits

This documentation is directly copying some content from the book of Clerk, a notebook system for Clojure.