space/shift+space to navigate slides
ctrl+enter to run code
up/down to select the previous/next code cell
optimized for full-screen mode
Sören Brunk
@soebrunk
An Interactive computation is a persistent computer program that runs with a "human in the loop," where the primary mode of interaction is through the human interactively writing/running blocks of code and looking at the result.
— Brian Granger (co-founder of Project Jupyter)
A worksheet is a Scala file that is evaluated on save, and the result of each expression is shown in a column to the right of your program. Worksheets are like a REPL session on steroids, and enjoy 1st class editor support: completion, hyperlinking, interactive errors-as-you-type, etc.
— Source: Dotty documentation
Tour of Scala
Higher-Order-Functions
Higher order functions take other functions as parameters or return other functions ...
One of the most common examples is the higher-order function map
which is available for collections in Scala.
// Use ctrl+enter to run the cell
val salaries = Seq(20000, 70000, 40000)
val doubleSalary = (x: Int) => x * 2
val newSalaries = salaries.map(doubleSalary)
salaries.map(x => x *3)
doubleSalary
is a function which takes a single Int, x
, and returns x * 2
. In general, the tuple on the left of the arrow =>
is a parameter list and the value of the expression on the right is what gets returned. On line 3, the function doubleSalary
gets applied to each element in the
list of salaries.
case class Person(name: String, age: Int)
val alice = Person("alice", 42)
val bob = Person("bob", 43)
Seq(alice, bob).map(_.name.capitalize)
"I'm a code cell, evaluate me!"
println("I'm so effectful!")
"I'm smaller, but you can still evaluate me."
interp.repositories() ++= Seq(coursier.maven.MavenRepository("https://jitpack.io"))
import $ivy.`org.apache.spark::spark-sql:2.4.3` // Or use any other 2.x version here
import $ivy.`sh.almond::almond-spark:0.5.0`
import org.apache.spark.sql._, org.apache.log4j.{Level, Logger}
Logger.getLogger("org").setLevel(Level.OFF)
val spark = {
NotebookSparkSession.builder()
.progress(false)
.master("local[*]")
.getOrCreate()
}
def sc = spark.sparkContext
import spark.implicits._
import $file.SparkHelpers, SparkHelpers._
val titanic = spark.read
.format("csv")
.option("inferSchema", "true").option("header", "true")
.load("titanic.csv")
titanic.showHTML()
import $ivy.`org.vegas-viz::vegas-spark:0.3.12-SNAPSHOT`
import vegas._, vegas.data.External._, vegas.sparkExt._
Vegas().
withDataFrame(titanic).
mark(vegas.Bar).
encodeY("*", aggregate=AggOps.Count, axis=vegas.Axis(title="Number of People", grid=false)).
encodeColumn("Pclass", Ord, scale=Scale(padding=16.0), axis=vegas.Axis(orient=Orient.Bottom, axisWidth=1.0, offset= -8.0)).
encodeX("Survived", Nominal, scale=Scale(bandSize = 20.0), hideAxis=true).
encodeColor("Survived", Nominal, scale=Scale(rangeNominals=List("red", "green"))).
configFacet(cell=CellConfig(strokeWidth = 0)).configCell(height=400).show
import $ivy.`org.plotly-scala::plotly-almond:0.7.0`
import plotly._, plotly.element._, plotly.layout._, plotly.Almond._
val trace1 = plotly.Bar(
Seq("giraffes", "orangutans", "monkeys"), Seq(20, 14, 23), name = "SF Zoo"
)
val trace2 = plotly.Bar(
Seq("giraffes", "orangutans", "monkeys"), Seq(15, 18, 29), name = "LA Zoo"
)
val data = Seq(trace1, trace2)
val layout = Layout(barmode = BarMode.Group)
plot(data, layout)
But we aren't restricted to visualizing data. We can also visualize code.
import $ivy.`io.github.stanch::reftree:1.4.0`
import reftree.render._, reftree.diagram._, reftree.contrib.SimplifiedInstances.string
case class Person(name: String, age: Int)
val people = List(Person("Alice", 29), Person("Bob", 25))
val renderer = Renderer(renderingOptions = RenderingOptions(density = 80))
renderer.render("example", Diagram.sourceCodeCaption(people))
Image.fromFile("example.png")
2001: IPython Shell
2011: IPython Notebook
2014: Project Jupyter (support for other languages besides Python)
2018: JupyterLab (next generation UI)
import $ivy.`org.typelevel::squants:1.4.0`
import squants.energy.Kilowatts, squants.time.Hours
val load = Kilowatts(1.2)
val time = Hours(2)
val energyUsed = load * time
Seq.fill(3)(Seq.fill(5)(f"${scala.util.Random.nextFloat}%1.4f"))
import $ivy.`org.typelevel::squants:` // put the cursor after the last colon and press shift, select 1.4.0
Seq("alice", "bob", "charlie").map(name => name.) // put the cursor after name. and press shift, select capitalize
// Run the cell, then put the cursor on map and press shift+tab multiple times until you get a type hint at the bottom
// Click on the link int the type hint for a metabrowse window
repl.history.takeRight(3).toList
interp.repositories().last
import almond.display._
Html("Some <b>bold</b> text")
Svg("""<svg height="250" xmlns="http://www.w3.org/2000/svg">
<rect x="25" y="25" width="200" height="200" fill="lime" stroke-width="4" stroke="pink" />
<circle cx="125" cy="125" r="75" fill="orange" />
</svg>""")
Image.from(url = "http://localhost:8888/static/base/images/logo.png")
Latex("""$$e^x=\sum_{i=0}^\infty \frac{1}{i!}x^i$$""")
Javascript("alert('Hello')") // JS execution is restricted in newer frontends
val handle = ProgressBar(10,100)
.withHtmlWidth("100%")
.withLabel("Overall Progress")
for {i <- 1 to 100} {
handle.withProgress(i).update()
Thread.sleep(30)
}
val result = Input().withPrompt(">>> ").request()
import scala.concurrent.Future
implicit val ec = scala.concurrent.ExecutionContext.global
val f = Future {
Thread.sleep(10000)
"finished"
}
val v = "a val"
var x = "a var that we'll update"
var y = "another var"
x = "updated x"
build.sbt of your library:
libraryDependencies += ("sh.almond" % "scala-kernel-api" % "0.5.0" % Provided)
.cross(CrossVersion.full))
Your library code:
def randomEmoji()(implicit kernel: almond.api.JupyterApi): Unit = {
val emoji = Character.toChars(scala.util.Random.nextInt(0x1F64F - 0x1F600) + 0x1F600).mkString
kernel.publish.html(s"""<p style="font-size:4em; text-align: center">$emoji</p>""")}
Some notebook:
// import $ivy.`my:library:1.0`
randomEmoji()
Jupyter notebooks
Integrate documentation, runnable code and rich output in a single document
Combine REPLs and worksheets
almond combines the power of Jupyter and Ammonite
Giving us first class interactive computing support in Scala
Sören Brunk
@soebrunk