首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >d3蜂群图-修改为金字塔状堆叠

d3蜂群图-修改为金字塔状堆叠
EN

Stack Overflow用户
提问于 2019-09-19 18:55:52
回答 2查看 162关注 0票数 1

我在复制描述性统计数据方面取得了相当大的进展,这是可以在here上看到的蜂群风格的视觉效果。为了更方便起见,我还将图片包括在这里:

从我的代码片段中,您将看到除了金字塔样式堆叠之外,我拥有该可视化的所有装饰。

代码语言:javascript
复制
var margins = {top:20, bottom:300, left:30, right:100};

var height = 150;
var width = 900;

var totalWidth = width+margins.left+margins.right;
var totalHeight = height+margins.top+margins.bottom;

var svg = d3.select('body')
    .append('svg')
    .attr('width', totalWidth)
    .attr('height', totalHeight);

var graphGroup = svg.append('g')
    .attr('transform', "translate("+margins.left+","+margins.top+")");

    var xScale = d3.scaleLinear()
        .range([0, width]);






var data = [{'age': 32.0, 'educ': 12.0, 'inlf': 1},
 {'age': 30.0, 'educ': 12.0, 'inlf': 1},
 {'age': 35.0, 'educ': 12.0, 'inlf': 1},
 {'age': 34.0, 'educ': 12.0, 'inlf': 1},
 {'age': 31, 'educ': 14.0, 'inlf': 1},
 {'age': 54.0, 'educ': 12.0, 'inlf': 1},
 {'age': 37.0, 'educ': 16.0, 'inlf': 1},
 {'age': 54.0, 'educ': 12.0, 'inlf': 1},
 {'age': 48.0, 'educ': 12.0, 'inlf': 1},
 {'age': 39.0, 'educ': 12.0, 'inlf': 1},
 {'age': 33.0, 'educ': 12.0, 'inlf': 1},
 {'age': 42.0, 'educ': 11, 'inlf': 1},
 {'age': 30.0, 'educ': 12.0, 'inlf': 1},
 {'age': 43.0, 'educ': 12.0, 'inlf': 1},
 {'age': 43.0, 'educ': 10.0, 'inlf': 1},
 {'age': 35.0, 'educ': 11, 'inlf': 1},
 {'age': 43.0, 'educ': 12.0, 'inlf': 1},
 {'age': 39.0, 'educ': 12.0, 'inlf': 1},
 {'age': 45.0, 'educ': 12.0, 'inlf': 1},
 {'age': 35.0, 'educ': 12.0, 'inlf': 1},
 {'age': 42.0, 'educ': 16.0, 'inlf': 1},
 {'age': 30.0, 'educ': 12.0, 'inlf': 1},
 {'age': 48.0, 'educ': 13.0, 'inlf': 1},
 {'age': 45.0, 'educ': 12.0, 'inlf': 1},
 {'age': 31, 'educ': 12.0, 'inlf': 1},
 {'age': 43.0, 'educ': 17.0, 'inlf': 1},
 {'age': 59.0, 'educ': 12.0, 'inlf': 1},
 {'age': 32.0, 'educ': 12.0, 'inlf': 1},
 {'age': 31, 'educ': 17.0, 'inlf': 1},
 {'age': 42.0, 'educ': 12.0, 'inlf': 1},
 {'age': 50.0, 'educ': 11, 'inlf': 1},
 {'age': 59.0, 'educ': 16.0, 'inlf': 1},
 {'age': 36.0, 'educ': 13.0, 'inlf': 1},
 {'age': 51, 'educ': 12.0, 'inlf': 1},
 {'age': 45.0, 'educ': 16.0, 'inlf': 1},
 {'age': 42.0, 'educ': 11, 'inlf': 1},
 {'age': 46.0, 'educ': 12.0, 'inlf': 1},
 {'age': 46.0, 'educ': 10.0, 'inlf': 1},
 {'age': 51, 'educ': 14.0, 'inlf': 1},
 {'age': 30.0, 'educ': 17.0, 'inlf': 1},
 {'age': 30.0, 'educ': 12.0, 'inlf': 1},
 {'age': 57.0, 'educ': 12.0, 'inlf': 1},
 {'age': 31, 'educ': 16.0, 'inlf': 1},
 {'age': 48.0, 'educ': 12.0, 'inlf': 1},
 {'age': 30.0, 'educ': 12.0, 'inlf': 1},
 {'age': 34.0, 'educ': 12.0, 'inlf': 1},
 {'age': 48.0, 'educ': 16.0, 'inlf': 1},
 {'age': 45.0, 'educ': 12.0, 'inlf': 1},
 {'age': 51, 'educ': 12.0, 'inlf': 1},
 {'age': 30.0, 'educ': 12.0, 'inlf': 1},
 {'age': 46.0, 'educ': 12.0, 'inlf': 1},
 {'age': 58.0, 'educ': 12.0, 'inlf': 1},
 {'age': 37.0, 'educ': 12.0, 'inlf': 1},
 {'age': 52.0, 'educ': 8.0, 'inlf': 1},
 {'age': 52.0, 'educ': 10.0, 'inlf': 1},
 {'age': 31, 'educ': 16.0, 'inlf': 1},
 {'age': 55.0, 'educ': 14.0, 'inlf': 1},
 {'age': 34.0, 'educ': 17.0, 'inlf': 1},
 {'age': 55.0, 'educ': 14.0, 'inlf': 1},
 {'age': 39.0, 'educ': 12.0, 'inlf': 1},
 {'age': 40.0, 'educ': 14.0, 'inlf': 1},
 {'age': 43.0, 'educ': 12.0, 'inlf': 1},
 {'age': 48.0, 'educ': 8.0, 'inlf': 1},
 {'age': 47.0, 'educ': 12.0, 'inlf': 1},
 {'age': 41, 'educ': 12.0, 'inlf': 1},
 {'age': 36.0, 'educ': 8.0, 'inlf': 1},
 {'age': 46.0, 'educ': 17.0, 'inlf': 1},
 {'age': 34.0, 'educ': 12.0, 'inlf': 1},
 {'age': 41, 'educ': 12.0, 'inlf': 1},
 {'age': 51, 'educ': 12.0, 'inlf': 1},
 {'age': 33.0, 'educ': 12.0, 'inlf': 1},
 {'age': 52.0, 'educ': 12.0, 'inlf': 1},
 {'age': 58.0, 'educ': 9.0, 'inlf': 1},
 {'age': 34.0, 'educ': 10.0, 'inlf': 1},
 {'age': 31, 'educ': 12.0, 'inlf': 1},
 {'age': 48.0, 'educ': 12.0, 'inlf': 1},
 {'age': 32.0, 'educ': 12.0, 'inlf': 1},
 {'age': 49.0, 'educ': 17.0, 'inlf': 1},
 {'age': 32.0, 'educ': 15.0, 'inlf': 1},
 {'age': 58.0, 'educ': 12.0, 'inlf': 1},
 {'age': 50.0, 'educ': 6.0, 'inlf': 1},
 {'age': 60.0, 'educ': 14.0, 'inlf': 1},
 {'age': 50.0, 'educ': 12.0, 'inlf': 1},
 {'age': 56.0, 'educ': 14.0, 'inlf': 1},
 {'age': 51, 'educ': 9.0, 'inlf': 1},
 {'age': 54.0, 'educ': 17.0, 'inlf': 1},
 {'age': 59.0, 'educ': 13.0, 'inlf': 1},
 {'age': 46.0, 'educ': 9.0, 'inlf': 1},
 {'age': 46.0, 'educ': 15.0, 'inlf': 1},
 {'age': 39.0, 'educ': 12.0, 'inlf': 0},
 {'age': 44.0, 'educ': 12.0, 'inlf': 0},
 {'age': 33.0, 'educ': 12.0, 'inlf': 0},
 {'age': 33.0, 'educ': 12.0, 'inlf': 0},
 {'age': 48.0, 'educ': 12.0, 'inlf': 0},
 {'age': 30, 'educ': 12.0, 'inlf': 0},
 {'age': 45.0, 'educ': 12.0, 'inlf': 0},
 {'age': 45.0, 'educ': 12.0, 'inlf': 0},
 {'age': 32.0, 'educ': 13.0, 'inlf': 0},
 {'age': 47.0, 'educ': 12.0, 'inlf': 0},
 {'age': 34.0, 'educ': 13.0, 'inlf': 0},
 {'age': 37.0, 'educ': 12.0, 'inlf': 0},
 {'age': 36.0, 'educ': 12.0, 'inlf': 0},
 {'age': 47.0, 'educ': 12.0, 'inlf': 0},
 {'age': 48.0, 'educ': 16.0, 'inlf': 0},
 {'age': 42.0, 'educ': 12.0, 'inlf': 0},
 {'age': 33.0, 'educ': 13.0, 'inlf': 0},
 {'age': 46.0, 'educ': 10, 'inlf': 0},
 {'age': 47.0, 'educ': 12.0, 'inlf': 0},
 {'age': 44.0, 'educ': 12.0, 'inlf': 0},
 {'age': 36.0, 'educ': 12.0, 'inlf': 0},
 {'age': 30, 'educ': 17.0, 'inlf': 0},
 {'age': 55.0, 'educ': 14.0, 'inlf': 0},
 {'age': 45.0, 'educ': 16.0, 'inlf': 0},
 {'age': 47.0, 'educ': 17.0, 'inlf': 0},
 {'age': 46.0, 'educ': 12.0, 'inlf': 0},
 {'age': 49.0, 'educ': 10, 'inlf': 0},
 {'age': 49.0, 'educ': 12.0, 'inlf': 0},
 {'age': 45.0, 'educ': 12.0, 'inlf': 0},
 {'age': 38.0, 'educ': 17.0, 'inlf': 0},
 {'age': 47.0, 'educ': 10.0, 'inlf': 0},
 {'age': 54.0, 'educ': 13.0, 'inlf': 0},
 {'age': 40, 'educ': 10, 'inlf': 0},
 {'age': 43.0, 'educ': 12.0, 'inlf': 0},
 {'age': 30, 'educ': 16.0, 'inlf': 0},
 {'age': 47.0, 'educ': 17.0, 'inlf': 0},
 {'age': 35.0, 'educ': 12.0, 'inlf': 0},
 {'age': 45.0, 'educ': 16.0, 'inlf': 0},
 {'age': 33.0, 'educ': 12.0, 'inlf': 0},
 {'age': 54.0, 'educ': 16.0, 'inlf': 0},
 {'age': 35.0, 'educ': 8.0, 'inlf': 0},
 {'age': 30, 'educ': 12.0, 'inlf': 0},
 {'age': 55.0, 'educ': 12.0, 'inlf': 0},
 {'age': 34.0, 'educ': 12.0, 'inlf': 0},
 {'age': 38.0, 'educ': 13.0, 'inlf': 0},
 {'age': 45.0, 'educ': 10, 'inlf': 0},
 {'age': 47.0, 'educ': 12.0, 'inlf': 0},
 {'age': 39.0, 'educ': 12.0, 'inlf': 0},
 {'age': 36.0, 'educ': 14.0, 'inlf': 0},
 {'age': 33.0, 'educ': 12.0, 'inlf': 0},
 {'age': 50.0, 'educ': 12.0, 'inlf': 0},
 {'age': 58.0, 'educ': 12.0, 'inlf': 0},
 {'age': 49.0, 'educ': 17.0, 'inlf': 0},
 {'age': 40, 'educ': 14.0, 'inlf': 0},
 {'age': 50, 'educ': 12.0, 'inlf': 0},
 {'age': 53.0, 'educ': 9.0, 'inlf': 0},
 {'age': 36.0, 'educ': 12.0, 'inlf': 0},
 {'age': 46.0, 'educ': 12.0, 'inlf': 0},
 {'age': 36.0, 'educ': 12.0, 'inlf': 0},
 {'age': 53.0, 'educ': 14.0, 'inlf': 0},
 {'age': 40.0, 'educ': 16.0, 'inlf': 0}];


  var colorScale = d3.scaleLinear()
      .range(["#e7eef8","#003366"]);



  xScale.domain(d3.extent(data, function(d) { return d.educ; }));
  colorScale.domain(d3.extent(data, function(d) {return d.age; }));

  var simulation = d3.forceSimulation(data)
    .force("x", d3.forceX(function(d) {
      return xScale(d.educ);
    }).strength(1))
    .force("y", d3.forceY(function(d) {
      return d.inlf ? height - 75 : height + 100
    }))
    .force("collide", d3.forceCollide(4))
    .stop();

for (var i = 0; i < 120; ++i) simulation.tick();

  graphGroup.append("g")
    .attr("class", "axis axis--x")
    .attr("transform", "translate(0," + height + ")")
    .call(d3.axisBottom(xScale));

  var circles = graphGroup.selectAll(null)
    .data(data)
    .enter()
    .append("circle")
    .attr("r", 3)
    .attr("cx", function(d) {
      return d.x;
    })
    .attr("cy", function(d) {
      return d.y;
    })
    .style('fill', function(d) {return colorScale(d.age)});

graphGroup.append('line')
    .attr('x1', xScale(5))
    .attr('x2', xScale(17))
    .attr('y1', height-5)
    .attr('y2', height-5)
    .style('stroke',"#000");

graphGroup.append('line')
    .attr('x1', xScale(5))
    .attr('x2', xScale(17))
    .attr('y1', height+35)
    .attr('y2', height+35)
    .style('stroke',"#000");

    graphGroup.append('line')
        .attr('x1', xScale(5))
        .attr('x2', xScale(12))
        .attr('y1', height-5)
        .attr('y2', height-5)
        .style('stroke',"#b8cce4")
        .style('stroke-width',"5px");

    graphGroup.append('line')
        .attr('x1', xScale(12))
        .attr('x2', xScale(14))
        .attr('y1', height-5)
        .attr('y2', height-5)
        .style('stroke',"#4f81b9")
        .style('stroke-width',"5px");

        graphGroup.append('rect')
            .attr('x',xScale(12))
            .attr('y', height-10)
            .attr('width', 5)
            .attr('height',10)
            .style('fill', "#f6d18b");

    graphGroup.append('line')
        .attr('x1', xScale(5))
        .attr('x2', xScale(11))
        .attr('y1', height+35)
        .attr('y2', height+35)
        .style('stroke',"#b8cce4")
        .style('stroke-width',"5px");

    graphGroup.append('line')
        .attr('x1', xScale(11))
        .attr('x2', xScale(12))
        .attr('y1', height+35)
        .attr('y2', height+35)
        .style('stroke',"#4f81b9")
        .style('stroke-width',"5px");

        graphGroup.append('rect')
            .attr('x',xScale(11.7))
            .attr('y', height+30)
            .attr('width', 5)
            .attr('height',10)
            .style('fill', "#f6d18b");
代码语言:javascript
复制
.cells path {
  fill: none;
  pointer-events: all;
}

.cells :hover circle {
  fill: red;
}


text {
  font-size: 17px;
  font-family: TW Cen MT;
}

.axis path, .axis line {
  fill: none;
  stroke: none;
}
代码语言:javascript
复制
<script src="https://d3js.org/d3.v5.min.js"></script>

现在,堆叠的形状看起来像是一种椭圆。我还没有找到改变默认形状的方法。

问题

如何修改圆形堆积的默认形状,使其类似于金字塔?它不一定非得是一个完美的金字塔,只是在底部追求更多,在顶部追求更少。我可以预见,对于d.educ=12的数据点,事情可能会特别棘手,因为它是高度饱和的。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2019-09-26 10:40:59

如果不一定要完美,可以通过对模拟施加硬约束并调整力来实现此效果。

硬约束

要形成硬约束(如具有天花板或地板),可以在每个记号后手动移动点。

例如,如果要为height - 15的顶点形成一个底板,并为height + 45的底点形成一个上限,则可以更改:

代码语言:javascript
复制
for (var i = 0; i < 120; ++i) simulation.tick();

至:

代码语言:javascript
复制
for (var i = 0; i < 120; ++i) {
  simulation.tick();
  data.forEach(function (d) {
    if (d.inlf) {
      d.y = Math.min(d.y, height - 15);
    } else {
      d.y = Math.max(d.y, height + 45);
    }    
  });
}

强制设置

在此之后,您可能希望发挥forceXforceY的优势。我还在forceCollide中添加了.iterations,以防您以后需要调整它。这些设置似乎对我来说没什么问题:

代码语言:javascript
复制
var simulation = d3.forceSimulation(data)
  .force("x", d3.forceX(function(d) {
    return xScale(d.educ);
  }).strength(0.05))
  .force("y", d3.forceY(function(d) {
    return d.inlf ? height - 15 : height + 45
  }).strength(0.1))
  .force("collide", d3.forceCollide(4).iterations(1))
  .stop();

对于弱力或重叠圆,可能需要增加刻度迭代次数。在本例中,我将其增加到240。

代码语言:javascript
复制
for (var i = 0; i < 120; ++i) {
  simulation.tick();
  // ...

至:

代码语言:javascript
复制
for (var i = 0; i < 240; ++i) {
  simulation.tick();
  // ...

初始位置

正如评论中指出的,圆圈不是他们应该在的地方!这是由于较弱的力没有将它们从初始位置移动到足够远。为了解决这个问题,我们可以将初始位置设置在我们想要的位置附近。

代码语言:javascript
复制
data.forEach(function (d) {
  d.x = xScale(d.educ);
  d.y = d.inlf ? height - 15 : height + 45;
});

结果

在向上移动这些点之后,总的来说,它看起来如下所示:

代码语言:javascript
复制
var margins = {top:20, bottom:300, left:30, right:100};

var height = 150;
var width = 900;

var totalWidth = width+margins.left+margins.right;
var totalHeight = height+margins.top+margins.bottom;

var svg = d3.select('body')
    .append('svg')
    .attr('width', totalWidth)
    .attr('height', totalHeight);

var graphGroup = svg.append('g')
    .attr('transform', "translate("+margins.left+","+margins.top+")");

    var xScale = d3.scaleLinear()
        .range([0, width]);






var data = [{'age': 32.0, 'educ': 12.0, 'inlf': 1},
 {'age': 30.0, 'educ': 12.0, 'inlf': 1},
 {'age': 35.0, 'educ': 12.0, 'inlf': 1},
 {'age': 34.0, 'educ': 12.0, 'inlf': 1},
 {'age': 31, 'educ': 14.0, 'inlf': 1},
 {'age': 54.0, 'educ': 12.0, 'inlf': 1},
 {'age': 37.0, 'educ': 16.0, 'inlf': 1},
 {'age': 54.0, 'educ': 12.0, 'inlf': 1},
 {'age': 48.0, 'educ': 12.0, 'inlf': 1},
 {'age': 39.0, 'educ': 12.0, 'inlf': 1},
 {'age': 33.0, 'educ': 12.0, 'inlf': 1},
 {'age': 42.0, 'educ': 11, 'inlf': 1},
 {'age': 30.0, 'educ': 12.0, 'inlf': 1},
 {'age': 43.0, 'educ': 12.0, 'inlf': 1},
 {'age': 43.0, 'educ': 10.0, 'inlf': 1},
 {'age': 35.0, 'educ': 11, 'inlf': 1},
 {'age': 43.0, 'educ': 12.0, 'inlf': 1},
 {'age': 39.0, 'educ': 12.0, 'inlf': 1},
 {'age': 45.0, 'educ': 12.0, 'inlf': 1},
 {'age': 35.0, 'educ': 12.0, 'inlf': 1},
 {'age': 42.0, 'educ': 16.0, 'inlf': 1},
 {'age': 30.0, 'educ': 12.0, 'inlf': 1},
 {'age': 48.0, 'educ': 13.0, 'inlf': 1},
 {'age': 45.0, 'educ': 12.0, 'inlf': 1},
 {'age': 31, 'educ': 12.0, 'inlf': 1},
 {'age': 43.0, 'educ': 17.0, 'inlf': 1},
 {'age': 59.0, 'educ': 12.0, 'inlf': 1},
 {'age': 32.0, 'educ': 12.0, 'inlf': 1},
 {'age': 31, 'educ': 17.0, 'inlf': 1},
 {'age': 42.0, 'educ': 12.0, 'inlf': 1},
 {'age': 50.0, 'educ': 11, 'inlf': 1},
 {'age': 59.0, 'educ': 16.0, 'inlf': 1},
 {'age': 36.0, 'educ': 13.0, 'inlf': 1},
 {'age': 51, 'educ': 12.0, 'inlf': 1},
 {'age': 45.0, 'educ': 16.0, 'inlf': 1},
 {'age': 42.0, 'educ': 11, 'inlf': 1},
 {'age': 46.0, 'educ': 12.0, 'inlf': 1},
 {'age': 46.0, 'educ': 10.0, 'inlf': 1},
 {'age': 51, 'educ': 14.0, 'inlf': 1},
 {'age': 30.0, 'educ': 17.0, 'inlf': 1},
 {'age': 30.0, 'educ': 12.0, 'inlf': 1},
 {'age': 57.0, 'educ': 12.0, 'inlf': 1},
 {'age': 31, 'educ': 16.0, 'inlf': 1},
 {'age': 48.0, 'educ': 12.0, 'inlf': 1},
 {'age': 30.0, 'educ': 12.0, 'inlf': 1},
 {'age': 34.0, 'educ': 12.0, 'inlf': 1},
 {'age': 48.0, 'educ': 16.0, 'inlf': 1},
 {'age': 45.0, 'educ': 12.0, 'inlf': 1},
 {'age': 51, 'educ': 12.0, 'inlf': 1},
 {'age': 30.0, 'educ': 12.0, 'inlf': 1},
 {'age': 46.0, 'educ': 12.0, 'inlf': 1},
 {'age': 58.0, 'educ': 12.0, 'inlf': 1},
 {'age': 37.0, 'educ': 12.0, 'inlf': 1},
 {'age': 52.0, 'educ': 8.0, 'inlf': 1},
 {'age': 52.0, 'educ': 10.0, 'inlf': 1},
 {'age': 31, 'educ': 16.0, 'inlf': 1},
 {'age': 55.0, 'educ': 14.0, 'inlf': 1},
 {'age': 34.0, 'educ': 17.0, 'inlf': 1},
 {'age': 55.0, 'educ': 14.0, 'inlf': 1},
 {'age': 39.0, 'educ': 12.0, 'inlf': 1},
 {'age': 40.0, 'educ': 14.0, 'inlf': 1},
 {'age': 43.0, 'educ': 12.0, 'inlf': 1},
 {'age': 48.0, 'educ': 8.0, 'inlf': 1},
 {'age': 47.0, 'educ': 12.0, 'inlf': 1},
 {'age': 41, 'educ': 12.0, 'inlf': 1},
 {'age': 36.0, 'educ': 8.0, 'inlf': 1},
 {'age': 46.0, 'educ': 17.0, 'inlf': 1},
 {'age': 34.0, 'educ': 12.0, 'inlf': 1},
 {'age': 41, 'educ': 12.0, 'inlf': 1},
 {'age': 51, 'educ': 12.0, 'inlf': 1},
 {'age': 33.0, 'educ': 12.0, 'inlf': 1},
 {'age': 52.0, 'educ': 12.0, 'inlf': 1},
 {'age': 58.0, 'educ': 9.0, 'inlf': 1},
 {'age': 34.0, 'educ': 10.0, 'inlf': 1},
 {'age': 31, 'educ': 12.0, 'inlf': 1},
 {'age': 48.0, 'educ': 12.0, 'inlf': 1},
 {'age': 32.0, 'educ': 12.0, 'inlf': 1},
 {'age': 49.0, 'educ': 17.0, 'inlf': 1},
 {'age': 32.0, 'educ': 15.0, 'inlf': 1},
 {'age': 58.0, 'educ': 12.0, 'inlf': 1},
 {'age': 50.0, 'educ': 6.0, 'inlf': 1},
 {'age': 60.0, 'educ': 14.0, 'inlf': 1},
 {'age': 50.0, 'educ': 12.0, 'inlf': 1},
 {'age': 56.0, 'educ': 14.0, 'inlf': 1},
 {'age': 51, 'educ': 9.0, 'inlf': 1},
 {'age': 54.0, 'educ': 17.0, 'inlf': 1},
 {'age': 59.0, 'educ': 13.0, 'inlf': 1},
 {'age': 46.0, 'educ': 9.0, 'inlf': 1},
 {'age': 46.0, 'educ': 15.0, 'inlf': 1},
 {'age': 39.0, 'educ': 12.0, 'inlf': 0},
 {'age': 44.0, 'educ': 12.0, 'inlf': 0},
 {'age': 33.0, 'educ': 12.0, 'inlf': 0},
 {'age': 33.0, 'educ': 12.0, 'inlf': 0},
 {'age': 48.0, 'educ': 12.0, 'inlf': 0},
 {'age': 30, 'educ': 12.0, 'inlf': 0},
 {'age': 45.0, 'educ': 12.0, 'inlf': 0},
 {'age': 45.0, 'educ': 12.0, 'inlf': 0},
 {'age': 32.0, 'educ': 13.0, 'inlf': 0},
 {'age': 47.0, 'educ': 12.0, 'inlf': 0},
 {'age': 34.0, 'educ': 13.0, 'inlf': 0},
 {'age': 37.0, 'educ': 12.0, 'inlf': 0},
 {'age': 36.0, 'educ': 12.0, 'inlf': 0},
 {'age': 47.0, 'educ': 12.0, 'inlf': 0},
 {'age': 48.0, 'educ': 16.0, 'inlf': 0},
 {'age': 42.0, 'educ': 12.0, 'inlf': 0},
 {'age': 33.0, 'educ': 13.0, 'inlf': 0},
 {'age': 46.0, 'educ': 10, 'inlf': 0},
 {'age': 47.0, 'educ': 12.0, 'inlf': 0},
 {'age': 44.0, 'educ': 12.0, 'inlf': 0},
 {'age': 36.0, 'educ': 12.0, 'inlf': 0},
 {'age': 30, 'educ': 17.0, 'inlf': 0},
 {'age': 55.0, 'educ': 14.0, 'inlf': 0},
 {'age': 45.0, 'educ': 16.0, 'inlf': 0},
 {'age': 47.0, 'educ': 17.0, 'inlf': 0},
 {'age': 46.0, 'educ': 12.0, 'inlf': 0},
 {'age': 49.0, 'educ': 10, 'inlf': 0},
 {'age': 49.0, 'educ': 12.0, 'inlf': 0},
 {'age': 45.0, 'educ': 12.0, 'inlf': 0},
 {'age': 38.0, 'educ': 17.0, 'inlf': 0},
 {'age': 47.0, 'educ': 10.0, 'inlf': 0},
 {'age': 54.0, 'educ': 13.0, 'inlf': 0},
 {'age': 40, 'educ': 10, 'inlf': 0},
 {'age': 43.0, 'educ': 12.0, 'inlf': 0},
 {'age': 30, 'educ': 16.0, 'inlf': 0},
 {'age': 47.0, 'educ': 17.0, 'inlf': 0},
 {'age': 35.0, 'educ': 12.0, 'inlf': 0},
 {'age': 45.0, 'educ': 16.0, 'inlf': 0},
 {'age': 33.0, 'educ': 12.0, 'inlf': 0},
 {'age': 54.0, 'educ': 16.0, 'inlf': 0},
 {'age': 35.0, 'educ': 8.0, 'inlf': 0},
 {'age': 30, 'educ': 12.0, 'inlf': 0},
 {'age': 55.0, 'educ': 12.0, 'inlf': 0},
 {'age': 34.0, 'educ': 12.0, 'inlf': 0},
 {'age': 38.0, 'educ': 13.0, 'inlf': 0},
 {'age': 45.0, 'educ': 10, 'inlf': 0},
 {'age': 47.0, 'educ': 12.0, 'inlf': 0},
 {'age': 39.0, 'educ': 12.0, 'inlf': 0},
 {'age': 36.0, 'educ': 14.0, 'inlf': 0},
 {'age': 33.0, 'educ': 12.0, 'inlf': 0},
 {'age': 50.0, 'educ': 12.0, 'inlf': 0},
 {'age': 58.0, 'educ': 12.0, 'inlf': 0},
 {'age': 49.0, 'educ': 17.0, 'inlf': 0},
 {'age': 40, 'educ': 14.0, 'inlf': 0},
 {'age': 50, 'educ': 12.0, 'inlf': 0},
 {'age': 53.0, 'educ': 9.0, 'inlf': 0},
 {'age': 36.0, 'educ': 12.0, 'inlf': 0},
 {'age': 46.0, 'educ': 12.0, 'inlf': 0},
 {'age': 36.0, 'educ': 12.0, 'inlf': 0},
 {'age': 53.0, 'educ': 14.0, 'inlf': 0},
 {'age': 40.0, 'educ': 16.0, 'inlf': 0}];


  var colorScale = d3.scaleLinear()
      .range(["#e7eef8","#003366"]);



  xScale.domain(d3.extent(data, function(d) { return d.educ; }));
  colorScale.domain(d3.extent(data, function(d) {return d.age; }));

  data.forEach(function (d) {
    d.x = xScale(d.educ);
    d.y = d.inlf ? height - 15 : height + 45;
  });

  var simulation = d3.forceSimulation(data)
    .force("x", d3.forceX(function(d) {
      return xScale(d.educ);
    }).strength(0.05))
    .force("y", d3.forceY(function(d) {
      return d.inlf ? height - 15 : height + 45
    }).strength(0.1))
    .force("collide", d3.forceCollide(4).iterations(1))
    .stop();
    
for (var i = 0; i < 240; ++i) {
  simulation.tick();
  data.forEach(function (d) {
    if (d.inlf) {
      d.y = Math.min(d.y, height - 15);
    } else {
      d.y = Math.max(d.y, height + 45);
    }    
  });
}

  graphGroup.append("g")
    .attr("class", "axis axis--x")
    .attr("transform", "translate(0," + height + ")")
    .call(d3.axisBottom(xScale));

  var circles = graphGroup.selectAll(null)
    .data(data)
    .enter()
    .append("circle")
    .attr("r", 3)
    .attr("cx", function(d) {
      return d.x;
    })
    .attr("cy", function(d) {
      return d.y;
    })
    .style('fill', function(d) {return colorScale(d.age)});

graphGroup.append('line')
    .attr('x1', xScale(5))
    .attr('x2', xScale(17))
    .attr('y1', height-5)
    .attr('y2', height-5)
    .style('stroke',"#000");

graphGroup.append('line')
    .attr('x1', xScale(5))
    .attr('x2', xScale(17))
    .attr('y1', height+35)
    .attr('y2', height+35)
    .style('stroke',"#000");

    graphGroup.append('line')
        .attr('x1', xScale(5))
        .attr('x2', xScale(12))
        .attr('y1', height-5)
        .attr('y2', height-5)
        .style('stroke',"#b8cce4")
        .style('stroke-width',"5px");

    graphGroup.append('line')
        .attr('x1', xScale(12))
        .attr('x2', xScale(14))
        .attr('y1', height-5)
        .attr('y2', height-5)
        .style('stroke',"#4f81b9")
        .style('stroke-width',"5px");

        graphGroup.append('rect')
            .attr('x',xScale(12))
            .attr('y', height-10)
            .attr('width', 5)
            .attr('height',10)
            .style('fill', "#f6d18b");

    graphGroup.append('line')
        .attr('x1', xScale(5))
        .attr('x2', xScale(11))
        .attr('y1', height+35)
        .attr('y2', height+35)
        .style('stroke',"#b8cce4")
        .style('stroke-width',"5px");

    graphGroup.append('line')
        .attr('x1', xScale(11))
        .attr('x2', xScale(12))
        .attr('y1', height+35)
        .attr('y2', height+35)
        .style('stroke',"#4f81b9")
        .style('stroke-width',"5px");

        graphGroup.append('rect')
            .attr('x',xScale(11.7))
            .attr('y', height+30)
            .attr('width', 5)
            .attr('height',10)
            .style('fill', "#f6d18b");
代码语言:javascript
复制
.cells path {
  fill: none;
  pointer-events: all;
}

.cells :hover circle {
  fill: red;
}


text {
  font-size: 17px;
  font-family: TW Cen MT;
}

.axis path, .axis line {
  fill: none;
  stroke: none;
}
代码语言:javascript
复制
<script src="https://d3js.org/d3.v5.min.js"></script>

票数 2
EN

Stack Overflow用户

发布于 2019-09-29 03:52:53

来得有点晚,但如果你想要一个更坚固的堆叠金字塔,我会放弃力模拟。下面是一个使用自定义金字塔堆叠算法的自定义实现:

代码语言:javascript
复制
<!DOCTYPE html>
<html>

<head>
  <script src="https://d3js.org/d3.v5.min.js"></script>
</head>

<body>
  <script>
    var margins = {
      top: 20,
      bottom: 300,
      left: 30,
      right: 100
    };

    var height = 150;
    var width = 900;

    var totalWidth = width + margins.left + margins.right;
    var totalHeight = height + margins.top + margins.bottom;

    var svg = d3.select('body')
      .append('svg')
      .attr('width', totalWidth)
      .attr('height', totalHeight);

    var graphGroup = svg.append('g')
      .attr('transform', "translate(" + margins.left + "," + margins.top + ")");

    var xScale = d3.scaleLinear()
      .range([0, width]);

    var data = [{
      'age': 32.0,
      'educ': 12.0,
      'inlf': 1
    }, {
      'age': 30.0,
      'educ': 12.0,
      'inlf': 1
    }, {
      'age': 35.0,
      'educ': 12.0,
      'inlf': 1
    }, {
      'age': 34.0,
      'educ': 12.0,
      'inlf': 1
    }, {
      'age': 31,
      'educ': 14.0,
      'inlf': 1
    }, {
      'age': 54.0,
      'educ': 12.0,
      'inlf': 1
    }, {
      'age': 37.0,
      'educ': 16.0,
      'inlf': 1
    }, {
      'age': 54.0,
      'educ': 12.0,
      'inlf': 1
    }, {
      'age': 48.0,
      'educ': 12.0,
      'inlf': 1
    }, {
      'age': 39.0,
      'educ': 12.0,
      'inlf': 1
    }, {
      'age': 33.0,
      'educ': 12.0,
      'inlf': 1
    }, {
      'age': 42.0,
      'educ': 11,
      'inlf': 1
    }, {
      'age': 30.0,
      'educ': 12.0,
      'inlf': 1
    }, {
      'age': 43.0,
      'educ': 12.0,
      'inlf': 1
    }, {
      'age': 43.0,
      'educ': 10.0,
      'inlf': 1
    }, {
      'age': 35.0,
      'educ': 11,
      'inlf': 1
    }, {
      'age': 43.0,
      'educ': 12.0,
      'inlf': 1
    }, {
      'age': 39.0,
      'educ': 12.0,
      'inlf': 1
    }, {
      'age': 45.0,
      'educ': 12.0,
      'inlf': 1
    }, {
      'age': 35.0,
      'educ': 12.0,
      'inlf': 1
    }, {
      'age': 42.0,
      'educ': 16.0,
      'inlf': 1
    }, {
      'age': 30.0,
      'educ': 12.0,
      'inlf': 1
    }, {
      'age': 48.0,
      'educ': 13.0,
      'inlf': 1
    }, {
      'age': 45.0,
      'educ': 12.0,
      'inlf': 1
    }, {
      'age': 31,
      'educ': 12.0,
      'inlf': 1
    }, {
      'age': 43.0,
      'educ': 17.0,
      'inlf': 1
    }, {
      'age': 59.0,
      'educ': 12.0,
      'inlf': 1
    }, {
      'age': 32.0,
      'educ': 12.0,
      'inlf': 1
    }, {
      'age': 31,
      'educ': 17.0,
      'inlf': 1
    }, {
      'age': 42.0,
      'educ': 12.0,
      'inlf': 1
    }, {
      'age': 50.0,
      'educ': 11,
      'inlf': 1
    }, {
      'age': 59.0,
      'educ': 16.0,
      'inlf': 1
    }, {
      'age': 36.0,
      'educ': 13.0,
      'inlf': 1
    }, {
      'age': 51,
      'educ': 12.0,
      'inlf': 1
    }, {
      'age': 45.0,
      'educ': 16.0,
      'inlf': 1
    }, {
      'age': 42.0,
      'educ': 11,
      'inlf': 1
    }, {
      'age': 46.0,
      'educ': 12.0,
      'inlf': 1
    }, {
      'age': 46.0,
      'educ': 10.0,
      'inlf': 1
    }, {
      'age': 51,
      'educ': 14.0,
      'inlf': 1
    }, {
      'age': 30.0,
      'educ': 17.0,
      'inlf': 1
    }, {
      'age': 30.0,
      'educ': 12.0,
      'inlf': 1
    }, {
      'age': 57.0,
      'educ': 12.0,
      'inlf': 1
    }, {
      'age': 31,
      'educ': 16.0,
      'inlf': 1
    }, {
      'age': 48.0,
      'educ': 12.0,
      'inlf': 1
    }, {
      'age': 30.0,
      'educ': 12.0,
      'inlf': 1
    }, {
      'age': 34.0,
      'educ': 12.0,
      'inlf': 1
    }, {
      'age': 48.0,
      'educ': 16.0,
      'inlf': 1
    }, {
      'age': 45.0,
      'educ': 12.0,
      'inlf': 1
    }, {
      'age': 51,
      'educ': 12.0,
      'inlf': 1
    }, {
      'age': 30.0,
      'educ': 12.0,
      'inlf': 1
    }, {
      'age': 46.0,
      'educ': 12.0,
      'inlf': 1
    }, {
      'age': 58.0,
      'educ': 12.0,
      'inlf': 1
    }, {
      'age': 37.0,
      'educ': 12.0,
      'inlf': 1
    }, {
      'age': 52.0,
      'educ': 8.0,
      'inlf': 1
    }, {
      'age': 52.0,
      'educ': 10.0,
      'inlf': 1
    }, {
      'age': 31,
      'educ': 16.0,
      'inlf': 1
    }, {
      'age': 55.0,
      'educ': 14.0,
      'inlf': 1
    }, {
      'age': 34.0,
      'educ': 17.0,
      'inlf': 1
    }, {
      'age': 55.0,
      'educ': 14.0,
      'inlf': 1
    }, {
      'age': 39.0,
      'educ': 12.0,
      'inlf': 1
    }, {
      'age': 40.0,
      'educ': 14.0,
      'inlf': 1
    }, {
      'age': 43.0,
      'educ': 12.0,
      'inlf': 1
    }, {
      'age': 48.0,
      'educ': 8.0,
      'inlf': 1
    }, {
      'age': 47.0,
      'educ': 12.0,
      'inlf': 1
    }, {
      'age': 41,
      'educ': 12.0,
      'inlf': 1
    }, {
      'age': 36.0,
      'educ': 8.0,
      'inlf': 1
    }, {
      'age': 46.0,
      'educ': 17.0,
      'inlf': 1
    }, {
      'age': 34.0,
      'educ': 12.0,
      'inlf': 1
    }, {
      'age': 41,
      'educ': 12.0,
      'inlf': 1
    }, {
      'age': 51,
      'educ': 12.0,
      'inlf': 1
    }, {
      'age': 33.0,
      'educ': 12.0,
      'inlf': 1
    }, {
      'age': 52.0,
      'educ': 12.0,
      'inlf': 1
    }, {
      'age': 58.0,
      'educ': 9.0,
      'inlf': 1
    }, {
      'age': 34.0,
      'educ': 10.0,
      'inlf': 1
    }, {
      'age': 31,
      'educ': 12.0,
      'inlf': 1
    }, {
      'age': 48.0,
      'educ': 12.0,
      'inlf': 1
    }, {
      'age': 32.0,
      'educ': 12.0,
      'inlf': 1
    }, {
      'age': 49.0,
      'educ': 17.0,
      'inlf': 1
    }, {
      'age': 32.0,
      'educ': 15.0,
      'inlf': 1
    }, {
      'age': 58.0,
      'educ': 12.0,
      'inlf': 1
    }, {
      'age': 50.0,
      'educ': 6.0,
      'inlf': 1
    }, {
      'age': 60.0,
      'educ': 14.0,
      'inlf': 1
    }, {
      'age': 50.0,
      'educ': 12.0,
      'inlf': 1
    }, {
      'age': 56.0,
      'educ': 14.0,
      'inlf': 1
    }, {
      'age': 51,
      'educ': 9.0,
      'inlf': 1
    }, {
      'age': 54.0,
      'educ': 17.0,
      'inlf': 1
    }, {
      'age': 59.0,
      'educ': 13.0,
      'inlf': 1
    }, {
      'age': 46.0,
      'educ': 9.0,
      'inlf': 1
    }, {
      'age': 46.0,
      'educ': 15.0,
      'inlf': 1
    }, {
      'age': 39.0,
      'educ': 12.0,
      'inlf': 0
    }, {
      'age': 44.0,
      'educ': 12.0,
      'inlf': 0
    }, {
      'age': 33.0,
      'educ': 12.0,
      'inlf': 0
    }, {
      'age': 33.0,
      'educ': 12.0,
      'inlf': 0
    }, {
      'age': 48.0,
      'educ': 12.0,
      'inlf': 0
    }, {
      'age': 30,
      'educ': 12.0,
      'inlf': 0
    }, {
      'age': 45.0,
      'educ': 12.0,
      'inlf': 0
    }, {
      'age': 45.0,
      'educ': 12.0,
      'inlf': 0
    }, {
      'age': 32.0,
      'educ': 13.0,
      'inlf': 0
    }, {
      'age': 47.0,
      'educ': 12.0,
      'inlf': 0
    }, {
      'age': 34.0,
      'educ': 13.0,
      'inlf': 0
    }, {
      'age': 37.0,
      'educ': 12.0,
      'inlf': 0
    }, {
      'age': 36.0,
      'educ': 12.0,
      'inlf': 0
    }, {
      'age': 47.0,
      'educ': 12.0,
      'inlf': 0
    }, {
      'age': 48.0,
      'educ': 16.0,
      'inlf': 0
    }, {
      'age': 42.0,
      'educ': 12.0,
      'inlf': 0
    }, {
      'age': 33.0,
      'educ': 13.0,
      'inlf': 0
    }, {
      'age': 46.0,
      'educ': 10,
      'inlf': 0
    }, {
      'age': 47.0,
      'educ': 12.0,
      'inlf': 0
    }, {
      'age': 44.0,
      'educ': 12.0,
      'inlf': 0
    }, {
      'age': 36.0,
      'educ': 12.0,
      'inlf': 0
    }, {
      'age': 30,
      'educ': 17.0,
      'inlf': 0
    }, {
      'age': 55.0,
      'educ': 14.0,
      'inlf': 0
    }, {
      'age': 45.0,
      'educ': 16.0,
      'inlf': 0
    }, {
      'age': 47.0,
      'educ': 17.0,
      'inlf': 0
    }, {
      'age': 46.0,
      'educ': 12.0,
      'inlf': 0
    }, {
      'age': 49.0,
      'educ': 10,
      'inlf': 0
    }, {
      'age': 49.0,
      'educ': 12.0,
      'inlf': 0
    }, {
      'age': 45.0,
      'educ': 12.0,
      'inlf': 0
    }, {
      'age': 38.0,
      'educ': 17.0,
      'inlf': 0
    }, {
      'age': 47.0,
      'educ': 10.0,
      'inlf': 0
    }, {
      'age': 54.0,
      'educ': 13.0,
      'inlf': 0
    }, {
      'age': 40,
      'educ': 10,
      'inlf': 0
    }, {
      'age': 43.0,
      'educ': 12.0,
      'inlf': 0
    }, {
      'age': 30,
      'educ': 16.0,
      'inlf': 0
    }, {
      'age': 47.0,
      'educ': 17.0,
      'inlf': 0
    }, {
      'age': 35.0,
      'educ': 12.0,
      'inlf': 0
    }, {
      'age': 45.0,
      'educ': 16.0,
      'inlf': 0
    }, {
      'age': 33.0,
      'educ': 12.0,
      'inlf': 0
    }, {
      'age': 54.0,
      'educ': 16.0,
      'inlf': 0
    }, {
      'age': 35.0,
      'educ': 8.0,
      'inlf': 0
    }, {
      'age': 30,
      'educ': 12.0,
      'inlf': 0
    }, {
      'age': 55.0,
      'educ': 12.0,
      'inlf': 0
    }, {
      'age': 34.0,
      'educ': 12.0,
      'inlf': 0
    }, {
      'age': 38.0,
      'educ': 13.0,
      'inlf': 0
    }, {
      'age': 45.0,
      'educ': 10,
      'inlf': 0
    }, {
      'age': 47.0,
      'educ': 12.0,
      'inlf': 0
    }, {
      'age': 39.0,
      'educ': 12.0,
      'inlf': 0
    }, {
      'age': 36.0,
      'educ': 14.0,
      'inlf': 0
    }, {
      'age': 33.0,
      'educ': 12.0,
      'inlf': 0
    }, {
      'age': 50.0,
      'educ': 12.0,
      'inlf': 0
    }, {
      'age': 58.0,
      'educ': 12.0,
      'inlf': 0
    }, {
      'age': 49.0,
      'educ': 17.0,
      'inlf': 0
    }, {
      'age': 40,
      'educ': 14.0,
      'inlf': 0
    }, {
      'age': 50,
      'educ': 12.0,
      'inlf': 0
    }, {
      'age': 53.0,
      'educ': 9.0,
      'inlf': 0
    }, {
      'age': 36.0,
      'educ': 12.0,
      'inlf': 0
    }, {
      'age': 46.0,
      'educ': 12.0,
      'inlf': 0
    }, {
      'age': 36.0,
      'educ': 12.0,
      'inlf': 0
    }, {
      'age': 53.0,
      'educ': 14.0,
      'inlf': 0
    }, {
      'age': 40.0,
      'educ': 16.0,
      'inlf': 0
    }];

    var colorScale = d3.scaleLinear()
      .range(["#e7eef8", "#003366"]);

    xScale.domain(d3.extent(data, function(d) {
      return d.educ;
    }));
    colorScale.domain(d3.extent(data, function(d) {
      return d.age;
    }));

    // bin the data based on top bottom and x-position
    var bins = d3.nest()
      .key(function(d) { return [(d.inlf ? 1 : 0), d.educ] })
      .entries(data);

    // calculate positions (build the pyramid)
    var r = 3;
    bins.forEach( (bin) => {
      var ds = bin.values;
      var br = 1, n = 1;
      while (br < ds.length){
        br += n; n += 1;
      }
      n -= 1
      var c = 0; rn = n; g = 0;
      var s = r * 2 + 3;
      ds.forEach((d)=>{
        d.y = (rn - n) * s;
        d.x = (c * s);
        d.g = g;
        c += 1;
        if (c == n){
          c = 0;
          n -= 1;
          g += 1
        }
      });
    });
    
    // re-bin by age and row so that we can traslate the rows
    var binsAndRow = d3.nest()
      .key(function(d) { return [(d.inlf ? 1 : 0), d.educ]; })
      .key(function(d) { return d.g; })
      .entries(data);
    
    // draw circles
    var x = graphGroup.selectAll("g")
      .data(binsAndRow)
      .enter()
      .append("g")
      .attr("class", (d) => "bin " + "b" + d.key)
      .selectAll("g")
      .data( (d) => {
        return d.values
      })
      .enter()
      .append("g")
      .attr("class", (d) => "row " + "r" + d.key)
      .selectAll("circle")
      .data( (d) => {
        return d.values
      })
      .enter()
      .append("circle")
      .attr("r", 3)
      .attr("cx", function(d) {
        return d.x;
      })
      .attr("cy", function(d) {
        return d.y;
      })
      .style('fill', function(d) {return colorScale(d.age)});
    
    // position the pyramids
    graphGroup
      .selectAll(".bin")
      .attr("transform", function(d){
        var bb = this.getBBox(),
            xPos = (xScale(d.key.split(",")[1]) - bb.width/2),
            isFlip = d.key.startsWith("1"),
            yPos = isFlip ? height - 20 : height + 50,
            t = "translate(" + xPos + "," + yPos + ")";
        if (isFlip) t+= "scale(1,-1)";
        return t;
      })
      .selectAll(".row")
      .attr("transform", function(d) {
        var pbb = this.parentNode.getBBox();
        var bb = this.getBBox();
        return "translate(" + ((pbb.width - bb.width)/2) + "," + 0 + ")";
      });

    graphGroup.append("g")
      .attr("class", "axis axis--x")
      .attr("transform", "translate(0," + height + ")")
      .call(d3.axisBottom(xScale));

    graphGroup.append('line')
      .attr('x1', xScale(5))
      .attr('x2', xScale(17))
      .attr('y1', height - 5)
      .attr('y2', height - 5)
      .style('stroke', "#000");

    graphGroup.append('line')
      .attr('x1', xScale(5))
      .attr('x2', xScale(17))
      .attr('y1', height + 35)
      .attr('y2', height + 35)
      .style('stroke', "#000");

    graphGroup.append('line')
      .attr('x1', xScale(5))
      .attr('x2', xScale(12))
      .attr('y1', height - 5)
      .attr('y2', height - 5)
      .style('stroke', "#b8cce4")
      .style('stroke-width', "5px");

    graphGroup.append('line')
      .attr('x1', xScale(12))
      .attr('x2', xScale(14))
      .attr('y1', height - 5)
      .attr('y2', height - 5)
      .style('stroke', "#4f81b9")
      .style('stroke-width', "5px");

    graphGroup.append('rect')
      .attr('x', xScale(12))
      .attr('y', height - 10)
      .attr('width', 5)
      .attr('height', 10)
      .style('fill', "#f6d18b");

    graphGroup.append('line')
      .attr('x1', xScale(5))
      .attr('x2', xScale(11))
      .attr('y1', height + 35)
      .attr('y2', height + 35)
      .style('stroke', "#b8cce4")
      .style('stroke-width', "5px");

    graphGroup.append('line')
      .attr('x1', xScale(11))
      .attr('x2', xScale(12))
      .attr('y1', height + 35)
      .attr('y2', height + 35)
      .style('stroke', "#4f81b9")
      .style('stroke-width', "5px");

    graphGroup.append('rect')
      .attr('x', xScale(11.7))
      .attr('y', height + 30)
      .attr('width', 5)
      .attr('height', 10)
      .style('fill', "#f6d18b");
      
    
  </script>
</body>

</html>

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/58009457

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档