- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我正在尝试重新创建 D3.js 示例:“又一个动画分区统计图”: http://bl.ocks.org/rgdonohue/9280446
只是,我尝试使用具有不同数据的不同 map 。我使用的 map 是美国各县的 map ,数据是各县 2 年的家庭值(value)中位数。我在显示 map 时遇到错误。错误:类型错误:counties[i].properties 未定义
出现在以下函数中(原始函数见上面的链接):
function processData(error, us, countyData) {
var counties = us.objects.counties.geometries; // store the path in variable for ease
for (var i in counties) { // for each geometry object
for (var j in countyData) { // for each row in the CSV
if(counties[i].properties.id == countyData[j].id) { // if they match
for(var k in countyData[i]) { // for each column in the a row within the CSV
if(k != 'name' && k != 'id') { // let's not add the name or id as props since we already have them
if(attributeArray.indexOf(k) == -1) {
attributeArray.push(k); // add new column headings to our array for later
}
counties[i].properties[k] = Number(countyData[j][k]) // add each CSV column key/value to geometry object
}
}
break; // stop looking through the CSV since we made our match
}
}
}
d3.select('#clock').html(attributeArray[currentAttribute]); // populate the clock initially with the current year
drawMap(us); // let's mug the map now with our newly populated data object
}
我相信正在发生的事情是“我们”由于某种原因未定义。原始示例使用 map world-topo.json,我无法找到其来源。我的 map 是http://d3js.org/us-10m.v1.json .
原始代码:
world.objects.countries.geometries
我改为:
us.objects.counties.geometries
在 Bostock 的原始 Choropleth 示例中,他使用了我正在使用的相同美国 map ,并将其引用为“我们”,但它似乎对我不起作用:
svg.append("g")
.data(topojson.feature(us, us.objects.counties).features)
我意识到我对 D3 没有很好的理解 - 我更像是一个代码黑客而不是开发人员。我只是想尝试一些可视化,并且对 javascript/d3 的经验很少。任何帮助,将不胜感激。
我的整个程序:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>d3 choropleth map</title>
<style>
#wrapper {
width: 960px;
margin: -30px auto 0;
}
#map {
width: 960px;
height: 580px;
position: relative;
}
.stroke {
fill: none;
stroke: #888;
stroke-width: 2px;
}
.fill {
fill: #fff;
}
.graticule {
fill: none;
stroke: #777;
stroke-width: .5px;
stroke-opacity: .5;
}
.land {
fill: #222;
}
.boundary {
fill: none;
stroke: #fff;
stroke-width: .5px;
}
.county {
fill: steelblue;
stroke: white;
}
#play, #clock {
position: absolute;
top: 15px;
}
#play {
left: 15px;
}
#clock {
left: 65px;
}
</style>
</head>
<body>
<div id="wrapper">
<div id="map"></div>
<button id="play">play</button>
<span id="clock">year</span>
</div>
<script src="d3.v3.min.js"></script>
<script src="d3.geo.projection.v0.min.js"></script>
<script src="queue.v1.min.js"></script>
<script src="topojson.v1.min.js"></script>
<script src="https://d3js.org/d3.v4.min.js"></script>
<script src="https://d3js.org/topojson.v2.min.js"></script>
<script>
//globals
var width, height, projection, path, graticule, svg, attributeArray = [], currentAttribute = 0, playing = false;
function init() {
setMap();
animateMap();
}
function setMap() {
width = 960, height = 580; // map width and height, matches
projection = d3.geo.eckert5() // define our projection with parameters
.scale(170)
.translate([width / 2, height / 2])
.precision(.1);
path = d3.geo.path() // create path generator function
.projection(projection); // add our define projection to it
graticule = d3.geo.graticule(); // create a graticule
svg = d3.select("#map").append("svg") // append a svg to our html div to hold our map
.attr("width", width)
.attr("height", height);
svg.append("defs").append("path") // prepare some svg for outer container of svg elements
.datum({type: "Sphere"})
.attr("id", "sphere")
.attr("d", path);
svg.append("use") // use that svg to style with css
.attr("class", "stroke")
.attr("xlink:href", "#sphere");
svg.append("path") // use path generator to draw a graticule
.datum(graticule)
.attr("class", "graticule")
.attr("d", path);
loadData(); // let's load our data next
}
function loadData() {
queue() // queue function loads all external data files asynchronously
.defer(d3.json, "us-10m.v1.json") // our geometries
.defer(d3.csv, "countiesRandom.csv") // and associated data in csv file
.await(processData); // once all files are loaded, call the processData function passing
// the loaded objects as arguments
}
function processData(error, us, countyData) {
var counties = us.objects.counties.geometries; // store the path in variable for ease
for (var i in counties) { // for each geometry object
for (var j in countyData) { // for each row in the CSV
if(counties[i].properties.id == countyData[j].id) { // if they match
for(var k in countyData[i]) { // for each column in the a row within the CSV
if(k != 'name' && k != 'id') { // let's not add the name or id as props since we already have them
if(attributeArray.indexOf(k) == -1) {
attributeArray.push(k); // add new column headings to our array for later
}
counties[i].properties[k] = Number(countyData[j][k]) // add each CSV column key/value to geometry object
}
}
break; // stop looking through the CSV since we made our match
}
}
}
d3.select('#clock').html(attributeArray[currentAttribute]); // populate the clock initially with the current year
drawMap(us); // let's mug the map now with our newly populated data object
}
function drawMap(us) {
svg.selectAll(".county") // select country objects (which don't exist yet)
.data(topojson.feature(us, us.objects.counties).features) // bind data to these non-existent objects
.enter().append("path") // prepare data to be appended to paths
.attr("class", "county") // give them a class for styling and access later
.attr("id", function(d) { return "code_" + d.properties.id; }, true) // give each a unique id for access later
.attr("d", path); // create them using the svg path generator defined above
var dataRange = getDataRange(); // get the min/max values from the current year's range of data values
d3.selectAll('.county') // select all the countries
.attr('fill-opacity', function(d) {
return getColor(d.properties[attributeArray[currentAttribute]], dataRange); // give them an opacity value based on their current value
});
}
function sequenceMap() {
var dataRange = getDataRange(); // get the min/max values from the current year's range of data values
d3.selectAll('.county').transition() //select all the countries and prepare for a transition to new values
.duration(750) // give it a smooth time period for the transition
.attr('fill-opacity', function(d) {
return getColor(d.properties[attributeArray[currentAttribute]], dataRange); // the end color value
})
}
function getColor(valueIn, valuesIn) {
var color = d3.scale.linear() // create a linear scale
.domain([valuesIn[0],valuesIn[1]]) // input uses min and max values
.range([.3,1]); // output for opacity between .3 and 1 %
return color(valueIn); // return that number to the caller
}
function getDataRange() {
// function loops through all the data values from the current data attribute
// and returns the min and max values
var min = Infinity, max = -Infinity;
d3.selectAll('.county')
.each(function(d,i) {
var currentValue = d.properties[attributeArray[currentAttribute]];
if(currentValue <= min && currentValue != -99 && currentValue != 'undefined') {
min = currentValue;
}
if(currentValue >= max && currentValue != -99 && currentValue != 'undefined') {
max = currentValue;
}
});
return [min,max]; //boomsauce
}
function animateMap() {
var timer; // create timer object
d3.select('#play')
.on('click', function() { // when user clicks the play button
if(playing == false) { // if the map is currently playing
timer = setInterval(function(){ // set a JS interval
if(currentAttribute < attributeArray.length-1) {
currentAttribute +=1; // increment the current attribute counter
} else {
currentAttribute = 0; // or reset it to zero
}
sequenceMap(); // update the representation of the map
d3.select('#clock').html(attributeArray[currentAttribute]); // update the clock
}, 2000);
d3.select(this).html('stop'); // change the button label to stop
playing = true; // change the status of the animation
} else { // else if is currently playing
clearInterval(timer); // stop the animation by clearing the interval
d3.select(this).html('play'); // change the button label to play
playing = false; // change the status again
}
});
}
window.onload = init(); // magic starts here
</script>
</body>
</html>
来自 countiesRandom.csv 的示例数据:
id,2010,2015
01001,141300,133900
最佳答案
关于:
I am running into an error in displaying my map. The error: TypeError: counties[i].properties is undefined
我们需要检查引用的世界 topojson 和美国 topojson。
在 world topojson ,几何形状定义如下:
"geometries":[
{"type":"Polygon","id":1,"arcs":[[0,1,2,3,4,5,6,7]],"properties":{"admin":"Afghanistan","id":"AFG"}},
{"type":"Polygon","id":4,"arcs":[[16,17,18,19,20]],"properties":{"admin":"Albania","id":"ALB"}},
每个几何体都有一个属性。
在 US topojson您引用的几何图形定义如下:
"geometries":[
{"type":"Polygon","arcs":[[0,1,2,3,4]],"id":"05089"},
{"type":"Polygon","arcs":[[5,6,7,8,9]],"id":"06079"},
{"type":"Polygon","arcs":[[10,11,12,13,14,15,16]],"id":"17111"},
没有为每个几何图形分配属性属性。因此,当您调用几何图形的属性时,它将返回未定义。
因此,您可能会发现使用 counties[i].id
更成功,而不是使用 counties[i].properties.id
。
如果您要比较示例,还可能值得注意的是,从 topojson 到 geojson 的转换 (topojson.feature(us, us.objects.counties).features
) 将修改结构以及数据:
d3.json("//d3js.org/us-10m.v1.json",function(error,us) {
console.log("Number of county geometries:");
console.log(us.objects.counties.geometries.length);
console.log("Example county id:");
console.log(us.objects.counties.geometries[0].id);
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
<script src="https://d3js.org/topojson.v2.min.js"></script>
d3.json("//d3js.org/us-10m.v1.json",function(error,us) {
var geojson = topojson.feature(us, us.objects.counties).features;
console.log("Number of features");
console.log(geojson.length);
console.log("Example county ID");
console.log(geojson[0].id);
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
<script src="https://d3js.org/topojson.v2.min.js"></script>
关于javascript - 使用新 map 和数据重建 D3 动画分区统计图,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43548332/
我有一个表,用于存储一段时间内网络上的带宽使用情况。一列将包含记录带宽的日期时间(主键),另一列将包含实际带宽值。 我需要根据这些数据生成一些图表(饼图、条形图等)和其他统计图表。但是,我想在数据库服
我是一名优秀的程序员,十分优秀!