Автоматическое обновление точечной диаграммы d3js не работает

Нужна помощь, чтобы понять, как автоматически обновлять точечную диаграмму 3djs. Код выглядит нормально, однако, когда функция обновления работает, график обновляется, но точечная диаграмма остается на месте. Я использую svg.selectAll(".dot").remove(), чтобы удалить устаревшие, но не могу найти способ добавить их обратно. Я нашел несколько решений в Интернете, но ни одно из них не сработало для моего кода.

Любая помощь приветствуется. Благодарность

Структура БД:

дтг | температура

2016-03-02 09:14:00 23

2016-03-02 09:10:00 22

Код:

<script>
// Set the dimensions of the canvas / graph
var margin = {top: 30, right: 20, bottom: 30, left: 40},
width = 400 - margin.left - margin.right,
height = 200 - margin.top - margin.bottom;

// Parse the date / time
var parseDate = d3.time.format("%Y-%m-%d %H:%M:%S").parse;
var formatTime = d3.time.format("%e %B %X");

// Set the ranges
var x = d3.time.scale().range([0, width]);
var y = d3.scale.linear().range([height, 0]);

// Define the axes
var xAxis = d3.svg.axis().scale(x)
    .orient("bottom").ticks(5);

var yAxis = d3.svg.axis().scale(y)
    .orient("left").ticks(5);

// Define the line
var valueline = d3.svg.line()
    .x(function(d) { return x(d.dtg); })
    .y(function(d) { return y(d.temperature); });

var div = d3.select("#chart1").append("div")    
    .attr("class", "tooltip")               
    .style("opacity", 0);

// Adds the svg canvas
var svg = d3.select("#chart1")
    .append("svg")
        .attr("width", width + margin.left + margin.right)
        .attr("height", height + margin.top + margin.bottom)
    .append("g")
        .attr("transform", 
              "translate(" + margin.left + "," + margin.top + ")");

function make_x_axis() {        
    return d3.svg.axis()
        .scale(x)
        .orient("bottom")
        .ticks(10)
}

function make_y_axis() {        
    return d3.svg.axis()
        .scale(y)
        .orient("left")
        .ticks(10)
}
// Get the data
d3.json("2301data.php", function(error, data) {
    data.forEach(function(d) {
        d.dtg = parseDate(d.dtg);
        d.temperature = +d.temperature;
   });

    // Scale the range of the data
    x.domain(d3.extent(data, function(d) { return d.dtg; }));
     y.domain([0, 60]); // 
 //   y.domain([0, d3.max(data, function(d) { return d.temperature; })]);

    // Add the valueline path.
    svg.append("path")
        .attr("class", "line")
        .attr("d", valueline(data));

    // draw the scatterplot
    svg.selectAll(".dot")   
        .data(data)                                         
        .enter().append("circle")   
        .attr("class", "dot")
        .filter(function(d) { return d.temperature > 30 })
        .style("fill", "red")   
        .attr("r", 3.5) 
        .attr("cx", function(d) { return x(d.dtg); })        
        .attr("cy", function(d) { return y(d.temperature); })

    // Tooltip stuff after this
        .on("mouseover", function(d) {      
            div.transition()
                .duration(500)  
                .style("opacity", 0);
            div.transition()
                .duration(200)  
                .style("opacity", .9);  
            div .html(
                d.temperature + "C" + "<br>" +
                formatTime(d.dtg)) 
                .style("left", (d3.event.pageX + 8) + "px")          
                .style("top", (d3.event.pageY - 18) + "px");})
        .on("mouseout", function(d) {       
            div.transition()        
                .duration(500)      
                .style("opacity", 0);   
        });

    // Add the X Axis
    svg.append("g")
        .attr("class", "x axis")
        .attr("transform", "translate(0," + height + ")")
    .style("font-size", "14px") 
        .call(xAxis);

    // Add the Y Axis
    svg.append("g")
        .attr("class", "y axis")
    .style("font-size", "14px") 
        .call(yAxis);

// Draw the grid 1
    svg.append("g")         
        .attr("class", "grid")
        .attr("transform", "translate(0," + height + ")")
        .call(make_x_axis()
            .tickSize(-height, 0, 0)
            .tickFormat("")
        )
// Draw the grid 2
    svg.append("g")         
        .attr("class", "grid")
        .call(make_y_axis()
            .tickSize(-width, 0, 0)
            .tickFormat("")
        )   
// Addon 3               // text label for the graph
    svg.append("text")
        .attr("x", (width / 2))             
        .attr("y", 0 - (margin.top / 2))
        .attr("text-anchor", "middle")  
        .style("font-size", "14px") 
        .style("text-decoration", "underline") 
        .style('fill', 'white')
    //.attr("class", "shadow") // using text css         
        .text("2301 Temperature read in the past 24h\n");


});

var inter = setInterval(function() {
                updateData();
        }, 5000); 

// ** Update data section (Called from the onclick)
function updateData() {

    // Get the data again
    d3.json("2301data.php", function(error, data) {
    data.forEach(function(d) {
        d.dtg = parseDate(d.dtg);
        d.temperature = +d.temperature;
        //d.hum = +d.hum; // Addon 9 part 3
    });


   // Scale the range of the data again 
     x.domain(d3.extent(data, function(d) { return d.dtg; }));
     y.domain([0, 60]); 

    var svg = d3.select("#chart1").transition(); 

    // Make the changes
        svg.selectAll(".dot").remove(); //remove old dots 
        svg.select(".line").duration(750).attr("d", valueline(data));
    svg.select("x.axis").duration(750).call(xAxis);
    svg.select("y.axis").duration(750).call(yAxis);

    //update the scatterplot
    svg.selectAll(".dotUpdate")
    .data(data)
        .attr("class", "dotUpdate")
    .enter().append("circle")
    .filter(function(d) { return d.temperature > 30 })
        .style("fill", "red")   
        .attr("r", 3.5) 
        .attr("cx", function(d) { return x(d.dtg); })        
        .attr("cy", function(d) { return y(d.temperature); });



    });
}


</script>

person badatz    schedule 01.04.2016    source источник
comment
Это действительно грязно. Любое исправление вашей конкретной проблемы будет просто пластырем. Сначала нужно провести рефакторинг, чтобы не было так много повторений. Загрузка данных должна происходить только в одном месте кода. То же самое и для рендеринга — должна быть одна функция рендеринга, которая обрабатывает как первоначальный рендеринг, так и все последующие обновления. Связывание данных D3 — с обновлением enter() и exit() — создано для этого. Следуйте инструкциям, связанным с из этого ответа.   -  person meetamit    schedule 02.04.2016
comment
Спасибо, митамит. Я принял метод обновления enter() и exit(), и все начало работать... Позже я опубликую более подробное обновление с дополнительным вопросом.   -  person badatz    schedule 03.04.2016


Ответы (1)


Первое, что я сделал неправильно, это использовать неправильный d3js.. необходимо заменить следующую строку

<script src="http://d3js.org/d3.v3.min.js"></script>

Со следующим, иначе svg.selectAll не будет работать.

<script type="text/javascript" src="http://d3js.org/d3.v3.js"></script>

Теперь, что касается обновления графиков рассеяния. Теперь я использую приведенный ниже код, который отлично работает с некоторыми базами данных. В моем случае это все еще не работает, и я опубликую его как отдельный вопрос, как того требует руководство по stakoverflow.

// ** Update data section (Called from the onclick)
function updateData() {

// Get the data again
data = d3.json("2301data.php", function(error, data) {
data.forEach(function(d) {
    d.dtg = parseDate(d.dtg);
    d.temperature = +d.temperature;
   // d.hum = +d.hum; // Addon 9 part 3
});


// Scale the range of the data again 
 x.domain(d3.extent(data, function(d) { return d.dtg; }));
 y.domain([0, 60]); // Addon 9 part 4

 var svg = d3.select("#chart1")
 var circle = svg.selectAll("circle").data(data)

svg.select(".x.axis") // change the x axis
        .transition()
        .duration(750)
        .call(xAxis);
    svg.select(".y.axis") // change the y axis
        .transition()
        .duration(750)
        .call(yAxis);
    svg.select(".line")   // change the line
        .transition()
        .duration(750)
        .attr("d", valueline(data));

circle.transition()
        .duration(750)
        .attr("cx", function(d) { return x(d.dtg); })

    // enter new circles
    circle.enter()
        .append("circle")
        .filter(function(d) { return d.temperature > 30 })
        .style("fill", "red")   
        .attr("r", 3.5) 
        .attr("cx", function(d) { return x(d.dtg); })

    // remove old circles
    circle.exit().remove()


});
}
person badatz    schedule 03.04.2016