JSFiddle - React, Tailwind, and code Playground

by Gordon Woodhull

HTML

<script src="https://unpkg.com/d3@5/dist/d3.js"></script>
<script src="https://unpkg.com/crossfilter2@1.4/crossfilter.js"></script>
<script src="https://rawgit.com/crossfilter/reductio/master/reductio.js"></script>
<script src="https://npmcdn.com/universe@latest/universe.js"></script>
<script src="https://unpkg.com/dc@4/dist/dc.js"></script>
<link rel="stylesheet" href="https://unpkg.com/dc@4/dist/style/dc.css">
<div id="bubble"></div>

JavaScript

const yearlyBubbleChart = new dc.BubbleChart('#yearly-bubble-chart');

d3.csv('https://dc-js.github.io/dc.js/ndx.csv')
	.then(data => {
    // Since its a csv file we need to format the data a bit.
    const dateFormatSpecifier = '%m/%d/%Y';
    const dateFormat = d3.timeFormat(dateFormatSpecifier);
    const dateFormatParser = d3.timeParse(dateFormatSpecifier);
    const numberFormat = d3.format('.2f');

    data.forEach(d => {
        d.dd = dateFormatParser(d.date);
        d.month = d3.timeMonth(d.dd); // pre-calculate month for better performance
        d.close = +d.close; // coerce to number
        d.open = +d.open;
    });
    const ndx = crossfilter(data);

		// Dimension by year
    const yearlyDimension = ndx.dimension(d => d3.timeYear(d.dd).getFullYear());
    // Maintain running tallies by year as filters are applied or removed
    const yearlyPerformanceGroup = yearlyDimension.group().reduce(
        /* callback for when data is added to the current filter results */
        (p, v) => {
            ++p.count;
            p.absGain += v.close - v.open;
            p.fluctuation += Math.abs(v.close - v.open);
            p.sumIndex += (v.open + v.close) / 2;
            p.avgIndex = p.sumIndex / p.count;
            p.percentageGain = p.avgIndex ? (p.absGain / p.avgIndex) * 100 : 0;
            p.fluctuationPercentage = p.avgIndex ? (p.fluctuation / p.avgIndex) * 100 : 0;
            return p;
        },
        /* callback for when data is removed from the current filter results */
        (p, v) => {
            --p.count;
            p.absGain -= v.close - v.open;
            p.fluctuation -= Math.abs(v.close - v.open);
            p.sumIndex -= (v.open + v.close) / 2;
            p.avgIndex = p.count ? p.sumIndex / p.count : 0;
            p.percentageGain = p.avgIndex ? (p.absGain / p.avgIndex) * 100 : 0;
            p.fluctuationPercentage = p.avgIndex ? (p.fluctuation / p.avgIndex) * 100 : 0;
            return p;
        },
        /*...