One, foreword

With the increasing demand for customized visualization, highly encapsulated visualization frameworks such as Highcharts and Echarts can no longer meet users’ various highly customized visualization needs. At this time, the unlimited customization ability of D3 stands out.

If you want to complete the visualization through D3, in addition to learning the D3 API itself, about the Web standards of HTML, SVG, CSS, Javascript and data visualization concepts and standards are required to learn. There is no doubt a high learning hurdle, but it is worth it, as with D3 we can achieve almost any 2D visualization needs.

In this paper, through the analysis of the D3 core module and specific case practice, to help beginners learn and understand the D3 drawing ideas.

2. What is D3

The full name of D3 is data-driven Documents. It is a JavaScript library that operates Documents based on Data. Its core is to use drawing instructions to transform Data and create new graphable Data on the basis of source Data. Generate SVG paths and create data visualization elements (such as axes) in the DOM through data and methods.

Relative to the Echats out-of-the-box visualization framework, such as D3 is closer to the bottom, it can directly control the native SVG element, and not directly provide any kind of ready-made visual chart, all the charts are need we choose appropriate method in its garage building, it also greatly improved its visual customization capabilities. Moreover, D3 introduces no new graphics elements. It follows Web standards (HTML, CSS, SVG, and Canvas) to present data, so it can run independently in modern browsers without relying on other frameworks.

Iii. D3 core module

After V4, the D3 API has now been broken down into modules that we can load on demand according to our visual needs. According to the generic sense, THE D3 API module can be divided into the following categories: DOM operation, data processing, data analysis and transformation, geographic path, behavior, etc.

Here, we mainly analyze d3-selection and D3-scale modules:

3.1 D3 – selection

D3-selection is the core module of D3js, mainly used to select elements, set attributes, data binding, event binding and other operations.

** Select elements: **D3-selection provides two methods to get the target element, d3.select() : returns the first node of the target element, d3.selectAll() : Returns a collection of target elements. At first glance, it looks a bit like the native API’s querySelector and querySelectorAll, but d3.select returns a selection object. QuerySelector returns a NodeList array. From the information printed on the console, you can see that groups under Selection holds the collection of all the selected elements, and parents holds the parents of all the selected elements.

** Set properties or bind events: ** We don’t need to care what the structure of groups is. When either select. attr or select. style is called, all children of all groups in a selection are called. The only effect of group existence is: When we pass a function, such as select.attr (‘attrName’, function(data, I)) or select.on (‘click’, function(data, I)) In function(data, I) passed, the second argument I is the index of the element in the group rather than in the entire selection.

** Data binding: ** actually assigns a value to the __data__ attribute of the selected DOM element. There are three ways to do this:

(1) Call select.datum for each individual DOM element: d3.select(‘body’).datum(20) equals document.body.__data__ = 20

(2) Inherits data from the parent node, such as: append, INSERT, select; the child node inherits data from the parent node actively:

(3) Call select.data (), support to pass the data with the underlying data type, also support to pass a function(parentNode, groupIndex) according to the node index and data mapping, The data() method introduces the very important join idea in D3:

Binding data to a DOM element in D3 is done by comparing the key values of the data to the DOM. If we do not set the key separately, the default key is set according to the index of the data, but when the order of the data changes, this default key becomes unreliable. In this case, we can use the second argument, keyFunction, in select.data (data, keyFunction), to return the corresponding key based on the current data. As can be seen from the legend below, no matter there is one or more groups (each group is independent), as long as we ensure that the key value in any group is unique, the data changes will be reflected to the corresponding DOM element (update process) :

3.2 the Join thought

If the number of elements in the DOM and data is not the same, let’s take a look at how D3 does data binding: Now it’s time to introduce the core Join idea of the D3-Selecion module, which simply says “You shouldn’t tell D3 how to create elements, you should tell D3, How should the selectAll() set correspond to the data bound to.data(data)?”

As can be seen from the figure above, during d3.data(data) data binding, three state selection sets will be generated:

  • Update: Collection of DOM elements that have been bound to data

  • **Enter: **Enter: **Enter: **Enter: **Enter: **Enter: **Enter: **Enter:

  • Exit: Set of DOM elements that are not data-bound (redundant DOM elements)

Using Join means that all we need to do is declare the relationship between the DOM set and the data set, and describe this relationship by handling the three different state sets enter, Update, and exit. In this way, we can greatly simplify the operation of DOM elements. We do not need to use if and for loops to make complex logical judgments to get the set of elements we need. In addition, when processing dynamic data, real-time data can be easily displayed and smooth dynamic interaction effects can be added by processing these three states.

3. 3 D3-scale

D3-scale offers a variety of different types of scales. Often used in conjunction with the D3-axis module.

D3-scale provides a variety of continuous and discontinuous scales, which can be generally divided into three categories:

  • Continuous input (Domain) and continuous output (range)

  • Continuous inputs (Domain) and discrete outputs (range)

  • Discrete input (Domain) and discrete output (range)

Some commonly used scales:

(1) D3-Scalelinear Linear Scale (continuous input and continuous output)

As you can see, calling d3.scalelinear () generates linear scales, with domain() being the input domain and range() being the output domain, which is equivalent to mapping the data set in domain to the data set in Range.

Example:

Mapping:

(2) D3-ScaleTime (continuous input and continuous output)

The time scale is similar to the linear scale, except that the input field becomes a time axis. Invert () and invertExtent() methods are also used to determine the value of the input field based on the output field value.

Example:

(3) D3. ScaleQuantize (continuous input and discrete output)

Quantization scale divides the continuous input domain into uniform segments according to the output domain, so its output domain is discrete.

Example:

Mapping:

(4) D3. ScaleThreshold (continuous input and discrete output)

A threshold scale can specify a split threshold for a set of consecutive data, with the default domain: [0.5] and the default range: [0, 1], so the default d3.scaleThreshold() is equivalent to the math.round function. If the threshold scale input field is N, the output field must be N + 1, otherwise the scale may return undefined for some values, or redundant values in the output field may be ignored.

Example:

There are three kinds of mappings:

A. When the domain and range data is N: N+1

B. When the domain and range data is N: N + is greater than 1

C. When the domain and range data is N + greater than 0: N

(5) D3. Ordinal scale (discrete input and discrete output)

Unlike continuous scales such as scaleLinear, the output domain and input domain of ordinal scale are discrete.

Example:

There are three kinds of mappings:

A. When the domain and range data are in one-to-one correspondence

B. When domain is less than range

C. When domain is greater than range

Four, in actual combat

Through the above learning, we should have a certain understanding of how D3 operates the DOM and the data mapping of coordinate axes into the corresponding visual performance. Now let’s actually use these two modules to realize our common visual chart: bar chart.

(1) First add an SVG element.

(2) Draw the axes according to the d3.scale and d3.axis modules mentioned above. D3.scaleband () is called ordinal Ordinal scale, similar to d3.scaleordinal (), but it supports output fields of continuous numeric types. A discrete input field can divide a continuous range into uniform segments. When drawing the grid, we do not add an extra line element. Instead, we use the axis ticks() method of the d3.axis module to set the scale, and tickSIze() to set the scale length. To simulate grid lines of equal width to the chart, and you can also format the Y-axis scale values using tickFormat().

(3) After the coordinate axis is drawn, we use data binding to draw the corresponding rect elements.

(4) At this time, the bar chart has been basically drawn, and then we can enrich the content display, add labels, titles and other prompt information.

(5) Finally, we realized the information floating layer interaction of Tooltips by binding listening event to the column.

Five, the summary

Through the study of modules such as D3. selection, D3. scale and d3.axis, we have been able to draw commonly used bar charts and other charts. We can also draw more complex visual effects through other modules provided by D3. For example, hierarchy visualization is realized through D3-Hierarchy (hierarchy module), and map data visualization is realized through D3-Geo (geographic projection). The content in this paper is only the tip of the iceberg of D3 library. So by the time we mastered D3, it was not technology but imagination that limited our ability to visualize.

Author: Ray