用D3.js创建人口金字塔

时间:2014-07-30 19:09:49

标签: javascript d3.js population census

我需要用D3.js制作一个经典的人口金字塔。与此图像类似的东西: enter image description here

我找到了一些看起来非常好的例子(thisthis),但它们比我正在寻找的更复杂。有谁知道我能看到的一个很好的SIMPLE例子?有什么建议吗?我应该只是制作两个彼此相邻的条形图,每个性别组一个吗?

1 个答案:

答案 0 :(得分:19)

进行这样的可视化的关键是在绘制任何内容之前花费大量时间预先设置布局。

当您需要为图表制作刻度和轴时,您需要使用一些关键测量值来使您的生活更轻松。然后,您可以使用带有翻译的<g>元素,以便在每个&#34;部分&#34;在图表中,您可以在当地坐标中工作。

目标是创建两个镜像区域,如下所示:

two mirrored regions

这将允许您为两个区域之间的x和y维度共享相同的比例。

要定义这些区域,您可以先为svg内部的边距设置一些值,然后创建一个组以放在这些边距内。这是d3可视化中的常见做法,如果您还不熟悉它,那么这是一个学习的好时机。它通常看起来像这样:

var width = 400,
    height = 300;

var margin = {
  top: 20,
  right: 10
  bottom: 40,
  left: 10
};

var svg = d3.select('body').append('svg')
  .attr('width', margin.left + width + margin.right)
  .attr('height', margin.top + height + margin.bottom)
  .append('g')
    .attr('class', 'inner-region')
    .attr('transform', 'translate(' + margin.left + ',' + margin.top + ')');

这是一个很好的做法,因为它允许您在svg文档上为轴标记,标签和标题留出空间,而无需在定位部分可视化本身时考虑该空间。然后,如果您发现需要更多空间,可以在代码顶部调整一个值,而不是重新定位整个图表。

其他重要的点是两个y轴的x坐标。换句话说,男性和女性的人口为零(以下显示为红线)。这些距离是您内部区域中心线的一个设定距离(如下面的蓝线所示):

middle margin

您可以向之前创建的边距对象添加中间边距属性,以引用此值:

margin.middle = 28;

您需要创建变量来存储上面两条红线的位置。现在,我们称之为pointA(男性人口零线的x坐标)和pointB(女性人口的对应点)。

var regionWidth = (width/2) - margin.middle;

var pointA = regionWidth,
    pointB = width - regionWidth;

设置完这些点之后,事情变得更加简单,因为您可以简单地将这些值插入到svg变换中,以将您创建的对象转换为这些位置。

最棘手的部分是两个中心y轴,它们共享一组标签。为此,您需要很好地处理d3.svg.axis()如何创建其文本标签以及可以操作哪些属性。有四个重要的属性需要知道:

  1. axis.orient(direction) 指定刻度点从轴出来的方向。在这种情况下,这会有点混乱,因为我们希望刻度线指向中心,因此左轴将为.orient('right'),右轴将为.orient('left')

  2. axis.tickSize(inner,outer) 设置从轴出来的刻度线的长度(以svg为单位)。 &#34;外部&#34;标记是轴的端点处的标记,在这种情况下可以设置为0,因为我们使用带有范围带的序数标度,因此端点不代表值。为内部刻度选择一个小值,对于此示例,我将使用4

  3. axis.tickPadding(padding) 设置标签文本的文本锚点的刻度标记末尾的距离。我们希望将文本锚点放在图像的中心,就在两个轴之间。由于我们已经知道中间边界(从中心线到每个轴的距离)并且我们知道tickSize(刻度线的长度),我们可以通过取这两个值的差值将它们放在中心:.tickPadding(margin.middle - 4)

  4. axis.tickFormat(format) 指定刻度标签的格式。它可以设置为空字符串以从其中一个轴上删除刻度标签,这样就不会发生重叠:.tickFormat('')

  5. 因此,两个y轴可以这样定义:

    var yAxisLeft = d3.svg.axis()
      .scale(yScale)
      .orient('right')
      .tickSize(4,0)
      .tickPadding(margin.middle - 4);
    
    var yAxisRight = d3.svg.axis()
      .scale(yScale)
      .orient('left')
      .tickSize(4,0)
      .tickFormat('');
    

    然后,当实际绘制左侧y轴时,选择其<text>元素并将文本锚设置为middle,使它们以锚点为中心:

    .call(yAxisLeft)
      .selectAll('text')
      .style('text-anchor', 'middle');
    

    HERE是使用一些人为设计数据的整个图表的简单示例。我试图尽可能多地评论一般结构,以便于遵循。我还创建了一个translation(x,y)函数,使每个翻译的x和y坐标比使用字符串连接时更容易发现。您可以在脚本底部找到它的定义。

    我希望这会有所帮助,如果您对细节有疑问,请与我联系。