如何根据 D3 中的分类数据绘制线和点的集合?

How can you draw a collection of lines and points based on categorical data in D3?

我是 JavaScript/D3 的新手,我正在尝试根据我拥有的一些玩具数据编写一个相对简单的可视化代码,但无法弄清楚。这是玩具数据:

toy_data = {
  'abstract' : ['a'],
  'introduction' : ['b', 'c'],
  'methods' : ['d', 'e', 'f'],
  'findings' : ['g', 'h', 'i', 'j'],
  'conclusion' : ['k', 'l', 'm', 'n', 'o']
  }

我想编写一个函数来接收像这样格式化的数据(或者如果需要,以稍微不同的方式)并在 D3 中生成一个大致如下所示的可视化(我在 Altair 中使用类似的方法生成了这个图数据):

不同之处在于 x 轴标签将对应于我的玩具数据中指定的术语,并且我的圆圈数量与每个关联键值对中的项目数量相同(例如,1 个圆圈用于摘要, 2 介绍, 3 方法等).最终,我还将添加额外的数据来控制圆圈的大小,如上图所示,但目前我对一个函数感到满意,它可以接受这种形式的任何数据,并且至少生成一个带有圆圈的原型大小一样。

我觉得这在 D3 中应该是相当可行的,也许通过定义散点图然后添加连接水平线,或者通过组合线图和散点图,但我不知道该怎么做。如果有人可以解释并举例说明如何实现这种行为,那将非常有帮助,因为我认为我可以以此为基础来实现我想要的。

这会让您入门,但我建议您重新处理数据。大多数 D3 模式以数组的数组或对象数组开头。包含各种长度数组的对象将很难处理。

const toy_data = {
  'abstract' : ['a'],
  'introduction' : ['b', 'c'],
  'methods' : ['d', 'e', 'f'],
  'findings' : ['g', 'h', 'i', 'j'],
  'conclusion' : ['k', 'l', 'm', 'n', 'o']
  }
  
 const margin = {top:10,left:90,bottom:25,right:10},
  width = 480 - margin.top - margin.bottom,
  height = 250 - margin.left - margin.right;
  
 const svg = d3.select('#chart')
  .append('svg')
  .attr('width', width + margin.left + margin.right)
  .attr('height', height + margin.top + margin.bottom)
  .append('g')
  .attr('transform','translate(' + margin.left + ',' + margin.top + ')')
 
 let rows = Object.getOwnPropertyNames(toy_data) 
 let cols = [];
 

 for(prop in toy_data) {
  cols = cols.concat(toy_data[prop])
 }
 const x = d3.scaleBand()
  .domain(cols)
  .range([0,width])
  
 const y = d3.scaleBand()
  .domain(rows)
  .range([0,height])
  
 svg.append('g')
  .call(d3.axisLeft(y))
 
 svg.append('g')
  .attr('transform','translate(0,' + height + ')')
  .call(d3.axisBottom(x))
  
for(prop in toy_data) {

  svg.selectAll(null)
    .data(toy_data[prop])
    .enter()
    .append('circle')
    .attr('cx', d => x(d) + x.bandwidth()/2)
    .attr('cy', y(prop) + y.bandwidth()/2)
    .attr('r', x.bandwidth()/4)
    .style('fill','steelblue')

}
 
 
 
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
<div id="chart"><div>

更新:我不知道你的数据的限制,但严格从 D3 的角度来看,这会更容易处理:

const toy_data = {
  'abstract' : ['a'],
  'introduction' : ['b', 'c'],
  'methods' : ['d', 'e', 'f'],
  'findings' : ['g', 'h', 'i', 'j'],
  'conclusion' : ['k', 'l', 'm', 'n', 'o']
 }
 
 let d3_data = [];
 for(prop in toy_data) {
   d3_data = d3_data.concat(toy_data[prop].map(d=> [prop, d]))
 }