This is the sixth day of my participation in the November Gwen Challenge. Check out the event details: The last Gwen Challenge 2021


See the Data Visualization column for a series of articles


Reference:

  • Learn D3: Scales
  • Scales (d3-scale)
  • D3-scale (Unofficial Chinese translation)
  • Axes (d3-axis)
  • D3-axis (Unofficial Chinese Translation)
  • Interpolators (d3-interpolate)
  • D3-interpolate (Unofficial Chinese translation)
  • Color Schemes (d3-scale-chromatic)
  • D3-scale-d4 – D4 (Unofficial Chinese Version)
  • Introducing d3-scale
  • Scales (Chinese translation) ⚠️ This article is based on d3.js v3.x
  • Introducing d3-scale
  • d3: scales, and color.

This paper mainly introduces the Scales module.

In Semiology of Graphics, Jacques Bertin describes the applicability of different attributes of graphical symbols (such as position, size, color, etc.) to presenting data. The key to linking the two is the scale, which maps data (a dimension) according to certain rules to a (specific) property of a graphical symbol, so that abstract data can be represented using a concrete visual graphical symbol.

Scale is actually a regular method of converting one type of data into another, for example, by linear scale, the monthly revenue for a year will be converted into the height value of the bar graph on the Y-axis. D3 provides multiple types of scales in the module D3-scale, suitable for converting different types of abstract data into different properties of graphical symbols:

💡 In the D3 documentation, the range of input data is called domain, and the range of output data after transformation is called range


The following scales apply to the continuous type of domain

Continuous Scales

Continuous Scales are used to map the domain of the Continuous type to the range of the Continuous type

Common methods for continuous scales of this type:

  • Continuous. Domain (domainArr) sets or returns the domain. If no argument is passed, return the scope of the current scale; If an array is passed, the scope of the domain is set to that array.

    The array passed in 💡 must contain two elements, and the elements must be of type numeric. If the array has more than one element (the elements are thus increasing or decreasing), you can create scales with more complex mappings. ⚠️ If the length of domain array M (number of elements) is different from the length of range array N (number of elements), then the mapping relationship is constructed according to min(N, M), and beyond the range, conversion cannot be carried out

    // Create a linear scale
    const color = d3.scaleLinear()
        .domain([-1.0.1]) // The domain is -1 to 1, where -1 to 0 is one part (negative) and 0 to 1 is the other part (positive)
        .range(["red"."white"."green"]); // The range of the negative mapping is RGB values from red to white; The range of the positive mapping is RGB values that fade from white to green
    
    color(-0.5); // "rgb(255, 128, 128)"
    color(+0.5); // "rgb(128, 192, 128)"
    Copy the code
  • Continuous. Range (rangeArr) Sets or returns the range. When passing an array to set a range, the array’s elements need not be numeric, just the types supported by the interpolator, such as color values. ⚠️ The type of the continuous. Invert (value) field must be numeric if you want scale support.

    💡 If you want to set both the range and interpolation method to D3.interpolateround (interpolating integers by rounding), you can use continuous. RangeRound (rangeArr). The element type of the array passed must be numeric

  • Continuous (value) Passes the value of a domain to the scale and returns the value of the corresponding range

  • Continuous. Invert (value) passes the value of a range to the scale, which in turn yields the value of the domain. This is useful for interaction, such as working backwards to explicitly figure out the corresponding data based on where the mouse is on a chart. ⚠️ This method only supports scales whose range is numeric, otherwise NaN is returned

  • Continuous. Clamp (clampState) Scale behavior is determined by clamp when the continuous(value) or continuous. Invert (value) input values are outside the range of the domain.

    • If the elextricity clamp function is enabledclampState=trueThe scale returns values that are limited to the corresponding range
    • If the elextricity clamp function is not enabledclampState=falseThe scale willBe inferredYields values that are out of range
    const x = d3.scaleLinear()
        .domain([10.130])
        .range([0.960]);
    
    // The clamping function is disabled by default
    x(-10); // -160 is out of range
    x.invert(-160); // -10 is out of scope
    
    // Enable the clamping function
    x.clamp(true);
    x(-10); // the 0 result is limited to the range
    x.invert(-160); // 10 The result is confined to the domain
    Copy the code
  • Continuous. Unknown (value) Sets the value that should be returned when the scale accepts undefined or NaN. This is useful when there are partial omissions in the data set (best handled in data cleansing, of course) to map data items to a specific visual attribute value

  • Continuous. Nice () edits the range of the domain to make it “neat” by rounding off the values at both ends of the domain, for example, the original range for the domain is [0.201479…, 0.996679…] Can be extended to [0.2, 1.0]

  • Continuous. Interpolate (interpolate) Interpolating function for a custom range of values

Linear Scales

Yyy in the value range of Linear Scales is connected with XXX in the definition field through the expression Y =mx+by=mx+ BY =mx+ B. This mapping method can retain the original difference ratio of data in the variables of visual elements

Build a linear scale using the method d3.scaleLinear(domain, range). The input parameter is optional. If omitted, the domain and range default is [0, 1]. You can also set the continuous. Domain (value) and continuous. Range (value) fields later.

const x = d3.scaleLinear([10.130], [0.960]);
const color = d3.scaleLinear([10.100], ["brown"."steelblue"]); <! -- Equivalent method -->const x = d3.scaleLinear()
    .domain([10.130])
    .range([0.960]);

x(20); / / 80
x(50); / / 320

const color = d3.scaleLinear()
    .domain([10.100])
    .range(["brown"."steelblue"]);

color(20); // "#9a3439"
color(50); // "#7b5167"
Copy the code

💡 Identity Scales is a special case of linear Scales, whose definition domain and range are the same. It is constructed using the method d3.scaleIdentity(range)

Power Scales

Power Scales will Power the value XXX in the domain, and then connect it with the value YYy in the range y= MXK +by=mx^{k}+ BY = MXK +b, where KKK is the Power

Build a power scale using the method const pow = d3.scalePow(domain, range). The default power is 111 (this is a linear scale)

The scale method pow.exponent(k) is used to set the powers

💡 Power scale POw (value) Can accept negative values. In this case, the value of the input parameter and the converted value are multiplied by −1-1−1

💡 D3 also provides a method d3.scalesqrt (domain, range) to conveniently generate power scales of k=0.5 K =0.5k=0.5k=0.5, equivalent to the power scales generated below

d3.scalePow()
  .exponent(0.5)
Copy the code

Log Scales

Log Scales perform logarithmic operations on the value XXX of the domain, and then associate it with the value YYy in the domain y=mlog(x)+ BY =mlog(x)+ BY =mlog(x)+ B

⚠️ Due to log limitations log(0)=−∞log(0)=-\inftylog(0)=−∞, the defined limit of the logarithmic scale is positive. If negative values are required, the scale needs to be encapsulated by explicitly pre-converting both the input and output values by multiplying them by −1-1−1

Build a log scale using the method const log = d3.scaleLog(domain, range) with the default base of 101010

Use the scale method log.base(N) to set the base

💡 Similarly, D3 also provides bisymmetric logarithmic Scales D3. ScaleSymlog (domain, range)

Radial Scales

Radial scale Radial scale is a variant of linear scale, which forms a linear relationship between the value of the defined domain and the square of the value of the range. For example, in the Radial bar chart, the data is mapped as radius, while the graphic element displayed on the page is area

Use method d3. ScaleRadial (domain, range) to build a radial scale

Time Scales

Time Scales, a variant of linear Scales, take the Time object Date as its domain

D3. scaleTime(domain, range) build a time scale. If domain is omitted, the default domain is [2000-01-01, 2000-01-02].

const x = d3.scaleTime()
    .domain([new Date(2000.0.1), new Date(2000.0.2)])
    .range([0.960]);

x(new Date(2000.0.1.5)); / / 200
x(new Date(2000.0.1.16)); / / 640
x.invert(200); // Sat Jan 01 2000 05:00:00 GMT-0800 (PST)
x.invert(640); // Sat Jan 01 2000 16:00:00 GMT-0800 (PST)
Copy the code

Sequential Scales

Similar to the continuous scale, it maps the range of the continuous type to the range of the continuous type, but the range of the scale usually specifies an interpolator

Constructs a sequential scale using the method const sequential = d3.scaleSequential(domain, interpolator), the identity function is used by default if the interpolator of the range is omitted

const rainbow = d3.scaleSequential(d3.interpolateRainbow);
Copy the code

💡 If the range/interpolator is an array of two elements representing the range of interpolation, D3 will call the method d3.interpolate() to convert it to an interpolator

In addition to the usual method of sequential scale, there are several different methods for this scale:

  • sequential.interpolator(interpolator)Set the scale interpolator
  • sequential.range(rangeArr)Set the interpolation range and D3 will convert it to an interpolator

💡 is similar to the continuous scale. The sequential scale has some derived scales, which can first perform power and logarithm operations on the values of the definition domain, and then transfer them to the interpolator for processing

  • d3.scaleSequentialLog(domain, interpolator)d3.scaleSequentialSqrt(domain, interpolator)
  • d3.scaleSequentialPow(domain, interpolator)d3.scaleSequentialSymlog(domain, interpolator)
  • d3.scaleSequentialQuantile(domain, interpolator)Similar to the quantile scale

Diverging Scales

It is similar to the continuous scale in that it maps the continuous domain to the continuous range, but the range of the scale is usually an array of three elements, and the range is usually specified by an interpolator

ScaleDiverging (domain, interpolator) constructs a diverging scale const diverging= d3.scaleDiverging(domain, interpolator) Constructs a diverging scale. If no domain is set, the default value is [0, 0.5, 1]. If no interpolator is set, the identity function is used by default

const spectral = d3.scaleDiverging(d3.interpolateSpectral);
Copy the code

Quantize Scale

Quantize Scale is used to map the continuous definition domain to the discrete value domain. Generally, the data are transformed into hierarchical mapping through rounding and other modification methods, so as to classify and distinguish the data.

The range of the definition domain will be divided into isometric segments according to the number of values available in the discrete range, that is, the discrete value YYy in each range can represent a range of definition domain y=m round(x)+ BY =m\space round(x)+ BY =m round(x)+ B, such as the isometric range graph/hierarchical statistical map

Use the method d3.scalequantize (domain, range) to build a hierarchical scale, which defaults to [1, 0] if the domain or range is omitted, and is equivalent to math.round

const color = d3.scaleQuantize()
    .domain([0.1])
    .range(["brown"."steelblue"]);

color(0.49); // "brown"
color(0.51); // "steelblue"
Copy the code

Common methods for the scale of this type (following quantize) :

  • Quantize.domain (domainArr) sets the domain, and the array consists of two elements forming a range, and the elements are of type numeric and arranged in ascending order

  • Quantize. Range (rangeArr) sets the range of values, and the array contains a number of discrete columns of values

  • Quantize (value) passes the value of a domain to the scale and returns the value of the corresponding range

  • Quantize. InvertExtent (value) passes the value of a range to the scale, which in turn yields the fragment corresponding to the domain

    const width = d3.scaleQuantize()
        .domain([10.100])
        .range([1.2.4]);
    
    width.invertExtent(2); / / [40, 70]
    Copy the code
  • quantize.nice()

Quantile Scales

Quantile Scales takes the input data as a population (a set of discrete values obtained by sampling), so that it can accept any input value in the population range (i.e. the domain is continuous), and can calculate its Quantile in the population. And then based on the quantile to find the corresponding value in the series of discrete values in the range.

Build a quantile scale using the method d3.scaleQuantile(domain, range)

Common methods for this type of scale (quantile below) :

  • Quantile.domain (domainArr) sets the domain, the array consists of a bunch of discrete values obtained by sampling, and the element type is numeric, then D3 copies the array and sorts the elements as a population for quantile calculation

  • Quantile.range (rangeArr) sets the range of values, and the array contains a number of discrete columns of values

  • Quantile (value) passes the value of a domain to the scale and returns the value of the corresponding range

  • Quantile. invertExtent(value) passes the value of a range to the scale and in turn obtains the fragment corresponding to the domain

  • Quantile.quantiles () segmented the quantiles according to the number of discrete values n of range, and then calculated the value of the domain of the corresponding domain according to the quantiles of each segment. This method is to return an array of N-1 threshold values.

Threshold Scales

Threshold Scales and stratified Quantize Scale are similar, but the mapping rules are more free. Each element in the domain array is a Threshold value, which can be more flexible to arbitrarily divide the domain. Then, D3 maps each segment of the domain to each discrete value of the range

Build a threshold scale using the method d3.scaleThreshold(domain, range)

const color = d3.scaleThreshold()
    .domain([0.1])
    .range(["red"."white"."green"]);

color(-1);   // "red"
color(0);    // "white"
color(0.5);  // "white"
color(1);    // "green"
color(1000); // "green"
Copy the code

Common methods for this type of scale (the following threshold) :

  • threshold.domain(domainArr)Sets up the domain, an array of thresholds, and then the elements are sorted in ascending order
  • threshold.range(rangeArr)Set the range, array contains a number of discrete columns of values

⚠️ If the number of discrete values in the range is N+1, the number of threshold values in the array of the domain needs to be N. If the number of threshold values is less than the expected value, the corresponding range discrete values will be ignored. If the number of thresholds is greater than the desired value, undefined may be returned when the threshold scale is called, because there are no corresponding discrete values in the range corresponding to the segment domain.

  • Threshold (value) passes the value of a domain to the scale and returns the value of the corresponding range

  • Threshold.invertextent (value) passes the value of a range to the scale, and in turn obtains the fragment corresponding to the domain

    const color = d3.scaleThreshold()
        .domain([0.1])
        .range(["red"."white"."green"]);
    
    color.invertExtent("red"); // [undefined, 0]
    color.invertExtent("white"); / / [0, 1]
    color.invertExtent("green"); // [1, undefined]
    Copy the code