epubjs
Version:
Render ePub documents in the browser, across many devices
178 lines (176 loc) • 36.9 kB
HTML
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:epub="http://www.idpf.org/2007/ops" xmlns:m="http://www.w3.org/1998/Math/MathML" xmlns:pls="http://www.w3.org/2005/01/pronunciation-lexicon" xmlns:ssml="http://www.w3.org/2001/10/synthesis" xmlns:svg="http://www.w3.org/2000/svg"><head><title>Chapter 8. Axes</title><link rel="stylesheet" type="text/css" href="core.css"/><meta name="generator" content="DocBook XSL Stylesheets V1.76.1"/><link rel="up" href="index.html" title="Interactive Data Visualization for the Web"/><link rel="prev" href="ch07.html" title="Chapter 7. Scales"/><link rel="next" href="ch09.html" title="Chapter 9. Updates, Transitions, and Motion"/></head><body><section class="chapter" title="Chapter 8. Axes" epub:type="chapter" id="_axes"><div class="titlepage"><div><div><h2 class="title">Chapter 8. Axes</h2></div></div></div><p>Having mastered the use of D3 scales, we now have the scatterplot shown in <a class="xref" href="ch08.html#Large_scaled_scatterplot2" title="Figure 8-1. Large, scaled scatterplot">Figure 8-1</a>.</p><div class="figure"><a id="Large_scaled_scatterplot2"/><div class="figure-contents"><div class="mediaobject"><a id="I_mediaobject8_id305057"/><img src="httpatomoreillycomsourceoreillyimages1614795.png.jpg" alt="Large, scaled scatterplot"/></div></div><div class="figure-title">Figure 8-1. Large, scaled scatterplot</div></div><p>Let’s add horizontal and vertical axes, so we can do away with the
horrible red numbers cluttering up our chart.<a id="ix_axes" class="indexterm"/><a id="I_indexterm8_id305090" class="indexterm"/></p><div class="sect1" title="Introducing Axes"><div class="titlepage"><div><div><h2 class="title" style="clear: both" id="_introducing_axes">Introducing Axes</h2></div></div></div><p>Much like its scales, <a class="ulink" href="https://github.com/mbostock/d3/wiki/SVG-Axes" target="_top">D3’s
<span class="emphasis"><em>axes</em></span></a> are actually <span class="emphasis"><em>functions</em></span> whose parameters you define. Unlike
scales, when an axis function is called, it doesn’t return a value, but
generates the visual elements of the axis, including lines, labels, and
ticks.<a id="I_indexterm8_id305129" class="indexterm"/><a id="I_indexterm8_id305135" class="indexterm"/></p><p>Note that the axis functions are SVG-specific, as they generate SVG
elements. Also, axes are intended for use with quantitative scales (as
opposed to ordinal ones).<a id="I_indexterm8_id305148" class="indexterm"/><a id="I_indexterm8_id305155" class="indexterm"/><a id="I_indexterm8_id305161" class="indexterm"/></p></div><div class="sect1" title="Setting Up an Axis"><div class="titlepage"><div><div><h2 class="title" style="clear: both" id="_setting_up_an_axis">Setting Up an Axis</h2></div></div></div><p>Use <code class="literal">d3.svg.axis()</code> to create a generic axis <a id="I_indexterm8_id305194" class="indexterm"/>function:</p><a id="I_programlisting8_id305205"/><pre class="programlisting"><code class="kd">var</code> <code class="nx">xAxis</code> <code class="o">=</code> <code class="nx">d3</code><code class="p">.</code><code class="nx">svg</code><code class="p">.</code><code class="nx">axis</code><code class="p">();</code></pre><p>At a minimum, each axis also needs to be told on what <span class="emphasis"><em>scale</em></span> to
operate. Here we’ll pass in the <code class="literal">xScale</code> from the scatterplot code:</p><a id="I_programlisting8_id305223"/><pre class="programlisting"><code class="nx">xAxis</code><code class="p">.</code><code class="nx">scale</code><code class="p">(</code><code class="nx">xScale</code><code class="p">);</code></pre><p>We can also specify where the labels should appear relative to the axis<a id="I_indexterm8_id305233" class="indexterm"/>
itself. The default is <code class="literal">bottom</code>, meaning the labels will appear below
the axis line. (Although this is the default, it can’t hurt to specify
it explicitly.) Possible orientations for horizontal axes are <code class="literal">top</code> and
<code class="literal">bottom</code>. For vertical axes, use <code class="literal">left</code> and <code class="literal">right</code>:</p><a id="I_programlisting8_id305263"/><pre class="programlisting"><code class="nx">xAxis</code><code class="p">.</code><code class="nx">orient</code><code class="p">(</code><code class="s2">"bottom"</code><code class="p">);</code></pre><p>Of course, we can be more concise and string all this together into one
line:</p><a id="I_programlisting8_id305273"/><pre class="programlisting"><code class="kd">var</code> <code class="nx">xAxis</code> <code class="o">=</code> <code class="nx">d3</code><code class="p">.</code><code class="nx">svg</code><code class="p">.</code><code class="nx">axis</code><code class="p">()</code>
<code class="p">.</code><code class="nx">scale</code><code class="p">(</code><code class="nx">xScale</code><code class="p">)</code>
<code class="p">.</code><code class="nx">orient</code><code class="p">(</code><code class="s2">"bottom"</code><code class="p">);</code></pre><p>Finally, to actually generate the axis and insert all those little lines
and labels into our SVG, we must <span class="emphasis"><em>call</em></span> the <code class="literal">xAxis</code> function. This is
similar to the scale functions, which we first configured by setting
parameters, and then later <span class="emphasis"><em>called</em></span>, to put them into action.<a id="I_indexterm8_id305295" class="indexterm"/></p><p>I’ll put this code at the end of our script, so the axis is generated
after the other elements in the SVG, and therefore appears “on top”:</p><a id="I_programlisting8_id305307"/><pre class="programlisting"><code class="nx">svg</code><code class="p">.</code><code class="nx">append</code><code class="p">(</code><code class="s2">"g"</code><code class="p">)</code>
<code class="p">.</code><code class="nx">call</code><code class="p">(</code><code class="nx">xAxis</code><code class="p">);</code></pre><p>This is where things get a little funky. You might be wondering why this
looks so different from our friendly scale functions. Here’s why: because
an <span class="emphasis"><em>axis</em></span> function actually draws something to the screen (by appending
SVG elements to the DOM), we need to specify <span class="emphasis"><em>where</em></span> in the DOM it
should place those new elements. This is in contrast to scale functions
like <code class="literal">xScale()</code>, for example, which calculate a value and return those
values, typically for use by yet another function, without impacting the
DOM at all.<a id="I_indexterm8_id305330" class="indexterm"/></p><p>So what we’re doing with the preceding code is to first reference <code class="literal">svg</code>, the
SVG image in the DOM. Then, we <code class="literal">append()</code> a new <code class="literal">g</code> element to the end
of the SVG. In SVG land, a <code class="literal">g</code> element is a <span class="emphasis"><em>group</em></span> element. Group<a id="I_indexterm8_id305364" class="indexterm"/><a id="I_indexterm8_id305374" class="indexterm"/>
elements are invisible, unlike <code class="literal">line</code>, <code class="literal">rect</code>, and <code class="literal">circle</code>, and they
have no visual presence themselves. Yet they help us in two ways: first,
<code class="literal">g</code> elements can be used to contain (or “group”) other elements, which
keeps our code nice and tidy. Second, we can apply <span class="emphasis"><em>transformations</em></span> to
<code class="literal">g</code> elements, which affects how visual elements within that group (such
as <code class="literal">line</code>s, <code class="literal">rect</code>s, and <code class="literal">circle</code>s) are rendered. We’ll get to
transformations in just a minute.</p><p>So we’ve created a new <code class="literal">g</code>, and then finally, the function <code class="literal">call()</code> is
called on our new <code class="literal">g</code>. So what is <code class="literal">call()</code>, and who is it calling?</p><p><a class="ulink" href="https://github.com/mbostock/d3/wiki/Selections#wiki-call" target="_top">D3’s <code class="literal">call()</code>
function</a> takes the incoming <span class="emphasis"><em>selection</em></span>, as received from the prior link in the chain, and hands that selection off to any <span class="emphasis"><em>function</em></span>. In this case, the selection is our new <code class="literal">g</code> group element. Although the <code class="literal">g</code> isn’t strictly necessary, we are using it because the axis function is about to generate lots of crazy lines and numbers, and it’s nice to contain all those elements within a single group object. <code class="literal">call()</code> hands off <code class="literal">g</code> to the <code class="literal">xAxis</code> function, so our axis is generated <span class="emphasis"><em>within</em></span> <code class="literal">g</code>.</p><p>If we were messy people who loved messy code, we could also rewrite the
preceding snippet as this exact equivalent:</p><a id="I_programlisting8_id305487"/><pre class="programlisting"><code class="nx">svg</code><code class="p">.</code><code class="nx">append</code><code class="p">(</code><code class="s2">"g"</code><code class="p">)</code>
<code class="p">.</code><code class="nx">call</code><code class="p">(</code><code class="nx">d3</code><code class="p">.</code><code class="nx">svg</code><code class="p">.</code><code class="nx">axis</code><code class="p">()</code>
<code class="p">.</code><code class="nx">scale</code><code class="p">(</code><code class="nx">xScale</code><code class="p">)</code>
<code class="p">.</code><code class="nx">orient</code><code class="p">(</code><code class="s2">"bottom"</code><code class="p">));</code></pre><p>See, you could cram the whole axis function within <code class="literal">call()</code>, but it’s
usually easier on our brains to define functions first, then call them
later.</p><p>In any case, <a class="xref" href="ch08.html#Simple_but_ugly_axis" title="Figure 8-2. Simple, but ugly axis">Figure 8-2</a> shows what that looks like. See code example
<span class="emphasis"><em>01_axes.html</em></span>.</p><div class="figure"><a id="Simple_but_ugly_axis"/><div class="figure-contents"><div class="mediaobject"><a id="I_mediaobject8_id305522"/><img src="httpatomoreillycomsourceoreillyimages1614796.png" alt="Simple, but ugly axis"/></div></div><div class="figure-title">Figure 8-2. Simple, but ugly axis</div></div></div><div class="sect1" title="Cleaning It Up"><div class="titlepage"><div><div><h2 class="title" style="clear: both" id="_cleaning_it_up">Cleaning It Up</h2></div></div></div><p>Technically, that is an axis, but it’s neither pretty nor useful. To<a id="I_indexterm8_id305556" class="indexterm"/><a id="I_indexterm8_id305565" class="indexterm"/>
clean it up, let’s first assign a class of <code class="literal">axis</code> to the new <code class="literal">g</code>
element, so we can target it with CSS:</p><a id="I_programlisting8_id305584"/><pre class="programlisting"><code class="nx">svg</code><code class="p">.</code><code class="nx">append</code><code class="p">(</code><code class="s2">"g"</code><code class="p">)</code>
<code class="p">.</code><code class="nx">attr</code><code class="p">(</code><code class="s2">"class"</code><code class="p">,</code> <code class="s2">"axis"</code><code class="p">)</code> <code class="c1">//Assign "axis" class</code>
<code class="p">.</code><code class="nx">call</code><code class="p">(</code><code class="nx">xAxis</code><code class="p">);</code></pre><p>Then, we introduce our first CSS styles, up in the <code class="literal"><head></code> of our page:</p><a id="I_programlisting8_id305597"/><pre class="programlisting"><code class="p">.</code><code class="nx">axis</code> <code class="nx">path</code><code class="p">,</code>
<code class="p">.</code><code class="nx">axis</code> <code class="nx">line</code> <code class="p">{</code>
<code class="nx">fill</code><code class="o">:</code> <code class="nx">none</code><code class="p">;</code>
<code class="nx">stroke</code><code class="o">:</code> <code class="nx">black</code><code class="p">;</code>
<code class="nx">shape</code><code class="o">-</code><code class="nx">rendering</code><code class="o">:</code> <code class="nx">crispEdges</code><code class="p">;</code>
<code class="p">}</code>
<code class="p">.</code><code class="nx">axis</code> <code class="nx">text</code> <code class="p">{</code>
<code class="nx">font</code><code class="o">-</code><code class="nx">family</code><code class="o">:</code> <code class="nx">sans</code><code class="o">-</code><code class="nx">serif</code><code class="p">;</code>
<code class="nx">font</code><code class="o">-</code><code class="nx">size</code><code class="o">:</code> <code class="mi">11</code><code class="nx">px</code><code class="p">;</code>
<code class="p">}</code></pre><p>See how useful it is to group all the axis elements within one <code class="literal">g</code>
group? Now we can very easily apply styles to anything within the group
using the simple CSS selector <code class="literal">.axis</code>. The axes themselves are made up of
<code class="literal">path</code>, <code class="literal">line</code>, and <code class="literal">text</code> elements, so those are the three elements
that we target in our CSS. The <code class="literal">path</code>s and <code class="literal">line</code>s can be styled with
the same rules, and <code class="literal">text</code> gets its own rules around font and font
size.</p><p>You might notice that when we use CSS rules to style SVG elements, only
SVG attribute names—not regular CSS properties—should be used. This
is confusing, because many properties share the same names in both CSS
and SVG, but some do not. For example, in regular CSS, to set the color<a id="I_indexterm8_id305644" class="indexterm"/>
of some text, you would use the <code class="literal">color</code> property, as in:</p><a id="I_programlisting8_id305658"/><pre class="programlisting"><code class="nt">p</code> <code class="p">{</code>
<code class="k">color</code><code class="o">:</code> <code class="nb">olive</code><code class="p">;</code>
<code class="p">}</code></pre><p>That will set the text color of all <code class="literal">p</code> paragraphs to be <code class="literal">olive</code>. But
try to apply this property to an SVG element, as with:</p><a id="I_programlisting8_id305675"/><pre class="programlisting"><code class="nt">text</code> <code class="p">{</code>
<code class="k">color</code><code class="o">:</code> <code class="nb">olive</code><code class="p">;</code>
<code class="p">}</code></pre><p>and it will have no effect because <code class="literal">color</code> is not a property recognized
by SVG. Instead, you must use SVG’s equivalent, <code class="literal">fill</code>:</p><a id="I_programlisting8_id305693"/><pre class="programlisting"><code class="nt">text</code> <code class="p">{</code>
<code class="n">fill</code><code class="o">:</code> <code class="nb">olive</code><code class="p">;</code>
<code class="p">}</code></pre><p>If you ever find yourself trying to style SVG elements, but for some
reason the stupid CSS code just isn’t working, I suggest you take
a deep breath, pause, and then review your <span class="emphasis"><em>property names</em></span> very closely
to ensure you’re using SVG names, not CSS ones. (You can reference the complete SVG attribute list on <a class="ulink" href="https://developer.mozilla.org/en-US/docs/SVG/Attribute" target="_top">the MDN site</a>.)<a id="I_indexterm8_id305714" class="indexterm"/></p><p><a class="ulink" href="https://developer.mozilla.org/en/SVG/Attribute/shape-rendering" target="_top">The
<code class="literal">shape-rendering</code> property</a> is another weird SVG attribute you should
know. We use it here to make sure our axis and its tick mark lines are
pixel-perfect. No blurry axes for us!<a id="I_indexterm8_id305738" class="indexterm"/><a id="I_indexterm8_id305744" class="indexterm"/></p><p>The chart looks like <a class="xref" href="ch08.html#Cleaner_axis" title="Figure 8-3. Cleaner axis">Figure 8-3</a> after our CSS clean-up.</p><div class="figure"><a id="Cleaner_axis"/><div class="figure-contents"><div class="mediaobject"><a id="I_mediaobject8_id305769"/><img src="httpatomoreillycomsourceoreillyimages1614797.png" alt="Cleaner axis"/></div></div><div class="figure-title">Figure 8-3. Cleaner axis</div></div><p>That’s better, but the top horizontal line of the axis is cut off, and
the axis itself should be down at the base of the chart anyway. Here’s
where SVG <span class="emphasis"><em>transformations</em></span> come in. By adding one line of code, we can<a id="I_indexterm8_id305794" class="indexterm"/><a id="I_indexterm8_id305800" class="indexterm"/>
<code class="literal">transform</code> the entire axis group, pushing it to the bottom:</p><a id="I_programlisting8_id305816"/><pre class="programlisting"><code class="nx">svg</code><code class="p">.</code><code class="nx">append</code><code class="p">(</code><code class="s2">"g"</code><code class="p">)</code>
<code class="p">.</code><code class="nx">attr</code><code class="p">(</code><code class="s2">"class"</code><code class="p">,</code> <code class="s2">"axis"</code><code class="p">)</code>
<code class="p">.</code><code class="nx">attr</code><code class="p">(</code><code class="s2">"transform"</code><code class="p">,</code> <code class="s2">"translate(0,"</code> <code class="o">+</code> <code class="p">(</code><code class="nx">h</code> <code class="o">-</code> <code class="nx">padding</code><code class="p">)</code> <code class="o">+</code> <code class="s2">")"</code><code class="p">)</code>
<code class="p">.</code><code class="nx">call</code><code class="p">(</code><code class="nx">xAxis</code><code class="p">);</code></pre><p>Note that we use <code class="literal">attr()</code> to apply <code class="literal">transform</code> as an attribute of <code class="literal">g</code>.
<a class="ulink" href="https://developer.mozilla.org/en-US/docs/SVG/Attribute/transform" target="_top">SVG
transforms</a> are quite powerful, and can accept several different kinds
of transform definitions, including scales and rotations. But we are
keeping it simple here with only a <span class="emphasis"><em>translation</em></span> transform, which simply
pushes the whole <code class="literal">g</code> group over and down by some amount.<a id="I_indexterm8_id305853" class="indexterm"/></p><p>Translation transforms are specified with the easy syntax of
<code class="literal">translate(x,y)</code>, where <code class="literal">x</code> and <code class="literal">y</code> are, obviously, the number of
horizontal and vertical pixels by which to translate the element. So, in
the end, we would like our <code class="literal">g</code> to look like this in the DOM:</p><a id="I_programlisting8_id305879"/><pre class="programlisting"><code class="nt"><g</code> <code class="na">class=</code><code class="s">"axis"</code> <code class="na">transform=</code><code class="s">"translate(0,280)"</code><code class="nt">></code></pre><p>As you can see, the <code class="literal">g.axis</code> isn’t moved horizontally at all, but it is
pushed 280 pixels down, conveniently to the base of our chart. We
specify as much in this line of code:</p><a id="I_programlisting8_id305894"/><pre class="programlisting"> <code class="p">.</code><code class="nx">attr</code><code class="p">(</code><code class="s2">"transform"</code><code class="p">,</code> <code class="s2">"translate(0,"</code> <code class="o">+</code> <code class="p">(</code><code class="nx">h</code> <code class="o">-</code> <code class="nx">padding</code><code class="p">)</code> <code class="o">+</code> <code class="s2">")"</code><code class="p">)</code></pre><p>Note the use of <code class="literal">(h - padding)</code>, so the group’s top edge is set to <code class="literal">h</code>,
the height of the entire image, minus the <code class="literal">padding</code> value we created
earlier. <code class="literal">(h - padding)</code> is calculated to be <code class="literal">280</code>, and then connected
to the rest of the string, so the final transform property value is<a id="I_indexterm8_id305924" class="indexterm"/>
<code class="literal">translate(0,280)</code>.</p><p>The result in <a class="xref" href="ch08.html#Nice_clean_axis" title="Figure 8-4. Nice, clean axis">Figure 8-4</a> is much better! Check out the code so far in <span class="emphasis"><em>02_axes_bottom.html</em></span>.</p><div class="figure"><a id="Nice_clean_axis"/><div class="figure-contents"><div class="mediaobject"><a id="I_mediaobject8_id305955"/><img src="httpatomoreillycomsourceoreillyimages1614798.png" alt="Nice, clean axis"/></div></div><div class="figure-title">Figure 8-4. Nice, clean axis</div></div></div><div class="sect1" title="Check for Ticks"><div class="titlepage"><div><div><h2 class="title" style="clear: both" id="_check_for_ticks">Check for Ticks</h2></div></div></div><p>Some ticks spread disease, but
<a class="ulink" href="https://github.com/mbostock/d3/wiki/Quantitative-Scales#wiki-linear_ticks" target="_top">D3’s
ticks</a> communicate information. Yet more ticks are not necessarily
better, and at a certain point, they begin to clutter your chart. You’ll
notice that we never specified how many ticks to include on the axis,
nor at what intervals they should appear. Without clear instruction, D3
has automagically examined our scale <code class="literal">xScale</code> and made informed
judgments about how many ticks to include, and at what intervals (every
50, in this case).<a id="I_indexterm8_id305997" class="indexterm"/><a id="I_indexterm8_id306006" class="indexterm"/><a id="I_indexterm8_id306012" class="indexterm"/></p><p>As you would expect, you can customize all aspects of your axes,
starting with the rough number of ticks, using <code class="literal">ticks()</code>:</p><a id="I_programlisting8_id306028"/><pre class="programlisting"><code class="kd">var</code> <code class="nx">xAxis</code> <code class="o">=</code> <code class="nx">d3</code><code class="p">.</code><code class="nx">svg</code><code class="p">.</code><code class="nx">axis</code><code class="p">()</code>
<code class="p">.</code><code class="nx">scale</code><code class="p">(</code><code class="nx">xScale</code><code class="p">)</code>
<code class="p">.</code><code class="nx">orient</code><code class="p">(</code><code class="s2">"bottom"</code><code class="p">)</code>
<code class="p">.</code><code class="nx">ticks</code><code class="p">(</code><code class="mi">5</code><code class="p">);</code> <code class="c1">//Set rough # of ticks</code></pre><p>See <span class="emphasis"><em>03_axes_clean.html</em></span> for that code.</p><p>You’ll notice in <a class="xref" href="ch08.html#Fewer_ticks" title="Figure 8-5. Fewer ticks">Figure 8-5</a> that, although we specified only five ticks, D3 has
made an executive decision and ordered up a total of seven. That’s
because D3 has got your back, and figured out that including only <span class="emphasis"><em>five</em></span>
ticks would require slicing the input domain into less-than-gorgeous
values—in this case, 0, 150, 300, 450, and 600. D3 inteprets the
<code class="literal">ticks()</code> value as merely a suggestion and will override your
suggestion with what it determines to be the most clean and
human-readable values—in this case, intervals of 100—even when that
requires including slightly more or fewer ticks than you requested. This
is actually a totally brilliant feature that increases the scalability
of your design; as the dataset changes and the input domain expands or
contracts (bigger numbers or smaller numbers), D3 ensures that the tick
labels remain easy to read.</p><div class="figure"><a id="Fewer_ticks"/><div class="figure-contents"><div class="mediaobject"><a id="I_mediaobject8_id306072"/><img src="httpatomoreillycomsourceoreillyimages1614799.png" alt="Fewer ticks"/></div></div><div class="figure-title">Figure 8-5. Fewer ticks</div></div></div><div class="sect1" title="Y Not?"><div class="titlepage"><div><div><h2 class="title" style="clear: both" id="_y_not">Y Not?</h2></div></div></div><p>Time to label the vertical axis! By copying and tweaking the code we<a id="I_indexterm8_id306106" class="indexterm"/><a id="I_indexterm8_id306113" class="indexterm"/><a id="I_indexterm8_id306121" class="indexterm"/>
already wrote for the <code class="literal">xAxis</code>, we add this near the top of of our code:</p><a id="I_programlisting8_id306136"/><pre class="programlisting"><code class="c1">//Define Y axis</code>
<code class="kd">var</code> <code class="nx">yAxis</code> <code class="o">=</code> <code class="nx">d3</code><code class="p">.</code><code class="nx">svg</code><code class="p">.</code><code class="nx">axis</code><code class="p">()</code>
<code class="p">.</code><code class="nx">scale</code><code class="p">(</code><code class="nx">yScale</code><code class="p">)</code>
<code class="p">.</code><code class="nx">orient</code><code class="p">(</code><code class="s2">"left"</code><code class="p">)</code>
<code class="p">.</code><code class="nx">ticks</code><code class="p">(</code><code class="mi">5</code><code class="p">);</code></pre><p>and this, near the bottom:</p><a id="I_programlisting8_id306147"/><pre class="programlisting"><code class="c1">//Create Y axis</code>
<code class="nx">svg</code><code class="p">.</code><code class="nx">append</code><code class="p">(</code><code class="s2">"g"</code><code class="p">)</code>
<code class="p">.</code><code class="nx">attr</code><code class="p">(</code><code class="s2">"class"</code><code class="p">,</code> <code class="s2">"axis"</code><code class="p">)</code>
<code class="p">.</code><code class="nx">attr</code><code class="p">(</code><code class="s2">"transform"</code><code class="p">,</code> <code class="s2">"translate("</code> <code class="o">+</code> <code class="nx">padding</code> <code class="o">+</code> <code class="s2">",0)"</code><code class="p">)</code>
<code class="p">.</code><code class="nx">call</code><code class="p">(</code><code class="nx">yAxis</code><code class="p">);</code></pre><p>Note in <a class="xref" href="ch08.html#Initial_Y_axis" title="Figure 8-6. Initial y-axis">Figure 8-6</a> that the labels will be oriented <code class="literal">left</code> and that the <code class="literal">yAxis</code> group
<code class="literal">g</code> is translated to the right by the amount <code class="literal">padding</code>.</p><div class="figure"><a id="Initial_Y_axis"/><div class="figure-contents"><div class="mediaobject"><a id="I_mediaobject8_id306185"/><img src="httpatomoreillycomsourceoreillyimages1614800.png" alt="Initial y-axis"/></div></div><div class="figure-title">Figure 8-6. Initial y-axis</div></div><p>This is starting to look like a real chart! But the <code class="literal">yAxis</code> labels are
getting cut off. To give them more room on the left side, I’ll bump up
the value of <code class="literal">padding</code> from 20 to 30:</p><a id="I_programlisting8_id306215"/><pre class="programlisting"><code class="kd">var</code> <code class="nx">padding</code> <code class="o">=</code> <code class="mi">30</code><code class="p">;</code></pre><p>Of course, you could also introduce separate <code class="literal">padding</code> variables for
each axis, say <code class="literal">xPadding</code> and <code class="literal">yPadding</code>, for more control over the
layout.<a id="I_indexterm8_id306239" class="indexterm"/></p><p>See the updated code in <span class="emphasis"><em>04_axes_y.html</em></span>. It looks like <a class="xref" href="ch08.html#Scatterplot_with_Y_axis" title="Figure 8-7. Scatterplot with y-axis">Figure 8-7</a>.</p><div class="figure"><a id="Scatterplot_with_Y_axis"/><div class="figure-contents"><div class="mediaobject"><a id="I_mediaobject8_id306265"/><img src="httpatomoreillycomsourceoreillyimages1614801.png" alt="Scatterplot with y-axis"/></div></div><div class="figure-title">Figure 8-7. Scatterplot with y-axis</div></div></div><div class="sect1" title="Final Touches"><div class="titlepage"><div><div><h2 class="title" style="clear: both" id="_final_touches">Final Touches</h2></div></div></div><p>I appreciate that so far you have been very quiet and polite, and not at
all confrontational. Yet I still feel as though I have to win you over.
So to prove to you that our new axes are dynamic and scalable, I’d like<a id="I_indexterm8_id306300" class="indexterm"/><a id="I_indexterm8_id306309" class="indexterm"/>
to switch from using a static dataset to using randomized numbers:</p><a id="I_programlisting8_id306317"/><pre class="programlisting"><code class="c1">//Dynamic, random dataset</code>
<code class="kd">var</code> <code class="nx">dataset</code> <code class="o">=</code> <code class="p">[];</code>
<code class="kd">var</code> <code class="nx">numDataPoints</code> <code class="o">=</code> <code class="mi">50</code><code class="p">;</code>
<code class="kd">var</code> <code class="nx">xRange</code> <code class="o">=</code> <code class="nb">Math</code><code class="p">.</code><code class="nx">random</code><code class="p">()</code> <code class="o">*</code> <code class="mi">1000</code><code class="p">;</code>
<code class="kd">var</code> <code class="nx">yRange</code> <code class="o">=</code> <code class="nb">Math</code><code class="p">.</code><code class="nx">random</code><code class="p">()</code> <code class="o">*</code> <code class="mi">1000</code><code class="p">;</code>
<code class="k">for</code> <code class="p">(</code><code class="kd">var</code> <code class="nx">i</code> <code class="o">=</code> <code class="mi">0</code><code class="p">;</code> <code class="nx">i</code> <code class="o"><</code> <code class="nx">numDataPoints</code><code class="p">;</code> <code class="nx">i</code><code class="o">++</code><code class="p">)</code> <code class="p">{</code>
<code class="kd">var</code> <code class="nx">newNumber1</code> <code class="o">=</code> <code class="nb">Math</code><code class="p">.</code><code class="nx">floor</code><code class="p">(</code><code class="nb">Math</code><code class="p">.</code><code class="nx">random</code><code class="p">()</code> <code class="o">*</code> <code class="nx">xRange</code><code class="p">);</code>
<code class="kd">var</code> <code class="nx">newNumber2</code> <code class="o">=</code> <code class="nb">Math</code><code class="p">.</code><code class="nx">floor</code><code class="p">(</code><code class="nb">Math</code><code class="p">.</code><code class="nx">random</code><code class="p">()</code> <code class="o">*</code> <code class="nx">yRange</code><code class="p">);</code>
<code class="nx">dataset</code><code class="p">.</code><code class="nx">push</code><code class="p">([</code><code class="nx">newNumber1</code><code class="p">,</code> <code class="nx">newNumber2</code><code class="p">]);</code>
<code class="p">}</code></pre><p>This code initializes an empty array, then loops through 50 times,
chooses two random numbers each time, and adds (“pushes”) that pair of
values to the <code class="literal">dataset</code> array (see <a class="xref" href="ch08.html#Scatterplot_with_random_data" title="Figure 8-8. Scatterplot with random data">Figure 8-8</a>).</p><div class="figure"><a id="Scatterplot_with_random_data"/><div class="figure-contents"><div class="mediaobject"><a id="I_mediaobject8_id306347"/><img src="httpatomoreillycomsourceoreillyimages1614802.png" alt="Scatterplot with random data"/></div></div><div class="figure-title">Figure 8-8. Scatterplot with random data</div></div><p>Try out that randomized dataset code in <span class="emphasis"><em>05_axes_random.html</em></span>. Each time you
reload the page, you’ll get different data values. Notice how both axes
scale to fit the new domains, and ticks and label values are chosen
accordingly.</p><p>Having made my point, I think we can finally cut those horrible, red
labels, by commenting out the relevant lines of code.</p><p>The result is shown in <a class="xref" href="ch08.html#Scatterplot_with_random_data_and_no_red_labels" title="Figure 8-9. Scatterplot with random data and no red labels">Figure 8-9</a>. Our final scatterplot code lives in <span class="emphasis"><em>06_axes_no_labels.html</em></span>.</p><div class="figure"><a id="Scatterplot_with_random_data_and_no_red_labels"/><div class="figure-contents"><div class="mediaobject"><a id="I_mediaobject8_id306399"/><img src="httpatomoreillycomsourceoreillyimages1614803.png" alt="Scatterplot with random data and no red labels"/></div></div><div class="figure-title">Figure 8-9. Scatterplot with random data and no red labels</div></div></div><div class="sect1" title="Formatting Tick Labels"><div class="titlepage"><div><div><h2 class="title" style="clear: both" id="_formatting_tick_labels">Formatting Tick Labels</h2></div></div></div><p>One last thing: so far, we’ve been working with integers—whole numbers—which are nice and easy. But data is often messier, and in those
cases, you might want more control over how the axis labels are formatted.<a id="I_indexterm8_id306433" class="indexterm"/><a id="I_indexterm8_id306441" class="indexterm"/>
Enter
<a class="ulink" href="https://github.com/mbostock/d3/wiki/Quantitative-Scales#wiki-linear_tickFormat" target="_top"><code class="literal">tickFormat()</code></a>,
which enables you to specify how your numbers should be formatted. For
example, you might want to include three places after the decimal point,
or display values as percentages, or both.</p><p>To use <code class="literal">tickFormat()</code>, first define a new number-formatting function.
This one, for example, says to treat values as percentages with one
decimal point precision. That is, if you give this function the number
<code class="literal">0.23</code>, it will return the string <code class="literal">23.0%</code>. (See
<a class="ulink" href="https://github.com/mbostock/d3/wiki/Formatting#wiki-d3_format" target="_top">the
reference entry for <code class="literal">d3.format()</code></a> for more options.)</p><a id="I_programlisting8_id306487"/><pre class="programlisting"><code class="kd">var</code> <code class="nx">formatAsPercentage</code> <code class="o">=</code> <code class="nx">d3</code><code class="p">.</code><code class="nx">format</code><code class="p">(</code><code class="s2">".1%"</code><code class="p">);</code></pre><p>Then, tell your axis to use that formatting function for its ticks,
for example:</p><a id="I_programlisting8_id306498"/><pre class="programlisting"><code class="nx">xAxis</code><code class="p">.</code><code class="nx">tickFormat</code><code class="p">(</code><code class="nx">formatAsPercentage</code><code class="p">);</code></pre><div class="tip" title="Tip"><h3 class="title">Tip</h3><p>I find it easiest to test these formatting functions out in the JavaScript console. For example, just open any page that loads D3, such as <span class="emphasis"><em>06_axes_no_labels.html</em></span>, and type your format rule into the console. Then test it by feeding it a value, as you would with any other function.<a id="I_indexterm8_id306519" class="indexterm"/></p><p>You can see in <a class="xref" href="ch08.html#Testing_format_console" title="Figure 8-10. Testing format() in the console">Figure 8-10</a> that a data value of <code class="literal">0.54321</code> is converted to <code class="literal">54.3%</code> for display purposes—perfect!</p><div class="figure"><a id="Testing_format_console"/><div class="figure-contents"><div class="mediaobject"><a id="I_mediaobject8_id306549"/><img src="httpatomoreillycomsourceoreillyimages1614804.png.jpg" alt="Testing format() in the console"/></div></div><div class="figure-title">Figure 8-10. Testing format() in the console</div></div></div><p>You can play with that code in <span class="emphasis"><em>07_axes_format.html</em></span>. Obviously, a percentage
format doesn’t make sense with our scatterplot’s current dataset, but
as an exercise, you could try tweaking how the random numbers are
generated, to make more appropriate, non-whole number values, or just
experiment with the format function itself.<a id="I_indexterm8_id306577" class="indexterm"/></p></div></section></body></html>