在d3.js v6中创建小倍数的最佳方法是什么?



我正在尝试使用d3 v6创建具有不同y轴刻度的小型多个条形图。有几个例子在那里(https://flowingdata.com/2014/10/15/linked-small-multiples/)小倍数的d3以前的版本,但不是v6,这似乎有一个很好的数量的变化实现。

我对d3没有太多的经验,所以我可能错过了一些明显的东西,但我不能得到条正确生成,轴正在生成(尽管我认为我生成它们太多次在彼此之上)。

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Small multiple bar charts</title>    
<script src="https://d3js.org/d3.v6.min.js"></script>
</head>
<body>
<div id='vis'></div>
<script type="text/javascript">

// Set the sizing metrics
var width = 150;
var height = 120;
var margin = {top: 15, right: 10, bottom: 40, left: 35};
// Create the axes
var xScale = d3.scaleBand()
.range([0, width])
.padding(0.1);

var yScale = d3.scaleLinear()
.range([height, 0]);
var xAxis = d3.axisBottom()
.scale(xScale);
// Load the data
d3.csv('data.csv').then(function(data) {
data.forEach(function(d) {
d.segment = d.segment;
d.parameter = d.parameter;
d.the_value = +d.the_value;
});

// set the x domain
xScale.domain(data.map(function(d) { return d.segment; }));
// group the data
metrics = Array.from(
d3.group(data, d => d.parameter), ([key, value]) => ({key, value})
);
// create a separate SVG object for each group
var svg = d3.select('#vis').selectAll('svg')
.data(metrics)
.enter()
.append('svg');
// loop over the data and create the bars
metrics.forEach(function(d, i) {
console.log(d);
console.log(metrics);
yScale.domain([0, d3.max(metrics, function(c) { return c.the_value; })]);
svg.selectAll('.bar')
.data(d)
.enter().append('rect')
.attr('class', 'bar')
.attr('x', function(c) { return xScale(c.segment); })
.attr('width', xScale.bandwidth())
.attr('y', function(c) { return yScale(c.the_value); })
.attr('height', function(c) { return height - yScale(c.the_value); })
.attr('fill', 'teal');
svg.append('g')
.attr('transform', 'translate(0,' + height + ')')
.call(xAxis)
});
});
</script>
</body>
</html>

数据文件如下:

segment,parameter,the_value
A,one,33
A,two,537723
A,three,14
A,four,5
A,five,0.093430759
B,one,76
B,two,137110
B,three,16
B,four,20
B,five,0.893868331
C,one,74
C,two,62020
C,three,25
C,four,14
C,five,0.862952872

最后,我还想获得图表链接,以便当系列A悬停在第一个图形上时,值将显示在所有图形上的每个系列,但第一步是使视觉效果正常工作。

有一些小的改变使它工作:

  • 当您将domain设置在x刻度上时,您只需要唯一的段,例如A, B, C,而不是数据中的完整段列表。

  • 当您创建5个svg时,您可以对它们进行分类,以便在循环遍历度量值时可以分别引用每个svg。第一个小倍数是一类one,第二个小倍数是一类two,等等

  • 使用你正在绘制的指标中的the_values集重置y域-即使用d而不是metrics

  • 当你先循环metrics时,select是该指标的小倍数,然后是selectAll('.bar')

  • d.value传递给data,因为这使得对c.the_value等的引用正常工作

  • 为了防止多次添加x轴,再次selectcall(xAxis)之前为特定的小倍数添加SVG,否则您将添加尽可能多的轴,因为每个小倍数有参数。

我伪造了你的数据,包括随机数据。

请看下面的例子——也许有一个更聪明的方法:

// fake data
var data = ["A", "B", "C"].map(seg => {
return ["one", "two", "three", "four", "five"].map((par, ix) => {
return {
"segment": seg, 
"parameter": par, 
"the_value": (Math.floor(Math.random() * 10) + 1) * (Math.floor(Math.random() * 10 * ix) + 1)
}
});
}).flat();
// Set the sizing metrics
var width = 150;
var height = 120;
var margin = {top: 15, right: 10, bottom: 40, left: 35};
// Create the axes
var xScale = d3.scaleBand()
.range([0, width])
.padding(0.1);
var yScale = d3.scaleLinear()
.range([height, 0]);
var xAxis = d3.axisBottom()
.scale(xScale);

// set the x domain
// put unique segments into the domain e.g. A, B, C
var uniqueSegments = Array.from(new Set(data.map(function(d) {return d.segment;} )));
xScale.domain(uniqueSegments);
// group the data
var metrics = Array.from(
d3.group(data, d => d.parameter), ([key, value]) => ({key, value})
);
// create a separate SVG object for each group
// class each SVG with parameter from metrics
var svg = d3.select('#vis').selectAll('svg')
.data(metrics)
.enter()
.append('svg')
.attr("class", function(d) { return d.value[0].parameter;});
// loop over the data and create the bars
metrics.forEach(function(d, i) {
//console.log(d);
//console.log(metrics);
// reset yScale domain based on the set of the_value's for these metrics
yScale.domain([0, d3.max(d.value, function(c) { return c.the_value; })]);
// select the right svg for this set of metrics
d3.select("svg." + d.value[0].parameter)
.selectAll('.bar')
.data(d.value) // use d.value to get to the the_value
.enter()
.append('rect')
.attr('class', 'bar')
.attr('x', function(c) { return xScale(c.segment); })
.attr('width', xScale.bandwidth())
.attr('y', function(c) { return yScale(c.the_value); })
.attr('height', function(c) { return height - yScale(c.the_value); })
.attr('fill', 'teal');
// call axis just on this SVG
// otherwise calling it 5 times for 5 metrics...
d3.select("svg." + d.value[0].parameter)
.append('g')
.attr('transform', 'translate(0,' + height + ')')
.call(xAxis)

});
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/6.5.0/d3.min.js"></script>
<div id='vis'></div>

相关内容

最新更新