【问题标题】:Creating Population Pyramid with D3.js使用 D3.js 创建人口金字塔
【发布时间】:2014-07-30 19:09:48
【问题描述】:

我需要使用 D3.js 制作一个外观经典的人口金字塔。类似于这张图片的东西:

我找到了一些看起来非常不错的示例(thisthis),但它们比我想要的要复杂。有谁知道我可以看的一个很好的简单例子?开始这个有什么建议吗?我应该只制作两个相邻的条形图,每个性别组一个吗?

【问题讨论】:

  • 听起来并排放置两个条形图是最简单的开始方式。

标签: javascript d3.js population census


【解决方案1】:

制作这样的可视化的关键是在开始绘制任何东西之前花大量时间提前设置布局。

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

目标是像这样创建两个镜像区域:

这将允许您在两个区域之间共享相同的 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 坐标。换句话说,男性和女性人口为零的点(如下图红线所示)。这些将是距您的内部区域中心线的固定距离(如下所示的蓝线):

您可以在之前创建的边距对象中添加一个中间边距属性来引用该值:

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 为单位)。 “外部”标记是轴端点处的标记,在这种情况下可以设置为0,因为我们使用的是带范围带的序数刻度,所以端点不代表值。为内部刻度选择一个较小的值,在此示例中,我将使用 4

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

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

所以,两个 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> 元素并将 text-anchor 设置为 middle,以便它们以锚为中心:

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

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

希望对您有所帮助,如果您对具体细节有任何疑问,请告诉我。

【讨论】:

  • 哇!感谢这个伟大的答案。如果我有任何问题,我会告诉你。
  • 如何在原始图形中添加代表“圣安东尼奥”人口的线?
  • 您可以像彩色条一样制作透明条,只需将填充设置为“透明”并给它一个笔触。
  • 嗨 jshanley,我发布了这个问题,这是人口金字塔 stackoverflow.com/questions/25851623/… 的一个变体,你能看一下吗?
  • @jshanley 写得很好。
猜你喜欢
  • 2023-03-31
  • 1970-01-01
  • 1970-01-01
  • 2022-11-15
  • 1970-01-01
  • 2021-12-20
  • 2020-12-16
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多