%useLatestDescriptors
// %use krangl
%use kotlin-statistics
%use lets-plot
LetsPlot.getInfo() // This prevents Krangl from loading an obsolete version of Lets-Plot classes.
Lets-Plot Kotlin API v.4.1.1. Frontend: Notebook with dynamically loaded JS. Lets-Plot JS v.2.5.1.
%use krangl
val mpgDf = DataFrame.readCSV("https://raw.githubusercontent.com/JetBrains/lets-plot-kotlin/master/docs/examples/data/mpg.csv")
mpgDf.head()
manufacturer | model | displ | year | cyl | trans | drv | cty | hwy | fl | class | |
---|---|---|---|---|---|---|---|---|---|---|---|
1 | audi | a4 | 1.8 | 1999 | 4 | auto(l5) | f | 18 | 29 | p | compact |
2 | audi | a4 | 1.8 | 1999 | 4 | manual(m5) | f | 21 | 29 | p | compact |
3 | audi | a4 | 2.0 | 2008 | 4 | manual(m6) | f | 20 | 31 | p | compact |
4 | audi | a4 | 2.0 | 2008 | 4 | auto(av) | f | 21 | 30 | p | compact |
5 | audi | a4 | 2.8 | 1999 | 6 | auto(l5) | f | 16 | 26 | p | compact |
Shape: 5 x 12.
val mpgMap = mpgDf.toMap()
val regModel = (mpgMap["cty"]!! zip mpgMap["hwy"]!!).simpleRegression(
xSelector = { it.first as Number },
ySelector = { it.second as Number }
)
val ctyMedian = mpgDf.get("cty").median()
val hwyMedian = mpgDf.get("hwy").median()
letsPlot(mpgMap) { x = "cty"; y = "hwy" } +
geomPoint() +
geomVLine(xintercept = ctyMedian, color = "#756bb1", linetype = "dashed") +
geomHLine(yintercept = hwyMedian, color = "#756bb1", linetype = "dashed") +
geomABLine(slope = regModel.slope, intercept = regModel.intercept, color = "#de2d26") +
themeMinimal()
fun generateParabolicDataMap(n: Int = 25, a: Double = 1.0): Map<String, List<Double>> {
val rand = java.util.Random(42)
val x = List(2 * n + 1) { i -> a * (i - n).toDouble() / n }
val y = x.map { i -> i * i + rand.nextGaussian() }
return mapOf("x" to x, "y" to y)
}
val pDataMap = generateParabolicDataMap(a = 3.0)
letsPlot(pDataMap) + geomLine() { x = "x"; y = "y" }
letsPlot(pDataMap) + geomPath() { x = "x"; y = "y" }
letsPlot(pDataMap) + geomStep() { x = "x"; y = "y" }
And what is the difference between geomLine()
and geomPath()
?
Let's have a look at the following example:
fun generateArchimedeanDataMap(n: Int = 25, k: Double = 1.0, a: Double = 1.0): Map<String, List<Double>> {
val phi = List(n) { i -> 2.0 * PI * k * i.toDouble() / (n - 1) }
val r = phi.map { angle -> (a * angle) / (2.0 * PI) }
val x = (r zip phi).map { p -> p.first * cos(p.second) }
val y = (r zip phi).map { p -> p.first * sin(p.second) }
return mapOf("x" to x, "y" to y)
}
val aDataMap = generateArchimedeanDataMap(n = 200, k = 2.0)
letsPlot(aDataMap) +
geomLine() { x = "x"; y = "y" } +
ggtitle("Plotting with geomLine()")
letsPlot(aDataMap) +
geomPath() { x = "x"; y = "y" } +
ggtitle("Plotting with geomPath()")
Also an interesting plot could be drawed with geomSegment()
:
letsPlot(generateArchimedeanDataMap(n = 50)) + geomSegment(xend = 0.0, yend = 0.0) { x = "x"; y = "y" }