2017-09-14 7 views
1

J'ai tenté de placer des points (éventuellement avec des infobulles de survol) à chaque point de données d'un graphique chronologique. La partie multiligne est basée sur this example et crée une fonction appelée draw() qui dessine le graphique en utilisant des générateurs externes d3.line(). J'essaie de créer des points de dispersion sur les points de données où les données de température et le temps se croisent - ce qui fonctionne sur les lignes mais pas sur mes ellipses, et je ne suis pas sûr de ce que je fais mal.Diagramme de dispersion D3 sur le graphique linéaire multi-lignes de série temporelle

The failing scatterplot attempt is here.

Quelle est la meilleure façon de faire les cercles se chevauchent les points de données? L'erreur que je reçois dans le débogueur JavaScript est

d3.v4.js:1381 Error: <circle> attribute cx: Expected length, "NaN". 
d3.v4.js:1381 Error: <circle> attribute cy: Expected length, "NaN". 

L'analyse des données semble fonctionner correctement avec les intersections de la ligne, mais pas le cx et les coordonnées cy.

JavaScript pour ne pas avoir tentative ci-dessous:

// set the dimensions and margins of the graph 
var margin = {top: 20, right: 20, bottom: 30, left: 50}, 
    width = 960 - margin.left - margin.right, 
    height = 500 - margin.top - margin.bottom; 

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

// set the ranges 
var x = d3.scaleTime().range([0, width]); 
var y = d3.scaleLinear().range([height, 0]); 

// define the div for the tooltip 
var div = d3.select("body").append("div") 
    .attr("class", "tooltip") 
    .style("opacity", 0); 


var tempprobe_line = d3.line() 
    .x(function(d) { return x(d.timestamp); }) 
    .y(function(d) { return y(d.tempprobe); }); 

var high_threshold_line = d3.line() 
    .x(function(d){ return x(d.timestamp); }) 
    .y(function(d){ return y(d.threshold_high); }); 

var low_threshold_line = d3.line() 
    .x(function(d){ 
     return x(d.timestamp); 
    }) 
    .y(function(d){ 
     return y(d.threshold_low); 
    }) 


var ambient_line = d3.line() 
    .x(function(d) 
     { return x(d.timestamp);} 
    ) 
    .y(function(d) { 
     return y(d.ambient); 
    }); 


var svg = d3.select("body").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 draw(data, tempdata) { 

    var data = data[tempdata]; 

    data.forEach(function(d, i) { 
     d.timestamp = parseDate(d.timestamp); 
     d.tempprobe = +d.tempprobe; 
     d.ambient = +d.ambient; 
    }); 

    data.sort(function(a, b){ 
     return a["timestamp"]-b["timestamp"]; 
    }); 

    // scale the range of data 
    x.domain(d3.extent(data, function(d){ 
     return d.timestamp; 
    })); 
    y.domain([0, d3.max(data, function(d){ 
     return Math.max(d.tempprobe, d.ambient); 
    })]); 

    // Add the tempprobe path. 
    svg.append("path") 
     .data([data]) 
     .attr("class", "line temp-probe temperature") 
     .attr("d", tempprobe_line); 

    // Add the ambient path 
    svg.append("path") 
     .data([data]) 
     .attr("class", "line ambient temperature") 
     .attr("d", ambient_line); 

    svg.append("path") 
     .data([data]) 
     .attr("class", "line high-threshold") 
     .attr("d", high_threshold_line) 

    svg.append("path") 
     .data([data]) 
     .attr("class", "line low-threshold") 
     .attr("d", low_threshold_line) 

    // add the X Axis 
    svg.append("g") 
     .attr("transform", "translate(0,"+ height + ")") 
     .call(d3.axisBottom(x)); 

    // add the Y Axis 
    svg.append("g") 
     .call(d3.axisLeft(y)); 
    } 

    d3.json("temp_data.json", 
     function(error, data){ 
    if (error){ 
     throw error; 
    } 
    draw(data[0], "tempdata"); 
    // Add the scatterplot -- the failing part 
    svg.selectAll("dot") 
     .data(data) 
     .enter().append("circle") 
     .attr("r", 3.5) 
     .attr("cx", function(d) { return x(d.timestamp); }) 
     .attr("cy", function(d) { return y(d.tempprobe); }); 
}); 

Répondre

1

Les données que vous passez à la fonction selection.data() est faux. Les données que vous souhaitez sont imbriquées dans la variable data.

Cela fonctionne pour moi:

svg.selectAll("dot") 
    .data(data[0]['tempdata']) 
    .enter() 
    .append("circle") 
    .attr("r", 3.5) 
    .attr("cx", function(d) { return x(d.timestamp); }) 
    .attr("cy", function(d) { return y(d.tempprobe); }); 

Cela ajoute des cercles sur chaque point de données sur la ligne bleue tempprobe.

+0

Quelqu'un peut-il expliquer ce que le modèle utilisé pour générer des lignes est un.) Appelé? et b.) comment je peux reproduire cette méthodologie pour générer des cercles (points) comme le nuage de points? Si j'ai besoin d'ouvrir une nouvelle question, j'en suis ravi, mais j'aimerais au moins utiliser le bon nom de modèle. – Smittles

+1

Je ne suis pas entièrement sûr. Il semble que vous définissiez la logique de dessin au trait dans une fonction, puis appelez cela avec vos données. Je pense que l'important est de comprendre quel objet de données chaque appel à '.data' devrait prendre. Si cela peut vous aider, je trouve que l'utilisation de Chrome Devtools et l'établissement de points de rupture pour inspecter les variables à divers points peuvent être très instructifs. –