UNPKG

d3

Version:

A small, free JavaScript library for manipulating documents based on data.

349 lines (319 loc) 35 kB
<!DOCTYPE html> <html> <head> <meta http-equiv="content-type" content="text/html;charset=utf-8"> <title>d3.js ~ A Bar Chart, Part 1</title> <script type="text/javascript" src="../d3.js?1.12.0"></script> <style type="text/css"> @import url("../style.css?1.10.0"); @import url("../syntax.css?1.6.0"); </style> </head> <body> <div class="body"> <div class="content"> <div class="topbar"> <a href="../">Overview</a> <a href="../ex/">Examples</a> <b><a href="../api/">Documentation</a></b> <a href="http://github.com/mbostock/d3/archives/master">Download</a> </div> <div class="sidebar"> <h1>d3.js</h1> </div> <h1 id='a_bar_chart_part_1'>A Bar Chart, Part 1</h1> <style type='text/css'> .chart { margin-left: 42px; font: 10px sans-serif; shape-rendering: crispEdges; } .chart div { background-color: steelblue; text-align: right; padding: 3px; margin: 1px; color: white; } .chart rect { stroke: white; fill: steelblue; } .chart text.bar { fill: white; } </style> <p>Say you have some data—a simple array of numbers:</p> <div class='highlight'><pre><code class='js'><span class='lineno'>1</span> <span class='kd'>var</span> <span class='nx'>data</span> <span class='o'>=</span> <span class='p'>[</span><span class='mi'>4</span><span class='p'>,</span> <span class='mi'>8</span><span class='p'>,</span> <span class='mi'>15</span><span class='p'>,</span> <span class='mi'>16</span><span class='p'>,</span> <span class='mi'>23</span><span class='p'>,</span> <span class='mi'>42</span><span class='p'>];</span> </code></pre> </div><script type='text/javascript'> var data = [4, 8, 15, 16, 23, 42]; </script> <p>One of the ways you might visualize this univariate data is a bar chart. This guide will examine how to create a simple bar chart using D3, first with basic HTML, and then a more advanced example with SVG.</p> <h2 id='html'>HTML</h2> <p>To get started with HTML, you&#8217;ll first need a container for the chart:</p> <div class='highlight'><pre><code class='js'><span class='lineno'>1</span> <span class='kd'>var</span> <span class='nx'>chart</span> <span class='o'>=</span> <span class='nx'>d3</span><span class='p'>.</span><span class='nx'>select</span><span class='p'>(</span><span class='s2'>&quot;body&quot;</span><span class='p'>)</span> <span class='lineno'>2</span> <span class='p'>.</span><span class='nx'>append</span><span class='p'>(</span><span class='s2'>&quot;div&quot;</span><span class='p'>)</span> <span class='lineno'>3</span> <span class='p'>.</span><span class='nx'>attr</span><span class='p'>(</span><span class='s2'>&quot;class&quot;</span><span class='p'>,</span> <span class='s2'>&quot;chart&quot;</span><span class='p'>);</span> </code></pre> </div> <p>This code selects the document body, which will be the parent of the new chart. Every visible node needs a parent, with the exception of the document&#8217;s root node. The chart container, a <code>div</code> element, is then created and appended to the body. The <code>append</code> operator adds the new node as the last child: the chart will appear at the end of the body.</p> <p>D3 uses the <a href='http://en.wikipedia.org/wiki/Method_chaining'>method chaining</a> design pattern. Above, setting the attribute returns the current selection, and the <code>chart</code> variable thus refers to the chart container element. This approach minimizes the amount of code needed to apply many selections and transformations in sequence.</p> <p>The <code>attr</code> operator sets the &#8220;class&#8221; attribute on the chart container, allowing stylesheets to be applied to the chart elements. This is convenient for static styles, such as the background color and font size. CSS code lives in a <code>style</code> element or an external stylesheet referenced by a <code>link</code> element, rather than the <code>script</code> element used for JavaScript:</p> <div class='highlight'><pre><code class='css'><span class='lineno'>1</span> <span class='nc'>.chart</span> <span class='nt'>div</span> <span class='p'>{</span> <span class='lineno'>2</span> <span class='k'>font</span><span class='o'>:</span> <span class='m'>10px</span> <span class='k'>sans-serif</span><span class='p'>;</span> <span class='lineno'>3</span> <span class='k'>background-color</span><span class='o'>:</span> <span class='nb'>steelblue</span><span class='p'>;</span> <span class='lineno'>4</span> <span class='k'>text-align</span><span class='o'>:</span> <span class='k'>right</span><span class='p'>;</span> <span class='lineno'>5</span> <span class='k'>padding</span><span class='o'>:</span> <span class='m'>3px</span><span class='p'>;</span> <span class='lineno'>6</span> <span class='k'>margin</span><span class='o'>:</span> <span class='m'>1px</span><span class='p'>;</span> <span class='lineno'>7</span> <span class='k'>color</span><span class='o'>:</span> <span class='nb'>white</span><span class='p'>;</span> <span class='lineno'>8</span> <span class='p'>}</span> </code></pre> </div> <p>Next, add some <code>div</code> elements to the container, setting the width by scaling the data:</p> <div class='highlight'><pre><code class='js'><span class='lineno'>1</span> <span class='nx'>chart</span><span class='p'>.</span><span class='nx'>selectAll</span><span class='p'>(</span><span class='s2'>&quot;div&quot;</span><span class='p'>)</span> <span class='lineno'>2</span> <span class='p'>.</span><span class='nx'>data</span><span class='p'>(</span><span class='nx'>data</span><span class='p'>)</span> <span class='lineno'>3</span> <span class='p'>.</span><span class='nx'>enter</span><span class='p'>().</span><span class='nx'>append</span><span class='p'>(</span><span class='s2'>&quot;div&quot;</span><span class='p'>)</span> <span class='lineno'>4</span> <span class='p'>.</span><span class='nx'>style</span><span class='p'>(</span><span class='s2'>&quot;width&quot;</span><span class='p'>,</span> <span class='kd'>function</span><span class='p'>(</span><span class='nx'>d</span><span class='p'>)</span> <span class='p'>{</span> <span class='k'>return</span> <span class='nx'>d</span> <span class='o'>*</span> <span class='mi'>10</span> <span class='o'>+</span> <span class='s2'>&quot;px&quot;</span><span class='p'>;</span> <span class='p'>})</span> <span class='lineno'>5</span> <span class='p'>.</span><span class='nx'>text</span><span class='p'>(</span><span class='kd'>function</span><span class='p'>(</span><span class='nx'>d</span><span class='p'>)</span> <span class='p'>{</span> <span class='k'>return</span> <span class='nx'>d</span><span class='p'>;</span> <span class='p'>});</span> </code></pre> </div> <p>This code selects the child <code>div</code> elements of the chart container. This selection is empty because the container was just added. However, by binding this selection to the array of numbers via the <code>data</code> operator, you can obtain the <em>entering</em> selection—a set of placeholder nodes, one per data element, to which you can append the desired child nodes for each bar.</p> <p>The <code>text</code> operator sets the text content of the bars. The identity function, <code>function(d) { return d; }</code>, causes each data value (number) to be formatted using JavaScript&#8217;s default string conversion, equivalent to the built-in <code>String</code> function. This may be ugly for some numbers (<em>e.g.</em>, 0.12000000000000001). The <code>d3.format</code> class, modeled after Python&#8217;s <a href='http://docs.python.org/library/stdtypes.html#string-formatting'>string formatting</a>, is available for more control over how the number is formatted, supporting comma-grouping of thousands and fixed precision.</p> <p>The above code results in a rudimentary bar chart:</p> <script type='text/javascript'> d3.select(".content") .append("div") .attr("class", "chart") .selectAll("div") .data(data) .enter().append("div") .style("width", function(d) { return d * 10 + "px"; }) .text(function(d) { return d; }); </script> <p>One weakness of the code so far is the <a href='http://en.wikipedia.org/wiki/Magic_number_(programming)#Unnamed_numerical_constants'>magic number</a> 10, which scales the data value to the appropriate bar width. This number depends on the <em>domain</em> of the data (the maximum value, 42), and the width of the chart (420). To avoid hard-coding the <em>x</em>-scale of 10, you can use D3&#8217;s linear scale class, and compute the maximum value from the data:</p> <div class='highlight'><pre><code class='js'><span class='lineno'>1</span> <span class='kd'>var</span> <span class='nx'>x</span> <span class='o'>=</span> <span class='nx'>d3</span><span class='p'>.</span><span class='nx'>scale</span><span class='p'>.</span><span class='nx'>linear</span><span class='p'>()</span> <span class='lineno'>2</span> <span class='p'>.</span><span class='nx'>domain</span><span class='p'>([</span><span class='mi'>0</span><span class='p'>,</span> <span class='nx'>d3</span><span class='p'>.</span><span class='nx'>max</span><span class='p'>(</span><span class='nx'>data</span><span class='p'>)])</span> <span class='lineno'>3</span> <span class='p'>.</span><span class='nx'>range</span><span class='p'>([</span><span class='s2'>&quot;0px&quot;</span><span class='p'>,</span> <span class='s2'>&quot;420px&quot;</span><span class='p'>]);</span> </code></pre> </div><script type='text/javascript'> var x = d3.scale.linear() .domain([0, d3.max(data)]) .range(["0px", "420px"]); </script> <p>Although it looks like an object, the <code>x</code> variable here is actually a <em>function</em> that converts data values (in the domain) to scaled values (in the range). For example, an input value of 4 returns &#8220;40px&#8221;, and an input value of 16 returns &#8220;160px&#8221;. The output range of the scale in this example are strings, with the appropriate <code>px</code> units for CSS. D3&#8217;s automatic interpolators detect the numbers within the strings, while retaining the constant remainder.</p> <p>The new scale arguably still has a magic number: 420px, the width of the chart. If you want to make the chart resizable, you can inspect the width of the chart container, <code>chart.style(&quot;width&quot;)</code>. Or, use percentages rather than pixels. In any case, the reusable scale makes the chart specification easier to modify—for example, you can easily replace the linear scale with a log or root scale.</p> <p>Using the new scale, you can simplify the width style definition:</p> <div class='highlight'><pre><code class='js'><span class='lineno'>1</span> <span class='nx'>chart</span><span class='p'>.</span><span class='nx'>selectAll</span><span class='p'>(</span><span class='s2'>&quot;div&quot;</span><span class='p'>)</span> <span class='lineno'>2</span> <span class='p'>.</span><span class='nx'>data</span><span class='p'>(</span><span class='nx'>data</span><span class='p'>)</span> <span class='lineno'>3</span> <span class='p'>.</span><span class='nx'>enter</span><span class='p'>().</span><span class='nx'>append</span><span class='p'>(</span><span class='s2'>&quot;div&quot;</span><span class='p'>)</span> <span class='lineno'>4</span> <span class='p'>.</span><span class='nx'>style</span><span class='p'>(</span><span class='s2'>&quot;width&quot;</span><span class='p'>,</span> <span class='nx'>x</span><span class='p'>)</span> <span class='lineno'>5</span> <span class='p'>.</span><span class='nx'>text</span><span class='p'>(</span><span class='nb'>String</span><span class='p'>);</span> </code></pre> </div> <p>Now, the HTML representation is very concise, but it&#8217;s not very flexible. Displaying reference lines in the background, or generating columns rather than bars, is difficult in pure HTML. Chart types such as pies and streamgraphs are practically impossible. Fortunately, there&#8217;s a convenient alternative: <a href='http://en.wikipedia.org/wiki/Scalable_Vector_Graphics'>Scalable Vector Graphics</a> (SVG)!</p> <h2 id='svg'>SVG</h2> <p>You use SVG much the same way as HTML, but it offers substantially more flexibility. To start with SVG, create an <code>svg:svg</code> container instead of a <code>div</code>:</p> <div class='highlight'><pre><code class='js'><span class='lineno'>1</span> <span class='kd'>var</span> <span class='nx'>chart</span> <span class='o'>=</span> <span class='nx'>d3</span><span class='p'>.</span><span class='nx'>select</span><span class='p'>(</span><span class='s2'>&quot;body&quot;</span><span class='p'>)</span> <span class='lineno'>2</span> <span class='p'>.</span><span class='nx'>append</span><span class='p'>(</span><span class='s2'>&quot;svg:svg&quot;</span><span class='p'>)</span> <span class='lineno'>3</span> <span class='p'>.</span><span class='nx'>attr</span><span class='p'>(</span><span class='s2'>&quot;class&quot;</span><span class='p'>,</span> <span class='s2'>&quot;chart&quot;</span><span class='p'>)</span> <span class='lineno'>4</span> <span class='p'>.</span><span class='nx'>attr</span><span class='p'>(</span><span class='s2'>&quot;width&quot;</span><span class='p'>,</span> <span class='mi'>420</span><span class='p'>)</span> <span class='lineno'>5</span> <span class='p'>.</span><span class='nx'>attr</span><span class='p'>(</span><span class='s2'>&quot;height&quot;</span><span class='p'>,</span> <span class='mi'>20</span> <span class='o'>*</span> <span class='nx'>data</span><span class='p'>.</span><span class='nx'>length</span><span class='p'>);</span> </code></pre> </div> <p>An immediate difference you will notice with SVG is that the units are implicitly pixels, and thus do not need the &#8220;px&#8221; suffix. Even with pixels, you can rescale the SVG without losing image quality. You can use percentages for relative positioning, too. To use a numeric range for the <em>x</em>-scale:</p> <div class='highlight'><pre><code class='js'><span class='lineno'>1</span> <span class='kd'>var</span> <span class='nx'>x</span> <span class='o'>=</span> <span class='nx'>d3</span><span class='p'>.</span><span class='nx'>scale</span><span class='p'>.</span><span class='nx'>linear</span><span class='p'>()</span> <span class='lineno'>2</span> <span class='p'>.</span><span class='nx'>domain</span><span class='p'>([</span><span class='mi'>0</span><span class='p'>,</span> <span class='nx'>d3</span><span class='p'>.</span><span class='nx'>max</span><span class='p'>(</span><span class='nx'>data</span><span class='p'>)])</span> <span class='lineno'>3</span> <span class='p'>.</span><span class='nx'>range</span><span class='p'>([</span><span class='mi'>0</span><span class='p'>,</span> <span class='mi'>420</span><span class='p'>]);</span> </code></pre> </div><script type='text/javascript'> var x = d3.scale.linear() .domain([0, d3.max(data)]) .range([0, 420]); </script> <p>Unlike HTML, SVG does not provide automatic flow layout. Shapes are positioned relative to the top-left corner, called the origin. Thus, by default, the bars would be drawn on top of each other. To fix this, set the <em>y</em>-coordinate and height explicitly:</p> <div class='highlight'><pre><code class='js'><span class='lineno'>1</span> <span class='nx'>chart</span><span class='p'>.</span><span class='nx'>selectAll</span><span class='p'>(</span><span class='s2'>&quot;rect&quot;</span><span class='p'>)</span> <span class='lineno'>2</span> <span class='p'>.</span><span class='nx'>data</span><span class='p'>(</span><span class='nx'>data</span><span class='p'>)</span> <span class='lineno'>3</span> <span class='p'>.</span><span class='nx'>enter</span><span class='p'>().</span><span class='nx'>append</span><span class='p'>(</span><span class='s2'>&quot;svg:rect&quot;</span><span class='p'>)</span> <span class='lineno'>4</span> <span class='p'>.</span><span class='nx'>attr</span><span class='p'>(</span><span class='s2'>&quot;y&quot;</span><span class='p'>,</span> <span class='kd'>function</span><span class='p'>(</span><span class='nx'>d</span><span class='p'>,</span> <span class='nx'>i</span><span class='p'>)</span> <span class='p'>{</span> <span class='k'>return</span> <span class='nx'>i</span> <span class='o'>*</span> <span class='mi'>20</span><span class='p'>;</span> <span class='p'>})</span> <span class='lineno'>5</span> <span class='p'>.</span><span class='nx'>attr</span><span class='p'>(</span><span class='s2'>&quot;width&quot;</span><span class='p'>,</span> <span class='nx'>x</span><span class='p'>)</span> <span class='lineno'>6</span> <span class='p'>.</span><span class='nx'>attr</span><span class='p'>(</span><span class='s2'>&quot;height&quot;</span><span class='p'>,</span> <span class='mi'>20</span><span class='p'>);</span> </code></pre> </div> <p>Also, the CSS changes slightly when using SVG. Rather than the background, the fill determines the bar color. You can also apply a white border to each bar by setting the stroke style:</p> <div class='highlight'><pre><code class='css'><span class='lineno'>1</span> <span class='nc'>.chart</span> <span class='nt'>rect</span> <span class='p'>{</span> <span class='lineno'>2</span> <span class='n'>stroke</span><span class='o'>:</span> <span class='nb'>white</span><span class='p'>;</span> <span class='lineno'>3</span> <span class='n'>fill</span><span class='o'>:</span> <span class='nb'>steelblue</span><span class='p'>;</span> <span class='lineno'>4</span> <span class='p'>}</span> </code></pre> </div> <p>The SVG-based chart is now almost identical to our original. The chart is currently missing labels, but that will be fixed shortly:</p> <script type='text/javascript'> d3.select(".content") .append("svg:svg") .attr("class", "chart") .attr("width", 420) .attr("height", 20 * data.length) .selectAll("rect") .data(data) .enter().append("svg:rect") .attr("y", function(d, i) { return i * 20; }) .attr("width", x) .attr("height", 20); </script> <p>Astute readers will notice that a magic number crept back into the chart description: the bar height of 20 pixels. Arguably, this number isn&#8217;t magic—twenty is a reasonable height for the bars, just as fourteen is a reasonable point size for text. However, if you prefer to set a height for the entire chart, use a second scale for the <em>y</em>-axis:</p> <div class='highlight'><pre><code class='js'><span class='lineno'>1</span> <span class='kd'>var</span> <span class='nx'>y</span> <span class='o'>=</span> <span class='nx'>d3</span><span class='p'>.</span><span class='nx'>scale</span><span class='p'>.</span><span class='nx'>ordinal</span><span class='p'>()</span> <span class='lineno'>2</span> <span class='p'>.</span><span class='nx'>domain</span><span class='p'>(</span><span class='nx'>data</span><span class='p'>)</span> <span class='lineno'>3</span> <span class='p'>.</span><span class='nx'>rangeBands</span><span class='p'>([</span><span class='mi'>0</span><span class='p'>,</span> <span class='mi'>120</span><span class='p'>]);</span> </code></pre> </div><script type='text/javascript'> var y = d3.scale.ordinal() .domain(data) .rangeBands([0, 120]); </script> <p>As with <code>x</code> previously, <code>y</code> is now a function. It takes as input values from the data array, and for each value returns the corresponding <em>y</em>-coordinate. For example, an input value of 4 returns 0, and an input value of 16 returns 60. This approach requires that the values in our dataset are unique; ordinal scales are often used to encode non-quantitative data, such as country names. Alternatively, you can use array indices as the ordinal domain: [0, 1, 2…].</p> <p>The new scale plugs into the bar specification, replacing the &#8220;y&#8221; attribute:</p> <div class='highlight'><pre><code class='js'><span class='lineno'>1</span> <span class='nx'>chart</span><span class='p'>.</span><span class='nx'>selectAll</span><span class='p'>(</span><span class='s2'>&quot;rect&quot;</span><span class='p'>)</span> <span class='lineno'>2</span> <span class='p'>.</span><span class='nx'>data</span><span class='p'>(</span><span class='nx'>data</span><span class='p'>)</span> <span class='lineno'>3</span> <span class='p'>.</span><span class='nx'>enter</span><span class='p'>().</span><span class='nx'>append</span><span class='p'>(</span><span class='s2'>&quot;svg:rect&quot;</span><span class='p'>)</span> <span class='lineno'>4</span> <span class='p'>.</span><span class='nx'>attr</span><span class='p'>(</span><span class='s2'>&quot;y&quot;</span><span class='p'>,</span> <span class='nx'>y</span><span class='p'>)</span> <span class='lineno'>5</span> <span class='p'>.</span><span class='nx'>attr</span><span class='p'>(</span><span class='s2'>&quot;width&quot;</span><span class='p'>,</span> <span class='nx'>x</span><span class='p'>)</span> <span class='lineno'>6</span> <span class='p'>.</span><span class='nx'>attr</span><span class='p'>(</span><span class='s2'>&quot;height&quot;</span><span class='p'>,</span> <span class='nx'>y</span><span class='p'>.</span><span class='nx'>rangeBand</span><span class='p'>());</span> </code></pre> </div> <p>The new scales can also be applied to render labels, showing the associated value. This code centers labels vertically within each bar, and right-aligns text:</p> <div class='highlight'><pre><code class='js'><span class='lineno'>1</span> <span class='nx'>chart</span><span class='p'>.</span><span class='nx'>selectAll</span><span class='p'>(</span><span class='s2'>&quot;text&quot;</span><span class='p'>)</span> <span class='lineno'>2</span> <span class='p'>.</span><span class='nx'>data</span><span class='p'>(</span><span class='nx'>data</span><span class='p'>)</span> <span class='lineno'>3</span> <span class='p'>.</span><span class='nx'>enter</span><span class='p'>().</span><span class='nx'>append</span><span class='p'>(</span><span class='s2'>&quot;svg:text&quot;</span><span class='p'>)</span> <span class='lineno'>4</span> <span class='p'>.</span><span class='nx'>attr</span><span class='p'>(</span><span class='s2'>&quot;x&quot;</span><span class='p'>,</span> <span class='nx'>x</span><span class='p'>)</span> <span class='lineno'>5</span> <span class='p'>.</span><span class='nx'>attr</span><span class='p'>(</span><span class='s2'>&quot;y&quot;</span><span class='p'>,</span> <span class='kd'>function</span><span class='p'>(</span><span class='nx'>d</span><span class='p'>)</span> <span class='p'>{</span> <span class='k'>return</span> <span class='nx'>y</span><span class='p'>(</span><span class='nx'>d</span><span class='p'>)</span> <span class='o'>+</span> <span class='nx'>y</span><span class='p'>.</span><span class='nx'>rangeBand</span><span class='p'>()</span> <span class='o'>/</span> <span class='mi'>2</span><span class='p'>;</span> <span class='p'>})</span> <span class='lineno'>6</span> <span class='p'>.</span><span class='nx'>attr</span><span class='p'>(</span><span class='s2'>&quot;dx&quot;</span><span class='p'>,</span> <span class='o'>-</span><span class='mi'>3</span><span class='p'>)</span> <span class='c1'>// padding-right</span> <span class='lineno'>7</span> <span class='p'>.</span><span class='nx'>attr</span><span class='p'>(</span><span class='s2'>&quot;dy&quot;</span><span class='p'>,</span> <span class='s2'>&quot;.35em&quot;</span><span class='p'>)</span> <span class='c1'>// vertical-align: middle</span> <span class='lineno'>8</span> <span class='p'>.</span><span class='nx'>attr</span><span class='p'>(</span><span class='s2'>&quot;text-anchor&quot;</span><span class='p'>,</span> <span class='s2'>&quot;end&quot;</span><span class='p'>)</span> <span class='c1'>// text-align: right</span> <span class='lineno'>9</span> <span class='p'>.</span><span class='nx'>text</span><span class='p'>(</span><span class='nb'>String</span><span class='p'>);</span> </code></pre> </div> <p>The formal <a href='http://www.w3.org/TR/SVG/text.html'>SVG Text</a> specification describes in detail the meaning of the &#8220;dx&#8221;, &#8220;dy&#8221; and &#8220;text-anchor&#8221; attributes. The full spec is dense, as SVG offers a level of control required by only the most ambitious typographers; fortunately, it&#8217;s not too hard to remember standard settings for alignment and padding!</p> <p>The SVG chart now looks identical to the earlier HTML version:</p> <script type='text/javascript'> var chart = d3.select(".content") .append("svg:svg") .attr("class", "chart") .attr("width", 420) .attr("height", 120); chart.selectAll("rect") .data(data) .enter().append("svg:rect") .attr("y", y) .attr("width", x) .attr("height", y.rangeBand()); chart.selectAll("text") .data(data) .enter().append("svg:text") .attr("class", "bar") .attr("x", x) .attr("y", function(d) { return y(d) + y.rangeBand() / 2; }) .attr("dx", -3) .attr("dy", ".35em") .attr("text-anchor", "end") .text(String); </script> <p>With the basic chart is in place, you can place additional marks to improve readability. As a first step, pad the SVG container to make space for labels:</p> <div class='highlight'><pre><code class='js'><span class='lineno'>1</span> <span class='kd'>var</span> <span class='nx'>chart</span> <span class='o'>=</span> <span class='nx'>d3</span><span class='p'>.</span><span class='nx'>select</span><span class='p'>(</span><span class='s2'>&quot;.content&quot;</span><span class='p'>)</span> <span class='lineno'>2</span> <span class='p'>.</span><span class='nx'>append</span><span class='p'>(</span><span class='s2'>&quot;svg:svg&quot;</span><span class='p'>)</span> <span class='lineno'>3</span> <span class='p'>.</span><span class='nx'>attr</span><span class='p'>(</span><span class='s2'>&quot;class&quot;</span><span class='p'>,</span> <span class='s2'>&quot;chart&quot;</span><span class='p'>)</span> <span class='lineno'>4</span> <span class='p'>.</span><span class='nx'>attr</span><span class='p'>(</span><span class='s2'>&quot;width&quot;</span><span class='p'>,</span> <span class='mi'>440</span><span class='p'>)</span> <span class='lineno'>5</span> <span class='p'>.</span><span class='nx'>attr</span><span class='p'>(</span><span class='s2'>&quot;height&quot;</span><span class='p'>,</span> <span class='mi'>140</span><span class='p'>)</span> <span class='lineno'>6</span> <span class='p'>.</span><span class='nx'>append</span><span class='p'>(</span><span class='s2'>&quot;svg:g&quot;</span><span class='p'>)</span> <span class='lineno'>7</span> <span class='p'>.</span><span class='nx'>attr</span><span class='p'>(</span><span class='s2'>&quot;transform&quot;</span><span class='p'>,</span> <span class='s2'>&quot;translate(10,15)&quot;</span><span class='p'>);</span> </code></pre> </div> <p>The <code>svg:g</code> element is a <a href='http://www.w3.org/TR/SVG/struct.html'>container element</a>, much like the <code>div</code> element in HTML. Setting a <a href='http://www.w3.org/TR/SVG/coords.html#TransformAttribute'>transform</a> on a container affects how its children are positioned. For padding, you need only to translate; however, for advanced graphical effects, you can use any affine transformation, such as scale, rotate and shear!</p> <p>The linear scale, <code>x</code>, provides a <code>ticks</code> routine that generates values in the domain at sensible intervals. For a chart this size, about ten ticks is appropriate; for smaller or larger charts, you can vary the number of ticks to generate. These tick values serve as data for reference lines:</p> <div class='highlight'><pre><code class='js'><span class='lineno'>1</span> <span class='nx'>chart</span><span class='p'>.</span><span class='nx'>selectAll</span><span class='p'>(</span><span class='s2'>&quot;line&quot;</span><span class='p'>)</span> <span class='lineno'>2</span> <span class='p'>.</span><span class='nx'>data</span><span class='p'>(</span><span class='nx'>x</span><span class='p'>.</span><span class='nx'>ticks</span><span class='p'>(</span><span class='mi'>10</span><span class='p'>))</span> <span class='lineno'>3</span> <span class='p'>.</span><span class='nx'>enter</span><span class='p'>().</span><span class='nx'>append</span><span class='p'>(</span><span class='s2'>&quot;svg:line&quot;</span><span class='p'>)</span> <span class='lineno'>4</span> <span class='p'>.</span><span class='nx'>attr</span><span class='p'>(</span><span class='s2'>&quot;x1&quot;</span><span class='p'>,</span> <span class='nx'>x</span><span class='p'>)</span> <span class='lineno'>5</span> <span class='p'>.</span><span class='nx'>attr</span><span class='p'>(</span><span class='s2'>&quot;x2&quot;</span><span class='p'>,</span> <span class='nx'>x</span><span class='p'>)</span> <span class='lineno'>6</span> <span class='p'>.</span><span class='nx'>attr</span><span class='p'>(</span><span class='s2'>&quot;y1&quot;</span><span class='p'>,</span> <span class='mi'>0</span><span class='p'>)</span> <span class='lineno'>7</span> <span class='p'>.</span><span class='nx'>attr</span><span class='p'>(</span><span class='s2'>&quot;y2&quot;</span><span class='p'>,</span> <span class='mi'>120</span><span class='p'>)</span> <span class='lineno'>8</span> <span class='p'>.</span><span class='nx'>attr</span><span class='p'>(</span><span class='s2'>&quot;stroke&quot;</span><span class='p'>,</span> <span class='s2'>&quot;#ccc&quot;</span><span class='p'>);</span> </code></pre> </div> <p>Positioning text above the reference lines reveals their value:</p> <div class='highlight'><pre><code class='js'><span class='lineno'>1</span> <span class='nx'>chart</span><span class='p'>.</span><span class='nx'>selectAll</span><span class='p'>(</span><span class='s2'>&quot;text.rule&quot;</span><span class='p'>)</span> <span class='lineno'>2</span> <span class='p'>.</span><span class='nx'>data</span><span class='p'>(</span><span class='nx'>x</span><span class='p'>.</span><span class='nx'>ticks</span><span class='p'>(</span><span class='mi'>10</span><span class='p'>))</span> <span class='lineno'>3</span> <span class='p'>.</span><span class='nx'>enter</span><span class='p'>().</span><span class='nx'>append</span><span class='p'>(</span><span class='s2'>&quot;svg:text&quot;</span><span class='p'>)</span> <span class='lineno'>4</span> <span class='p'>.</span><span class='nx'>attr</span><span class='p'>(</span><span class='s2'>&quot;class&quot;</span><span class='p'>,</span> <span class='s2'>&quot;rule&quot;</span><span class='p'>)</span> <span class='lineno'>5</span> <span class='p'>.</span><span class='nx'>attr</span><span class='p'>(</span><span class='s2'>&quot;x&quot;</span><span class='p'>,</span> <span class='nx'>x</span><span class='p'>)</span> <span class='lineno'>6</span> <span class='p'>.</span><span class='nx'>attr</span><span class='p'>(</span><span class='s2'>&quot;y&quot;</span><span class='p'>,</span> <span class='mi'>0</span><span class='p'>)</span> <span class='lineno'>7</span> <span class='p'>.</span><span class='nx'>attr</span><span class='p'>(</span><span class='s2'>&quot;dy&quot;</span><span class='p'>,</span> <span class='o'>-</span><span class='mi'>3</span><span class='p'>)</span> <span class='lineno'>8</span> <span class='p'>.</span><span class='nx'>attr</span><span class='p'>(</span><span class='s2'>&quot;text-anchor&quot;</span><span class='p'>,</span> <span class='s2'>&quot;middle&quot;</span><span class='p'>)</span> <span class='lineno'>9</span> <span class='p'>.</span><span class='nx'>text</span><span class='p'>(</span><span class='nb'>String</span><span class='p'>);</span> </code></pre> </div> <p>Note that the rule labels are assigned the class &#8220;rule&#8221;; this avoids a selector collision with the value labels on each bar. (Another way to disambiguate is to put reference labels in a separate <code>g</code> container.) Lastly, add a single black line for the <em>y</em>-axis:</p> <div class='highlight'><pre><code class='js'><span class='lineno'>1</span> <span class='nx'>chart</span><span class='p'>.</span><span class='nx'>append</span><span class='p'>(</span><span class='s2'>&quot;svg:line&quot;</span><span class='p'>)</span> <span class='lineno'>2</span> <span class='p'>.</span><span class='nx'>attr</span><span class='p'>(</span><span class='s2'>&quot;y1&quot;</span><span class='p'>,</span> <span class='mi'>0</span><span class='p'>)</span> <span class='lineno'>3</span> <span class='p'>.</span><span class='nx'>attr</span><span class='p'>(</span><span class='s2'>&quot;y2&quot;</span><span class='p'>,</span> <span class='mi'>120</span><span class='p'>)</span> <span class='lineno'>4</span> <span class='p'>.</span><span class='nx'>attr</span><span class='p'>(</span><span class='s2'>&quot;stroke&quot;</span><span class='p'>,</span> <span class='s2'>&quot;#000&quot;</span><span class='p'>);</span> </code></pre> </div> <p>Et voilà!</p> <script type='text/javascript'> var chart = d3.select(".content") .append("svg:svg") .attr("class", "chart") .attr("width", 440) .attr("height", 140) .style("margin-left", "32px") // Tweak alignment… .append("svg:g") .attr("transform", "translate(10,15)"); chart.selectAll("line") .data(x.ticks(10)) .enter().append("svg:line") .attr("x1", x) .attr("x2", x) .attr("y1", 0) .attr("y2", 120) .attr("stroke", "#ccc"); chart.selectAll("text.rule") .data(x.ticks(10)) .enter().append("svg:text") .attr("x", x) .attr("y", 0) .attr("dy", -3) .attr("text-anchor", "middle") .text(String); chart.selectAll("rect") .data(data) .enter().append("svg:rect") .attr("y", y) .attr("width", x) .attr("height", y.rangeBand()); chart.selectAll("text.bar") .data(data) .enter().append("svg:text") .attr("class", "bar") .attr("x", x) .attr("y", function(d) { return y(d) + y.rangeBand() / 2; }) .attr("dx", -3) .attr("dy", ".35em") .attr("text-anchor", "end") .text(String); chart.append("svg:line") .attr("y1", 0) .attr("y2", 120) .attr("stroke", "#000"); </script> <p>This tutorial covered many of the core concepts in D3, including selections, dynamic properties, and scales. However, this only scratches the surface! Continue reading <a href='bar-2.html'>part 2</a> to learn about transitions in dynamic visualizations. Or, explore the <a href='../ex/'>examples gallery</a> to see more advanced techniques with D3.</p> </div> <div class="foot">Copyright &copy; 2011 <a href="http://bost.ocks.org/mike">Mike Bostock</a></div> </div> </div> <a href="http://github.com/mbostock/d3"><img style="position:absolute;top:0;right:0;border:0;" width="149" height="149" src="../forkme.png" alt="Fork me on GitHub" /></a> </body> </html>