This question had previously been closed as being a duplicate of "What is 'Currying'?". Although it technically might be interpreted as a case of currying I, personally, think this interpretation is totally missing the point of how it's done the D3-way. I re-opened the question because I think it is worthwile describing it in D3's own terminology.
Various D3 modules know a concept of generators—not to be confused with JavaScript's own generator functions which were introduced to the standard with ES6—that are used to create some sort of SVG data representing the data passed to the generator. In your case, d3.contours()
returns the contour generator from the d3-contour module. Other well-known examples are the generators from the d3-shape module that create various types of shapes for lines and paths to be used in the resulting SVG. These generators are constructed by functions that in terms of D3 are sometimes referred to as factories. In your code that factory is
d3.contours() // factory returning a countour generator object
The resulting generator has a default configuration determining its standard behavior which can be re-configured by calling methods on the generator object. Because all those methods return the generator object they were called upon they facilitate method chaining that is often seen in D3 code:
d3.contours()
// The next two lines are used to configure the generator.
.size([grid.n, grid.m])
.thresholds(thresholds);
Since the last of those calls—in your case .thresholds(thresholds)
—does also return the generator the whole expression evalutes to the newly created and configured generator object. Quite often, you will see the reference to that object being stored in some field for purposes of clarity and re-use.
const contourGenerator = d3.contours()
.size([grid.n, grid.m])
.thresholds(thresholds);
The resulting generator can then be called passing in the data, i.e. grid
in your case, and will return the transformed data that can be used to build the SVG:
Computes the contours for the given array of values, returning an array
Given the information above, it is easy to see that the following two statements are basically equivalent:
// 1. call the generator by the stored reference
const contourArray = contourGenerator(grid);
// 2. call the generator directly on the evaluated expression
const contourArray = d3.contours().size([grid.n, grid.m]).thresholds(thresholds) (grid);
// ^---------------evaluates to the generator----------------^
Just to round things up, the following call to .map()
could be implemented for either of the above approaches as it is just the standard mapping function called on the resulting array that is returned from the generator. Verbosely, your code could be rewritten as:
const contourGenerator = d3.contours()
.size([grid.n, grid.m])
.thresholds(thresholds);
const contourArray = contourGenerator(grid);
const mappedArray = contourArray.map(transform);