- Data Visualization with D3 4.x Cookbook(Second Edition)
- Nick Zhu
- 676字
- 2021-07-09 19:26:21
Performing subselection
It is quite common that you will need to perform scoped selection when working on visualization. For example, selecting all p
elements within a particular section
element is one such use case of scoped selection. In this recipe, we will demonstrate how this can be achieved with different approaches and their advantages and disadvantages.
Getting ready
Open your local copy of the following file in your web browser:
https://github.com/NickQiZhu/d3-cookbook-v2/blob/master/src/chapter2/sub-selection.html .
How to do it...
The following code example selects two different p
elements using two different styles of subselection supported by D3:
<section id="section1"> <p> <p>blue box</p> </p> </section> <section id="section2"> <p> <p>red box</p> </p> </section> <script type="text/javascript"> d3.select("#section1 > p") // <-- A .attr("class", "blue box"); d3.select("#section2") // <-- B .select("p") // <-- C .attr("class", "red box"); </script>
This code generates the following visual output:

Subselection
How it works...
Though it produces the same visual effect, this example demonstrates two very different subselection techniques. We will discuss them separately here so you can understand their pros and cons as well as when to use one versus the other:
- Selector level-3 combinators: On line
A
,d3.select
is used with a special-looking string, which consists of one tag name connected with another one using a greater-than sign (U+003E, >). This syntax is called combinators (the greater-than sign here indicates it is a child combinator). Level-3 selector supports a few different kinds of structural combinators. Here, we will give a quick introduction to the most common ones. - The descendant combinator: This combinator has the syntax just like
selector selector
. The descendant combinator, as suggested by its name, is used to describe a loose parent-child relationship between two selections. The reason why it is called a loose parent-child relationship is that the descendant combinatory does not care if the second selection is a child or a grandchild or a great-grandchild of the parent selection. Let's take a look at some examples to illustrate this loose relationship concept:<p> <span> The quick <em>red</em> fox jumps over the lazy brown dog </span> </p>
If we use the following selector:
p em
It will select the
em
element sincep
is the ancestor of theem
element andem
is a descendent of thep
element. - Child combinator: This combinator has the syntax such as
selector > selector
. The child combinator offers a more restrictive way to describe a parent-child relationship between two elements. A child combinator is defined using a greater-than sign (U+003E, >) character separating the two selectors, as follows:span > em
It will select the
em
element sinceem
is a direct child of thespan
element in our example. The selectorp > em
will not produce any valid selection sinceem
is not a direct child of thep
element.Note
The level-3 selector also supports sibling combinators; however, since it is less common, we will not cover it here; interested readers can refer to W3C level-3 selector documentation at http://www.w3.org/TR/css3-selectors/#sibling-combinators . The W3C level-4 selector offers some interesting additional combinators, that is, following-sibling and reference combinators that can yield some very powerful target selection capability; refer to https://drafts.csswg.org/selectors-4/#combinators for more details.
- The D3 nested subselection: On lines
B
andC
, a different kind of subselection technique was used. In this case, a simple D3 selection was made first on lineB
by selecting thesection #section2
element. Immediately afterward, anotherselect
was chained to select ap
element on lineC
. This kind of nested selection defines a scoped selection. In plain English, this basically means to select ap
element that is nested under#section2
. In semantics, this is essentially the same as using a descendant combinator#section2 p
. However, the advantage of this form of subselection is that since the parent element is separately selected, it allows you to handle the parent element before selecting the child element. To demonstrate this, let's take a look at the following code snippet:d3.select("#section2") // <-- B .style("font-size", "2em") // <-- B-1 .select("p") // <-- C .attr("class", "red box");
As shown in the preceding code snippet, you can see that before we select the
p
element, we can apply a modifier function to#section2
on lineB-1
. This flexibility will be further explored in the next section.