Skip to content

Sort transform

The sort transform sorts a mark’s index to change the effective order of data. The sort transform affects the order in which a mark’s graphical elements are drawn (z-order), which can have a dramatic effect when these elements overlap. For example, see the bubble map of U.S. county population below; when the null sort order is used for input order, many small dots are hidden underneath larger ones.

Fork
js
Plot.plot({
  projection: "albers-usa",
  marks: [
    Plot.geo(statemesh, {strokeOpacity: 0.4}),
    Plot.dot(counties, Plot.geoCentroid({
      r: (d) => d.properties.population,
      fill: "currentColor",
      stroke: "white",
      strokeWidth: 1,
      sort: sorted ? {channel: "-r"} : null
    }))
  ]
})

TIP

Dots are sorted by descending r by default, so you may not need the sort option.

The sort transform can be applied either via the sort mark option, as above, or as an explicit sort transform. The latter is generally only needed when composing multiple transforms, or to disambiguate the sort transform from imputed ordinal scale domains, i.e., scale sorting.

As another example, in the line chart of unemployment rates below, lines for metropolitan areas in Michigan (which saw exceptionally high unemployment following the financial crisis of 2008, in part due to the auto industry collapse) are highlighted in red, and the sort option is used to draw them on top of other series.

0Unemployment (%)dateFork
js
Plot.plot({
  y: {
    grid: true,
    label: "Unemployment (%)"
  },
  color: {
    domain: [false, true],
    range: ["#ccc", "red"]
  },
  marks: [
    Plot.ruleY([0]),
    Plot.line(bls, {
      x: "date",
      y: "unemployment",
      z: "division",
      sort: (d) => /, MI /.test(d.division),
      stroke: (d) => /, MI /.test(d.division)
    })
  ]
})

TIP

You could say sort: {channel: "stroke"} here to avoid repeating the test function.

The index order also affects the behavior of certain transforms such as stack and dodge.

Sort x order:

2,0002,5003,0003,5004,0004,5005,000weight (lb) →Fork
js
Plot.plot({
  height: 180,
  marks: [
    Plot.dotX(cars, Plot.dodgeY({
      x: "weight (lb)",
      title: "name",
      fill: "currentColor",
      sort: {channel: "x", order}
    }))
  ]
})

The closely-related reverse transform likewise reverses the mark index, while the shuffle transform for randomizes the mark index’s order.

sort(order, options)

js
Plot.sort("body_mass_g", {x: "culmen_length_mm", y: "culmen_depth_mm"})

Sorts the data by the specified order, which is one of:

  • a comparator function, as with array.sort
  • an accessor function
  • a field name
  • a {channel, order} object

In the object case, the channel option specifies the name of the channel, while the order option specifies ascending (the default) or descending order. You can also use the shorthand -name ^0.6.7 to sort by descending order of the channel with the given name. For example, sort: {channel: "-r"} will sort by descending radius (r).

In the function case, if the sort function does not take exactly one argument, it is interpreted as a comparator function; otherwise it is interpreted as an accessor function.

shuffle(options)

js
Plot.shuffle({x: "culmen_length_mm", y: "culmen_depth_mm"})

Shuffles the data randomly. If a seed option is specified, a linear congruential generator with the given seed is used to generate random numbers; otherwise, Math.random is used.

reverse(options)

js
Plot.reverse({x: "culmen_length_mm", y: "culmen_depth_mm"})

Reverses the order of the data.