Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    text
    copied!<p>More generally, if the user interacts with element <em>A</em>, how do you select (and then modify) related elements <em>B</em>? There are many ways of achieving this, but here are three common approaches.</p> <h2>Option 1. For one-to-one mappings, select by id.</h2> <p>If each element in <em>A</em> has exactly one corresponding element in <em>B</em>, you can select the related element B by id, such as <code>d3.select("#foo")</code> to select a <code>&lt;div id="foo"&gt;</code>.</p> <p>This approach requires setting an id for each element in <em>B</em> using <a href="https://github.com/mbostock/d3/wiki/Selections#wiki-attr" rel="nofollow noreferrer">selection.attr</a>. This is easiest if your data has an intrinsic unique identifier, such as <code>d.name</code> or <code>d.id</code>:</p> <pre><code>b.attr("id", function(d) { return d.id; }); </code></pre> <p>Next, to enable clicking on elements <em>A</em> to change the fill color of the corresponding element in <em>B</em>, use <a href="https://github.com/mbostock/d3/wiki/Selections#wiki-on" rel="nofollow noreferrer">selection.on</a> to register a click listener, and then select by id:</p> <pre><code>a.on("click", function(d) { d3.select("#" + d.id).style("fill", "red"); }); </code></pre> <p>Identifiers must be both <em>unique and <a href="http://www.w3.org/TR/html4/types.html#type-id" rel="nofollow noreferrer">valid</a></em>. For example, the id must start with a letter and not a number, and can't contain spaces. If your data doesn't already have a unique identifier, you could generate one from the index, such as</p> <pre><code>b.attr("id", function(d, i) { return "b-" + i; }); </code></pre> <p>And later, assuming the elements <em>A</em> are in the same order,</p> <pre><code>a.on("click", function(d, i) { d3.select("#b-" + i).style("fill", "red"); }); </code></pre> <p>You could also <a href="https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/forEach" rel="nofollow noreferrer">iterate over your data array</a> to generate a unique identifier.</p> <h2>Option 2. For one-to-many mappings, select by class.</h2> <p>To select elements of class "foo", such as a <code>&lt;div class="foo"&gt;</code>, say <code>d3.selectAll(".foo")</code>. Use this approach if any element in <em>A</em> corresponds to multiple elements in <em>B</em>. For example, if you had a force-directed graph showing the relationships between students, you might color the nodes based on each student's year, and then use a legend to toggle the visibility of each year.</p> <p>As with the previous approach, you can use <a href="https://github.com/mbostock/d3/wiki/Selections#wiki-attr" rel="nofollow noreferrer">selection.attr</a> to set the "class" attribute. In this case, the class attribute is not unique, so it might come from a <code>d.type</code> property in the data:</p> <pre><code>b.attr("class", function(d) { return d.type; }) </code></pre> <p>If you have multiple legends for different categorical attributes of data, you could also be more specific and prefix the class name. To continue the student year example:</p> <pre><code>b.attr("class", function(d) { return "year-" + d.year; }) </code></pre> <p>Setting the class attribute will replace any previously-set classes, so if you want to apply multiple classes to the elements, you need to join them together with a space when setting the "class" attribute.</p> <p>Next, to enable clicking on elements <em>A</em> to change the fill color of the corresponding elements in <em>B</em>, use selection.on to register a click listener, and then select by class:</p> <pre><code>a.on("click", function(d) { d3.selectAll("." + d.type).style("fill", "red"); }); </code></pre> <p>Note that we're using <a href="https://github.com/mbostock/d3/wiki/Selections#wiki-d3_selectAll" rel="nofollow noreferrer">selectAll</a> here rather than <a href="https://github.com/mbostock/d3/wiki/Selections#wiki-d3_select" rel="nofollow noreferrer">select</a>; that's because we want to select all corresponding elements, rather than just the first one. Again, you'll need to make sure that the class attribute is <a href="https://stackoverflow.com/questions/448981/what-characters-are-valid-in-css-class-names">valid</a>.</p> <h2>Option 3. For everything else, select and filter by data.</h2> <p>The previous two approaches generate ids and classes so that the browser can index the elements in <em>B</em> for efficient selection. For a small number of elements, or when more general selection methods are needed, you can omit specifying "id" or "class" attributes and simply select manually by <a href="https://github.com/mbostock/d3/wiki/Selections#wiki-filter" rel="nofollow noreferrer">selection.filter</a>.</p> <p>Let's call the datum associated with each element in <em>A</em> <code>da</code>, and the datum associated with each element in <em>B</em> <code>db</code>. Now all we have to do is define an expression that returns true when <code>da</code> matches <code>db</code>. For example, if we wanted to filter by type:</p> <pre><code>a.on("click", function(da) { b.filter(function(db) { return da.type == db.type; }).style("fill", "red"); }); </code></pre> <p>The first two options are preferred, but occasionally manual filtering is useful, such as when you have a range slider and want to filter based on a quantitative variable.</p>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload