2017-02-28 66 views
0

我正在研究d3圖表(多折線圖)。
我試圖表示股票預測,所以基本上圖表包含兩行:股票價值線和另一個用於我的預測。d3.js - 多個折線圖不會更新圓圈

預測是每月,所有月份的日子都在圖表中表示。
爲了選擇我添加了下拉菜單的月份。

我在每個日常數據上附加了一個圓圈,並且第一次運作良好。當用戶嘗試更改月份時,舊的圈子不會更新,但會添加新的圈子。

按照有關圈子代碼:

topicEnter.append("g").selectAll("circle") 
    .data(function(d){return d.values}) 
    .enter() 
    .append("circle") 
    .attr("r", 5) 
    .attr("cx", function(dd){return x(dd.date)}) 
    .attr("cy", function(dd){return y(dd.probability)}) 
    .attr("fill", "none") 
    .attr("stroke", "black"); 

我已經做了fiddle更好地瞭解情況,以顯示代碼。

我在這裏錯過了什麼?爲什麼這些圈子沒有用線更新自己?

回答

1

爲了解決有關圈子的問題,沒有更新,你可以做到以下幾點:

function update(topics) { 
    // Calculate min and max values with arrow functions 
    const minValue = d3.min(topics, t => d3.min(t.values, v => v.probability)); 
    const maxValue = d3.max(topics, t => d3.max(t.values, v => v.probability)); 
    y.domain([minValue, maxValue]); 
    x2.domain(x.domain()); 
    y2.domain(y.domain()); 
    // update axes 
    d3.transition(svg).select('.y.axis').call(yAxis); 
    d3.transition(svg).select('.x.axis').call(xAxis); 
    // Update context 
    var contextUpdate = context.selectAll(".topic").data(topics); 
    contextUpdate.exit().remove(); 
    contextUpdate.select('path') 
    .transition().duration(600) 
    .call(drawCtxPath); 
    contextUpdate.enter().append('g') // append new topics 
    .attr('class', 'topic') 
    .append('path').call(drawCtxPath); 
    // New data join 
    var focusUpdate = focus.selectAll('.topic').data(topics); 
    // Remove extra topics not found in data 
    focusUpdate.exit().remove(); //remove topics 
    // Update paths 
    focusUpdate.select('path') 
    .transition().duration(600) 
    .call(drawPath) 
    // Update circles 
    var circlesUpdate = focusUpdate 
    .selectAll('.topic-circle') 
    .data(d => d.values); 
    circlesUpdate.exit().remove(); 
    circlesUpdate.transition().duration(600).call(drawCircle); 
    circlesUpdate.enter().append('circle').call(drawCircle); 
    // Add new topics 
    var newTopics = focusUpdate.enter().append('g') // append new topics 
    .attr('class', 'topic'); 
    // Add new paths 
    newTopics.append('path').call(drawPath) 
    // Add new circles 
    newTopics.selectAll('.topic-circle') 
    .data(d => d.values) 
    .enter() 
    .append('circle') 
    .call(drawCircle); 
} 

使用這些輔助功能,以減少重複代碼:

function drawCtxPath(path) { 
    path.attr("d", d => line2(d.values)) 
    .style("stroke", d => color(d.name)); 
} 
function drawPath(path) { 
    path.attr("d", d => line(d.values)) 
    .attr('clip-path', 'url(#clip)') 
    .style("stroke", d => color(d.name)); 
} 
function drawCircle(circle) { 
    circle.attr('class', 'topic-circle') 
    .attr('clip-path', 'url(#clip)') 
    .attr("r", d => 5) 
    .attr("cx", d => x(d.date)) 
    .attr("cy", d => y(d.probability)) 
    .attr("fill", "none") 
    .attr("stroke", "black"); 
} 

我覺得有一些額外的問題,在您的代碼,當您選擇同一個月兩次出現錯誤時,我們可以通過執行以下操作來解決該問題:

d3.select('#month_chart').on("change", function() { 
    // Get selected value of the select 
    var month = this.options[this.selectedIndex].value; 
    // Since you have hardcoded data we need to return a new array 
    // This is why if you select the same month twice your code breaks 
    // since parseDate will fail since the data will be already parsed 
    // the second time 
    var monthData = get_monthly_data(month).map(d => { 
    return { 
     date: parseDate(d.date), 
     predicted_bool: d.predicted_bool, 
     target: d.target 
    }; 
    }); 
    // Lets use arrow functions! 
    var keys = d3.keys(monthData[0]).filter(k => k !== 'date'); 
    color.domain(keys); 
    // More arrow functions! 
    var topics = keys.map(key => { 
    return { 
     name: key, 
     values: monthData.map(d => { 
     return { 
      date: d.date, 
      probability: +d[key] 
     }; 
     }) 
    }; 
    }); 
    x.domain(d3.extent(monthData, d => d.date)); 
    update(topics); 
}); 

// A good ol' switch 
function get_monthly_data(month) { 
    switch (month) { 
    case 'gennaio': 
     return data_1; 
    case 'febbraio': 
     return data_2; 
    case 'marzo': 
     return data_3; 
    default: 
     return data_1; 
    } 
} 

工作的jsfiddle:

https://jsfiddle.net/g699scgt/37/

+0

非常感謝你,非常詳細的答案!再次感謝你! – Giordano

1

問題在於你的更新週期,但在d3中有很多的輸入,更新,退出過程的例子。

但從本質:

  1. 您可以附加一個新g元素界的每一批,這意味着你有一個空的選擇(無界都使得G還),每次和每個數據點被追加(並沒有被刪除)。你不需要這個額外的追加。查看現有代碼中每個附件的DOM結構。

  2. 您的enter()選項返回新元素 - 未修改的元素。因此,如果你的元素總數保持不變,你將有一個空的enter()選擇。您需要單獨更新現有元素(或者,全部刪除它們並將它們全部追加)。

你想要的東西更接近this

// set the data 
    circles = topic.selectAll("circle") 
     .data(function(d){return d.values}); 
// update existing circles  
    circles.attr("cx", function(dd){return x(dd.date)}) 
     .attr("cy", function(dd){return y(dd.probability)}); 
// add new circles  
    circles.enter() 
     .append("circle") 
     .attr("r", 5) 
     .attr("cx", function(dd){return x(dd.date)}) 
     .attr("cy", function(dd){return y(dd.probability)}) 
     .attr("fill", "none") 
     .attr("stroke", "black"); 
    // remove excess circles 
    circles.exit().remove(); 

你可能也想修改該追加線,以反映輸入,更新,出口在D3週期線。

+0

太謝謝你了!你是對的,我找到了很多例子,但我沒有很好地理解它們。 – Giordano