javascript - How can I nest GeoJSON / TopoJSON geometries OR nest the generated paths with D3? -
problem:
i'm attempting create interactive map of in state, county , national boundaries displayed. counties shaded based on data, , hovering on state should highlight counties in state, , state should clickable. want achieve having svg county shapes inside of state shapes, inside of shape.
i can generate county map based on census county shape file, , can shade states based on data in external csv prepping file topojson command line , using following code in d3:
<!doctype html> <meta charset="utf-8"> <style> path { fill: none; stroke-linejoin: round; stroke-linecap: round; } </style> <body> <script src="http://d3js.org/d3.v3.min.js"></script> <script src="http://d3js.org/topojson.v1.min.js"></script> <script> var width = 960, height = 600; var path = d3.geo.path() .projection(d3.geo.albersusa()); var svg = d3.select("body").append("svg") .attr("width", width) .attr("height", height); d3.json("counties_pa.json", function(error, us) { if (error) return console.error(error); var color = d3.scale.threshold() .domain([1, 10, 50, 100, 500, 1000, 2000, 5000]) .range(["#fff7ec", "#fee8c8", "#fdd49e", "#fdbb84", "#fc8d59", "#ef6548", "#d7301f", "#b30000", "#7f0000"]); svg.append('g').attr('class','counties').selectall("path").data(topojson.feature(us, us.objects.cb_2014_us_county_20m).features).enter().append('path').attr('d',path).attr('style',function(d){return 'fill:'+color(d.properties.population / d.properties.area * 2.58999e6);}); }); </script>
this visually acceptable (except doesn't have discrete state / national boundaries) - functionally inadequate. in order apply css counties on state hover, counties need within state shape, or grouped somehow.
what i've tried:
- using topojson-merge in command line merge counties state shapes, , render state shapes separately - helps having discrete state borders - haven't figured way nest counties respective state shapes.
what i'm working out now:
somehow combining state topojson file , county topojson file , nesting counties in states, rendering d3.
somehow using d3 take non-nested state , county data , nest on client on client level.
in end learn effective , quickest rendering process achieve desired functionality.
thanks in advance.
i took punt on data sources, , here looks you're trying achieve: http://bl.ocks.org/benlyall/55bc9474e6d531a1c1fe
basically, have generated topojson file using following command line:
topojson -o counties_pa.json --id-property=+geoid -p -e pop01.txt --id-property=+stcou -p population=+pop010210d,area=aland,state=+statefp,county=+countyfp cb_2014_us_county_20m.shp cb_2014_us_state_20m.shp
some explanation on this:
-o counties_pa.json
sets name of output file--id-property=+geoid
use property in input fileid
of each output geometry-p
means include properties input file-e pop01.txt
pull external data in filepop01.txt
. file csv file generatedpop01.xls
spreadsheet available http://www.census.gov/support/usacdatadownloads.html#pop--id-property=+stcou
means id property external file (pop01.txt
) in stcou column. used match matchingid
s in input file (which ingeoid
property explained above)-p population=+pop010210d,area=aland,state=+statefp,county=+countyfp
explicitly lists properties want in output file, won't included. pop010210d column name population @ 2010 census, used demonstration purposes.cb_2014_us_county_20m.shp cb_2014_us_state_20m.shp
2 input files. 1 county shapes , 1 state shapes. each added output file in seperate properties named after filenames.
i did way, seemed colouring county areas based on population density, both population , area needed in output file. population pulled pop01
spreadsheet , linked each county based on geoid
(which state number concatentated county number).
i looking quick , easy way recreate dataset, , add state boundaries post answer. not sure how closely matches original data, seems work demonstration purposes.
from that, took code above , updated to:
<!doctype html> <meta charset="utf-8"> <style> path { fill: none; stroke-linejoin: round; stroke-linecap: round; } path.state { fill: none; stroke: black; stroke-width: .5px; } </style> <body> <script src="http://d3js.org/d3.v3.min.js"></script> <script src="http://d3js.org/topojson.v1.min.js"></script> <script> var width = 960, height = 600; var path = d3.geo.path() .projection(d3.geo.albersusa()); var svg = d3.select("body").append("svg") .attr("width", width) .attr("height", height); d3.json("counties_pa.json", function(error, us) { if (error) return console.error(error); var color = d3.scale.threshold() .domain([1, 10, 50, 100, 500, 1000, 2000, 5000]) .range(["#fff7ec", "#fee8c8", "#fdd49e", "#fdbb84", "#fc8d59", "#ef6548", "#d7301f", "#b30000", "#7f0000"]); svg.append('g') .attr('class','counties') .selectall("path") .data(topojson.feature(us, us.objects.cb_2014_us_county_20m).features).enter() .append('path') .attr('d', path) .attr("id", function(d) { return "county-" + d.id; }) .attr("data-state", function(d) { return d.properties.state; }) .attr('style',function(d) { return 'fill:'+color(d.properties.population / d.properties.area * 2.58999e6); }) .on("mouseover", hovercounty) .on("mouseout", outcounty); svg.append('g') .attr('class', 'states') .selectall("path") .data(topojson.feature(us, us.objects.cb_2014_us_state_20m).features).enter() .append("path") .attr("class", "state") .attr("id", function(d) { return "state-" + d.id; }) .attr("d", path); }); function hovercounty(county) { d3.selectall("path[data-state='" + county.properties.state + "']").style("opacity", .5); } function outcounty(county) { d3.select(".counties").selectall("path").style("opacity", null); } </script>
the new , interesting bits of code are:
add
data-state
attribute each county determine state belongs to:.attr("data-state", function(d) { return d.properties.state; })
add state boundaries (i combined states topojson file in
topojson
command line)svg.append('g') .attr('class', 'states') .selectall("path") .data(topojson.feature(us, us.objects.cb_2014_us_state_20m).features).enter() .append("path") .attr("class", "state") .attr("id", function(d) { return "state-" + d.id; }) .attr("d", path); });
added hover handlers can see how i'm determining grouping of counties states:
function hovercounty(county) { d3.selectall("path[data-state='" + county.properties.state + "']").style("opacity", .5); } function outcounty(county) { d3.select(".counties").selectall("path").style("opacity", null); }
tied these hover handlers each county executed @ appropriate times:
.on("mouseover", hovercounty) .on("mouseout", outcounty);
Comments
Post a Comment