根据用户输入过滤.csv数据并刷新d3.js映射

时间:2016-04-29 17:11:21

标签: javascript csv d3.js filter bind

我是一名d3.js菜鸟,并且能够为一个项目共同制作一张地图,但现在我被卡住了。我想根据用户输入/选择五维的任意组合刷新地图。根据用户输入,我希望我的代码只过滤到符合所选条件的数据行,汇总该地理位置的人数并刷新地图。由于各种项目限制,我必须使用.csv或.json作为我的数据源。我知道我可以根据用户输入切换数据源并刷新地图,但由于可能的选择组合的数量,解决方案对我的项目来说是不可行的。我想我已经接近了,但我不确定如何越过终点线。我已将用户选择存储在变量中,创建了我的数据的d3.nest并且能够在指定的d3.nest密钥上创建d3.sums。

我认为我找到的帖子可以回答我的问题,但是我太过于理解如何综合我项目的相关信息了。我需要做的是根据用户输入动态创建d3.nest和d3.sum,但我不知道如何将我的用户选择变量链接到我创建嵌套和放大器的函数。和。我想在每次用户做出选择时刷新地图和数据,但我会打开在屏幕上放一个刷新数据的按钮,如果这样做更容易的话。以下是我的地图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;
            })
        });
    }

以下是我的示例数据的屏幕截图:

sample data

我已经在网上和书中搜索了一个多星期了,并且既没有找到我尝试做的其他D3示例,也没有回答我的数据绑定,过滤和聚合问题。

感谢任何帮助。我保证,当我有技能时,我会向前付钱。如果我能够开展这项工作,我将很乐意在github上发布我的完整解决方案并从这个问题链接到它。

1 个答案:

答案 0 :(得分:0)

在我看来,你的问题不是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_c1filter_data(),但您现在又面临同样的问题:var filtered_data仅存在于filter_data内,您有2个选项将它传递给你的绘图函数:

  1. 使其全球化;
  2. 将其作为参数传递。
  3. 这只是一个部分答案,你仍然需要努力将所有这些放在一起。