2015-02-09 108 views
4

我有一个基于此示例http://bl.ocks.org/mbostock/3887118散点图。用d3制作交互式散点图?

我想要做的是通过允许用户选择x和y尺寸以及基于数据文件中某一列的圆圈大小来添加交互性。当他们选择一些东西时,图表应该自动缩放轴线。

我该如何去做这件事? 这是我的代码到目前为止:http://plnkr.co/edit/ZCdEBa79Y85Koz7MepXw?p=preview

谢谢。

<!DOCTYPE html> 
<meta charset="utf-8"> 
<style> 

/*set the axis line color, dot stroke, font size, and font position*/ 
body { 
    font: 15px sans-serif; 
} 

.name{ 
    position: relative; 
    top: 90px; 
    text-align: left; 
    font-weight: bold; 
} 

.title { 
    position: relative; 
    text-align: left; 
    font-size: 25px; 
} 

.axis path, 
.axis line { 
    fill: none; 
    stroke: #000; 
    shape-rendering: crispEdges; 
} 

.dot { 
    stroke: #000; 
} 

#filter { 
    position: absolute; 
} 

#mark { 
    padding-left: 150px; 
    position: inherit; 
} 

#xAXs { 
    position: relative; 
    left: 290px; 
    bottom: 30px; 
} 

#yAXs { 
position: relative; 
bottom: 30px; 
left: 315px; 

} 

#label { 
position: absolute; 
top: 599px; 
bottom: 125px; 
left: 300px; 
right: 0px; 
} 

#label2 { 
position: absolute; 
top: 599px; 
bottom: 125px; 
left: 430px; 
right: 0px; 
} 

</style> 

<body> 


<script src="d3.min.js"></script> 

<script> 

var margin = {top: 20, right: 20, bottom: 30, left: 40}, 
    width = 960 - margin.left - margin.right, 
    height = 500 - margin.top - margin.bottom; 


var x = d3.scale.linear() 
    .range([0, width]); 

var y = d3.scale.linear() 
    .range([height, 0]); 


var color = d3.scale.category10(); 

var xAxis = d3.svg.axis() 
    .scale(x) 
    .orient("bottom"); 

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


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


d3.csv("iris.csv", function(error, data) { 
    data.forEach(function(d) { 
    d.petalLength = +d.petalLength; 
    d.petalWidth = +d.petalWidth; 
    d.sepalLength = +d.sepalLength; 
    d.sepalWidth = +d.sepalWidth; 
    }); 

    x.domain(d3.extent(data, function(d) { return d.petalWidth; })).nice(); 
    y.domain(d3.extent(data, function(d) { return d.petalLength; })).nice(); 

    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("Petal Width (cm)"); 

    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("Petal Length (cm)") 

var circles = svg.selectAll(".dot") 
     .data(data) 
    .enter().append("circle") 
     .attr("class", "dot") 
     .attr("r", 3.5) 
     .attr("cx", function(d) { return x(d.petalWidth); }) 
     .attr("cy", function(d) { return y(d.petalLength); }) 
     .style("fill", function(d) { return color(d.species); }); 


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


    legend.append("rect") 
     .attr("x", width - 18) 
     .attr("width", 18) 
     .attr("height", 18) 
     .style("fill", color); 


    legend.append("text") 
     .attr("x", width - 24) 
     .attr("y", 9) 
     .attr("dy", ".35em") 
     .style("text-anchor", "end") 
     .text(function(d) { return d; }); 



    d3.selectAll("[name=v]").on("change", function() { 
     var selected = this.value; 
     display = this.checked ? "inline" : "none"; 


    svg.selectAll(".dot") 
     .filter(function(d) {return selected == d.species;}) 
     .attr("display", display); 
     }); 



    d3.selectAll("[name=sepal]").on("change", function(d) { 
    radius = this.value; 


    svg.selectAll(".dot") 
    console.log(radius); 
    circles.attr("r", radius); 
    }); 



    d3.select("[name=xAX]").on("change", function(){ 
    xAxy = this.value; 
    console.log(xAxy) 
    }) 

    d3.select("[name=yAX]").on("change", function(){ 
    yAxy = this.value; 
    console.log(yAxy) 
    }) 

}); 

</script> 
<br><br> 


    <div id="filter"> 
    <b>Species Filter:</b> 
     <br> 
    <input name='v' value="Iris-setosa" type="checkbox" checked>Iris-setosa 
    </input> 
     <br> 
    <input name="v" value="Iris-versicolor" type="checkbox" checked >Iris-versicolor 
    </input> 
     <br> 
    <input name="v" value="Iris-virginica" type="checkbox" checked >Iris-virginica 
    </input> 
    </div> 


    <form id="mark"> 
    <b>Size of Mark:</b> 
    <div><input type="radio" name="sepal" value='sepalWidth'>Sepal Width</div> 
    <div><input type="radio" name="sepal" value="sepalLength">Sepal Length</div> 
    </form> 

<div id="label"><b>x-Axis:</b></div> 
    <select name="xAX" id="xAXs"> 
     <option value ="petalWidth">petalWidth</option> 
     <option value ="petalLength">petalLength</option> 
     <option value ="sepalLength">sepalLength</option> 
     <option value ="sepalWidth">sepalWidth</option> 
    </select> 

<div id="label2"><b>y-Axis:</b></div> 
    <select name="yAX" id="yAXs"> 
     <option value ="petalLength">petalLength</option> 
     <option value ="petalWidth">petalWidth</option> 
     <option value ="sepalLength">sepalLength</option> 
     <option value ="sepalWidth">sepalWidth</option> 
    </select> 

    <br> 
</body> 

回答

2

试试这个plunkr:http://plnkr.co/edit/MkZcXJPS7hrcWh3M0MZ1?p=preview

你是几乎没有,我刚更新了几个自己的函数。下面介绍的亮点:

d3.selectAll("[name=sepal]").on("change", function(d) { 
    radius = this.value; 

    svg.selectAll(".dot") 
    console.log(radius); 
    circles.attr("r", function(d) { return d[radius]; }); 
}); 

要设置radius到要读半径CSV列,所以现在你只需要更新你的社交圈半径在svg,这是基本上和你最初设置时一样。

d3.select("[name=xAX]").on("change", function(){ 
    xAxy = this.value; 
    console.log(xAxy) 
    x.domain(d3.extent(data, function(d) { return d[xAxy]; })).nice(); 

    svg.select(".x.axis").transition().call(xAxis); 

    svg.selectAll(".dot").transition().attr("cx", function(d) { 
     return x(d[xAxy]); 
    }); 
    svg.selectAll(".x.axis").selectAll("text.label").text(axisNames[xAxy] + " (cm)"); 
}); 

d3.select("[name=yAX]").on("change", function(){ 
    yAxy = this.value; 
    console.log(yAxy) 
    y.domain(d3.extent(data, function(d) { return d[yAxy]; })).nice(); 
    svg.select(".y.axis").transition().call(yAxis); 
    svg.selectAll(".dot").transition().attr("cy", function(d) { 
     return y(d[yAxy]); 
    }); 
    svg.selectAll(".y.axis").selectAll("text.label").text(axisNames[yAxy] + " (cm)"); 
}); 

xy轴的变化基本上是彼此相同的,与被引用只是轴线得到改变。在这里我做:

  1. 更新与新的范围中的域(基于xAxyyAxy值)
  2. 更新在svg实际轴通过建立一个过渡并调用xAxisyAxis组件。
  3. 更新每个.dot
  4. 更新text在轴上通过在一个新的数组(axisNames)查找它的cxcy位置这给该变量的一个相当打印被作图。
2

你的问题是问很多。通常动态d3可视化遵循输入,退出和更新模式。有一些greattutorial's在那里让你开始。

要修复您的特定代码,您分为三部分。第一初始化图的非更新-能够部分:

var margin = {top: 20, right: 20, bottom: 30, left: 40}, 
    width = 500 - margin.left - margin.right, 
    height = 500 - margin.top - margin.bottom; 

var x = d3.scale.linear() 
    .range([0, width]); 

var y = d3.scale.linear() 
    .range([height, 0]); 

var color = d3.scale.category10(); 

var xAxis = d3.svg.axis() 
    .scale(x) 
    .orient("bottom"); 

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

var svg = d3.select("body").insert("svg",":first-child") 
    .attr("width", width + margin.left + margin.right) 
    .attr("height", height + margin.top + margin.bottom) 
    .append("g") 
    .attr("transform", "translate(" + margin.left + "," + margin.top + ")"); 

// keep reference to axises 
var xg = svg.append("g") 
     .attr("class", "x axis") 
     .attr("transform", "translate(0," + height + ")"); 
xg 
    .append("text") 
    .attr("class", "label") 
    .attr("x", width) 
    .attr("y", -6) 
    .style("text-anchor", "end"); 

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

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

legend.append("rect") 
    .attr("x", width - 18) 
    .attr("width", 18) 
    .attr("height", 18) 
    .style("fill", color); 

legend.append("text") 
    .attr("x", width - 24) 
    .attr("y", 9) 
    .attr("dy", ".35em") 
    .style("text-anchor", "end") 
    .text(function(d) { return d; }); 

然后,在功能包住更新能够部分:

function update(){ 

    // get user selections 
    var xVar = d3.select('#xAXs').node().value, 
    yVar = d3.select('#yAXs').node().value; 

    var checks = {}; 
    d3.selectAll('input[type=checkbox]').each(function(){ 
    checks[this.value] = this.checked; 
    }); 

    var radAttr = d3.select('input[type=radio]:checked').node().value; 

    // filter data based on user selections 
    var data = baseData.filter(function(d,i){ 
    d.x = d[xVar]; // create/modify a x,y so that d3 will know it's an update 
    d.y = d[yVar]; 
    return checks[d.species]; 
    }); 

    // set domains 
    x.domain(d3.extent(data, function(d) { return d.x; })).nice(); 
    y.domain(d3.extent(data, function(d) { return d.y; })).nice(); 

    xg.call(xAxis); 
    yg.call(yAxis); 

    xg.select("text").text(xVar); 
    yg.select("text").text(yVar); 

    // on enter 
    var circles = svg.selectAll(".dot") 
    .data(data); 

    circles.enter() 
    .append("circle") 
    .attr("class", "dot"); 

    circles.exit().remove(); 

    // on update 
    circles.attr("cx", function(d) { return x(d.x); }) 
    .attr("cy", function(d) { return y(d.y); }) 
    .style("fill", function(d) { return color(d.species); }) 
    .attr("r", function(d){ return d[radAttr]; }); 
} 

最后触发用户动作更新:

d3.selectAll('select').on('change',function(){ 
    update(); 
}); 

d3.selectAll('input').on('click', function(){ 
    update(); 
}) 

这是一个example把它放在一起。