d3js scatter plot auto update doesnt work

2019-09-10 02:00发布

Need some help figuring out how to auto update 3djs scatter plot. The code looks fine ,however, when the update function is running the graph gets updated but the scatter plot remains at place. I'm using svg.selectAll(".dot").remove() in order to remove the outdated ones but unable to find a way to added them back. I found a few solutions online but none of them worked for my code.

Any help would be much appreciated. thanks

DB structure:

dtg | temperature

2016-03-02 09:14:00 23

2016-03-02 09:10:00 22

Code:

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

1条回答
迷人小祖宗
2楼-- · 2019-09-10 02:57

The first thing I did wrong was using the wrong d3js.. the following line has to be replaced

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

With the following or else svg.selectAll would not work.

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

Now, as far as the scatter plots update goes. I'm now using the code below which works fine with some databases. In my case it still does not work well and I'll be posting it as a sepearte question as stakoverflow guidlines requsts..

// ** 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()


});
}
查看更多
登录 后发表回答