2016-11-13 32 views
0

我的編碼是將x軸與位置,y軸與(值1,值2或值3)以及類型(高,中,低)的圖例一起繪製。我想要做的是添加值爲1,2,3的菜單,並添加不同類型的圖例,所以如果我從任一菜單更改或單擊圖例,繪圖都會更新爲只有選定的數據。但是,我的下面的代碼只能創建圖例設置爲默認類型或單擊,但無法包含所有類型。有沒有什麼方法可以不斷輸入所有類型的傳說?無論點擊哪種類型,只更新圖表? 謝謝你,保持圖例不變,只更新D3中的圖表

<script> 
var margin = {top: 20, right: 20, bottom: 30, left: 40}, 
    width = 960- margin.left - margin.right, 
    height = 900 - margin.top - margin.bottom, 
    radius = 3.5, 
    padding = 1, 
    xVar = "location", 
    cVar= " type"; 
    default = "high"; 


// add the tooltip area to the webpage 
var tooltip = d3.select("body").append("div") 
       .attr("class", "tooltip") 
       .style("opacity", 0); 


// force data to update when menu is changed  
var menu = d3.select("#menu select") 
    .on("change", change); 

// load data 
d3.csv("sample.csv", function(error, data) { 
    formatted = data; 

    draw(); 
}); 


// set terms of transition that will take place 
// when new indicator from menu or legend is chosen 
function change() { 
    //remove old plot and data 
    var svg = d3.select("svg"); 
     svg.transition().duration(100).remove(); 

    //redraw new plot with new data 
    d3.transition() 
     .duration(750) 
     .each(draw) 
} 


function draw() { 

// add the graph canvas to the body of the webpage 

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 + ")") 


    // setup x 
    var xValue = function(d) { return d[xVar];}, // data -> value 
     xScale = d3.scale.ordinal() 
         .rangeRoundBands([0,width],1), //value -> display 
     xMap = function(d) { return (xScale(xValue(d)) + Math.random()*10);}, // data -> display 
     xAxis = d3.svg.axis().scale(xScale).orient("bottom"); 

    // setup y 
    var yVar = menu.property("value"), 

     yValue = function(d) { return d[yVar];}, // data -> value 
     yScale = d3.scale.linear().range([height, 0]), // value -> display 
     yMap = function(d) { return yScale(yValue(d));}, // data -> display 
     yAxis = d3.svg.axis().scale(yScale).orient("left"); 


    // setup fill color 
    var cValue = function(d) { return d[cVar];}, 
     color = d3.scale.category10(); 


    // filter the unwanted data and plot with only chosen dataset. 
data = formatted.filter(function(d, i) 
    { 
      if (d[cVar] == default) 
      { 
       return d; 
      } 
    }); 
    data = formatted; 
    // change string (from CSV) into number format 
    data.forEach(function(d) { 
    d[xVar] = d[xVar]; 
    d[yVar] = +d[yVar]; 
    }); 


    xScale.domain(data.sort(function(a, b) { return d3.ascending(a[xVar], b[xVar])}) 
        .map(xValue)); 
    // don't want dots overlapping axis, so add in buffer to data domain 
    yScale.domain([d3.min(data, yValue)-1, d3.max(data, yValue)+1]); 


    // x-axis 

    svg.append("g") 
     .attr("class", "x axis") 
     .attr("transform", "translate(0," + height + ")") 
     .call(xAxis) 
    .append("text") 
     .attr("class", "label") 
     .attr("x", width) 
     .attr("y", -6) 
     .style("text-anchor", "end") 
     .text(xVar); 


    // y-axis 

    svg.append("g") 
     .attr("class", "y axis") 
     .call(yAxis) 
    .append("text") 
     .attr("class", "label") 
     .attr("transform", "rotate(-90)") 
     .attr("y", 6) 
     .attr("dy", ".71em") 
     .style("text-anchor", "end") 
     .text(yVar); 

    // draw dots 
    var dot = svg.selectAll(".dot") 
     .data(data) 
     .enter() 
     .append("circle") 
     .attr("class", "dot") 
     .attr("r", radius) 
     .attr("cx", xMap) 
     .attr("cy", yMap) 
     .style("fill", function(d) { return color(cValue(d));}) 
     .on("mouseover", function(d) { 
      tooltip.transition() 
       .duration(200) 
       .style("opacity", .9); 
      tooltip.html(d[SN] + "<br/> (" + xValue(d) 
      + ", " + yValue(d) + ")") 
       .style("left", (d3.event.pageX + 5) + "px") 
       .style("top", (d3.event.pageY - 28) + "px"); 
     }) 
     .on("mouseout", function(d) { 
      tooltip.transition() 
       .duration(500) 
       .style("opacity", 0); 
     }); 

    // draw legend 

    var legend = svg.selectAll(".legend") 
     .data(color.domain().slice()) 
     .enter().append("g") 
     .attr("class", "legend") 
     .attr("transform", function(d, i) { return "translate(0," + i * 20 + ")"; }); 

    // draw legend colored rectangles 
    legend.append("rect") 
     .attr("x", width - 18) 
     .attr("width", 18) 
     .attr("height", 18) 
     .style("fill", color) 

     .on("click", function (d){ 
     default = d; 
     return change(); 
     }); 

    // draw legend text 
    legend.append("text") 
     .attr("x", width - 24) 
     .attr("y", 9) 
     .attr("dy", ".35em") 
     .style("text-anchor", "end") 
     .text(function(d) { return d;}) 
     .on("click", function (d) { 
     default = d; 
     return change(); 
     }); 

}; 

</script> 
</body> 

sample.csv

location type value1 value2 value3 
A  high 1  -2  -5 
B  medium 2  3   4 
C  low  4  1   2 
C  medium 6  3   4 
A  high 4  5   6 
D  low  -1  3   2 

回答

0

我找到了一種方法,包括傳說中的所有類型。首先,從列「type」中提取唯一類型,並將它們作爲數組保存在「legend_keys」中。第二,不是預先定義「默認」,而是將「legend_keys」中的第一個類型設置爲默認值。但下一個默認值將由點擊圖例外的事件設置。

d3.csv("sample.csv", function(error, data) { 
    formatted = data; 
    var nest = d3.nest() 
    .key(function(d) { return d[cVar]; }) 
    .entries(formatted); 

    console.log(nest); 

    legend_keys = nest.map(function(o){return o.key}); 
    default = legend_keys[0]; 
    //console.log(legend_keys[0]); 
    draw(); 
}); 

最後,在定義圖例時,請將「legend_keys」作爲數據讀取,如下所示。 通過這樣做,我總是可以保留圖例中的所有類型。

var legend = svg.selectAll(".legend") 
     .data(legend_keys) 
     .enter().append("g") 
     .attr("class", "legend") 
     .attr("transform", function(d, i) { return "translate(0," + i * 20 + ")"; }) 
     .on("click", function (d){ 
     default = d; 
     console.log(default); 
     return change(); 
     });