根据用户输入过滤 .csv 数据并刷新 d3.js 地图
Filter .csv data based on user input and refresh d3.js map
我是一个 d3.js 新手,已经能够为一个项目拼凑出一张地图,但现在我被卡住了。我想根据用户 input/selection 在五个维度的任意组合上刷新地图。根据用户输入,我希望我的代码仅筛选满足所选条件的数据行,汇总该地理位置的人数并刷新地图。由于各种项目限制,我必须使用 .csv 或 .json 作为我的数据源。我知道我可以切换数据源并根据用户输入刷新地图,但由于可能的选择组合数量,该解决方案对我的项目不可行。我想我很接近,但我不确定如何越过终点线。我已将用户选择存储在变量中,创建了我的数据的 d3.nest,并且能够在指定的 d3.nest 键上创建 d3.sums。
我想我已经找到 post 可以回答我的问题,但我太菜鸟了,无法理解如何为我的项目综合相关信息。我需要做的是根据用户输入动态创建 d3.nest 和 d3.sum,但我不知道如何 link 我的用户选择变量到我创建巢与总和。我想在用户每次进行选择时刷新地图和数据,但如果更容易的话,我愿意在屏幕上放置一个按钮来刷新数据。这是我的地图的截图 map sample.
以下是我的代码的相关部分:
// ######################################################################
// BUILD THE MAP, PLOT THE DATA AND SIZE THE BUBBLES
// ######################################################################
var projection = d3.geo.mercator()
.center([0, 0])
.scale(225)
.translate([width / 2, height / 2]);
var path = d3.geo.path()
.projection(projection);
// LOAD THE GEOJSON DATA FOR THE MAP
// ---------------------------------
d3.json("world-50m.json", function ready(error, world) {
g.selectAll('path')
.data(topojson.feature(world, world.objects.countries).features)
.enter().append('path')
.attr("id", function(d) {
return d.properties.abbreviation;
})
.attr("d", path)
.attr("fill", "#ffcc99")
.attr("stroke", "#ffffff")
.on("click", clicked);
// LOAD THE CSV DATA TO POPULATE THE LOCATIONS
// AND BUBBLE SIZES ON THE MAP
// -------------------------------------------
d3.csv("sample_data.csv", function(data) {
// INCLUDE ONLY THOSE ROWS OF DATA WITH
// LATITUDE AND LONGITUDE VALUES AND CONVERT
// CSV DATA INTO NUMERIC VALUES
// -----------------------------------------
data = data.filter(function(d, i) {
if (d.LATITUDE && d.LONGITUDE) {
// CONVERT LATITUDE AND LONGITUDE
// VALUES FROM CSV FILE TO NUMBERS
d.LATITUDE = +d.LATITUDE;
d.LONGITUDE = +d.LONGITUDE;
// CONVERT HEADCOUNT VALUES FROM
// CSV FILE TO NUMBERS
d.HEADCOUNT = +Math.round((d.HEADCOUNT) * 1) / 1;
// CALCULATE THE POSITION OF THE
// HEADCOUNT DATA POINT WITHIN
// THE PROJECTION
d.position = projection([
d.LONGITUDE, d.LATITUDE
]);
return true;
}
});
// DRAW THE CIRCLES ON THE MAP AND SIZE THEM
// BASED ON HEADCOUNT
// -----------------------------------------
g.selectAll("circle")
.data(data)
.enter().append("circle")
.attr("cx", function(d) {
return d.position[0];
})
.attr("cy", function(d) {
return d.position[1];
})
.attr("r", function(d) {
return (bubblescale(d.HEADCOUNT));
})
.attr("fill", "#b300b3")
.attr("fill-opacity", "0.7")
.on("mouseover", function(d) {
div.transition()
.duration(200)
.style("opacity", .9);
div.html(d.HEADCOUNT + " people in " + d.GEOCODE_LOCATION)
.style("left", (d3.event.pageX) + "px")
.style("top", (d3.event.pageY - 28) + "px");
})
.on("mouseout", function(d) {
div.transition()
.duration(500)
.style("opacity", 0);;
});
});
});
// ######################################################################
// NESTING, FILTERING AND SUMMARIZING DATA
// ######################################################################
d3.csv("sample_data.csv", function(csv) {
var data_nest = d3.nest()
.key(function(d) {
return d.GEOCODE_LOCATION;
})
.key(function(d) {
return d.CATEGORY1;
})
.key(function(d) {
return d.CATEGORY2;
})
.key(function(d) {
return d.CATEGORY3;
})
.key(function(d) {
return d.TYPE1;
})
.key(function(d) {
return d.TYPE2;
})
.sortKeys(d3.ascending)
.entries(csv);
console.log(data_nest);
var data_sums = d3.nest()
.key(function(d) {
return d.GEOCODE_LOCATION;
})
.key(function(d) {
return d.LONGITUDE;
})
.key(function(d) {
return d.LATITUDE;
})
.sortKeys(d3.ascending)
.rollup(function(d) {
return {
headcount: d3.sum(d, function(g) {
return +g.HEADCOUNT;
})
};
})
.entries(csv);
console.log(data_sums);
});
// ######################################################################
// POPULATE THE FIVE MENU LISTS
// ######################################################################
function load_menus() {
d3.csv("category1.csv", function(error, data_c1) {
var select = d3.select("#c1_div")
.append("div")
.append("select")
select
.on("change", function(d) {
var selected_c1 = d3.select(this).property("value");
alert(value);
});
select.selectAll("option")
.data(data_c1)
.enter()
.append("option")
.attr("value", function(d) {
return d.x;
})
.text(function(d) {
return d.x;
});
});
d3.csv("category2.csv", function(error, data_c2) {
var select = d3.select("#c2_div")
.append("div")
.append("select")
select
.on("change", function(d) {
var selected_c2 = d3.select(this).property("value");
alert(value);
});
select.selectAll("option")
.data(data_c2)
.enter()
.append("option")
.attr("value", function(d) {
return d.x;
})
.text(function(d) {
return d.x;
});
});
d3.csv("category3.csv", function(error, data_c3) {
var select = d3.select("#c3_div")
.append("div")
.append("select")
select
.on("change", function(d) {
var selected_c3 = d3.select(this).property("value");
alert(value);
});
select.selectAll("option")
.data(data_c3)
.enter()
.append("option")
.attr("value", function(d) {
return d.x;
})
.text(function(d) {
return d.x;
});
});
d3.csv("type1.csv", function(error, data_t1) {
var select = d3.select("#t1_div")
.append("div")
.append("select")
select
.on("change", function(d) {
var selected_t1 = d3.select(this).property("value");
alert(value);
});
select.selectAll("option")
.data(data_t1)
.enter()
.append("option")
.attr("value", function(d) {
return d.x;
})
.text(function(d) {
return d.x;
});
});
d3.csv("type2.csv", function(error, data_t2) {
var select = d3.select("#t2_div")
.append("div")
.append("select")
select
.on("change", function(d) {
var selected_t2 = d3.select(this).property("value");
alert(value);
});
select.selectAll("option")
.data(data_t2)
.enter()
.append("option")
.attr("value", function(d) {
return d.x;
})
.text(function(d) {
return d.x;
});
});
}
window.onload = load_menus;
// ######################################################################
// FILTER DATA BASED ON USER SELECTION - NOT WORKING
// ######################################################################
function filter_data() {
d3.csv("map_data.csv", function(error, data) {
var filterCategory1 = selected_c1;
var filterCategory2 = selected_c2;
var filterCategory3 = selected_c3;
var filterType1 = selected_t1;
var filterType2 = selected_t2;
var filtered_data = data.filter(function(d) {
return d.CATEGORY1 == filterCategory1;
})
});
}
这是我的示例数据的屏幕截图:
我已经在网上和书中搜索了一个多星期,但既没有找到我正在尝试做的事情的其他 D3 示例,也没有找到我的数据绑定、过滤和聚合问题的答案。
感谢任何帮助。我保证,当我有能力这样做时,我会把它付清。如果我能得到这个工作,我会很高兴 post 我的完整解决方案 github 和 link 从这个问题到它。
在我看来,您的问题不在于 D3,而是 JavaScript 范围。
当你写这样的东西时:
d3.csv("category1.csv", function(error, data_c1) {
var select = d3.select("#c1_div")
.append("div")
.append("select")
select
.on("change", function(d) {
var selected_c1 = d3.select(this).property("value");
alert(value);
});
那个变量 selected_c1
只存在于包含它的匿名函数中。局部变量只能在定义它的函数内部使用。它对其他函数和其他脚本代码隐藏(请参阅此处:http://www.w3schools.com/js/js_function_closures.asp)。
因此,当您稍后尝试使用它时,在 filter_data()
中,它不可用。
此处的解决方案是将 selected_c1
和所有其他 4 个变量作为参数传递给 filter_data
。可能是这样的:
d3.csv("category1.csv", function(error, data_c1) {
var select = d3.select("#c1_div")
.append("div")
.append("select")
select
.on("change", function(d) {
var selected_c1 = d3.select(this).property("value");
filter_data(selected_c1);
});
然后,更改您的 filter_data()
参数:
function filter_data(selection) {
d3.csv("map_data.csv", function(error, data) {
var filtered_data = data.filter(function(d) {
return d.CATEGORY1 == selection;
})
});
}
请记住,尽管您已成功将 selected_c1
传递给 filter_data()
,但您现在再次面临同样的问题:var filtered_data
仅存在于 filter_data
中,并且您有将其传递给绘图函数的 2 个选项:
- 使其全球化;
- 将其作为参数传递。
这只是部分答案,您还需要付出一些努力才能将所有这些组合在一起。
我是一个 d3.js 新手,已经能够为一个项目拼凑出一张地图,但现在我被卡住了。我想根据用户 input/selection 在五个维度的任意组合上刷新地图。根据用户输入,我希望我的代码仅筛选满足所选条件的数据行,汇总该地理位置的人数并刷新地图。由于各种项目限制,我必须使用 .csv 或 .json 作为我的数据源。我知道我可以切换数据源并根据用户输入刷新地图,但由于可能的选择组合数量,该解决方案对我的项目不可行。我想我很接近,但我不确定如何越过终点线。我已将用户选择存储在变量中,创建了我的数据的 d3.nest,并且能够在指定的 d3.nest 键上创建 d3.sums。
我想我已经找到 post 可以回答我的问题,但我太菜鸟了,无法理解如何为我的项目综合相关信息。我需要做的是根据用户输入动态创建 d3.nest 和 d3.sum,但我不知道如何 link 我的用户选择变量到我创建巢与总和。我想在用户每次进行选择时刷新地图和数据,但如果更容易的话,我愿意在屏幕上放置一个按钮来刷新数据。这是我的地图的截图 map sample.
以下是我的代码的相关部分:
// ######################################################################
// BUILD THE MAP, PLOT THE DATA AND SIZE THE BUBBLES
// ######################################################################
var projection = d3.geo.mercator()
.center([0, 0])
.scale(225)
.translate([width / 2, height / 2]);
var path = d3.geo.path()
.projection(projection);
// LOAD THE GEOJSON DATA FOR THE MAP
// ---------------------------------
d3.json("world-50m.json", function ready(error, world) {
g.selectAll('path')
.data(topojson.feature(world, world.objects.countries).features)
.enter().append('path')
.attr("id", function(d) {
return d.properties.abbreviation;
})
.attr("d", path)
.attr("fill", "#ffcc99")
.attr("stroke", "#ffffff")
.on("click", clicked);
// LOAD THE CSV DATA TO POPULATE THE LOCATIONS
// AND BUBBLE SIZES ON THE MAP
// -------------------------------------------
d3.csv("sample_data.csv", function(data) {
// INCLUDE ONLY THOSE ROWS OF DATA WITH
// LATITUDE AND LONGITUDE VALUES AND CONVERT
// CSV DATA INTO NUMERIC VALUES
// -----------------------------------------
data = data.filter(function(d, i) {
if (d.LATITUDE && d.LONGITUDE) {
// CONVERT LATITUDE AND LONGITUDE
// VALUES FROM CSV FILE TO NUMBERS
d.LATITUDE = +d.LATITUDE;
d.LONGITUDE = +d.LONGITUDE;
// CONVERT HEADCOUNT VALUES FROM
// CSV FILE TO NUMBERS
d.HEADCOUNT = +Math.round((d.HEADCOUNT) * 1) / 1;
// CALCULATE THE POSITION OF THE
// HEADCOUNT DATA POINT WITHIN
// THE PROJECTION
d.position = projection([
d.LONGITUDE, d.LATITUDE
]);
return true;
}
});
// DRAW THE CIRCLES ON THE MAP AND SIZE THEM
// BASED ON HEADCOUNT
// -----------------------------------------
g.selectAll("circle")
.data(data)
.enter().append("circle")
.attr("cx", function(d) {
return d.position[0];
})
.attr("cy", function(d) {
return d.position[1];
})
.attr("r", function(d) {
return (bubblescale(d.HEADCOUNT));
})
.attr("fill", "#b300b3")
.attr("fill-opacity", "0.7")
.on("mouseover", function(d) {
div.transition()
.duration(200)
.style("opacity", .9);
div.html(d.HEADCOUNT + " people in " + d.GEOCODE_LOCATION)
.style("left", (d3.event.pageX) + "px")
.style("top", (d3.event.pageY - 28) + "px");
})
.on("mouseout", function(d) {
div.transition()
.duration(500)
.style("opacity", 0);;
});
});
});
// ######################################################################
// NESTING, FILTERING AND SUMMARIZING DATA
// ######################################################################
d3.csv("sample_data.csv", function(csv) {
var data_nest = d3.nest()
.key(function(d) {
return d.GEOCODE_LOCATION;
})
.key(function(d) {
return d.CATEGORY1;
})
.key(function(d) {
return d.CATEGORY2;
})
.key(function(d) {
return d.CATEGORY3;
})
.key(function(d) {
return d.TYPE1;
})
.key(function(d) {
return d.TYPE2;
})
.sortKeys(d3.ascending)
.entries(csv);
console.log(data_nest);
var data_sums = d3.nest()
.key(function(d) {
return d.GEOCODE_LOCATION;
})
.key(function(d) {
return d.LONGITUDE;
})
.key(function(d) {
return d.LATITUDE;
})
.sortKeys(d3.ascending)
.rollup(function(d) {
return {
headcount: d3.sum(d, function(g) {
return +g.HEADCOUNT;
})
};
})
.entries(csv);
console.log(data_sums);
});
// ######################################################################
// POPULATE THE FIVE MENU LISTS
// ######################################################################
function load_menus() {
d3.csv("category1.csv", function(error, data_c1) {
var select = d3.select("#c1_div")
.append("div")
.append("select")
select
.on("change", function(d) {
var selected_c1 = d3.select(this).property("value");
alert(value);
});
select.selectAll("option")
.data(data_c1)
.enter()
.append("option")
.attr("value", function(d) {
return d.x;
})
.text(function(d) {
return d.x;
});
});
d3.csv("category2.csv", function(error, data_c2) {
var select = d3.select("#c2_div")
.append("div")
.append("select")
select
.on("change", function(d) {
var selected_c2 = d3.select(this).property("value");
alert(value);
});
select.selectAll("option")
.data(data_c2)
.enter()
.append("option")
.attr("value", function(d) {
return d.x;
})
.text(function(d) {
return d.x;
});
});
d3.csv("category3.csv", function(error, data_c3) {
var select = d3.select("#c3_div")
.append("div")
.append("select")
select
.on("change", function(d) {
var selected_c3 = d3.select(this).property("value");
alert(value);
});
select.selectAll("option")
.data(data_c3)
.enter()
.append("option")
.attr("value", function(d) {
return d.x;
})
.text(function(d) {
return d.x;
});
});
d3.csv("type1.csv", function(error, data_t1) {
var select = d3.select("#t1_div")
.append("div")
.append("select")
select
.on("change", function(d) {
var selected_t1 = d3.select(this).property("value");
alert(value);
});
select.selectAll("option")
.data(data_t1)
.enter()
.append("option")
.attr("value", function(d) {
return d.x;
})
.text(function(d) {
return d.x;
});
});
d3.csv("type2.csv", function(error, data_t2) {
var select = d3.select("#t2_div")
.append("div")
.append("select")
select
.on("change", function(d) {
var selected_t2 = d3.select(this).property("value");
alert(value);
});
select.selectAll("option")
.data(data_t2)
.enter()
.append("option")
.attr("value", function(d) {
return d.x;
})
.text(function(d) {
return d.x;
});
});
}
window.onload = load_menus;
// ######################################################################
// FILTER DATA BASED ON USER SELECTION - NOT WORKING
// ######################################################################
function filter_data() {
d3.csv("map_data.csv", function(error, data) {
var filterCategory1 = selected_c1;
var filterCategory2 = selected_c2;
var filterCategory3 = selected_c3;
var filterType1 = selected_t1;
var filterType2 = selected_t2;
var filtered_data = data.filter(function(d) {
return d.CATEGORY1 == filterCategory1;
})
});
}
这是我的示例数据的屏幕截图:
我已经在网上和书中搜索了一个多星期,但既没有找到我正在尝试做的事情的其他 D3 示例,也没有找到我的数据绑定、过滤和聚合问题的答案。
感谢任何帮助。我保证,当我有能力这样做时,我会把它付清。如果我能得到这个工作,我会很高兴 post 我的完整解决方案 github 和 link 从这个问题到它。
在我看来,您的问题不在于 D3,而是 JavaScript 范围。
当你写这样的东西时:
d3.csv("category1.csv", function(error, data_c1) {
var select = d3.select("#c1_div")
.append("div")
.append("select")
select
.on("change", function(d) {
var selected_c1 = d3.select(this).property("value");
alert(value);
});
那个变量 selected_c1
只存在于包含它的匿名函数中。局部变量只能在定义它的函数内部使用。它对其他函数和其他脚本代码隐藏(请参阅此处:http://www.w3schools.com/js/js_function_closures.asp)。
因此,当您稍后尝试使用它时,在 filter_data()
中,它不可用。
此处的解决方案是将 selected_c1
和所有其他 4 个变量作为参数传递给 filter_data
。可能是这样的:
d3.csv("category1.csv", function(error, data_c1) {
var select = d3.select("#c1_div")
.append("div")
.append("select")
select
.on("change", function(d) {
var selected_c1 = d3.select(this).property("value");
filter_data(selected_c1);
});
然后,更改您的 filter_data()
参数:
function filter_data(selection) {
d3.csv("map_data.csv", function(error, data) {
var filtered_data = data.filter(function(d) {
return d.CATEGORY1 == selection;
})
});
}
请记住,尽管您已成功将 selected_c1
传递给 filter_data()
,但您现在再次面临同样的问题:var filtered_data
仅存在于 filter_data
中,并且您有将其传递给绘图函数的 2 个选项:
- 使其全球化;
- 将其作为参数传递。
这只是部分答案,您还需要付出一些努力才能将所有这些组合在一起。