我正在尝试将圆圈添加到以下折线图示例中的数据点:https://ibb.co/cnHqgb
要生成圆圈,我使用了以下内容:
onHandleIntent(Intent)
然而,正如https://bl.ocks.org/ProQuestionAsker/8382f70af7f4a7355827c6dc4ee8817d所见,每个水果的所有圆圈。我想只根据线条显示所选水果的圆圈。
非常感谢 詹姆斯
答案 0 :(得分:2)
您会看到每个水果的圆圈,因为您没有根据下拉选项过滤数据。
这是一个代码片段,用于数据过滤并附加点:
var dataAsCsv = `Month,Sales,Fruit,Year
Jan,87,strawberry,2016
Feb,3,strawberry,2016
Mar,89,strawberry,2016
Apr,56,strawberry,2016
May,1,strawberry,2016
Jun,17,strawberry,2016
Jul,59,strawberry,2016
Aug,43,strawberry,2016
Sep,16,strawberry,2016
Oct,94,strawberry,2016
Nov,99,strawberry,2016
Dec,53,strawberry,2016
Jan,93,grape,2016
Feb,8,grape,2016
Mar,95,grape,2016
Apr,62,grape,2016
May,5,grape,2016
Jun,24,grape,2016
Jul,62,grape,2016
Aug,49,grape,2016
Sep,18,grape,2016
Oct,101,grape,2016
Nov,103,grape,2016
Dec,53,grape,2016
Jan,94,blueberry,2016
Feb,15,blueberry,2016
Mar,95,blueberry,2016
Apr,64,blueberry,2016
May,11,blueberry,2016
Jun,33,blueberry,2016
Jul,64,blueberry,2016
Aug,53,blueberry,2016
Sep,27,blueberry,2016
Oct,103,blueberry,2016
Nov,108,blueberry,2016
Dec,62,blueberry,2016
Jan,80,strawberry,2015
Feb,0,strawberry,2015
Mar,71,strawberry,2015
Apr,51,strawberry,2015
May,3,strawberry,2015
Jun,11,strawberry,2015
Jul,56,strawberry,2015
Aug,34,strawberry,2015
Sep,12,strawberry,2015
Oct,75,strawberry,2015
Nov,94,strawberry,2015
Dec,46,strawberry,2015
Jan,76,grape,2015
Feb,0,grape,2015
Mar,78,grape,2015
Apr,58,grape,2015
May,10,grape,2015
Jun,22,grape,2015
Jul,47,grape,2015
Aug,36,grape,2015
Sep,18,grape,2015
Oct,86,grape,2015
Nov,98,grape,2015
Dec,40,grape,2015
Jan,79,blueberry,2015
Feb,0,blueberry,2015
Mar,78,blueberry,2015
Apr,49,blueberry,2015
May,5,blueberry,2015
Jun,31,blueberry,2015
Jul,62,blueberry,2015
Aug,49,blueberry,2015
Sep,7,blueberry,2015
Oct,86,blueberry,2015
Nov,100,blueberry,2015
Dec,46,blueberry,2015`;
// Set the margins
var margin = {top: 60, right: 100, bottom: 20, left: 80},
width = 850 - margin.left - margin.right,
height = 370 - margin.top - margin.bottom;
// Parse the month variable
var parseMonth = d3.timeParse("%b");
var formatMonth = d3.timeFormat("%b");
var formatYear = d3.timeFormat("%Y");
var parseYear = d3.timeParse("%Y");
// Set the ranges
var x = d3.scaleTime().domain([parseMonth("Jan"), parseMonth("Dec")]).range([0, width]);
var y = d3.scaleLinear().range([height, 0]);
// Define the line
var valueLine = d3.line()
.x(function(d) { return x(d.Month); })
.y(function(d) { return y(+d.Sales); })
// Create the svg canvas in the "graph" div
var svg = d3.select("#graph")
.append("svg")
.style("width", width + margin.left + margin.right + "px")
.style("height", height + margin.top + margin.bottom + "px")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform","translate(" + margin.left + "," + margin.top + ")")
.attr("class", "svg");
var data = d3.csvParse(dataAsCsv);
// Format the data
data.forEach(function(d) {
d.Month = parseMonth(d.Month);
d.Sales = +d.Sales;
d.Fruit = d.Fruit;
d.Year = formatYear(parseYear(+d.Year));
});
var nest = d3.nest()
.key(function(d){
return d.Fruit;
})
.key(function(d){
return d.Year;
})
.entries(data)
// Scale the range of the data
x.domain(d3.extent(data, function(d) { return d.Month; }));
y.domain([0, d3.max(data, function(d) { return d.Sales; })]);
// Set up the x axis
var xaxis = svg.append("g")
.attr("transform", "translate(0," + height + ")")
.attr("class", "x axis")
.call(d3.axisBottom(x)
.ticks(d3.timeMonth)
.tickSize(0, 0)
.tickFormat(d3.timeFormat("%B"))
.tickSizeInner(0)
.tickPadding(10));
// Add the Y Axis
var yaxis = svg.append("g")
.attr("class", "y axis")
.call(d3.axisLeft(y)
.ticks(5)
.tickSizeInner(0)
.tickPadding(6)
.tickSize(0, 0));
// Add a label to the y axis
svg.append("text")
.attr("transform", "rotate(-90)")
.attr("y", 0 - 60)
.attr("x", 0 - (height / 2))
.attr("dy", "1em")
.style("text-anchor", "middle")
.text("Monthly Sales")
.attr("class", "y axis label");
svg.append('g').classed('data-points', true);
// Create a dropdown
var fruitMenu = d3.select("#fruitDropdown")
fruitMenu
.append("select")
.selectAll("option")
.data(nest)
.enter()
.append("option")
.attr("value", function(d){
return d.key;
})
.text(function(d){
return d.key;
})
// Function to create the initial graph
var initialGraph = function(fruit){
// Filter the data to include only fruit of interest
var selectFruit = nest.filter(function(d){
return d.key == fruit;
})
var selectFruitGroups = svg.selectAll(".fruitGroups")
.data(selectFruit, function(d){
return d ? d.key : this.key;
})
.enter()
.append("g")
.attr("class", "fruitGroups")
var initialPath = selectFruitGroups.selectAll(".line")
.data(function(d) { return d.values; })
.enter()
.append("path")
initialPath
.attr("d", function(d){
return valueLine(d.values)
})
.attr("class", "line")
svg.select('g.data-points').selectAll("dot")
.data(data.filter(function(d) {
return d.Fruit === fruit;
}))
.enter().append("circle").classed('dot', true)
.attr("r", 3)
.style("fill", "pink").style('stroke', '#000')
.attr("cx", function(d) { return x(d.Month); })
.attr("cy", function(d) { return y(+d.Sales); });
}
// Create initial graph
initialGraph("strawberry")
// Update the data
var updateGraph = function(fruit){
// Filter the data to include only fruit of interest
var selectFruit = nest.filter(function(d){
return d.key == fruit;
})
// Select all of the grouped elements and update the data
var selectFruitGroups = svg.selectAll(".fruitGroups")
.data(selectFruit)
// Select all the lines and transition to new positions
selectFruitGroups.selectAll("path.line")
.data(function(d){
return (d.values);
})
.transition()
.duration(1000)
.attr("d", function(d){
return valueLine(d.values)
});
var circles = svg.select('g.data-points').selectAll(".dot")
.data(data.filter(function(d) {
return d.Fruit === fruit;
}));
circles
.enter().append("circle")
.merge(circles).classed('data-point', true)
.attr("r", 3)
.style("fill", "pink").style('stroke', '#000')
.transition().duration(1000)
.attr("cx", function(d) { return x(d.Month); })
.attr("cy", function(d) { return y(+d.Sales); });
}
// Run update function when dropdown selection changes
fruitMenu.on('change', function(){
// Find which fruit was selected from the dropdown
var selectedFruit = d3.select(this)
.select("select")
.property("value")
// Run update function with the selected fruit
updateGraph(selectedFruit)
});
.line {
fill: none;
stroke: #EF5285;
stroke-width: 2px;
}
<script src="https://d3js.org/d3.v4.js"></script>
<div id = "fruitDropdown"></div>
<div id="graph"></div>
重要的代码更改:
我没有直接将circles
添加到SVG
,而是创建了一个包含所有点的组<g class="data-points"></g>
。
svg.append('g').classed('data-points', true);
在两个函数中输入/更新/退出上述组中的所有点,即initialGraph
和updateGraph
<强> InitialGraph:强>
svg.select('g.data-points').selectAll("dot")
.data(data.filter(function(d) {
return d.Fruit === fruit;
}))
.enter().append("circle").classed('dot', true)
.attr("r", 3)
.style("fill", "pink").style('stroke', '#000')
.attr("cx", function(d) { return x(d.Month); })
.attr("cy", function(d) { return y(+d.Sales); });
<强> UpdateGraph:强>
var circles = svg.select('g.data-points').selectAll(".dot")
.data(data.filter(function(d) {
return d.Fruit === fruit;
}));
circles
.enter().append("circle")
.merge(circles).classed('data-point', true)
.attr("r", 3)
.style("fill", "pink").style('stroke', '#000')
.transition().duration(1000)
.attr("cx", function(d) { return x(d.Month); })
.attr("cy", function(d) { return y(+d.Sales); });
观察绑定到圆圈的数据过滤 和应用的过渡,以匹配线条的过渡。
style
来申请fill
而不是attr
。这是一个很好的做法。添加color:pink
不会更改圈子的颜色,但会fill
。另外,我添加了stroke
,以便即使使用粉红色颜色也可以看到它们。你总是可以改变它。我建议您每次提出问题时都添加代码段而不提供链接。对于任何人来说,调试和帮助修复错误都会更容易。
希望这会有所帮助。 :)