D3 фильтрация точек данных

Я реализую классический пример меркатора (https://github.com/mbostock/d3/blob/master/examples/mercator/mercator.html), который я изменил, чтобы увеличить масштаб Афганистана и использовать только один настраиваемый ползунок. . Я читаю в GeoJSON данные о местах, где произошли взрывы, и график отображает их все при нагрузке. Я хочу использовать ползунок для просмотра только точек взрыва за месяц, но у меня возникают проблемы с фильтрацией результатов. Я пробовал несколько вещей на основе сообщений в группе Google, но не понимаю, как фильтровать данные, считанные ранее из «explosions.json». Спасибо за помощь!

    <!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>


person user1245530    schedule 29.08.2012    source источник


Ответы (2)


Вам нужно будет опубликовать часть или весь ваш объект Explosions.json для конкретного ответа. Однако что-то вроде этого будет фильтровать JSON, если он структурирован как {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;
}

(например, filterJSON(myjson, "data1", true) выдаст все взрывы с data1:true)

Это не относится к d3.

Затем вы можете использовать что-то вроде этого для d3-стороны вещей:

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

Насколько я понимаю ваше приложение, на самом деле было бы лучше просто переключить атрибут visiblity элементов SVG.

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";
});
person ZachB    schedule 01.09.2012
comment
Спасибо, Зак. Да, в конечном итоге я отфильтровал точки, просто нарисовав их все в начале (как указано выше), а затем переключив отображаемое значение каждой точки между «блок» и «нет». Это работает быстро и, вероятно, лучше, чем перезагрузка отфильтрованных данных. - person user1245530; 13.09.2012

У D3 есть очень естественный способ сделать это. Я предполагаю, что ваши данные выглядят примерно так:

[{name: explosion1name, day: 20040110,...}, {name: explosion2name, day: 20040111,...}]

...и что у вас есть какая-то переменная, назовем ее explosionsData для ссылки на данные.

Затем вы можете нарисовать свои взрывы с помощью функции, которая берет значения из вашего ползунка. См. .filter, который я добавил ниже.

function drawExplosions(startDay, endDay) {
    explosions.selectAll("path") //make a path and attach data
            .data(collection.features)
            .enter().append("path")
            .filter( function (d) { return ( (d.day > startDay) && (d.day < endDay) )})
            .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; });

Просто вызывайте эту функцию всякий раз, когда значения вашего ползунка меняются.

person ACPrice    schedule 08.06.2014