Skip to content

boxenplot

Mojo function 🡭

boxenplot

fn def boxenplot(df: DataFrame, category: String, value: String, theme: Theme = Theme(WHITE, Color(UInt8(30), UInt8(100), UInt8(180), UInt8(255)), Color(UInt8(80), UInt8(80), UInt8(80), UInt8(255)), Color(UInt8(225), UInt8(225), UInt8(225), UInt8(255)), Color(UInt8(40), UInt8(40), UInt8(40), UInt8(255)), SIMD(12), SIMD(3.5), SIMD(2), Int(60), Int(20), Int(20), Int(50), True, False, False, Color(UInt8(240), UInt8(240), UInt8(240), UInt8(255)), Int(3), Color(UInt8(60), UInt8(110), UInt8(200), UInt8(255)), Color(UInt8(235), UInt8(235), UInt8(235), UInt8(255)), Color(UInt8(220), UInt8(90), UInt8(40), UInt8(255)), ColorRamp(), ColorPalette(), SIMD(3), SIMD(15), True, SIMD(1), Int(0), False, Color(UInt8(200), UInt8(60), UInt8(60), UInt8(255)), Color(UInt8(224), UInt8(224), UInt8(224), UInt8(255)), Color(UInt8(120), UInt8(120), UInt8(120), UInt8(255)), Color(UInt8(100), UInt8(100), UInt8(100), UInt8(255)), Color(UInt8(230), UInt8(230), UInt8(230), UInt8(255)), Color(UInt8(255), UInt8(255), UInt8(255), UInt8(255)), UInt8(90), UInt8(160), False, False, SIMD(0), SIMD(18), SIMD(14), Color(UInt8(110), UInt8(110), UInt8(110), UInt8(255)), SIMD(14), Color(UInt8(150), UInt8(150), UInt8(150), UInt8(255)), Color(UInt8(224), UInt8(236), UInt8(246), UInt8(200)), Color(UInt8(255), UInt8(255), UInt8(255), UInt8(255)), True, False, False, True, AxisPosition.EDGE, AxisPosition.EDGE, String("sans-serif"), True, UInt8(90), Int(5), Int(4), Int(130), Int(14), Int(8), Int(14), Int(100), Int(8), SIMD(4), OutputFormat.SVG, Tooltips.AUTO, Missing.DRAW, String("(missing)"), Int(1000), False, LineStyle.SOLID, SIMD(1.5), LineStyle.SOLID, LegendPosition.RIGHT, XAxisLabelRotation.AUTO, TickFormat.AUTO, TickFormat.AUTO), width: Int = Int(640), height: Int = Int(420), title: String = "", subtitle: String = "", x_title: String = "", y_title: String = "", horizontal: Bool = False) -> Chart[Boxenplot]

boxenplot() over a long-form dataframe_mojo DataFrame (#743): one row per observation, with category naming each row’s group and value holding the number.

A frame stores these long while the mark wants one list per category, so the rows are bucketed by category, in first-appearance order. The axis titles default to the two column names.

Args:

  • df (DataFrame): The frame to read.
  • category (String): The string column naming each observation’s group.
  • value (String): The numeric column holding the observations.
  • theme (Theme): Full styling knobs beyond this function’s own parameters.
  • width (Int): Pixel width of the returned Plot (.size()).
  • height (Int): Pixel height of the returned Plot (.size()).
  • title (String): The chart’s title, shown above the plot.
  • subtitle (String): A line under the title.
  • x_title (String): The x-axis caption; defaults to category.
  • y_title (String): The y-axis caption; defaults to value.
  • horizontal (Bool): Draw the categories down the y axis instead.

Returns:

Chart[Boxenplot]: The finished chart – unrendered.

Raises:

Error: A named column is missing, has the wrong dtype for its channel, or has missing values.

fn def boxenplot[dtype: DType](categories: List[String], values: List[List[Scalar[dtype]]], theme: Theme = Theme(WHITE, Color(UInt8(30), UInt8(100), UInt8(180), UInt8(255)), Color(UInt8(80), UInt8(80), UInt8(80), UInt8(255)), Color(UInt8(225), UInt8(225), UInt8(225), UInt8(255)), Color(UInt8(40), UInt8(40), UInt8(40), UInt8(255)), SIMD(12), SIMD(3.5), SIMD(2), Int(60), Int(20), Int(20), Int(50), True, False, False, Color(UInt8(240), UInt8(240), UInt8(240), UInt8(255)), Int(3), Color(UInt8(60), UInt8(110), UInt8(200), UInt8(255)), Color(UInt8(235), UInt8(235), UInt8(235), UInt8(255)), Color(UInt8(220), UInt8(90), UInt8(40), UInt8(255)), ColorRamp(), ColorPalette(), SIMD(3), SIMD(15), True, SIMD(1), Int(0), False, Color(UInt8(200), UInt8(60), UInt8(60), UInt8(255)), Color(UInt8(224), UInt8(224), UInt8(224), UInt8(255)), Color(UInt8(120), UInt8(120), UInt8(120), UInt8(255)), Color(UInt8(100), UInt8(100), UInt8(100), UInt8(255)), Color(UInt8(230), UInt8(230), UInt8(230), UInt8(255)), Color(UInt8(255), UInt8(255), UInt8(255), UInt8(255)), UInt8(90), UInt8(160), False, False, SIMD(0), SIMD(18), SIMD(14), Color(UInt8(110), UInt8(110), UInt8(110), UInt8(255)), SIMD(14), Color(UInt8(150), UInt8(150), UInt8(150), UInt8(255)), Color(UInt8(224), UInt8(236), UInt8(246), UInt8(200)), Color(UInt8(255), UInt8(255), UInt8(255), UInt8(255)), True, False, False, True, AxisPosition.EDGE, AxisPosition.EDGE, String("sans-serif"), True, UInt8(90), Int(5), Int(4), Int(130), Int(14), Int(8), Int(14), Int(100), Int(8), SIMD(4), OutputFormat.SVG, Tooltips.AUTO, Missing.DRAW, String("(missing)"), Int(1000), False, LineStyle.SOLID, SIMD(1.5), LineStyle.SOLID, LegendPosition.RIGHT, XAxisLabelRotation.AUTO, TickFormat.AUTO, TickFormat.AUTO), width: Int = Int(640), height: Int = Int(420), title: String = "", subtitle: String = "", x_title: String = "", y_title: String = "", horizontal: Bool = False) -> Chart[Boxenplot]

A letter-value plot: like box(), but the single box and two whiskers become nested boxes at successively finer quantiles – the quartiles, then the eighths, the sixteenths and on – each half as wide as the last, with only the observations beyond the deepest box drawn as points.

A box plot is the right summary for a small sample and a poor one for a large one: with thousands of observations “outlier” under the 1.5 IQR rule stops meaning anything, and the whiskers plus a cloud of points say nothing about the shape of the tail. This draws the tail instead of discarding it. How deep the nest goes follows the sample size (Tukey’s rule, floor(log2(n)) - 3 levels), so a small sample gets a plain quartile box and a large one several levels.

Mark.BOXENPLOT over encode_boxenplot().

Example:

from dataviz import boxenplot, save

def main() raises:
    # Illustrative page-load times (ms) for three deployments, 256
    # samples each with a long right tail -- the case a box plot's
    # outlier cloud says nothing useful about.
    var names: List[String] = ["v1", "v2", "v3"]
    var samples = List[List[Float64]]()
    for d in range(3):
        var s = List[Float64]()
        var seed = 7 + d
        for _ in range(256):
            seed = (seed * 1103515245 + 12345) % 2147483648
            var u = Float64(seed % 10000) / 10000.0
            # Skewed: most loads are quick, a few are very slow.
            s.append(120.0 + 40.0 * Float64(d) + 900.0 * u * u * u)
        samples.append(s^)
    var chart = boxenplot(
        names,
        samples,
        title="Illustrative Page-Load Time by Deployment",
        y_title="Load time (ms)",
    )
    save(chart, "docs/src/examples/out_boxenplot.svg")

Parameters:

  • dtype (DType)

Args:

  • categories (List[String]): One label per group.
  • values (List[List[Scalar[dtype]]]): values[i] is every raw observation in categories[i].
  • theme (Theme): Full styling knobs beyond this function’s own arguments.
  • width (Int): Canvas width in pixels.
  • height (Int): Canvas height in pixels.
  • title (String): Chart title; empty for none.
  • subtitle (String): Chart subtitle; empty for none.
  • x_title (String): X-axis title; empty for none.
  • y_title (String): Y-axis title; empty for none.
  • horizontal (Bool): Draw categories top-to-bottom with values running left-to-right.

Returns:

Chart[Boxenplot]: The finished Plot, ready to render() or save().

Raises:

Error: categories and values differ in length, or a group is empty.