Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
473 views
in Technique[技术] by (71.8m points)

d3.js - D3 filtering data points

I'm implementing the classic mercator example (https://github.com/mbostock/d3/blob/master/examples/mercator/mercator.html), which I've changed to zoom into Afghanistan and to use only one custom slider. I'm reading in GeoJSON data of places where explosions have happened and the graph maps them all at load. I want to use the slider to view only a month of explosion points at a time but am having trouble filtering the results. I've tried several things based on posts in the Google group but fail to understand how to filter the data read in previously from 'explosions.json'. Thanks for the help!

    <!DOCTYPE html>
    <html>
    <head>
<meta http-equiv="Content-Type" content="text/html;charset=utf-8">
<title>IED Attacks in Afghanistan (2004-2009)</title>
<script type="text/javascript" src="../d3.v2.js"></script>
<script type="text/javascript" src="../lib/jquery/jquery.min.js"></script>
<script type="text/javascript" src="../lib/jquery-ui/jquery-ui.min.js"></script>
<style type="text/css">

    @import url("../lib/jquery-ui/jquery-ui.css");

    body, .ui-widget {
    font: 14px Helvetica Neue;
    }

    svg {
    width: 960px;
    height: 600px;
    border: solid 1px #ccc;
    background: #eee;
    }

    line {
    stroke: brown;
    stroke-dasharray: 4,2;
    }

    path {
    fill: #ccc;
    stroke: #fff;
    }

    div {
    width: 960px;
    }

</style>
</head>
<body>
<h3>IED Attacks in Afghanistan (2004-2009)</h3>
<script type="text/javascript">

        // Create the Mercator Projection (Map)
        var xy = d3.geo.mercator(),
            path = d3.geo.path().projection(xy);


        // Create the states variable
        var states = d3.select("body")
        .append("svg")
        .append("g")
            .attr("id", "states");
        // Create the equator variable
        var equator = d3.select("svg")
        .append("line")
            .attr("x1", "0%")
            .attr("x2", "100%");
        // Create the explosions variable
        var explosions = d3.select("svg")
        .append("g")
            .attr("id","explosions");

        // Load in the states & equator data from the file 'world-countries.json'
        d3.json("world-countries.json", function(collection) {
            states
                .selectAll("path")
                .data(collection.features)
                .enter().append("path")
                .attr("d", path)
                .append("title")
                .text(function(d) { return d.properties.name; });
            equator
                .attr("y1", xy([0, 0])[1])
                .attr("y2", xy([0, 0])[1]);
        });

        // the variable that holds our translate, center on Afghanistan
        var translate = xy.translate(); //create translation to center gride in different area
        translate[0] = -1741;
        translate[1] = 1487;
        xy.translate(translate); // center

        xy.scale(12000); //zoom in

        // Load in the explosions data from the file 'explosions.json'
        d3.json("explosions.json", function(collection) {
            explosions
                .selectAll("path") //make a path and attach data
                .data(collection.features)
                .enter().append("path")
                .attr("d", path)
                .style("stroke","red") //color the path points
                .style("stroke-width",2) //size of point stroke
                .attr("class","explosionpoint")
                .append("title") //title is the 'name' field in the json file
                .text(function(d) { return d.properties.name; });
        });



    </script>

    <p></p>
    <!-- Slider -->
    <div id="scale"></div><p></p>
    <script type="text/javascript">

        $("#scale").slider({
        min: 20040101, //min : 1/1/04
        max: 20100101, //max: 1/1/10
        value: 20060601, //default slider value
        step: 100, // step is the allow increments the slider can move. 100 = one month
        slide: function(event, ui) {


            /* REMOVE ALL EXPLOSION PATHS EXCEPT FOR A PARTICULAR MONTH OR RELOAD WITH FILTERED RESULTS */
        }
        });

</script>

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

You'll need to post part or all of your explosions.json object for a concrete answer. However, something like this will filter a JSON if it's structured like {explosion1:{data1:true, data2:true}, explosion2:{data1:true, data2:false}}:

function filterJSON(json, key, value) {
  var result = {};
  for (var explosionIndex in json) {
    if (json[explosionIndex][key] === value) {
      result[explosionIndex] = json[explosionIndex];
    }
  }
  return result;
}

(e.g. filterJSON(myjson, "data1", true) will give all explosions with data1:true)

This is not specific to d3.

Then you could use something like this for the d3-side of things:

explosions.data(myFilteredData).exit().remove(); // remove ones you don't want
explosions.enter().append("path")... // add back ones you do want

If I understand your application, it would actually be better to just toggle the visiblity attribute of the SVG elements.

var sliderrange = [20040101, 20040201]; //replace with code based on your slider
explosions.selectAll(".explosionpoint").attr("visibility", function(d) {
  //Replace with the correct date comparison logic
  return d.date < sliderrange[1] && d.date > sliderrange[0] ? "visible" : "hidden";
});

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...