Legend Wrap¶
When the legend contains many items, it automatically wraps to prevent overlap - up to 15 rows for vertical legends and 5 columns for horizontal ones.
In [1]:
%useLatestDescriptors
%use lets-plot
In [2]:
LetsPlot.getInfo()
Out[2]:
Lets-Plot Kotlin API v.4.12.0. Frontend: Notebook with dynamically loaded JS. Lets-Plot JS v.4.8.1. Outputs: Web (HTML+JS), Kotlin Notebook (Swing), Static SVG (hidden)
In [3]:
// Prepare a dataset
import kotlin.math.roundToInt
import kotlin.random.Random
private fun Double.to255(): Int = (coerceIn(0.0, 1.0) * 255.0).roundToInt()
fun hlsToRgb(h: Double, l: Double, s: Double): Triple<Int, Int, Int> {
fun hue2rgb(p: Double, q: Double, t0: Double): Double {
var t = t0
if (t < 0) t += 1.0
if (t > 1) t -= 1.0
return when {
t < 1.0 / 6 -> p + (q - p) * 6 * t
t < 1.0 / 2 -> q
t < 2.0 / 3 -> p + (q - p) * (2.0 / 3 - t) * 6
else -> p
}
}
val q = if (l < 0.5) l * (1 + s) else l + s - l * s
val p = 2 * l - q
val r = hue2rgb(p, q, h + 1.0 / 3)
val g = hue2rgb(p, q, h)
val b = hue2rgb(p, q, h - 1.0 / 3)
return Triple(r.to255(), g.to255(), b.to255())
}
fun distinctPalette(n: Int, s: Double = 0.72, l: Double = 0.53): List<String> =
List(n) { i ->
val (r, g, b) = hlsToRgb(i.toDouble() / n, l, s)
"#%02X%02X%02X".format(r, g, b)
}
val nCats = 36
val ptsPerCat = 13
val cats = (1..nCats).map { i -> "C%02d".format(i) }
val cols = 6
val rnd = Random(42)
data class Pt(val x: Double, val y: Double, val cat: String)
val points: List<Pt> = cats.flatMapIndexed { i, c ->
List(ptsPerCat) {
val x = (i % cols) + rnd.nextDouble(-0.4, 0.4)
val y = (i / cols) + rnd.nextDouble(-0.4, 0.4)
Pt(x, y, c)
}
}
val xs = points.map { it.x }
val ys = points.map { it.y }
val catCol = points.map { it.cat }
val data = mapOf("x" to xs, "y" to ys, "cat" to catCol)
val palette = distinctPalette(nCats)
In [4]:
val base =
letsPlot(data) { x = "x"; y = "y"; color = "cat" } +
geomPoint(size = 3.0, alpha = 0.9) +
scaleColorManual(values = palette, name = "Categories ($nCats)") +
ggsize(800, 460)
In [5]:
// The default legend layout (vertical)
base
Out[5]:
In [6]:
// The horizontal case
base + theme().legendPositionBottom()
Out[6]:
In [7]:
// You can still adjust the number of legend rows or columns manually.
base +
theme().legendPositionBottom() +
guides(
color = guideLegend(
ncol = 10,
byRow = true)
)
Out[7]: