//# dc.js Getting Started and How-To Guide 'use strict'; /* jshint globalstrict: true */ /* global dc,d3,crossfilter,colorbrewer */ // ### Create Chart Objects // Create chart objects associated with the container elements identified by the css selector. // Note: It is often a good idea to have these objects accessible at the global scope so that they can be modified or // filtered by other page controls. var gainOrLossChart = dc.pieChart('#gain-loss-chart'); var fluctuationChart = dc.barChart('#fluctuation-chart'); var quarterChart = dc.pieChart('#quarter-chart'); var dayOfWeekChart = dc.rowChart('#day-of-week-chart'); var moveChart = dc.lineChart('#monthly-move-chart'); var volumeChart = dc.barChart('#monthly-volume-chart'); var yearlyBubbleChart = dc.bubbleChart('#yearly-bubble-chart'); var nasdaqCount = dc.dataCount('.dc-data-count'); var nasdaqTable = dc.dataTable('.dc-data-table'); // ### Anchor Div for Charts /* // A div anchor that can be identified by id
// Title or anything you want to add above the chart
Days by Gain or Loss
// ##### .turnOnControls() // If a link with css class `reset` is present then the chart // will automatically hide/show it based on whether there is a filter // set on the chart (e.g. slice selection for pie chart and brush // selection for bar chart). Enable this with `chart.turnOnControls(true)` // dc.js >=2.1 uses `visibility: hidden` to hide/show controls without // disrupting the layout. To return the old `display: none` behavior, // set `chart.controlsUseVisibility(false)` and use that style instead.
// dc.js will also automatically inject the current filter value into // any html element with its css class set to `filter`
*/ //### Load your data //Data can be loaded through regular means with your //favorite javascript library // //```javascript //d3.csv('data.csv', function(data) {...}); //d3.json('data.json', function(data) {...}); //jQuery.getJson('data.json', function(data){...}); //``` d3.csv('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(function (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. //
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. //
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. //
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. //
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)`. //
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. //
API: [Data Count Widget](https://github.com/dc-js/dc.js/blob/master/web/docs/api-latest.md#data-count-widget) // //```html //
// // selected out of records. //
//``` 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: '%filter-count selected out of %total-count records' + ' | Reset All', 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. //
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 // //
// //
// Date // Open // Close // Change // Volume //
// //
// ``` // 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. //
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. //
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'); */ }); //#### Versions //Determine the current version of dc with `dc.version` d3.selectAll('#version').text(dc.version); // Determine latest stable version in the repo via Github API d3.json('https://api.github.com/repos/dc-js/dc.js/releases/latest', function (error, latestRelease) { /*jshint camelcase: false */ d3.selectAll('#latest').text(latestRelease.tag_name); /* jscs:disable */ });