Skip to content

Instantly share code, notes, and snippets.

@idan
Created January 5, 2012 09:54
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save idan/1564489 to your computer and use it in GitHub Desktop.
Save idan/1564489 to your computer and use it in GitHub Desktop.
d3charts Histogram

d3charts Histogram

Shows off two histograms of a randomly-generated Irwin-Hall distribution.

Note that a lot of the options to the histogram widget can take either a set value or a function. If you supply a function, it will be called once per chart. This is a nifty way of dynamically controlling things like the number of bins—note that each chart has between ten and twenty bins (at random).

Reload the page to see variations.

<!DOCTYPE html>
<html>
<head>
<title>Histogram</title>
<script type="text/javascript" src="https://github.com/mbostock/d3/raw/v2.7.1/d3.js"></script>
<script type="text/javascript" src="https://github.com/mbostock/d3/raw/v2.7.1/d3.layout.js"></script>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.js"></script>
<script src="jquery.d3charts.js"></script>
<script src="jquery.d3charts.histogram.js"></script>
<style>
body {
width: 500px;
margin: 100px auto;
}
.chart {
height: 100px;
margin-bottom: 50px;
}
rect {
fill: #444;
stroke: #fff;
shape-rendering: crispEdges;
-webkit-transition: fill 0.3s;
-moz-transition: fill 0.3s;
-o-transition: fill 0.3s;
-ms-transition: fill 0.3s;
transition: fill 0.3s;
}
rect:hover {
fill: #777;
}
line {
stroke: #ccc;
shape-rendering: crispEdges;
}
text {
fill: #666;
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
}
</style>
</head>
<body>
<div class="chart"></div>
<div class="chart"></div>
<script>
var generateData = function() {
// Generate an Irwin-Hall distribution.
var n = 10000, // number of trials
m = 10, // number of random variables
data = [];
for (var i = 0; i < n; i++) {
for (var s = 0, j = 0; j < m; j++) {
s += Math.random();
}
data.push(s);
}
return data;
}
settings = {
'data': generateData,
'height': 100,
// 10-20 bins, at random
'bins': function() { return Math.floor(Math.random() * (20 - 10 + 1) + 10);},
'bottompad': 15,
'labelsize': 10,
// label each bin with the percent of the total population in that bin
'labelGenerator': function(d, i) {
var val = d3.round(d.y * 100.0);
if (val == 0) {
return '-';
} else {
return val + "%";
}
}
};
$(function() {
// see, chaining still works.
$(".chart").d3histogram(settings).toggleClass("foo");
});
</script>
</body>
</html>
// d3charts.histogram
// (c) 2012 Idan Gazit & Contributors
// d3charts is freely distributable under the BSD 3-clause license.
// For all details and documentation:
// http://github.com/idangazit/d3charts
;(function($) {
$.widget("d3charts.d3histogram", {
options: {
// width, height
// The dimensions of the chart. If null, will use the dimension of
// the containing element.
width: null, // uses the width of the containing element
height: null, // uses the height of the containing element
// data
// May be either an array of values or a function which returns one
data: [],
// bins
// The number of bins in the histogram
// May be an integer or a function which returns one
bins: 10,
// bottompad
// Pixels of room to leave at the bottom for bin labels
bottompad: 10,
// labelsize
// The size of the labels, in pixels.
// If null, will use the height of the padding - 2px for the font size
labelsize: null,
// labelGenerator
// A function which generates bin labels
// By default it labels the bins from 1 to N, where N is the number of bins
labelGenerator: function(d, i) { return i+1+""; }
},
_create: function() {
var widget = this;
var w = this.options.width === null ? this.element.width() : this.options.width;
var h = this.options.height === null ? this.element.height() : this.options.height;
var ls = this.options.labelsize === null ? this.options.bottompad - 2 : this.options.labelsize;
if ($.isFunction(this.options.data)) {
}
d3.select(this.element[0]).each(function(d, i) {
var data = widget._optValue(widget.options.data);
var bins = widget._optValue(widget.options.bins);
var histogram = d3.layout.histogram().bins(bins)
(data);
var x = d3.scale.ordinal()
.domain(histogram.map(function(d) { return d.x; }))
.rangeRoundBands([0, w]);
var y = d3.scale.linear()
.domain([0, d3.max(histogram, function(d) { return d.y; })])
.range([0, h - widget.options.bottompad]);
var vis = d3.select(this).append("svg:svg")
.attr("class", "chart")
.attr("width", w)
.attr("height", h);
vis.selectAll("rect")
.data(histogram)
.enter().append("svg:rect")
// move the bars down by their total height, so they animate up (not down)
.attr("transform", function(d) { return "translate(" + x(d.x) + "," + (h - y(d.y) - widget.options.bottompad) + ")"; })
.attr("width", x.rangeBand())
// they all start at zero height
.attr("y", function(d) { return y(d.y); })
.attr("height", 0)
.transition()
.duration(750)
// they all animate up to the top of their context, which would be the top
// of the chart if not for the transform above.
.attr("y", 0)
.attr("height", function(d) { return y(d.y); });
// bottom line
vis.append("svg:line")
.attr("x1", 0)
.attr("x2", w)
.attr("y1", h - widget.options.bottompad)
.attr("y2", h - widget.options.bottompad);
// bucket numbers
vis.selectAll("text")
.data(histogram)
.enter().append("svg:text")
.attr("x", function(d, i) { return x(d.x) + x.rangeBand() / 2; })
.attr("y", h)
.attr("width", x.rangeBand())
.attr("text-anchor", function(d) { return "middle"; })
.attr("font-size", ls)
.text(widget.options.labelGenerator);
});
},
_optValue: function(option) {
return $.isFunction(option) ? option() : option;
}
});
})( jQuery );
/*!
* jQuery UI Widget 1.8.16
*
* Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
* Dual licensed under the MIT or GPL Version 2 licenses.
* http://jquery.org/license
*
* http://docs.jquery.com/UI/Widget
*/
(function(b,j){if(b.cleanData){var k=b.cleanData;b.cleanData=function(a){for(var c=0,d;(d=a[c])!=null;c++)try{b(d).triggerHandler("remove")}catch(e){}k(a)}}else{var l=b.fn.remove;b.fn.remove=function(a,c){return this.each(function(){if(!c)if(!a||b.filter(a,[this]).length)b("*",this).add([this]).each(function(){try{b(this).triggerHandler("remove")}catch(d){}});return l.call(b(this),a,c)})}}b.widget=function(a,c,d){var e=a.split(".")[0],f;a=a.split(".")[1];f=e+"-"+a;if(!d){d=c;c=b.Widget}b.expr[":"][f]=
function(h){return!!b.data(h,a)};b[e]=b[e]||{};b[e][a]=function(h,g){arguments.length&&this._createWidget(h,g)};c=new c;c.options=b.extend(true,{},c.options);b[e][a].prototype=b.extend(true,c,{namespace:e,widgetName:a,widgetEventPrefix:b[e][a].prototype.widgetEventPrefix||a,widgetBaseClass:f},d);b.widget.bridge(a,b[e][a])};b.widget.bridge=function(a,c){b.fn[a]=function(d){var e=typeof d==="string",f=Array.prototype.slice.call(arguments,1),h=this;d=!e&&f.length?b.extend.apply(null,[true,d].concat(f)):
d;if(e&&d.charAt(0)==="_")return h;e?this.each(function(){var g=b.data(this,a),i=g&&b.isFunction(g[d])?g[d].apply(g,f):g;if(i!==g&&i!==j){h=i;return false}}):this.each(function(){var g=b.data(this,a);g?g.option(d||{})._init():b.data(this,a,new c(d,this))});return h}};b.Widget=function(a,c){arguments.length&&this._createWidget(a,c)};b.Widget.prototype={widgetName:"widget",widgetEventPrefix:"",options:{disabled:false},_createWidget:function(a,c){b.data(c,this.widgetName,this);this.element=b(c);this.options=
b.extend(true,{},this.options,this._getCreateOptions(),a);var d=this;this.element.bind("remove."+this.widgetName,function(){d.destroy()});this._create();this._trigger("create");this._init()},_getCreateOptions:function(){return b.metadata&&b.metadata.get(this.element[0])[this.widgetName]},_create:function(){},_init:function(){},destroy:function(){this.element.unbind("."+this.widgetName).removeData(this.widgetName);this.widget().unbind("."+this.widgetName).removeAttr("aria-disabled").removeClass(this.widgetBaseClass+
"-disabled ui-state-disabled")},widget:function(){return this.element},option:function(a,c){var d=a;if(arguments.length===0)return b.extend({},this.options);if(typeof a==="string"){if(c===j)return this.options[a];d={};d[a]=c}this._setOptions(d);return this},_setOptions:function(a){var c=this;b.each(a,function(d,e){c._setOption(d,e)});return this},_setOption:function(a,c){this.options[a]=c;if(a==="disabled")this.widget()[c?"addClass":"removeClass"](this.widgetBaseClass+"-disabled ui-state-disabled").attr("aria-disabled",
c);return this},enable:function(){return this._setOption("disabled",false)},disable:function(){return this._setOption("disabled",true)},_trigger:function(a,c,d){var e=this.options[a];c=b.Event(c);c.type=(a===this.widgetEventPrefix?a:this.widgetEventPrefix+a).toLowerCase();d=d||{};if(c.originalEvent){a=b.event.props.length;for(var f;a;){f=b.event.props[--a];c[f]=c.originalEvent[f]}}this.element.trigger(c,d);return!(b.isFunction(e)&&e.call(this.element[0],c,d)===false||c.isDefaultPrevented())}}})(jQuery);
;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment