d3.json('src/stores/untappd.json', function (error, data) {
                  var beerData = data.response.beers.items;

                  var fullDateFormat = d3.time.format('%a, %d %b %Y %X %Z');
                  var yearFormat = d3.time.format('%Y');
                  var monthFormat = d3.time.format('%b');
                  var dayOfWeekFormat = d3.time.format('%a');

                  // normalize/parse data so dc can correctly sort & bin them
                  // I like to think of each "d" as a row in a spreadsheet
                  beerData.forEach(d => {
                    d.count = +d.count;
                    // round to nearest 0.25
                    d.rating_score = Math.round(+d.rating_score * 4) / 4;
                    d.beer.rating_score = Math.round(+d.beer.rating_score *4) / 4;
                    // round to nearest 0.5
                    d.beer.beer_abv = Math.round(+d.beer.beer_abv * 2) / 2;
                    // round to nearest 10
                    d.beer.beer_ibu = Math.floor(+d.beer.beer_ibu / 10) * 10;

                    d.first_had_dt = fullDateFormat.parse(d.first_had);
                    d.first_had_year = +yearFormat(d.first_had_dt);
                    d.first_had_month = monthFormat(d.first_had_dt);
                    d.first_had_day = dayOfWeekFormat(d.first_had_dt);
                  });

                  // set crossfilter
                  var ndx = crossfilter(beerData);

                  // create dimensions (x-axis values)
                  var yearDim  = ndx.dimension(function(d) {return d.first_had_year;}),
                      // pluck: short-hand for same kind of anon. function we used for yearDim
                      monthDim  = ndx.dimension(pluck('first_had_month')),
                      dayOfWeekDim = ndx.dimension(pluck('first_had_day')),
                      ratingDim = ndx.dimension(pluck('rating_score')),
                      commRatingDim = ndx.dimension(function(d) {return d.beer.rating_score;}),
                      abvDim = ndx.dimension(function(d) {return d.beer.beer_abv;}),
                      ibuDim = ndx.dimension(function(d) {return d.beer.beer_ibu;}),
                      allDim = ndx.dimension(function(d) {return d;});

                  // create groups (y-axis values)
                  var all = ndx.groupAll();
                  var countPerYear = yearDim.group().reduceCount(),
                      countPerMonth = monthDim.group().reduceCount(),
                      countPerDay = dayOfWeekDim.group().reduceCount(),
                      countPerRating = ratingDim.group().reduceCount(),
                      countPerCommRating = commRatingDim.group().reduceCount(),
                      countPerABV = abvDim.group().reduceCount(),
                      countPerIBU = ibuDim.group().reduceCount();

                  // specify charts
                  var yearChart   = pieChart('#chart-ring-year'),
                      monthChart   = pieChart('#chart-ring-month'),
                      dayChart   = pieChart('#chart-ring-day'),
                      ratingCountChart  = barChart('#chart-rating-count'),
                      commRatingCountChart  = barChart('#chart-community-rating-count'),
                      abvCountChart  = barChart('#chart-abv-count'),
                      ibuCountChart  = barChart('#chart-ibu-count');
                    var  myDataCount = dataCount('#data-count');
                    var  myDataTable = dataTable('#data-table');

                  yearChart
                      .width(150)
                      .height(150)
                      .dimension(yearDim)
                      .group(countPerYear)
                      .innerRadius(20);

                  monthChart
                      .width(150)
                      .height(150)
                      .dimension(monthDim)
                      .group(countPerMonth)
                      .innerRadius(20)
                      .ordering(function (d) {
                        var order = {
                          'Jan': 1, 'Feb': 2, 'Mar': 3, 'Apr': 4,
                          'May': 5, 'Jun': 6, 'Jul': 7, 'Aug': 8,
                          'Sep': 9, 'Oct': 10, 'Nov': 11, 'Dec': 12
                        };
                        return order[d.key];
                      });

                  dayChart
                      .width(150)
                      .height(150)
                      .dimension(dayOfWeekDim)
                      .group(countPerDay)
                      .innerRadius(20)
                      .ordering(function (d) {
                        var order = {
                          'Mon': 0, 'Tue': 1, 'Wed': 2, 'Thu': 3,
                          'Fri': 4, 'Sat': 5, 'Sun': 6
                        }
                        return order[d.key];
                      }
                     );

                  ratingCountChart
                      .width(300)
                      .height(180)
                      .dimension(ratingDim)
                      .group(countPerRating)
                      .x(d3.scale.linear().domain([0,5.2]))
                      .elasticY(true)
                      .centerBar(true)
                      .barPadding(5)
                      .xAxisLabel('My rating')
                      .yAxisLabel('Count')
                      .margins({top: 10, right: 20, bottom: 50, left: 50});
                  ratingCountChart.xAxis().tickValues([0, 1, 2, 3, 4, 5]);

                  commRatingCountChart
                      .width(300)
                      .height(180)
                      .dimension(commRatingDim)
                      .group(countPerCommRating)
                      .x(d3.scale.linear().domain([0,5.2]))
                      .elasticY(true)
                      .centerBar(true)
                      .barPadding(5)
                      .xAxisLabel('Community rating')
                      .yAxisLabel('Count')
                      .margins({top: 10, right: 20, bottom: 50, left: 50});
                  commRatingCountChart.xAxis().tickValues([0, 1, 2, 3, 4, 5]);

                  abvCountChart
                      .width(300)
                      .height(180)
                      .dimension(abvDim)
                      .group(countPerABV)
                      .x(d3.scale.linear().domain([-0.2, d3.max(beerData, function (d) { return d.beer.beer_abv; }) + 0.2]))
                      .elasticY(true)
                      .centerBar(true)
                      .barPadding(2)
                      .xAxisLabel('Alcohol By Volume (%)')
                      .yAxisLabel('Count')
                      .margins({top: 10, right: 20, bottom: 50, left: 50});

                  ibuCountChart
                      .width(300)
                      .height(180)
                      .dimension(ibuDim)
                      .group(countPerIBU)
                      .x(d3.scale.linear().domain([-2, d3.max(beerData, function (d) { return d.beer.beer_ibu; }) + 2]))
                      .elasticY(true)
                      .centerBar(true)
                      .barPadding(5)
                      .xAxisLabel('International Bitterness Units')
                      .yAxisLabel('Count')
                      .xUnits(function (d) { return 5;})
                      .margins({top: 10, right: 20, bottom: 50, left: 50});

                  myDataCount
                      .dimension(ndx)
                      .group(all);

                   myDataTable
                    .dimension(allDim)
                    .group(function (d) { return 'dc.js insists on putting a row here so I remove it using JS'; })
                    .size(100)
                    .columns([
                      function (d) { return d.brewery.brewery_name; },
                      function (d) { return d.beer.beer_name; },
                      function (d) { return d.beer.beer_style; },
                      function (d) { return d.rating_score; },
                      function (d) { return d.beer.rating_score; },
                      function (d) { return d.beer.beer_abv; },
                      function (d) { return d.beer.beer_ibu; }
                    ])
                    .sortBy(pluck('rating_score'))
                    .order(d3.descending)
                    .on('renderlet', function (table) {
                      // each time table is rendered remove nasty extra row dc.js insists on adding
                      table.select('tr.dc-table-group').remove();
                    });

                  // register handlers
                  d3.selectAll('a#all').on('click', function () {
                    filterAll();
                    renderAll();
                  });

                  d3.selectAll('a#year').on('click', function () {
                    yearChart.filterAll();
                    redrawAll();
                  });

                  d3.selectAll('a#month').on('click', function () {
                    monthChart.filterAll();
                    redrawAll();
                  });

                  d3.selectAll('a#day').on('click', function () {
                    dayChart.filterAll();
                    redrawAll();
                  });

                  // showtime!
                  renderAll();

                });
d3.csv("./src/stores/ndx.csv", function(error, data) {
        var dateFormat = d3.time.format("%m/%d/%Y");
        data.forEach(function (d) {
            d.dd = dateFormat.parse(d.date);
            d.month = d3.time.month(d.dd).getMonth(); // pre-calculate month for better performance
            d.year = d3.time.year(d.dd).getFullYear();
            d.close = +d.close; // coerce to number
            d.open = +d.open;
        });
        var ndx = crossfilter(data),
            monthOfTheYearDimension = ndx.dimension(function(d) { return [+d.month, +d.year]; }),
            percentageGainByMonthOfYearGroup = monthOfTheYearDimension.group().reduce(
                /* callback for when data is added to the current filter results */
                function (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;
                },
                /* callback for when data is removed from the current filter results */
                function (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;
                },
                /* initialize p */
                function () {
                    return {count: 0, absGain: 0, fluctuation: 0, fluctuationPercentage: 0, sumIndex: 0, avgIndex: 0, percentageGain: 0};
                }
            );
        var heatColorMapping = function(d) {
            if (d < 0) {
                return d3.scale.linear().domain([-23,0]).range(["red", "#e5e5e5"])(d);
            }
            else {
                return d3.scale.linear().domain([0,23]).range(["#e5e5e5", "green"])(d);
            }
        };
        heatColorMapping.domain = function() {
            return [-23,23];
        };
        heatmapChart
                .width(12 * 80 + 80)
                .height(27 * 10 + 40)
                .dimension(monthOfTheYearDimension)
                .group(percentageGainByMonthOfYearGroup)
                .keyAccessor(function(d) { return +d.key[0]; })
                .valueAccessor(function(d) { return +d.key[1]; })
                .colorAccessor(function(d) { return +d.value.percentageGain; })
                .title(function(d) {
                    return " Month:   " + d.key[0] + "\n" +
                           "  Year:   " + d.key[1] + "\n" +
                           "  Gain:   " + d.value.percentageGain + "%";})
                .colors(heatColorMapping)
                .calculateColorDomain();
        heatmapChart.xBorderRadius(0);
        heatmapChart.yBorderRadius(0);
        heatmapChart.render();
        var monthlyDimension = ndx.dimension(function (d) { return +d.month; });
        var percentageGainByMonthArrayGroup = monthlyDimension.group().reduce(
            function(p,v) {
                var absGain = v.close - v.open;
                var percentageGain = v.open ? (absGain / v.open) * 100 : 0;
                return p + percentageGain;
            },
            function(p,v) {
                var absGain = v.close - v.open;
                var percentageGain = v.open ? (absGain / v.open) * 100 : 0;
                return p - percentageGain;
            },
            function() {
                return 0;
            }
        );
        barChart
                .dimension(monthlyDimension)
                .group(percentageGainByMonthArrayGroup)
                .width(12 * 80 + 80)
                .height(480)
                .y(d3.scale.linear().domain([-10.0,100.0]))
                .x(d3.scale.linear().domain([-0.5,11.5]))
                .elasticY(true)
                .centerBar(true);
        barChart.render();
    });
    d3.csv('src/stores/ndx.csv', function (data) {
      // Since its a csv file we need to format the data a bit.
      var dateFormat = d3.time.format('%m/%d/%Y');
      var numberFormat = d3.format('.2f');

      data.forEach(d => {
        d.dd = dateFormat.parse(d.date);
        d.month = d3.time.month(d.dd); // pre-calculate month for better performance
        d.close = +d.close; // coerce to number
        d.open = +d.open;
      });

      //### Create Crossfilter Dimensions and Groups

      //See the [crossfilter API](https://github.com/square/crossfilter/wiki/API-Reference) for reference.
      var ndx = crossfilter(data);
      var all = ndx.groupAll();

      // Dimension by year
      var yearlyDimension = ndx.dimension(function (d) {
        return d3.time.year(d.dd).getFullYear();
      });
      // Maintain running tallies by year as filters are applied or removed
      var yearlyPerformanceGroup = yearlyDimension.group().reduce(
        /* callback for when data is added to the current filter results */
        function (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 */
        function (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;
        },
        /* initialize p */
        function () {
          return {
            count: 0,
            absGain: 0,
            fluctuation: 0,
            fluctuationPercentage: 0,
            sumIndex: 0,
            avgIndex: 0,
            percentageGain: 0
          };
        }
      );

      // Dimension by full date
      var dateDimension = ndx.dimension(function (d) {
        return d.dd;
      });

      // Dimension by month
      var moveMonths = ndx.dimension(function (d) {
        return d.month;
      });
      // Group by total movement within month
      var monthlyMoveGroup = moveMonths.group().reduceSum(function (d) {
        return Math.abs(d.close - d.open);
      });
      // Group by total volume within move, and scale down result
      var volumeByMonthGroup = moveMonths.group().reduceSum(function (d) {
        return d.volume / 500000;
      });
      var indexAvgByMonthGroup = moveMonths.group().reduce(
        function (p, v) {
                    ++p.days;
          p.total += (v.open + v.close) / 2;
          p.avg = Math.round(p.total / p.days);
          return p;
        },
        function (p, v) {
                    --p.days;
          p.total -= (v.open + v.close) / 2;
          p.avg = p.days ? Math.round(p.total / p.days) : 0;
          return p;
        },
        function () {
          return {days: 0, total: 0, avg: 0};
        }
      );

      // Create categorical dimension
      var gainOrLoss = ndx.dimension(function (d) {
        return d.open > d.close ? 'Loss' : 'Gain';
      });
      // Produce counts records in the dimension
      var gainOrLossGroup = gainOrLoss.group();

      // Determine a histogram of percent changes
      var fluctuation = ndx.dimension(function (d) {
        return Math.round((d.close - d.open) / d.open * 100);
      });
      var fluctuationGroup = fluctuation.group();

      // Summarize volume by quarter
      var quarter = ndx.dimension(function (d) {
        var month = d.dd.getMonth();
        if (month <= 2) {
          return 'Q1';
        } else if (month > 2 && month <= 5) {
          return 'Q2';
        } else if (month > 5 && month <= 8) {
          return 'Q3';
        } else {
          return 'Q4';
        }
      });
      var quarterGroup = quarter.group().reduceSum(function (d) {
        return d.volume;
      });

      // Counts per weekday
      var dayOfWeek = ndx.dimension(function (d) {
        var day = d.dd.getDay();
        var name = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'];
        return day + '.' + name[day];
      });
      var dayOfWeekGroup = dayOfWeek.group();

      //### Define Chart Attributes
      // Define chart attributes using fluent methods. See the
      // [dc.js API Reference](https://github.com/dc-js/dc.js/blob/master/web/docs/api-latest.md) for more information
      //

      //#### Bubble Chart

      //Create a bubble chart and use the given css selector as anchor. You can also specify
      //an optional chart group for this chart to be scoped within. When a chart belongs
      //to a specific group then any interaction with the chart will only trigger redraws
      //on charts within the same chart group.
      // <br>API: [Bubble Chart](https://github.com/dc-js/dc.js/blob/master/web/docs/api-latest.md#bubble-chart)

      yearlyBubbleChart /* dc.bubbleChart('#yearly-bubble-chart', 'chartGroup') */
      // (_optional_) define chart width, `default = 200`
        .width(990)
      // (_optional_) define chart height, `default = 200`
        .height(250)
      // (_optional_) define chart transition duration, `default = 750`
        .transitionDuration(1500)
        .margins({top: 10, right: 50, bottom: 30, left: 40})
        .dimension(yearlyDimension)
      //The bubble chart expects the groups are reduced to multiple values which are used
      //to generate x, y, and radius for each key (bubble) in the group
        .group(yearlyPerformanceGroup)
      // (_optional_) define color function or array for bubbles: [ColorBrewer](http://colorbrewer2.org/)
        .colors(colorbrewer.RdYlGn[9])
      //(optional) define color domain to match your data domain if you want to bind data or color
        .colorDomain([-500, 500])
      //##### Accessors

      //Accessor functions are applied to each value returned by the grouping

      // `.colorAccessor` - the returned value will be passed to the `.colors()` scale to determine a fill color
        .colorAccessor(function (d) {
          return d.value.absGain;
        })
      // `.keyAccessor` - the `X` value will be passed to the `.x()` scale to determine pixel location
        .keyAccessor(function (p) {
          return p.value.absGain;
        })
      // `.valueAccessor` - the `Y` value will be passed to the `.y()` scale to determine pixel location
        .valueAccessor(function (p) {
          return p.value.percentageGain;
        })
      // `.radiusValueAccessor` - the value will be passed to the `.r()` scale to determine radius size;
      //   by default this maps linearly to [0,100]
        .radiusValueAccessor(function (p) {
          return p.value.fluctuationPercentage;
        })
        .maxBubbleRelativeSize(0.3)
        .x(d3.scale.linear().domain([-2500, 2500]))
        .y(d3.scale.linear().domain([-100, 100]))
        .r(d3.scale.linear().domain([0, 4000]))
      //##### Elastic Scaling

      //`.elasticY` and `.elasticX` determine whether the chart should rescale each axis to fit the data.
        .elasticY(true)
        .elasticX(true)
      //`.yAxisPadding` and `.xAxisPadding` add padding to data above and below their max values in the same unit
      //domains as the Accessors.
        .yAxisPadding(100)
        .xAxisPadding(500)
      // (_optional_) render horizontal grid lines, `default=false`
        .renderHorizontalGridLines(true)
      // (_optional_) render vertical grid lines, `default=false`
        .renderVerticalGridLines(true)
      // (_optional_) render an axis label below the x axis
        .xAxisLabel('Index Gain')
      // (_optional_) render a vertical axis lable left of the y axis
        .yAxisLabel('Index Gain %')
      //##### Labels and  Titles

      //Labels are displayed on the chart for each bubble. Titles displayed on mouseover.
      // (_optional_) whether chart should render labels, `default = true`
        .renderLabel(true)
        .label(function (p) {
          return p.key;
        })
      // (_optional_) whether chart should render titles, `default = false`
        .renderTitle(true)
        .title(function (p) {
          return [
            p.key,
            'Index Gain: ' + numberFormat(p.value.absGain),
            'Index Gain in Percentage: ' + numberFormat(p.value.percentageGain) + '%',
            'Fluctuation / Index Ratio: ' + numberFormat(p.value.fluctuationPercentage) + '%'
          ].join('\n');
        })
      //#### Customize Axes

      // Set a custom tick format. Both `.yAxis()` and `.xAxis()` return an axis object,
      // so any additional method chaining applies to the axis, not the chart.
        .yAxis().tickFormat(function (v) {
          return v + '%';
        });

      // #### Pie/Donut Charts

      // Create a pie chart and use the given css selector as anchor. You can also specify
      // an optional chart group for this chart to be scoped within. When a chart belongs
      // to a specific group then any interaction with such chart will only trigger redraw
      // on other charts within the same chart group.
      // <br>API: [Pie Chart](https://github.com/dc-js/dc.js/blob/master/web/docs/api-latest.md#pie-chart)

      gainOrLossChart /* dc.pieChart('#gain-loss-chart', 'chartGroup') */
      // (_optional_) define chart width, `default = 200`
        .width(180)
      // (optional) define chart height, `default = 200`
        .height(180)
      // Define pie radius
        .radius(80)
      // Set dimension
        .dimension(gainOrLoss)
      // Set group
        .group(gainOrLossGroup)
      // (_optional_) by default pie chart will use `group.key` as its label but you can overwrite it with a closure.
        .label(function (d) {
          if (gainOrLossChart.hasFilter() && !gainOrLossChart.hasFilter(d.key)) {
            return d.key + '(0%)';
          }
          var label = d.key;
          if (all.value()) {
            label += '(' + Math.floor(d.value / all.value() * 100) + '%)';
          }
          return label;
        })
      /*
         // (_optional_) whether chart should render labels, `default = true`
         .renderLabel(true)
         // (_optional_) if inner radius is used then a donut chart will be generated instead of pie chart
         .innerRadius(40)
         // (_optional_) define chart transition duration, `default = 350`
         .transitionDuration(500)
         // (_optional_) define color array for slices
         .colors(['#3182bd', '#6baed6', '#9ecae1', '#c6dbef', '#dadaeb'])
         // (_optional_) define color domain to match your data domain if you want to bind data or color
         .colorDomain([-1750, 1644])
         // (_optional_) define color value accessor
         .colorAccessor(function(d, i){return d.value;})
       */;

      quarterChart /* dc.pieChart('#quarter-chart', 'chartGroup') */
        .width(180)
        .height(180)
        .radius(80)
        .innerRadius(30)
        .dimension(quarter)
        .group(quarterGroup);

      //#### Row Chart

      // Create a row chart and use the given css selector as anchor. You can also specify
      // an optional chart group for this chart to be scoped within. When a chart belongs
      // to a specific group then any interaction with such chart will only trigger redraw
      // on other charts within the same chart group.
      // <br>API: [Row Chart](https://github.com/dc-js/dc.js/blob/master/web/docs/api-latest.md#row-chart)
      dayOfWeekChart /* dc.rowChart('#day-of-week-chart', 'chartGroup') */
        .width(180)
        .height(180)
        .margins({top: 20, left: 10, right: 10, bottom: 20})
        .group(dayOfWeekGroup)
        .dimension(dayOfWeek)
      // Assign colors to each value in the x scale domain
        .ordinalColors(['#3182bd', '#6baed6', '#9ecae1', '#c6dbef', '#dadaeb'])
        .label(function (d) {
          return d.key.split('.')[1];
        })
      // Title sets the row text
        .title(function (d) {
          return d.value;
        })
        .elasticX(true)
        .xAxis().ticks(4);

      //#### Bar Chart

      // Create a bar chart and use the given css selector as anchor. You can also specify
      // an optional chart group for this chart to be scoped within. When a chart belongs
      // to a specific group then any interaction with such chart will only trigger redraw
      // on other charts within the same chart group.
      // <br>API: [Bar Chart](https://github.com/dc-js/dc.js/blob/master/web/docs/api-latest.md#bar-chart)
      fluctuationChart /* dc.barChart('#volume-month-chart', 'chartGroup') */
        .width(420)
        .height(180)
        .margins({top: 10, right: 50, bottom: 30, left: 40})
        .dimension(fluctuation)
        .group(fluctuationGroup)
        .elasticY(true)
      // (_optional_) whether bar should be center to its x value. Not needed for ordinal chart, `default=false`
        .centerBar(true)
      // (_optional_) set gap between bars manually in px, `default=2`
        .gap(1)
      // (_optional_) set filter brush rounding
        .round(dc.round.floor)
        .alwaysUseRounding(true)
        .x(d3.scale.linear().domain([-25, 25]))
        .renderHorizontalGridLines(true)
      // Customize the filter displayed in the control span
        .filterPrinter(function (filters) {
          var filter = filters[0], s = '';
          s += numberFormat(filter[0]) + '% -> ' + numberFormat(filter[1]) + '%';
          return s;
        });

      // Customize axes
      fluctuationChart.xAxis().tickFormat(
        function (v) { return v + '%'; });
      fluctuationChart.yAxis().ticks(5);

      //#### Stacked Area Chart

      //Specify an area chart by using a line chart with `.renderArea(true)`.
      // <br>API: [Stack Mixin](https://github.com/dc-js/dc.js/blob/master/web/docs/api-latest.md#stack-mixin),
      // [Line Chart](https://github.com/dc-js/dc.js/blob/master/web/docs/api-latest.md#line-chart)
      moveChart /* dc.lineChart('#monthly-move-chart', 'chartGroup') */
        .renderArea(true)
        .width(990)
        .height(200)
        .transitionDuration(1000)
        .margins({top: 30, right: 50, bottom: 25, left: 40})
        .dimension(moveMonths)
        .mouseZoomable(true)
      // Specify a "range chart" to link its brush extent with the zoom of the current "focus chart".
        .rangeChart(volumeChart)
        .x(d3.time.scale().domain([new Date(1985, 0, 1), new Date(2012, 11, 31)]))
        .round(d3.time.month.round)
        .xUnits(d3.time.months)
        .elasticY(true)
        .renderHorizontalGridLines(true)
      //##### Legend

      // Position the legend relative to the chart origin and specify items' height and separation.
        .legend(dc.legend().x(800).y(10).itemHeight(13).gap(5))
        .brushOn(false)
      // Add the base layer of the stack with group. The second parameter specifies a series name for use in the
      // legend.
      // The `.valueAccessor` will be used for the base layer
        .group(indexAvgByMonthGroup, 'Monthly Index Average')
        .valueAccessor(function (d) {
          return d.value.avg;
        })
      // Stack additional layers with `.stack`. The first paramenter is a new group.
      // The second parameter is the series name. The third is a value accessor.
        .stack(monthlyMoveGroup, 'Monthly Index Move', function (d) {
          return d.value;
        })
      // Title can be called by any stack layer.
        .title(function (d) {
          var value = d.value.avg ? d.value.avg : d.value;
          if (isNaN(value)) {
            value = 0;
          }
          return dateFormat(d.key) + '\n' + numberFormat(value);
        });

      //#### Range Chart

      // Since this bar chart is specified as "range chart" for the area chart, its brush extent
      // will always match the zoom of the area chart.
      volumeChart.width(990) /* dc.barChart('#monthly-volume-chart', 'chartGroup'); */
                 .height(40)
                 .margins({top: 0, right: 50, bottom: 20, left: 40})
                 .dimension(moveMonths)
                 .group(volumeByMonthGroup)
                 .centerBar(true)
                 .gap(1)
                 .x(d3.time.scale().domain([new Date(1985, 0, 1), new Date(2012, 11, 31)]))
                 .round(d3.time.month.round)
                 .alwaysUseRounding(true)
                 .xUnits(d3.time.months);

      //#### Data Count

      // Create a data count widget and use the given css selector as anchor. You can also specify
      // an optional chart group for this chart to be scoped within. When a chart belongs
      // to a specific group then any interaction with such chart will only trigger redraw
      // on other charts within the same chart group.
      // <br>API: [Data Count Widget](https://github.com/dc-js/dc.js/blob/master/web/docs/api-latest.md#data-count-widget)
      //
      //```html
      //<div class='dc-data-count'>
      //  <span class='filter-count'></span>
      //  selected out of <span class='total-count'></span> records.
      //</div>
      //```

      nasdaqCount /* dc.dataCount('.dc-data-count', 'chartGroup'); */
        .dimension(ndx)
        .group(all)
      // (_optional_) `.html` sets different html when some records or all records are selected.
      // `.html` replaces everything in the anchor with the html given using the following function.
      // `%filter-count` and `%total-count` are replaced with the values obtained.
        .html({
          some: '<strong>%filter-count</strong> selected out of <strong>%total-count</strong> records' +
                ' | <a href=\'javascript:dc.filterAll(); dc.renderAll();\'>Reset All</a>',
          all: 'All records selected. Please click on the graph to apply filters.'
        });

      //#### Data Table

      // Create a data table widget and use the given css selector as anchor. You can also specify
      // an optional chart group for this chart to be scoped within. When a chart belongs
      // to a specific group then any interaction with such chart will only trigger redraw
      // on other charts within the same chart group.
      // <br>API: [Data Table Widget](https://github.com/dc-js/dc.js/blob/master/web/docs/api-latest.md#data-table-widget)
      //
      // You can statically define the headers like in
      //
      // ```html
      //    <!-- anchor div for data table -->
      //    <div id='data-table'>
      //       <!-- create a custom header -->
      //       <div class='header'>
      //           <span>Date</span>
      //           <span>Open</span>
      //           <span>Close</span>
      //           <span>Change</span>
      //           <span>Volume</span>
      //       </div>
      //       <!-- data rows will filled in here -->
      //    </div>
      // ```
      // or do it programmatically using `.columns()`.

      nasdaqTable /* dc.dataTable('.dc-data-table', 'chartGroup') */
        .dimension(dateDimension)
      // Data table does not use crossfilter group but rather a closure
      // as a grouping function
        .group(function (d) {
          var format = d3.format('02d');
          return d.dd.getFullYear() + '/' + format((d.dd.getMonth() + 1));
        })
      // (_optional_) max number of records to be shown, `default = 25`
        .size(10)
      // There are several ways to specify the columns; see the data-table documentation.
      // This code demonstrates generating the column header automatically based on the columns.
        .columns([
          // Use the `d.date` field; capitalized automatically
          'date',
          // Use `d.open`, `d.close`
          'open',
          'close',
          {
            // Specify a custom format for column 'Change' by using a label with a function.
            label: 'Change',
            format: function (d) {
              return numberFormat(d.close - d.open);
            }
          },
          // Use `d.volume`
          'volume'
        ])

      // (_optional_) sort using the given field, `default = function(d){return d;}`
        .sortBy(function (d) {
          return d.dd;
        })
      // (_optional_) sort order, `default = d3.ascending`
        .order(d3.ascending)
      // (_optional_) custom renderlet to post-process chart using [D3](http://d3js.org)
        .on('renderlet', function (table) {
          table.selectAll('.dc-table-group').classed('info', true);
        });

      /*
         //#### Geo Choropleth Chart

         //Create a choropleth chart and use the given css selector as anchor. You can also specify
         //an optional chart group for this chart to be scoped within. When a chart belongs
         //to a specific group then any interaction with such chart will only trigger redraw
         //on other charts within the same chart group.
         // <br>API: [Geo Chroropleth Chart][choro]
         // [choro]: https://github.com/dc-js/dc.js/blob/master/web/docs/api-latest.md#geo-choropleth-chart
         dc.geoChoroplethChart('#us-chart')
         // (_optional_) define chart width, default 200
         .width(990)
         // (optional) define chart height, default 200
         .height(500)
         // (optional) define chart transition duration, default 1000
         .transitionDuration(1000)
         // set crossfilter dimension, dimension key should match the name retrieved in geojson layer
         .dimension(states)
         // set crossfilter group
         .group(stateRaisedSum)
         // (_optional_) define color function or array for bubbles
         .colors(['#ccc', '#E2F2FF','#C4E4FF','#9ED2FF','#81C5FF','#6BBAFF','#51AEFF','#36A2FF','#1E96FF','#0089FF',
         '#0061B5'])
         // (_optional_) define color domain to match your data domain if you want to bind data or color
         .colorDomain([-5, 200])
         // (_optional_) define color value accessor
         .colorAccessor(function(d, i){return d.value;})
         // Project the given geojson. You can call this function multiple times with different geojson feed to generate
         // multiple layers of geo paths.
         //
         // * 1st param - geojson data
         // * 2nd param - name of the layer which will be used to generate css class
         // * 3rd param - (_optional_) a function used to generate key for geo path, it should match the dimension key
         // in order for the coloring to work properly
         .overlayGeoJson(statesJson.features, 'state', function(d) {
         return d.properties.name;
         })
         // (_optional_) closure to generate title for path, `default = d.key + ': ' + d.value`
         .title(function(d) {
         return 'State: ' + d.key + '\nTotal Amount Raised: ' + numberFormat(d.value ? d.value : 0) + 'M';
         });

         //#### Bubble Overlay Chart

         // Create a overlay bubble chart and use the given css selector as anchor. You can also specify
         // an optional chart group for this chart to be scoped within. When a chart belongs
         // to a specific group then any interaction with the chart will only trigger redraw
         // on charts within the same chart group.
         // <br>API: [Bubble Overlay Chart][bubble]
         // [bubble]: https://github.com/dc-js/dc.js/blob/master/web/docs/api-latest.md#bubble-overlay-chart
         dc.bubbleOverlay('#bubble-overlay', 'chartGroup')
         // The bubble overlay chart does not generate its own svg element but rather reuses an existing
         // svg to generate its overlay layer
         .svg(d3.select('#bubble-overlay svg'))
         // (_optional_) define chart width, `default = 200`
         .width(990)
         // (_optional_) define chart height, `default = 200`
         .height(500)
         // (_optional_) define chart transition duration, `default = 1000`
         .transitionDuration(1000)
         // Set crossfilter dimension, dimension key should match the name retrieved in geo json layer
         .dimension(states)
         // Set crossfilter group
         .group(stateRaisedSum)
         // Closure used to retrieve x value from multi-value group
         .keyAccessor(function(p) {return p.value.absGain;})
         // Closure used to retrieve y value from multi-value group
         .valueAccessor(function(p) {return p.value.percentageGain;})
         // (_optional_) define color function or array for bubbles
         .colors(['#ccc', '#E2F2FF','#C4E4FF','#9ED2FF','#81C5FF','#6BBAFF','#51AEFF','#36A2FF','#1E96FF','#0089FF',
         '#0061B5'])
         // (_optional_) define color domain to match your data domain if you want to bind data or color
         .colorDomain([-5, 200])
         // (_optional_) define color value accessor
         .colorAccessor(function(d, i){return d.value;})
         // Closure used to retrieve radius value from multi-value group
         .radiusValueAccessor(function(p) {return p.value.fluctuationPercentage;})
         // set radius scale
         .r(d3.scale.linear().domain([0, 3]))
         // (_optional_) whether chart should render labels, `default = true`
         .renderLabel(true)
         // (_optional_) closure to generate label per bubble, `default = group.key`
         .label(function(p) {return p.key.getFullYear();})
         // (_optional_) whether chart should render titles, `default = false`
         .renderTitle(true)
         // (_optional_) closure to generate title per bubble, `default = d.key + ': ' + d.value`
         .title(function(d) {
         return 'Title: ' + d.key;
         })
         // add data point to its layer dimension key that matches point name: it will be used to
         // generate a bubble. Multiple data points can be added to the bubble overlay to generate
         // multiple bubbles.
         .point('California', 100, 120)
         .point('Colorado', 300, 120)
         // (_optional_) setting debug flag to true will generate a transparent layer on top of
         // bubble overlay which can be used to obtain relative `x`,`y` coordinate for specific
         // data point, `default = false`
         .debug(true);
       */

      //#### Rendering

      //simply call `.renderAll()` to render all charts on the page
      dc.renderAll();
      /*
         // Or you can render charts belonging to a specific chart group
         dc.renderAll('group');
         // Once rendered you can call `.redrawAll()` to update charts incrementally when the data
         // changes, without re-rendering everything
         dc.redrawAll();
         // Or you can choose to redraw only those charts associated with a specific chart group
         dc.redrawAll('group');
       */

    });
   d3.csv('src/stores/ndx.csv', function (data) {
      // Since its a csv file we need to format the data a bit.
      var dateFormat = d3.time.format('%m/%d/%Y');
      var numberFormat = d3.format('.2f');

      data.forEach(d => {
        d.dd = dateFormat.parse(d.date);
        d.month = d3.time.month(d.dd); // pre-calculate month for better performance
        d.close = +d.close; // coerce to number
        d.open = +d.open;
      });

      //### Create Crossfilter Dimensions and Groups

      //See the [crossfilter API](https://github.com/square/crossfilter/wiki/API-Reference) for reference.
      var ndx = crossfilter(data);
      var all = ndx.groupAll();

      // Dimension by year
      var yearlyDimension = ndx.dimension(function (d) {
        return d3.time.year(d.dd).getFullYear();
      });
      // Maintain running tallies by year as filters are applied or removed
      var yearlyPerformanceGroup = yearlyDimension.group().reduce(
        /* callback for when data is added to the current filter results */
        function (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 */
        function (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;
        },
        /* initialize p */
        function () {
          return {
            count: 0,
            absGain: 0,
            fluctuation: 0,
            fluctuationPercentage: 0,
            sumIndex: 0,
            avgIndex: 0,
            percentageGain: 0
          };
        }
      );


      //#### Bubble Chart

      //Create a bubble chart and use the given css selector as anchor. You can also specify
      //an optional chart group for this chart to be scoped within. When a chart belongs
      //to a specific group then any interaction with the chart will only trigger redraws
      //on charts within the same chart group.
      // <br>API: [Bubble Chart](https://github.com/dc-js/dc.js/blob/master/web/docs/api-latest.md#bubble-chart)

      yearlyBubbleChart /* dc.bubbleChart('#yearly-bubble-chart', 'chartGroup') */
      // (_optional_) define chart width, `default = 200`
        .width(990)
      // (_optional_) define chart height, `default = 200`
        .height(250)
      // (_optional_) define chart transition duration, `default = 750`
        .transitionDuration(1500)
        .margins({top: 10, right: 50, bottom: 30, left: 40})
        .dimension(yearlyDimension)
      //The bubble chart expects the groups are reduced to multiple values which are used
      //to generate x, y, and radius for each key (bubble) in the group
        .group(yearlyPerformanceGroup)
      // (_optional_) define color function or array for bubbles: [ColorBrewer](http://colorbrewer2.org/)
        .colors(colorbrewer.RdYlGn[9])
      //(optional) define color domain to match your data domain if you want to bind data or color
        .colorDomain([-500, 500])
      //##### Accessors

      //Accessor functions are applied to each value returned by the grouping

      // `.colorAccessor` - the returned value will be passed to the `.colors()` scale to determine a fill color
        .colorAccessor(function (d) {
          return d.value.absGain;
        })
      // `.keyAccessor` - the `X` value will be passed to the `.x()` scale to determine pixel location
        .keyAccessor(function (p) {
          return p.value.absGain;
        })
      // `.valueAccessor` - the `Y` value will be passed to the `.y()` scale to determine pixel location
        .valueAccessor(function (p) {
          return p.value.percentageGain;
        })
      // `.radiusValueAccessor` - the value will be passed to the `.r()` scale to determine radius size;
      //   by default this maps linearly to [0,100]
        .radiusValueAccessor(function (p) {
          return p.value.fluctuationPercentage;
        })
        .maxBubbleRelativeSize(0.3)
        .x(d3.scale.linear().domain([-2500, 2500]))
        .y(d3.scale.linear().domain([-100, 100]))
        .r(d3.scale.linear().domain([0, 4000]))
      //##### Elastic Scaling

      //`.elasticY` and `.elasticX` determine whether the chart should rescale each axis to fit the data.
        .elasticY(true)
        .elasticX(true)
      //`.yAxisPadding` and `.xAxisPadding` add padding to data above and below their max values in the same unit
      //domains as the Accessors.
        .yAxisPadding(100)
        .xAxisPadding(500)
      // (_optional_) render horizontal grid lines, `default=false`
        .renderHorizontalGridLines(true)
      // (_optional_) render vertical grid lines, `default=false`
        .renderVerticalGridLines(true)
      // (_optional_) render an axis label below the x axis
        .xAxisLabel('Index Gain')
      // (_optional_) render a vertical axis lable left of the y axis
        .yAxisLabel('Index Gain %')
      //##### Labels and  Titles

      //Labels are displayed on the chart for each bubble. Titles displayed on mouseover.
      // (_optional_) whether chart should render labels, `default = true`
        .renderLabel(true)
        .label(function (p) {
          return p.key;
        })
      // (_optional_) whether chart should render titles, `default = false`
        .renderTitle(true)
        .title(function (p) {
          return [
            p.key,
            'Index Gain: ' + numberFormat(p.value.absGain),
            'Index Gain in Percentage: ' + numberFormat(p.value.percentageGain) + '%',
            'Fluctuation / Index Ratio: ' + numberFormat(p.value.fluctuationPercentage) + '%'
          ].join('\n');
        })
      //#### Customize Axes

      // Set a custom tick format. Both `.yAxis()` and `.xAxis()` return an axis object,
      // so any additional method chaining applies to the axis, not the chart.
        .yAxis().tickFormat(function (v) {
          return v + '%';
        });



      //#### Rendering

      //simply call `.renderAll()` to render all charts on the page
      dc.renderAll();
      /*
         // Or you can render charts belonging to a specific chart group
         dc.renderAll('group');
         // Once rendered you can call `.redrawAll()` to update charts incrementally when the data
         // changes, without re-rendering everything
         dc.redrawAll();
         // Or you can choose to redraw only those charts associated with a specific chart group
         dc.redrawAll('group');
       */

    });