d3.js - D3: ordinal scales, rangebands, and the new york subway -
i've got visualization showing median income levels in census tracts nyc subway runs through (image here — https://dl.dropbox.com/u/17156665/screen%20shot%202013-04-08%20at%209.56.20%20pm.png). looking show stops in boroughs. using file data (https://docs.google.com/spreadsheet/pub?key=0apl2zvhpomondfdtuwhxv252elnorvnqt0g5y0nzv1e&output=html). thinking best way draw single vertical line when county switches, , appending name of borough @ bottom.
right i've got series of rects in background if statement coloring each, it's pretty clunky. have played around ordinal scales , rangebands no avail. better solutions appreciated.
(this interesting juxtaposition of data!)
imo ordinal scale unwieldy this, more importantly, there problem in case in line goes through same borough more once (like m line, starts , ends in queens); because ordinal scale expects unique values.
probably best solution first build array of data representing each borough's start position , number of stops spans. e.g. m line, this:
[ { "county": "81", "countyname": "queens" "start": 1, "span": 14 }, { "county": "61", "countyname": "manhattan" "start": 15, "span": 10 }, { "county": "47", "countyname": "brooklyn" "start": 25, "span": 7 }, { "county": "81", "countyname": "queens" "start": 32, "span": 5 } ]
one (somewhat cryptic pretty concise) way create data array calling reduce()
method on filtered data. this:
boroughs = filtered_data.reduce( function(memo, stop, i) { var len = memo.length; if(len == 0 || (memo[len - 1].county != stop.county)) { memo.push({ county: stop.county, start: i+1, span: 1 countyname: "foo"// needs dictionary mapping county code name }); } else { memo[len - 1].span++; } return memo; }, [] )
after constructing data, you'd bind d3 selection , create group each entry. i.e, if line goes through 3 boroughs, you'd create 3 groups. inside each group can append text
borough's name , rect
or line
delineation. this:
// note use of `stop_scale` calculating positions/widths d3.selectall('g.borough').data(boroughs) gcounties.enter() .append('g')// create group .attr('class', 'borough' .attr('transform', function(d) {// move group appropriate x position return 'translate(' + stop_scale(d.start+1) + ')'; }) .each(function(d, i) {// inside each group: // append rect (this example) d3.select(this) .append('rect') .style('stroke', '#000') .attr('x', 0) .attr('width', stop_scale(d.span)) .attr('height', 50);// height should changed match chart // append text d3.select(this) .append('text') .text(d.countyname); });
as aside, code use refactoring. shouldn't have repeat code between draw_first_line
, update_chart
functions. more info on this, check out general update pattern (parts i, ii, , iii) on d3 tutorials page.
Comments
Post a Comment