%useLatestDescriptors
%use lets-plot
LetsPlot.getInfo()
Lets-Plot Kotlin API v.0.0.0-SNAPSHOT. Frontend: Notebook with dynamically loaded JS. Lets-Plot JS v.4.3.0.
themeGrey()
as default theme. It improves plots readability.¶LetsPlot.theme = themeGrey()
val labelsData = mapOf(
"x" to listOf(0, 1, 2, 3, 4, 5, 6, 7, 8),
"y" to listOf(0, 45, 90, 135, 180, 225, 270, 315, 360),
"r_y" to listOf(360, 315, 270, 225, 180, 135, 90, 45, 0),
"l" to listOf("l0", "l45", "l90", "l135", "l180", "l225", "l270", "l315", "l360"),
"g" to listOf("g1", "g1", "g1", "g2", "g2", "g2", "g3", "g3", "g3")
)
val lollipopData = mapOf(
"c" to listOf("a", "b", "c", "d", "e", "f"),
"x" to listOf(1, 2, 3, 4, 5, 6),
"y" to listOf(1, 2, 3, 4, 5, 6)
)
val studentData = mapOf(
"subj" to listOf("progr", "math", "physic", "chemistry", "biology"),
"subjId" to listOf(1, 2, 3, 4, 5),
"student" to List(5) { "John" },
"score" to listOf(19, 15, 18, 12, 9)
)
geomArea()
¶Line get transformed into a circle:
val p = letsPlot() + geomArea() { x = listOf(0, 1); y = listOf(1, 1) }
gggrid(listOf(
p,
p + coordPolar()
))
flat = true
¶The plot can be transformed into a radar plot by using flat = true
and a discrete x-scale.
val p = letsPlot(studentData) +
geomArea(flat = true) { x = "subjId"; y = "score" } +
geomPoint() { x = "subjId"; y = "score" }
val labels = mapOf(1 to "progr", 2 to "math", 3 to "physic", 4 to "chemistry", 5 to "biology")
val continuous = scaleXContinuous(labels = labels)
val discrete = scaleXDiscrete(labels = labels)
gggrid(listOf(
p + continuous,
p + continuous + coordPolar() + ggtitle("scaleXContinuous"),
p + discrete + coordPolar() + ggtitle("scaleXDiscrete"),
))
geomSegment()
¶val p = letsPlot() +
geomSegment(x = 0, y = 0, xend = 4, yend = 4, arrow = arrow(), size = 1) +
geomSegment(x = 8, y = 0, xend = 4, yend = 4, arrow = arrow(), size = 1)
gggrid(listOf(
p,
p + coordPolar()
))
sizeEnd
/strokeEnd
precision length adjustment parameters:
// known problem - zero-length segment because of second datapoint.
// this is a temp workaround to sync stroke/stroke_end and size/size_ens domains
val d = mapOf(
"x" to listOf(0, 1),
"y" to listOf(0, 0),
"size" to listOf(8, 10),
"stroke" to listOf(1, 2),
"size_end" to listOf(10, 0),
"stroke_end" to listOf(2, 0)
)
val p = letsPlot(d) { x = "x"; y = "y" } +
geomPoint(shape = 21, alpha = 0.5, color = "red", showLegend = false) { size = "size"; stroke = "stroke" } +
geomSegment(xend = 1, yend = 0, size = 2,
arrow = arrow(ends = "both", type = "open", length = 22, angle = 30)) {
sizeStart = "size"
strokeStart = "stroke";
sizeEnd = "size_end"
strokeEnd = "stroke_end"
} +
scaleSizeIdentity()
gggrid(listOf(
p,
p + coordPolar(xlim = -0.35 to 1.35, ylim = -2 to 2) // lims are only to make the figure smiling
))
geomLabel()
¶Regular scatter plot.
val p = letsPlot(labelsData) { x = "x"; y = "y"; label = "l" } + geomLabel()
gggrid(listOf(
p,
p + coordPolar() + ggtitle("coordPolar()"),
p + coordPolar(theta = "y") + ggtitle("theta=y"),
))
geomPath()
¶The transform resamples path data by converting straight segments into curves. The flat
parameter controls this behaviour.
val p = letsPlot(labelsData) { x = "x"; y = "y"; color = "y" } + scaleColorBrewer(palette = "GnBu")
gggrid(listOf(
p + geomPath(size = 3) + coordPolar() + ggtitle("coordPolar()"),
p + geomPath(size = 3, flat = true) + coordPolar(theta = "x") + ggtitle("coordPolar(), flat=true")
), ncol=2)
ggplot(studentData) + geomPath(flat = true) { x = "subj"; y = "score" } + coordPolar(ylim = 0 to 20)
geomLollipop()
¶See the Params
section for details on using the ylim
parameters.
val p = letsPlot(lollipopData) { x = "c"; y = "y" } + geomLollipop()
gggrid(listOf(
p,
p + coordPolar()
))
geomBar()
¶This works similarly to rects, but with the addition of tooltips.
position='stack'
¶val barData = mapOf("foo" to listOf(1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3))
val p = letsPlot(barData) + geomBar(size = 0) { fill = asDiscrete("foo", order = 1) }
gggrid(listOf(
p,
p + coordPolar(theta="y") + ggtitle("position=stack, coord_polar(theta=y)"),
p + coordPolar(theta="x") + ggtitle("position=stack, coord_polar(theta=x)"),
))
position='dodge'
¶val p = letsPlot(barData) + geomBar(size = 0, position = positionDodge()) { fill = asDiscrete("foo", order = 1) }
gggrid(listOf(
p,
p + coordPolar(theta="y") + ggtitle("position=dodge, coord_polar(theta=y)"),
p + coordPolar(theta="x") + ggtitle("position=dodge, coord_polar(theta=x)"),
))
stat='identity'
¶On a continuous x-scale the first and last bars stuck. The expand
parameter can be used to fix this.
val data = mapOf(
"x" to listOf(1, 2, 3),
"y" to listOf(5, 3, 4)
)
val barId = letsPlot(data) + geomBar(stat = Stat.identity, width = 0.8) { x = "x"; y = "y" } + coordPolar()
gggrid(listOf(
barId + ggtitle("Continuous x"),
barId + scaleXContinuous(expand = listOf(0, 0.1)) + ggtitle("scaleXContinuous(expand=[0, 0.1))")
))
barId + scaleXDiscrete() + ggtitle("Discrete x")
geomHLine()
/geomVLine()
¶val p = letsPlot() +
geomHLine(yintercept = 5, color = "red") +
geomHLine(yintercept = 10, color = "green") +
geomHLine(yintercept = 15, color = "blue") +
geomHLine(yintercept = 20, color = "orange") +
geomVLine(xintercept = 10, color = "pink") +
geomVLine(xintercept = 20, color = "magenta") +
geomVLine(xintercept = 30, color = "dark_green") +
xlim(0 to 30) +
ylim(0 to 20)
gggrid(listOf(p, p + coordPolar()))
geomTile()
¶fun meshgridPoints(x:List<Double>, y:List<Double>):List<Pair<Double, Double>> {
val xSer = y.flatMap { x }
var yInd = -1
val ySer = y.flatMap {
yInd++
List(x.size) {y[yInd]}
}
return xSer.zip(ySer)
}
val gridPoints = meshgridPoints(
generateSequence(0.0, {it + 6.0/50} ).takeWhile { it <= 1.0 }.toList(),
generateSequence(0.0, {it + 6.0/40} ).takeWhile { it <= 1.0 }.toList())
fun f(x:Double, y:Double): Double {
return sin(x).pow(10) + cos(10 + y * x) * cos(x)
}
val X = gridPoints.map { it.first }
val Y = gridPoints.map { it.second }
val Z = gridPoints.map { f(it.first, it.second) }
val p = letsPlot {x=X; y=Y; fill=Z} + geomTile() + scaleFillHue()
gggrid(listOf(
p,
p + coordPolar(ylim = -0.5 to null) // ylim to make a hole
))
geomRect()
¶are transformed into a pie chart
val c1 = "#66c2a5"
val c2 = "#fc8d62"
val c3 = "#8da0cb"
val p = ggplot() +
geomRect(xmin=0, xmax=5, ymin=0, ymax=7, fill=c1, size=0) +
geomRect(xmin=0, xmax=5, ymin=7, ymax=11, fill=c2, size=0) +
geomRect(xmin=0, xmax=5, ymin=11, ymax=14, fill=c3, size=0)
gggrid(listOf(
p,
p + coordPolar() + ggtitle("coordPolar()"),
p + coordPolar(theta = "y") + ggtitle("coordPolar(theta=y)"),
)).show()
gggrid(listOf(
p + coordPolar(theta = "y", direction = -1) + ggtitle("coordPolar(theta=y, dir=-1)"),
p + coordPolar(theta = "y", direction = -1, start = 3.14/2) +
ggtitle("coordPolar(theta=y, dir=-1, start=PI/2)"),
)).show()
val p = letsPlot() +
geomRect(xmin=0, xmax=1, ymin=0, ymax=7, fill=c1, size=0) +
geomRect(xmin=1, xmax=2, ymin=0, ymax=4, fill=c2, size=0) +
geomRect(xmin=2, xmax=3, ymin=0, ymax=3, fill=c3, size=0)
gggrid(listOf(
p,
p + coordPolar(theta = "y") + ggtitle("coordPolar(theta=y)"),
p + coordPolar(theta = "x") + ggtitle("coordPolar(theta=x)"),
))
val p = letsPlot() +
geomRect(ymin=0, ymax=1, xmin=0, xmax=7, fill=c1, size=0) +
geomRect(ymin=1, ymax=2, xmin=0, xmax=4, fill=c2, size=0) +
geomRect(ymin=2, ymax=3, xmin=0, xmax=3, fill=c3, size=0)
gggrid(listOf(
p,
p + coordPolar(theta = "y") + ggtitle("coordPolar(theta=y)"),
p + coordPolar(theta = "x") + ggtitle("coordPolar(theta=x)"),
))
val p = letsPlot(labelsData) { x = "x"; y = "y"; color = "y" } +
geomPath(size = 3, showLegend = false) +
scaleColorBrewer(palette = "GnBu")
p + coordPolar() + ggtitle("Default plot with coordPolar()")
transformBkgr
¶When using the transformBkgr
parameter, the panel is not transformed into a circle, but remains a rectangle. This behaviour is similar to ggplot2
.
p + coordPolar(transformBkgr = false) + ggtitle("coordPolar(transformBkgr=false)")
direction
¶p + coordPolar(direction = -1) + ggtitle("coordPolar(direction=-1)")
start
¶gggrid(listOf(
p + coordPolar(start = 3.14 / 2) + ggtitle("start=PI/2"),
p + coordPolar(start = -3.14 / 2) + ggtitle("start=-PI/2"),
))
direction
+ start
¶gggrid(listOf(
p + coordPolar(start = 3.14 / 2, direction=-1) + ggtitle("dir=-1, start=PI/2"),
p + coordPolar(start = -3.14 / 2, direction=-1) + ggtitle("dir=-1, start=-PI/2"),
))
xlim
and ylim
¶The xlim
parameter can be used to prevent overlap between the first and last values.
The ylim
parameter can be used to shift data away from the centre or the outer circle.
To prevent overlap between 6
and 1
, we adjust the xlim
to [null, 7]
while keeping the default minimum limit as it is not relevant.
In addition, we change ylim
to [null, 6.5]
to prevent the lollipop's top from overlapping with the outer circle.
val p = letsPlot(lollipopData) { x = "x"; y = "y" } + geomLollipop()
gggrid(listOf(
p + coordPolar(),
p + coordPolar(xlim = null to 7, ylim = null to 6.5)
))
Interaction between scales and polar coordinate system.
val pie = letsPlot() +
geomRect(xmin=0, xmax=1, ymin=0, ymax=7, fill="red", size=0) +
geomRect(xmin=1, xmax=2, ymin=0, ymax=4, fill="blue", size=0) +
geomRect(xmin=2, xmax=3, ymin=0, ymax=3, fill="green", size=0) +
coordPolar()
val sticksData = mapOf(
'x' to listOf(0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5),
'y' to listOf(0, 1, 0, 2, 0, 3, 0, 4, 0, 5, 0, 6),
'g' to listOf(5, 5, 4, 4, 3, 3, 2, 2, 1, 1, 0, 0)
)
val sticks = letsPlot(sticksData) + geomPath{ x='x'; y='y'; group='g'; size='g' } + coordPolar()
The limits
parameter sets the lower and upper limits individually, but expects absolute values.
x=[null, 6]
limit to make the first and last elements not overlap.
y=[-2, 7]
limit to make a medium sized centre hole and a small outer buffer (with a length of 1).
gggrid(listOf(
sticks + ggtitle("No limits"),
sticks + lims(x = null to 6, y = -2 to 7) + ggtitle("lims(x=[null, 6], y=[-2, 7])"),
))
If the x-scale is discrete, the coordinate system will automatically adjust domain so that the first and last values don't overlap.
gggrid(listOf(
sticks + ggtitle("Continuous"),
sticks + scaleXDiscrete() + ggtitle("scaleXDiscrete()")
))
Segments should not get rendered outside the panel boundaries.
gggrid(listOf(
sticks,
sticks + coordPolar(ylim = 0 to 1.5)
))
By default coordPolar()
resets the expansion to zero, but it can still be set explicitly.
Horizontal non-zero expand will produce a gap between first and last sectors, so the plot will never become a circle.
Vertical non-zero expand creates a central hole (expand for the bottom of the domain) and a buffer between the plot and the axis (expand for the top of the domain).
expand
is symmetric, so it can't be used to adjust only the bottom or only the top.
gggrid(listOf(
sticks + ggtitle("No expand"),
sticks + scaleXContinuous(expand = listOf(0, 2.5)) +
scaleYContinuous(expand = listOf(0, 2)) +
ggtitle("scale_XY_continuous(expand=...)")
))
scaleYLog10()
¶Log-scale works fine.
val d = mapOf(
'x' to listOf(1, 2, 3, 4, 5, 6, 7, 8),
'y' to listOf(1, 10, 100, 1_000, 10_000, 100_000, 1_000_000, 10_000_000),
)
val p = letsPlot(d) + geomPath(flat = true) { x='x'; y='y'}
p
gggrid(listOf(
p,
p + coordPolar(),
p + scaleYLog10(),
p + scaleYLog10(format=".1~e") + coordPolar(),
), ncol = 2)
val p = letsPlot(labelsData) { x = "x"; y = "y"; color = "y" } +
scaleColorBrewer(palette = "GnBu") +
geomPath(size = 3)
val polar_p = p + coordPolar()
gggrid(listOf(
p,
polar_p + themeMinimal2() + ggtitle("minimal2"),
polar_p + themeBW() + ggtitle("bw"),
polar_p + themeClassic() + ggtitle("classic"),
polar_p + themeGrey() + ggtitle("grey"),
polar_p + themeLight() + ggtitle("light"),
polar_p + themeMinimal() + ggtitle("minimal"),
polar_p + themeNone() + ggtitle("none"),
polar_p + themeVoid() + ggtitle("void"),
), ncol = 3)
val p_tmp = p + theme(
axisLineY = elementLine(color="red", size=2),
axisLineX = elementLine(color="blue", size=2),
axisTicksLengthY = 5,
axisTicksLengthX = 10,
axisTicksY = elementLine(size=5, color="red"),
axisTicksX = elementLine(size=3, color="blue"),
axisTextX = elementText(color="blue"),
axisTextY = elementText(color="red"),
)
gggrid(listOf(
p_tmp,
p_tmp + coordPolar()
))
The panelInset
parameter can be used to create space between the axis and the panel content:
val p_themed = p_tmp + theme(
plotBackground = elementRect(fill="pink"),
panelBackground = elementRect(fill="grey"),
panelBorder = elementRect(color="green", size=1),
panelInset = 10
)
gggrid(listOf(
p_themed,
p_themed + coordPolar()
))