<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/"
    xmlns:atom="http://www.w3.org/2005/Atom" xmlns:media="http://search.yahoo.com/mrss/" version="2.0">
    <channel>
        
        <title>
            <![CDATA[ Wen Tjun Chan - freeCodeCamp.org ]]>
        </title>
        <description>
            <![CDATA[ Browse thousands of programming tutorials written by experts. Learn Web Development, Data Science, DevOps, Security, and get developer career advice. ]]>
        </description>
        <link>https://www.freecodecamp.org/news/</link>
        <image>
            <url>https://cdn.freecodecamp.org/universal/favicons/favicon.png</url>
            <title>
                <![CDATA[ Wen Tjun Chan - freeCodeCamp.org ]]>
            </title>
            <link>https://www.freecodecamp.org/news/</link>
        </image>
        <generator>Eleventy</generator>
        <lastBuildDate>Wed, 14 Oct 2026 18:34:06 +0000</lastBuildDate>
        <atom:link href="https://www.freecodecamp.org/news/author/wentjun/rss.xml" rel="self" type="application/rss+xml" />
        <ttl>60</ttl>
        
            <item>
                <title>
                    <![CDATA[ How to work with D3.js’s general update pattern ]]>
                </title>
                <description>
                    <![CDATA[ A guided tour on implementing visualization modules with dynamic datasets It is common to remove the existing Scalable Vector Graphics (SVG) element by calling d3.select('#chart').remove(), before ren ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-work-with-d3-jss-general-update-pattern-8adce8d55418/</link>
                <guid isPermaLink="false">66d46174bd438296f45cd3d2</guid>
                
                    <category>
                        <![CDATA[ Data Science ]]>
                    </category>
                
                    <category>
                        <![CDATA[ JavaScript ]]>
                    </category>
                
                    <category>
                        <![CDATA[ General Programming ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Software Engineering ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Web Development ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Wen Tjun Chan ]]>
                </dc:creator>
                <pubDate>Thu, 21 Mar 2019 17:03:27 +0000</pubDate>
                <media:content url="https://cdn-media-1.freecodecamp.org/images/1*qyybxSDlom1vFlZ4LwppTg.jpeg" medium="image" />
                <content:encoded>
                    <![CDATA[ <h4 id="heading-a-guided-tour-on-implementing-visualization-modules-with-dynamic-datasets">A guided tour on implementing visualization modules with dynamic datasets</h4>
<p>It is common to remove the existing Scalable Vector Graphics (SVG) element by calling <code>d3.select('#chart').remove()</code>, before rendering a new chart.</p>
<p>However, there may be scenarios when you have to produce dynamic visualizations from sources such as external APIs. This article will show you how to do this using D3.js.</p>
<p>D3.js handles dynamic data by adopting the general update pattern. This is commonly described as a data-join, followed by operations on the enter, update and exit selections. Mastering these selection methods will enable you to produce seamless transitions between states, allowing you to tell meaningful stories with data.</p>
<h3 id="heading-getting-started">Getting Started</h3>
<h4 id="heading-requirements">Requirements</h4>
<p>We will be building a graph that illustrates the movement of a few Exchange-Traded Funds (ETFs) over the second half of 2018. The graph consists of the following tools:</p>
<ol>
<li><p><a href="https://www.investopedia.com/terms/l/linechart.asp">Closing price line chart</a></p>
</li>
<li><p><a href="https://www.investopedia.com/terms/v/volumeoftrade.asp">Trade volume</a> bar chart</p>
</li>
<li><p>50-day simple <a href="https://www.investopedia.com/terms/m/movingaverage.asp">moving average</a></p>
</li>
<li><p><a href="https://www.investopedia.com/terms/b/bollingerbands.asp">Bollinger Bands</a> (20-day simple moving average, with standard deviation set at 2.0)</p>
</li>
<li><p>Open-high-low-close (<a href="https://www.investopedia.com/terms/o/ohlcchart.asp">OHLC</a>) chart</p>
</li>
<li><p><a href="https://www.investopedia.com/terms/c/candlestick.asp">Candlesticks</a></p>
</li>
</ol>
<p>These tools are commonly utilized in the technical analysis of stocks, commodities, and other securities. For example, traders may make use of the Bollinger Bands and Candlesticks to derive patterns which represent buy or sell signals.</p>
<p>This is how the graph will look like:</p>
<img src="https://cdn-media-1.freecodecamp.org/images/1*v3ebquZIF6E5DUL5rbbpdQ.gif" alt="Image" width="1172" height="614" loading="lazy">

<p><em>Powered by D3.js. Observe how the graph responds to user interactions, and changes in data or state.</em></p>
<p>This article aims to equip you with the fundamental theories of data joins and the enter-update-exit pattern in order to allow you to easily visualize dynamic datasets. In addition, we will be covering <a href="https://github.com/d3/d3-selection/blob/master/README.md#selection_join">selection.join</a>, which is introduced in D3.js’s v5.8.0 release.</p>
<h3 id="heading-the-general-update-pattern">The general update pattern</h3>
<p>The gist of the general update pattern is the selection of Document Object Model (DOM) elements, followed by binding of data to these elements. These elements are then created, updated or removed, to represent the necessary data.</p>
<h4 id="heading-joining-new-data">Joining new data</h4>
<p>Data join is the mapping of <code>n</code> number of elements in the dataset with <code>n</code>number of selected Document Object Model (DOM) nodes, specifying the required action to the DOM as the data changes.</p>
<p>We use the <code>data()</code> method to map each data point to a corresponding element in the DOM selection. In addition, it is good practice to maintain <a href="https://bost.ocks.org/mike/constancy/">object constancy</a> by specifying a key as the unique identifier in each data point. Let’s take a look at the following example, which is the first step towards rendering the trade volume bars:</p>
<pre><code class="language-js">const bars = d3
  .select('#volume-series')
  .selectAll(.'vol')
  .data(this.currentData, d =&gt; d['date']);
</code></pre>
<p>The above line of code selects all elements with the class <code>vol</code> , followed by mapping the <code>this.currentData</code> array with the selection of DOM elements using the <code>data()</code> method.</p>
<p>The second optional argument of <code>data()</code> takes a data point as input and returns the <code>date</code> property as the selected key for each data point.</p>
<h4 id="heading-enterupdate-selection">Enter/Update selection</h4>
<p><code>.enter()</code> returns an enter selection which represents the elements that need to be added when the joined array is longer than the selection. This is followed by calling <code>.append()</code>, which creates or updates elements on the DOM. We can implement this in the following manner:</p>
<pre><code class="language-js">bars
  .enter()
  .append('rect')
  .attr('class', 'vol')
  .merge(bars)
  .transition()
  .duration(750)
  .attr('x', d =&gt; this.xScale(d['date']))
  .attr('y', d =&gt; yVolumeScale(d['volume']))
  .attr('fill', (d, i) =&gt; {
    if (i === 0) {
      return '#03a678';
    } else {
      // green bar if price is rising during that period, and red when price is falling
      return this.currentData[i - 1].close &gt; d.close
        ? '#c0392b'
        : '#03a678';
    }
  })
  .attr('width', 1)
  .attr('height', d =&gt; this.height - yVolumeScale(d['volume']));
</code></pre>
<p><code>.merge()</code> merges the update and enter selections, before applying the subsequent method chains to create animations between transitions, and to update their associated attributes. The above block of code enables you to perform the following actions on the selected DOM elements:</p>
<ol>
<li><p>The update selection, which consists of data points represented by the <code>&lt;rect&gt;</code> elements on the graph, will have their attributes updated accordingly.</p>
</li>
<li><p>The creation of <code>&lt;rect&gt;</code> elements with the class <code>vol</code>, with the above attributes defined within each element as the enter selection consists of data points that are not represented on the graph.</p>
</li>
</ol>
<h4 id="heading-exit-selection">Exit selection</h4>
<p>Remove items from our dataset by following the simple steps below:bars.exit().remove();</p>
<p><code>.exit()</code> returns an exit selection, which specifies the data points that need to be removed. The <code>.remove()</code> method subsequently deletes the selection from the DOM.</p>
<p>This is how the volume series bars will respond to changes in data:</p>
<img src="https://cdn-media-1.freecodecamp.org/images/1*dEZBCu-p5hRGZNJGMCtG4Q.gif" alt="Image" width="1222" height="606" loading="lazy">

<p><em>Notice how the bars change as we switch between datasets.</em></p>
<p>Take note of how the DOM and the respective attributes of each <code>&lt;rect&gt;</code>element are updated as we select a different dataset:</p>
<img src="https://cdn-media-1.freecodecamp.org/images/1*XI_7a6kYRLT__mvLEPD0qA.gif" alt="Image" width="1162" height="610" loading="lazy">

<p><em>Observe the changes in the DOM via the built-in Chrome DevTools.</em></p>
<h3 id="heading-selectionjoin-as-of-v580">Selection.join (as of v5.8.0)</h3>
<p>The introduction of <code>selection.join</code> in v5.8.0 of D3.js has simplified the entire data join process. Separate functions are now passed to handle enter_,_ update_,_ and exit which in turn returns the merged enter and update selections.</p>
<pre><code class="language-js">selection.join(
    enter =&gt; // enter.. ,
    update =&gt; // update.. ,
    exit =&gt; // exit.. 
  )
  // allows chained operations on the returned selections
</code></pre>
<p>In the case of the volume series bars, the application of <code>selection.join</code> will result in the following changes on our code:</p>
<pre><code class="language-js">//select, followed by updating data join
const bars = d3
  .select('#volume-series')
  .selectAll('.vol')
  .data(this.currentData, d =&gt; d['date']);
bars.join(
  enter =&gt;
    enter
      .append('rect')
      .attr('class', 'vol')
      .attr('x', d =&gt; this.xScale(d['date']))
      .attr('y', d =&gt; yVolumeScale(d['volume']))
      .attr('fill', (d, i) =&gt; {
        if (i === 0) {
          return '#03a678';
        } else {
          return this.currentData[i - 1].close &gt; d.close
            ? '#c0392b'
            : '#03a678';
        }
      })
      .attr('width', 1)
      .attr('height', d =&gt; this.height - yVolumeScale(d['volume'])),
  update =&gt;
    update
      .transition()
      .duration(750)
      .attr('x', d =&gt; this.xScale(d['date']))
      .attr('y', d =&gt; yVolumeScale(d['volume']))
      .attr('fill', (d, i) =&gt; {
        if (i === 0) {
          return '#03a678';
        } else {
          return this.currentData[i - 1].close &gt; d.close
            ? '#c0392b'
            : '#03a678';
        }
      })
      .attr('width', 1)
      .attr('height', d =&gt; this.height - yVolumeScale(d['volume']))
);
</code></pre>
<p>Also, note that we have made some changes to the animation of the bars. Instead of passing the <code>transition()</code> method to the merged enter and update selections, it is now used in the update selection such that transitions will only be applied when the dataset has changed.</p>
<p>The returned enter and update selections are then merged and returned by <code>selection.join</code>.</p>
<h4 id="heading-bollinger-bands">Bollinger Bands</h4>
<p>Similarly, we can apply <code>selection.join</code> on the rendering of Bollinger Bands. Before rendering the Bands, we are required to calculate the following properties of each data point:</p>
<ol>
<li><p>20-day simple moving average.</p>
</li>
<li><p>The upper and lower bands, which have a standard deviation of 2.0 above and below the 20-day simple moving average, respectively.</p>
</li>
</ol>
<p>This is the formula for calculating standard deviation:</p>
<img src="https://cdn-media-1.freecodecamp.org/images/0*aVvmssYG1cPl2aDB" alt="Image" width="512" height="288" loading="lazy">

<p><em>Credits:</em> <a href="https://www.khanacademy.org/math/probability/data-distributions-a1/summarizing-spread-distributions/a/calculating-standard-deviation-step-by-step"><em>Khan Academy</em></a></p>
<p>Now, we shall translate the above formula into JavaScript code:</p>
<pre><code class="language-js">calculateBollingerBands(data, numberOfPricePoints) {
  let sumSquaredDifference = 0;
  return data.map((row, index, total) =&gt; {
    const start = Math.max(0, index - numberOfPricePoints);
    const end = index; 
    
    // divide the sum with subset.length to obtain moving average
    const subset = total.slice(start, end + 1);
    const sum = subset.reduce((a, b) =&gt; {
      return a + b['close'];
    }, 0);
    const sumSquaredDifference = subset.reduce((a, b) =&gt; {
      const average = sum / subset.length;
      const dfferenceFromMean = b['close'] - average;
      const squaredDifferenceFromMean = Math.pow(dfferenceFromMean, 2);
      return a + squaredDifferenceFromMean;
    }, 0);
    const variance = sumSquaredDifference / subset.length;
  return {
      date: row['date'],
      average: sum / subset.length,
      standardDeviation: Math.sqrt(variance),
      upperBand: sum / subset.length + Math.sqrt(variance) * 2,
      lowerBand: sum / subset.length - Math.sqrt(variance) * 2
    };
  });
}
.
.
// calculates simple moving average, and standard deviation over 20 days
this.bollingerBandsData = this.calculateBollingerBands(validData, 19);
</code></pre>
<p>A quick explanation of the calculation of the standard deviation, and Bollinger Band values on the above block of code is as follows:</p>
<p>For each iteration,</p>
<ol>
<li><p>Calculate the average of the close price.</p>
</li>
<li><p>Find the difference between the average value and close price for that data point.</p>
</li>
<li><p>Square the result of each difference.</p>
</li>
<li><p>Find the sum of squared differences.</p>
</li>
<li><p>Calculate the mean of the squared differences to get the variance</p>
</li>
<li><p>Get the square root of the variance to obtain the standard deviation for each data point.</p>
</li>
<li><p>Multiply the standard deviation by 2. Calculate the upper and lower band values by adding or subtracting the average with the multiplied value.</p>
</li>
</ol>
<p>With the data points defined, we can then make use of <code>selection.join</code> to render Bollinger Bands:</p>
<pre><code class="language-js">// code not shown: rendering of upper and lower bands 
.
.
// bollinger bands area chart
const area = d3
  .area()
  .x(d =&gt; this.xScale(d['date']))
  .y0(d =&gt; this.yScale(d['upperBand']))
  .y1(d =&gt; this.yScale(d['lowerBand']));
const areaSelect = d3
  .select('#chart')
  .select('svg')
  .select('g')
  .selectAll('.band-area')
  .data([this.bollingerBandsData]);
areaSelect.join(
  enter =&gt;
    enter
      .append('path')
      .style('fill', 'darkgrey')
      .style('opacity', 0.2)
      .style('pointer-events', 'none')
      .attr('class', 'band-area')
      .attr('clip-path', 'url(#clip)')
      .attr('d', area),
  update =&gt;
    update
      .transition()
      .duration(750)
      .attr('d', area)
);
</code></pre>
<p>This renders the area chart which denotes the area filled by the Bollinger Bands. On the update function, we can use the <code>selection.transition()</code>method to provide animated transitions on the update selection.</p>
<h4 id="heading-candlesticks">Candlesticks</h4>
<p>The candlesticks chart displays the high, low, open and close prices of a stock for a specific period. Each candlestick represents a data point. Green represents when the stock closes higher while red represents when the stock closes at a lower value.</p>
<img src="https://cdn-media-1.freecodecamp.org/images/0*GGsqZeYDGuZzrvGd" alt="Image" width="250" height="185" loading="lazy">

<p><em>Credits:</em> <a href="https://www.investopedia.com/terms/c/candlestick.asp"><em>Investopedia</em></a></p>
<p>Unlike the Bollinger Bands, there is no need for additional calculations, as the prices are available in the existing dataset.</p>
<pre><code class="language-js">const bodyWidth = 5;
const candlesticksLine = d3
  .line()
  .x(d =&gt; d['x'])
  .y(d =&gt; d['y']);
const candlesticksSelection = d3
  .select('#chart')
  .select('g')
  .selectAll('.candlesticks')
  .data(this.currentData, d =&gt; d['volume']);
candlesticksSelection.join(enter =&gt; {
  const candlesticksEnter = enter
    .append('g')
    .attr('class', 'candlesticks')
    .append('g')
    .attr('class', 'bars')
    .classed('up-day', d =&gt; d['close'] &gt; d['open'])
    .classed('down-day', d =&gt; d['close'] &lt;= d['open']);
</code></pre>
<p>On the enter function, each candlestick is rendered based on its individual properties.</p>
<p>First and foremost, each candlestick group element is assigned a class of <code>up-day</code> if the close price is higher than the open price, and <code>down-day</code> if the close price is lower than or equal to the open-price.</p>
<pre><code class="language-js">candlesticksEnter
    .append('path')
    .classed('high-low', true)
    .attr('d', d =&gt; {
      return candlesticksLine([
        { x: this.xScale(d['date']), y: this.yScale(d['high']) },
        { x: this.xScale(d['date']), y: this.yScale(d['low']) }
      ]);
    });
</code></pre>
<p>Next, we append the <code>path</code> element, which represents the highest and lowest price of that day, to the above selection.</p>
<pre><code class="language-js">  candlesticksEnter
    .append('rect')
    .attr('x', d =&gt; this.xScale(d.date) - bodyWidth / 2)
    .attr('y', d =&gt; {
      return d['close'] &gt; d['open']
        ? this.yScale(d.close)
        : this.yScale(d.open);
    })
    .attr('width', bodyWidth)
    .attr('height', d =&gt; {
      return d['close'] &gt; d['open']
        ? this.yScale(d.open) - this.yScale(d.close)
        : this.yScale(d.close) - this.yScale(d.open);
    });
});
</code></pre>
<p>This is followed by appending the <code>rect</code> element to the selection. The height of each <code>rect</code> element is directly proportionate to its day range, derived by subtracting the open price with the close price.</p>
<p>On our stylesheets, we will define the following CSS properties to our classes making the candlesticks red or green:</p>
<pre><code class="language-js">.bars.up-day path {
 stroke: #03a678;
}
.bars.down-day path {
 stroke: #c0392b;
}
.bars.up-day rect {
 fill: #03a678;
}
.bars.down-day rect {
 fill: #c0392b;
}
</code></pre>
<p>This results in the rendering of the Bollinger Bands and candlesticks:</p>
<img src="https://cdn-media-1.freecodecamp.org/images/1*TOj5vW_eVXLlscri0zbY4A.gif" alt="Image" width="1172" height="614" loading="lazy">

<p><em>It is common for traders to use both Bollinger Bands and candlesticks for technical analysis.</em></p>
<p>The new syntax has proven to be simpler and more intuitive than explicitly calling <code>selection.enter</code>, <code>selection.append</code>, <code>selection.merge</code>, and <code>selection.remove</code>.</p>
<p>Note that for those who are developing with D3.js’s v5.8.0 and beyond, it has been <a href="https://bl.ocks.org/mbostock/3808218">recommended</a> by Mike Bostock that these users start using <code>selection.join</code> due to the above advantages.</p>
<h3 id="heading-conclusion">Conclusion</h3>
<p>The potential of D3.js is limitless and the above illustrations are merely the tip of the iceberg. Many satisfied users have created visualizations which are vastly more complex and sophisticated than the one show above. This <a href="https://github.com/toddmotto/public-apis">list of free APIs</a> may interest you if you are keen to embark on your own data visualization projects.</p>
<p>Feel free to check out the <a href="https://github.com/wentjun/d3-historical-prices-data-joins">source code</a> and the <a href="https://wentjun.com/d3-historical-prices-data-joins/">full demonstration</a> of this project.</p>
<p>Thank you very much for reading this article. If you have any questions or suggestions, feel free to leave them on the comments below!</p>
<p><em>New to D3.js? You may refer to this</em> <a href="https://medium.freecodecamp.org/how-to-build-historical-price-charts-with-d3-js-72214aaf6ba3"><em>article</em></a> <em>on the basics of implementing common chart components.</em></p>
<p><em>Special thanks to Debbie Leong for reviewing this article.</em></p>
<p>Additional references:</p>
<ol>
<li><p><a href="https://github.com/d3/d3/blob/master/API.md">D3.js API documentation</a></p>
</li>
<li><p><a href="https://beta.observablehq.com/@d3/selection-join">Interactive demonstration of selection.join</a></p>
</li>
</ol>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to build historical price charts with D3.js ]]>
                </title>
                <description>
                    <![CDATA[ A step by step approach towards visualizing financial datasets It is a challenge to communicate data and display these visualizations on multiple devices and platforms. “Data is just like crude. It’s ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-build-historical-price-charts-with-d3-js-72214aaf6ba3/</link>
                <guid isPermaLink="false">66d46171768263422736e8c8</guid>
                
                    <category>
                        <![CDATA[ data visualization ]]>
                    </category>
                
                    <category>
                        <![CDATA[ fintech ]]>
                    </category>
                
                    <category>
                        <![CDATA[ JavaScript ]]>
                    </category>
                
                    <category>
                        <![CDATA[ tech  ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Web Development ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Wen Tjun Chan ]]>
                </dc:creator>
                <pubDate>Thu, 24 Jan 2019 17:15:18 +0000</pubDate>
                <media:content url="https://cdn-media-1.freecodecamp.org/images/1*4xr6-FwevPj7MIL756bDwA.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <h4 id="heading-a-step-by-step-approach-towards-visualizing-financial-datasets">A step by step approach towards visualizing financial datasets</h4>
<p>It is a challenge to communicate data and display these visualizations on multiple devices and platforms.</p>
<blockquote>
<p>“Data is just like crude. It’s valuable, but if unrefined it cannot really be used.” - <a href="https://ana.blogs.com/maestros/2006/11/data_is_the_new.html">Michael Palmer</a></p>
</blockquote>
<p>D3 (Data-Driven Documents) solves this age-old dilemma. It provides developers and analysts the ability to build customized visualizations for the Web with complete freedom. D3.js allows us to bind data to the DOM (Document Object Model). Then apply data-driven transformations to create refined visualizations of data.</p>
<p>In this tutorial, we will understand how we can make the D3.js library work for us.</p>
<h4 id="heading-getting-started">Getting started</h4>
<p>We will be building a chart that illustrates the movement of a financial instrument over a period of time. This visualization resembles the price charts provided by <a href="https://finance.yahoo.com">Yahoo Finance</a>. We will break down the various components required to render an interactive price chart that tracks a particular <a href="https://sg.finance.yahoo.com/quote/VIG/chart?p=VIG">stock</a>.</p>
<p>Required components:</p>
<ol>
<li><p>Loading and parsing of data</p>
</li>
<li><p>SVG element</p>
</li>
<li><p>X and Y axes</p>
</li>
<li><p>Close price line chart</p>
</li>
<li><p>Simple moving average curve chart with some calculations</p>
</li>
<li><p>Volume series bar chart</p>
</li>
<li><p>Mouseover crosshair and legend</p>
</li>
</ol>
<h4 id="heading-loading-and-parsing-of-data">Loading and Parsing of Data</h4>
<pre><code class="language-js">const loadData = d3.json('sample-data.json').then(data =&gt; {
  const chartResultsData = data['chart']['result'][0];
  const quoteData = chartResultsData['indicators']['quote'][0];
  return chartResultsData['timestamp'].map((time, index) =&gt; ({
    date: new Date(time * 1000),
    high: quoteData['high'][index],
    low: quoteData['low'][index],
    open: quoteData['open'][index],
    close: quoteData['close'][index],
    volume: quoteData['volume'][index]
  }));
});
</code></pre>
<p>First, we will use the <a href="https://github.com/d3/d3-fetch">fetch</a> module to load our sample data. D3-fetch also supports other formats such as TSV and CSV files. The data will then be further processed to return an array of objects. Each object contains the trade timestamp, high price, low price, open price, close price, and trade volume.</p>
<pre><code class="language-css">body {
  background: #00151c;
}
#chart {
  background: #0e3040;
  color: #67809f;
}
</code></pre>
<p>Add the above base CSS properties to personalize the style of your chart for maximum visual appeal.</p>
<h4 id="heading-appending-the-svg-element">Appending the SVG Element</h4>
<pre><code class="language-js">const initialiseChart = data =&gt; {
  const margin = { top: 50, right: 50, bottom: 50, left: 50 };
  const width = window.innerWidth - margin.left - margin.right;
  const height = window.innerHeight - margin.top - margin.bottom; 
  // add SVG to the page
  const svg = d3
    .select('#chart')
    .append('svg')
    .attr('width', width + margin['left'] + margin['right'])
    .attr('height', height + margin['top'] + margin['bottom'])
    .call(responsivefy)
    .append('g')
    .attr('transform', `translate(${margin['left']},  ${margin['top']})`);
</code></pre>
<p>Subsequently, we can use the <code>append()</code> method to append the SVG element to the <code>&lt;d</code>iv&gt; element with th<code>e id,</code> chart. Next, we us<code>e the</code> attr() method to assign the width and height of the SVG element. We then cal<code>l the responsi</code>vefy() method (originally writt<a href="https://brendansudol.com/writing/responsive-d3">en by Brendan</a> Sudol). This allows the SVG element to have responsive capabilities by listening to window resize events.</p>
<p>Remember to append the SVG group element to the above SVG element before translating it using the values from the <code>margin</code> constant.</p>
<h4 id="heading-rendering-the-x-and-y-axes">Rendering the X and Y Axes</h4>
<p>Before rendering the axes component, we will need to define our domain and range, which will then be used to create our scales for the axes</p>
<pre><code class="language-js">// find data range
const xMin = d3.min(data, d =&gt; {
  return d['date'];
});
const xMax = d3.max(data, d =&gt; {
  return d['date'];
});
const yMin = d3.min(data, d =&gt; {
  return d['close'];
});
const yMax = d3.max(data, d =&gt; {
  return d['close'];
});
// scales for the charts
const xScale = d3
  .scaleTime()
  .domain([xMin, xMax])
  .range([0, width]);
const yScale = d3
  .scaleLinear()
  .domain([yMin - 5, yMax])
  .range([height, 0]);
</code></pre>
<p>The x and y axes for the close price line chart consist of the trade date and close price respectively. Therefore, we have to define the minimum and maximum x and y values, using <code>d3.max()</code> and <code>d3.min()</code>. We can then make use of <a href="https://github.com/d3/d3-scale">D3-scale</a>’s <code>scaleTime()</code> and <code>scaleLinear()</code> to create the time scale on the x-axis and the linear scale on the y-axis respectively. The range of the scales is defined by the width and height of our SVG element.</p>
<pre><code class="language-js">// create the axes component
svg
  .append('g')
  .attr('id', 'xAxis')
  .attr('transform', `translate(0, ${height})`)
  .call(d3.axisBottom(xScale));
svg
  .append('g')
  .attr('id', 'yAxis')
  .attr('transform', `translate(${width}, 0)`)
  .call(d3.axisRight(yScale));
</code></pre>
<p>After this step, we need to append the first <code>g</code> element to the SVG element, which calls the <code>d3.axisBottom()</code> method, taking in <code>xScale</code> as the parameter to generate the x-axis. The x-axis is then translated to the bottom of the chart area. Similarly, the y-axis is generated by appending the <code>g</code> element, calling d3.axisRight() with <code>yScale</code> as the parameter, before translating the y-axis to the right of the chart area.</p>
<h4 id="heading-rendering-the-close-price-line-chart">Rendering the Close Price Line Chart</h4>
<pre><code class="language-plaintext">// generates close price line chart when called
const line = d3
  .line()
  .x(d =&gt; {
    return xScale(d['date']);
  })
  .y(d =&gt; {
    return yScale(d['close']);
  });
// Append the path and bind data
svg
 .append('path')
 .data([data])
 .style('fill', 'none')
 .attr('id', 'priceChart')
 .attr('stroke', 'steelblue')
 .attr('stroke-width', '1.5')
 .attr('d', line);
</code></pre>
<p>Now, we can append the <code>[path](https://developer.mozilla.org/en-US/docs/Web/SVG/Tutorial/Paths)</code> element inside our main SVG element, followed by passing our parsed dataset,<code>data</code>. We set the attribute <code>d</code> with our helper function, <code>line</code>. which calls the <code>d3.line()</code> method. The <code>x</code> and <code>y</code> attributes of the line accept the anonymous functions and return the date and close price respectively.</p>
<p>By now, this is how your chart should look like:</p>
<img src="https://cdn-media-1.freecodecamp.org/images/fnbftLMqi8MQnIy8ZZBrqsKN8fXYVfodvgQ2" alt="Image" style="display: block;" width="800" height="407" loading="lazy">

<p><em>Checkpoint #1: Close price line chart, with the X and Y Axes.</em></p>
<h4 id="heading-rendering-the-simple-moving-average-curve">Rendering the Simple Moving Average Curve</h4>
<p>Instead of relying purely on the close price as our only form of technical indicator, we use the <a href="https://www.investopedia.com/terms/s/sma.asp">Simple Moving Average</a>. This average identifies uptrends and downtrends for the particular security.</p>
<pre><code class="language-plaintext">const movingAverage = (data, numberOfPricePoints) =&gt; {
  return data.map((row, index, total) =&gt; {
    const start = Math.max(0, index - numberOfPricePoints);
    const end = index;
    const subset = total.slice(start, end + 1);
    const sum = subset.reduce((a, b) =&gt; {
      return a + b['close'];
    }, 0);
    return {
      date: row['date'],
      average: sum / subset.length
    };
  });
};
</code></pre>
<p>We define our helper function, <code>movingAverage</code> to calculate the simple moving average. This function accepts two parameters, namely the dataset, and the number of price points, or periods. It then returns an array of objects, with each object containing the date and average for each data point.</p>
<pre><code class="language-js">// calculates simple moving average over 50 days
const movingAverageData = movingAverage(data, 49);
// generates moving average curve when called
const movingAverageLine = d3
 .line()
 .x(d =&gt; {
  return xScale(d['date']);
 })
 .y(d =&gt; {
  return yScale(d['average']);
 })
  .curve(d3.curveBasis);
svg
  .append('path')
  .data([movingAverageData])
  .style('fill', 'none')
  .attr('id', 'movingAverageLine')
  .attr('stroke', '#FF8900')
  .attr('d', movingAverageLine);
</code></pre>
<p>For our current context, <code>movingAverage()</code> calculates the simple moving average over a period of 50 days. Similar to the close price line chart, we append the <code>path</code> element within our main SVG element, followed by passing our moving average dataset, and setting the attribute <code>d</code> with our helper function, <code>movingAverageLine</code>. The only difference from the above is that we passed <code>d3.curveBasis</code> to <code>d3.line().curve()</code> in order to achieve a curve.</p>
<p>This results in the simple moving average curve overlaid on top of our current chart:</p>
<img src="https://cdn-media-1.freecodecamp.org/images/XhcAf6lV84KJ5fOpcZ6reXZ4ovtPqA9Y07dM" alt="Image" style="display: block;" width="800" height="412" loading="lazy">

<p><em>Checkpoint #2: Orange curve, which depicts the simple moving average. This gives us a better idea of the price movement.</em></p>
<h4 id="heading-rendering-the-volume-series-bar-chart">Rendering the Volume Series Bar Chart</h4>
<p>For this component, we will be rendering the trade <a href="https://commodity.com/technical-analysis/volume/">volume</a> in the form of a color-coded bar chart occupying the same SVG element. The bars are green when the stock closes higher than the previous day’s close price. They are red when the stock closes lower than the previous day’s close price. This illustrates the volume traded for each trade date. This can then be used alongside the above chart to analyze price movements.</p>
<pre><code class="language-js">/* Volume series bars */
const volData = data.filter(d =&gt; d['volume'] !== null &amp;&amp; d['volume']   !== 0);
const yMinVolume = d3.min(volData, d =&gt; {
  return Math.min(d['volume']);
});
const yMaxVolume = d3.max(volData, d =&gt; {
  return Math.max(d['volume']);
});
const yVolumeScale = d3
  .scaleLinear()
  .domain([yMinVolume, yMaxVolume])
  .range([height, 0]);
</code></pre>
<p>The x and y axes for the volume series bar chart consist of the trade date and volume respectively. Thus, we will need to redefine the minimum and maximum y values and make use of <code>scaleLinear()</code>on the y-axis. The range of these scales are defined by the width and height of our SVG element. We will be reusing <code>xScale</code> since the x-axis of the bar chart corresponds similarly to the trade date.</p>
<pre><code class="language-js">svg
  .selectAll()
  .data(volData)
  .enter()
  .append('rect')
  .attr('x', d =&gt; {
    return xScale(d['date']);
  })
  .attr('y', d =&gt; {
    return yVolumeScale(d['volume']);
  })
  .attr('fill', (d, i) =&gt; {
    if (i === 0) {
      return '#03a678';
    } else {  
      return volData[i - 1].close &gt; d.close ? '#c0392b' : '#03a678'; 
    }
  })
  .attr('width', 1)
  .attr('height', d =&gt; {
    return height - yVolumeScale(d['volume']);
  });
</code></pre>
<p>This section relies on your understanding of how the<code>selectAll()</code> method works with the <code>enter()</code> and <code>append()</code> methods. You may wish to read <a href="https://bost.ocks.org/mike/join/">this</a> (written by <a href="https://bost.ocks.org/mike/">Mike Bostock</a> himself) if you are unfamiliar with those methods. This may be important as those methods are used as part of the <a href="https://bost.ocks.org/mike/join/">enter-update-exit</a> pattern, which I may cover in a subsequent tutorial.</p>
<p>To render the bars, we will first use <code>.selectAll()</code> to return an empty selection, or an empty array. Next, we pass <code>volData</code> to define the height of each bar. The <code>enter()</code> method compares the <code>volData</code> dataset with the selection from <code>selectAll()</code>, which is currently empty. Currently, the DOM does not contain any <code>&lt;re</code>ct&gt; element. Thus<code>, the ap</code>pend() method accepts an arg<code>ument</code> ‘rect’, which creates <code>a new</code> element in the DOM for every singl<code>e objec</code>t in volData.</p>
<p>Here is a breakdown of the attributes of the bars. We will be using the following attributes: <code>x</code>, <code>y</code>, <code>fill</code>, <code>width</code>, and <code>height</code>.</p>
<pre><code class="language-plaintext">.attr('x', d =&gt; {
  return xScale(d['date']);
})
.attr('y', d =&gt; {
  return yVolumeScale(d['volume']);
})
</code></pre>
<p>The first <code>attr()</code> method defines the x-coordinate. It accepts an anonymous function which returns the date. Similarly, the second <code>attr()</code> method defines the y-coordinate. It accepts an anonymous function which returns the volume. These will define the position of each bar.</p>
<pre><code class="language-plaintext">.attr('width', 1)
.attr('height', d =&gt; {
  return height - yVolumeScale(d['volume']);
});
</code></pre>
<p>We assign a width of 1 pixel to each bar. To make the bar stretch from the top (defined by <code>y</code>)to the x-axis, simply deduct the height with the <code>y</code> value.</p>
<pre><code class="language-plaintext">.attr('fill', (d, i) =&gt; {
  if (i === 0) {
    return '#03a678';
  } else {  
    return volData[i - 1].close &gt; d.close ? '#c0392b' : '#03a678'; 
  }
})
</code></pre>
<p>Remember the way that the bars will be color coded? We will be using the <code>fill</code> attribute to define the colors of each bar. For stocks that closed higher than the previous day’s close price, the bar will be green in color. Otherwise, the bar will be red.</p>
<p>This is how your current chart should look like:</p>
<img src="https://cdn-media-1.freecodecamp.org/images/f3q6i4i1wTbBzHe4TXuLTR3Blcg4YbOYUsCW" alt="Image" style="display: block;" width="800" height="403" loading="lazy">

<p><em>Checkpoint #3: Volume series chart, represented by red and green bars.</em></p>
<h4 id="heading-rendering-crosshair-and-legend-for-interactivity">Rendering Crosshair and Legend for interactivity</h4>
<p>We have reached the final step of this tutorial, whereby we will generate a mouseover crosshair that displays drop lines. Mousing over the various points in the chart will cause the legends to be updated. This provides us the full information (open price, close price, high price, low price, and volume) for each trade date.</p>
<p>The following section is referenced from <a href="https://bl.ocks.org/micahstubbs/e4f5c830c264d26621b80b754219ae1b">Micah Stubb’s excellent example</a>.</p>
<pre><code class="language-js">// renders x and y crosshair
const focus = svg
  .append('g')
  .attr('class', 'focus')
  .style('display', 'none');
focus.append('circle').attr('r', 4.5);
focus.append('line').classed('x', true);
focus.append('line').classed('y', true);
svg
  .append('rect')
  .attr('class', 'overlay')
  .attr('width', width)
  .attr('height', height)
  .on('mouseover', () =&gt; focus.style('display', null))
  .on('mouseout', () =&gt; focus.style('display', 'none'))
  .on('mousemove', generateCrosshair);
d3.select('.overlay').style('fill', 'none');
d3.select('.overlay').style('pointer-events', 'all');
d3.selectAll('.focus line').style('fill', 'none');
d3.selectAll('.focus line').style('stroke', '#67809f');
d3.selectAll('.focus line').style('stroke-width', '1.5px');
d3.selectAll('.focus line').style('stroke-dasharray', '3 3');
</code></pre>
<p>The crosshair consists of a translucent circle with drop lines consisting of dashes. The above code block provides the styling of the individual elements. Upon mouseover, it will generate the crosshair based on the function below.</p>
<pre><code class="language-js">const bisectDate = d3.bisector(d =&gt; d.date).left;
function generateCrosshair() {
  //returns corresponding value from the domain
  const correspondingDate = xScale.invert(d3.mouse(this)[0]);
  //gets insertion point
  const i = bisectDate(data, correspondingDate, 1);
  const d0 = data[i - 1];
  const d1 = data[i];
  const currentPoint = correspondingDate - d0['date'] &gt; d1['date'] - correspondingDate ? d1 : d0;
  
  focus.attr('transform',`translate(${xScale(currentPoint['date'])},     ${yScale(currentPoint['close'])})`);
focus
  .select('line.x')
  .attr('x1', 0)
  .attr('x2', width - xScale(currentPoint['date']))
  .attr('y1', 0)
  .attr('y2', 0);
focus
  .select('line.y')
  .attr('x1', 0)
  .attr('x2', 0)
  .attr('y1', 0)
  .attr('y2', height - yScale(currentPoint['close']));
 updateLegends(currentPoint);
}
</code></pre>
<p>We can then make use of the <a href="https://github.com/d3/d3-array#bisect">d3.bisector()</a> method to locate the insertion point, which will highlight the closest data point on the close price line graph. After determining the <code>currentPoint</code>, the drop lines will be updated. The <code>updateLegends()</code> method uses the <code>currentPoint</code> as the parameter.</p>
<pre><code class="language-plaintext">const updateLegends = currentData =&gt; {  d3.selectAll('.lineLegend').remove();
</code></pre>
<pre><code class="language-plaintext">const updateLegends = currentData =&gt; {
  d3.selectAll('.lineLegend').remove();
  const legendKeys = Object.keys(data[0]);
  const lineLegend = svg
    .selectAll('.lineLegend')
    .data(legendKeys)
    .enter()
    .append('g')
    .attr('class', 'lineLegend')
    .attr('transform', (d, i) =&gt; {
      return `translate(0, ${i * 20})`;
    });
  lineLegend
    .append('text')
    .text(d =&gt; {
      if (d === 'date') {
        return `${d}: ${currentData[d].toLocaleDateString()}`;
      } else if ( d === 'high' || d === 'low' || d === 'open' || d === 'close') {
        return `${d}: ${currentData[d].toFixed(2)}`;
      } else {
        return `${d}: ${currentData[d]}`;
      }
    })
    .style('fill', 'white')
    .attr('transform', 'translate(15,9)');
  };
</code></pre>
<p>The <code>updateLegends()</code> method updates the legend by displaying the date, open price, close price, high price, low price, and volume of the selected mouseover point on the close line graph. Similar to the Volume bar charts, we will make use of the <code>selectAll()</code> method with the <code>enter()</code> and <code>append()</code> methods.</p>
<p>To render the legends, we will use<code>.selectAll('.lineLegend')</code> to select the legends, followed by calling the <code>remove()</code> method to remove them. Next, we pass the keys of the legends, <code>legendKeys</code>, which will be used to define the height of each bar. The <code>enter()</code> method is called, which compares the <code>volData</code> dataset and at the selection from <code>selectAll()</code>, which is currently empty. Currently, the DOM does not contain any <code>&lt;re</code>ct&gt; element. Thus<code>, the ap</code>pend() method accepts an arg<code>ument</code> ‘rect’, which creates <code>a new</code> element in the DOM for every singl<code>e objec</code>t in volData.</p>
<p>Next, append the legends with their respective properties. We further process the values by converting the prices to 2 decimal places. We also set the date object to the <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toLocaleDateString">default locale</a> for readability.</p>
<p>This will be the end result:</p>
<img src="https://cdn-media-1.freecodecamp.org/images/TdHsr5qhwh-KFRJHOeGi0RfqtYS8XD4QbCjG" alt="Image" style="display: block;" width="800" height="399" loading="lazy">

<p><em>Checkpoint #4: Mouseover any part of the chart!</em></p>
<h4 id="heading-closing-thoughts">Closing Thoughts</h4>
<p>Congratulations! You have reached the end of this tutorial. As demonstrated above, D3.js is simple yet dynamic. It allows you to create custom visualizations for all your data sets. In the coming weeks, I will release the second part of this series which will deep dive into D3.js’s enter-update-exit pattern. Meanwhile, you may wish to check out the <a href="https://github.com/d3/d3/wiki">API documentation</a>, <a href="https://github.com/d3/d3/wiki/Tutorials">more tutorials</a>, and <a href="https://github.com/d3/d3/wiki/Gallery">other interesting visualizations built with D3.js</a>.</p>
<p>Feel free to check out the <a href="https://github.com/wentjun/d3-historical-price-chart-basic">source code</a> as well as the <a href="https://wentjun.com/d3-historical-price-chart-basic/">full demonstration</a> of this tutorial. Thank you, and I hope you have learned something new today!</p>
<p><em>Special thanks to Debbie Leong for reviewing this article.</em></p>
 ]]>
                </content:encoded>
            </item>
        
    </channel>
</rss>
