Skip to content

Instantly share code, notes, and snippets.

@sfrdmn
Created October 5, 2011 06:17
Show Gist options
  • Save sfrdmn/1263780 to your computer and use it in GitHub Desktop.
Save sfrdmn/1263780 to your computer and use it in GitHub Desktop.
DAI 523 - Bubble Chart Skeleton Round 2
/*
Hey. We're going to continue with this bubble chart we were working on last class.
Here is some motivational ASCII.
,. _~-., . YOU'RE BEAUTIFUL!
~'`_ \/,_. \_
/ ,"_>@`,__`~.) | .
| | @@@@' ",! . . '
|/ ^^@ .! \ | /
`' .^^^ ,' ' | . .
.^^^ . \ / .
.^^^ ' . \ | / . '
.,.,. ^^^ ` . .,+~'`^`'~+,. , '
&&&&&&, ,^^^^. . ._ ..__ _ .' '. '_ __ ____ __ _ .. . .
%%%%%%%%%^^^^^^%%&&;_,.-=~'`^`'~=-.,__,.-=~'`^`'~=-.,__,.-=~'`^`'~=-.,
&&&&&%%%%%%%%%%%%%%%%%%&&;,.-=~'`^`'~=-.,__,.-=~'`^`'~=-.,__,.-=~'`^`'~=
%%%%%&&&&&&&&&&&%%%%&&&_,.;^`'~=-.,__,.-=~'`^`'~=-.,__,.-=~'`^`'~=-.,__,
%%%%%%%%%&&&&&&&&&-=~'`^`'~=-.,__,.-=~'`^`'~=-.,__,.-==--^'~=-.,__,.-=~'
##mjy#####*"'
_,.-=~'`^`'~=-.,__,.-=~'`^`'~=-.,__,.-=~'`^`'~=-.,.-=~'`^`'~=-.,__,.-=~'
~`'^`'~=-.,__,.-=~'`^`'~=-.,__,.-=~'`^`'~=-.,__,.-=~'`^`'~=-.,__,.-=~'`^
*/
var w = 800; // width
var h = 600; // height
var margin = 100; // margin
var xlabel = "murder"; // what we want on the x axis
var ylabel = "robbery"; // what we want on the y axis
var rlabel = "population"; // what we want for the bubble area
/*
Selection of body, append SVG, give attributes
*/
d3.select("body").append("svg:svg")
.attr("width", w+margin)
.attr("height", h+margin)
.attr("class","chart");
/*
Selection of SVG, append group (will group our entire chart), give attributes
*/
var chart = d3.select(".chart").append("svg:g")
.attr("class","content")
.attr("transform", "translate(" + margin/2 + "," + margin/2 + ")"); // The transform with trasnlate will shift our group down and to the right
/*
The following statement creates a line for our x axis
*/
chart.append("svg:line")
.attr("stroke-width", 1)
.attr( "stroke","gray")
.attr("x1", 0)
.attr("y1", h)
.attr("x2", w)
.attr("y2", h);
/*
The following statement creates a line for our y axis
*/
chart.append("svg:line")
.attr("stroke-width", 1)
.attr( "stroke","gray")
.attr("x1", 1)
.attr("y1", 0)
.attr("x2", 1)
.attr("y2", h-1);
/*
This line takes comma delimited data (aka CSV data) and turns it into
JSON (same as Mr. Data Converter). The data is held in a variable named 'csv'. All lines within the
curly brackets have access to the data. To use the data, we simply bind it to a selection
(using selection.data(csv)) This means all the data in our csv variable is tied to the
selection.
The 'csv' variable (the data) is just a list of pieces of data. Each piece contains a 'state'
value ,a 'population' value, a 'murder' value and so on. And likewise, each piece has (or will have when
we append) a corresponding visual element on the screen.
If we want the appearance of our visual element to change based on its personal piece of
data, we need to give d3 a function. This tells d3, instead of applying the same value
to all the visual elements in our selection, apply a different value to each indivdual element
according to a ruleset (a function).
It is important to remember that your function takes two objects (thingies [pieces]) as input, one
is the data object for a given element, and the other is the element's position in the selection
(zeroth circle, first circle, second circle, third, etc)
Zeroth Circle is also probably a metal band.
Our functions will be written in this format:
var name = function(d,i) {
return "some kinda thing";
}
This creates the function. In order to use it, you must plug it in to d3.
*/
d3.csv( "data/crimeRatesByState2005.csv", function(csv) {
/*
The the following two thingamadudes are d3's way of helping you out by creating
functions for you. xgrid and ygrid now contain functions created by d3.
All these do is relate the range of the data (all possible values) to the
range of the chart size. A data value which is around 50% of the largest
data value should correspondingly be placed around the center of the chart
(50% of max width and/or height).
*/
var xMax = d3.max( csv.map( function(d) {
return parseFloat(d[xlabel]);
}));
console.log(xMax);
var yMax = d3.max( csv.map( function(d) {
return parseFloat( d[ylabel] );
}));
var xgrid = d3.scale.linear()
.domain([0.0,xMax]) // range of data
.range([0.0,w]); // range of width
// 0 in, 0 out
// 10 in, w out
/* NOTE: Code from last time was false here.
For our y values, we want data of value 0 to be at the bottom of the chart,
therefore 0 should correspond to h (y-axis increases top down) and our max value
should correspond to zero.
*/
var ygrid = d3.scale.linear()
.domain([0.0,yMax]) // range of data
.range([h,0.0]); // range of height
// 0 in, h out
// 260 in, 0 out
var colorScale = d3.scale.linear()
.domain([0,500])
.range(["rgb(200,200,200)", "rgb(20,20,20)"]);
/*
Here are the functions we wrote. 'd' and 'i' are our inputs. For any given circle,
'd' is its piece of data and 'i' is its position in the selection. To access values
in a data piece (data object) just be all like d.whatever or d["whatever"]. They
do the same thing. In the bracket version you can put a variable inside to make
it more dynamic. We're going to do that below:
*/
var radius = function(d,i) {
return Math.sqrt( d[rlabel] ) / 150; // FUN FACT: we could use another scale function here instead of arbitrarily using 150
}
var xpos = function(d,i) {
return xgrid( d[xlabel] ); // d.murder in, corresponding x value out
}
var ypos = function(d,i) {
return ygrid( d[ylabel] ); // d.robbery in, corresponding x value out
}
var color = function(d,i) {
return colorScale( d["aggravated_assault"] );
}
/*
This is the code which places the bubbles.
First, it makes an empty selection of all circles named bubble (none exist yet).
Then it attaches our dataset to that selection.
For every member in that dataset, it adds a new circle to the image.
After that, it is only a matter of adding attributes to those bubbles.
*/
chart.selectAll("circle.bubble").data(csv)
.enter().append("svg:circle")
.attr("class", "bubble")
.attr("cx", xpos )
.attr("cy", ypos )
.attr("r", radius )
.attr("fill", color );
/*
The following statements create grid lines
You can reuse this later if you need to. Only thing, is it uses our
ygrid and xgrid functions. In another visualisation, if you name your
x and y scale functions something else, you'll have to rename it in the
grid line code too.
*/
chart.selectAll("line.xgrid").data( xgrid.ticks(10) )
.enter().insert("svg:line", "circle")
.attr("class", xgrid)
.attr("stroke-width", .5)
.attr("stroke", "lavender")
.attr("x1", xgrid)
.attr("y1", 0 )
.attr("x2", xgrid)
.attr("y2", h-1 );
chart.selectAll("line.ygrid").data( ygrid.ticks(10) )
.enter().insert("svg:line", "circle")
.attr("class", "ygrid")
.attr("stroke-width", .5)
.attr("stroke", "lavender")
.attr("x1", 0)
.attr("y1", ygrid)
.attr("x2", w-1)
.attr("y2", ygrid);
var page = d3.select("body");
page.append("div")
.attr("class", "xlabel")
.style("width", w + "px" )
.style("height", 30 )
.style("text-align", "center")
.append("p")
.text( xlabel );
page.append("div")
.attr("class", "ylabel")
.style("width", 30 )
.style("height", h + "px" )
.style("position", "absolute")
.style("left", "0px" )
.style("top", "300px")
.append("p")
.text( ylabel );
// The following lines create the labels for our axes. Uses the same method as making grid
chart.selectAll("text.xrule").data( xgrid.ticks(10) )
.enter().append("svg:text")
.attr("class", "xrule")
.attr("x", xgrid)
.attr("y", h )
.attr("dx", -7 )
.attr("dy", 15 )
.text( function(d) {
return d;
});
chart.selectAll("text.yrule").data( ygrid.ticks(10) )
.enter().append("svg:text")
.attr("class", "yrule")
.attr("x", 0)
.attr("y", function(d,i) {
return ygrid(d,i);
})
.attr("dx", -25)
.attr("dy", 5 )
.text( function(d,i) {
if( i != 0 )
return d;
else
return "";
});
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment