Skip to content

Map transform

The map transform groups data into series and then transforms each series’ values, say to normalize them relative to some basis or to apply a moving average. For example, below the map transform computes a cumulative sum (cumsum) of a series of random numbers sampled from a normal distribution — in other words, a random walk.

−8−6−4−2024681012141618200100200300400500Fork
js
Plot.plot({
  marks: [
    Plot.ruleY([0]),
    Plot.lineY({length: 600}, Plot.mapY("cumsum", {y: d3.randomNormal()}))
  ]
})

As another example, we can map the daily trading volume of Apple stock to a p-quantile in [0, 1] using the quantile map method, where 0 represents the minimum daily trade volume and 1 represents the maximum, and then apply a 30-day rolling mean with the window transform to smooth out the noise.

0.00.10.20.30.40.50.60.70.80.91.0↑ Volume20142015201620172018Fork
js
Plot.plot({
  marks: [
    Plot.ruleY([0, 1]),
    Plot.lineY(aapl, Plot.mapY("quantile", {x: "Date", y: "Volume", strokeOpacity: 0.2})),
    Plot.lineY(aapl, Plot.windowY(30, Plot.mapY("quantile", {x: "Date", y: "Volume"})))
  ]
})

The mapY transform above is shorthand for applying the given map method to all y channels. There’s also a less-common mapX transform for x channels.

The more explicit map transform lets you specify which channels to map, and what map method to use for each channel. Like the group and bin transforms, it takes two arguments: an outputs object that describes the output channels to compute, and an options object that describes the input channels and additional options. So this:

js
Plot.mapY("cumsum", {y: d3.randomNormal()})

Is shorthand for this:

js
Plot.map({y: "cumsum"}, {y: d3.randomNormal()})

As a more practical example, we can use the map transform to construct Bollinger bands, showing both the price and volatility of Apple stock.

Fork
js
Plot.plot({
  y: {
    grid: true
  },
  marks: [
    Plot.areaY(aapl, Plot.map({y1: Plot.bollinger({n, k: -k}), y2: Plot.bollinger({n, k})}, {x: "Date", y: "Close", fillOpacity: 0.2})),
    Plot.lineY(aapl, Plot.map({y: Plot.bollinger({n})}, {x: "Date", y: "Close", stroke: "blue"})),
    Plot.lineY(aapl, {x: "Date", y: "Close", strokeWidth: 1})
  ]
})

The bollinger map method is implemented atop the window map method, computing the mean of values within the rolling window, and then offsetting the mean by a multiple of the rolling deviation.

The map transform is akin to running array.map on the input channel’s values with the given map method. However, the map transform is series-aware: the data are first grouped into series using the z, fill, or stroke channel in the same fashion as the area and line marks so that series are processed independently.

Map options

The following map methods are supported:

  • cumsum - a cumulative sum
  • rank - the rank of each value in the sorted array
  • quantile - the rank, normalized between 0 and 1
  • a function to be passed an array of values, returning new values
  • a function to be passed an index and array of channel values, returning new values
  • an object that implements the mapIndex method

If a function is used, it must return an array of the same length as the given input. If a mapIndex method is used, it is repeatedly passed the index for each series (an array of integers), the corresponding input channel’s array of values, and the output channel’s array of values; it must populate the slots specified by the index in the output array.

map(outputs, options)

js
Plot.map({y: "cumsum"}, {y: d3.randomNormal()})

Groups on the first channel of z, fill, or stroke, if any, and then for each channel declared in the specified outputs object, applies the corresponding map method. Each channel in outputs must have a corresponding input channel in options.

mapX(map, options)

js
Plot.mapX("cumsum", {x: d3.randomNormal()})

Equivalent to Plot.map({x: map, x1: map, x2: map}, options), but ignores any of x, x1, and x2 not present in options. In addition, if none of x, x1, or x2 are specified, then x defaults to identity.

mapY(map, options)

js
Plot.mapY("cumsum", {y: d3.randomNormal()})

Equivalent to Plot.map({y: map, y1: map, y2: map}, options), but ignores any of y, y1, and y2 not present in options. In addition, if none of y, y1, or y2 are specified, then y defaults to identity.