【问题标题】:Make a Group Bar Chart after nesting data in D3 using CSV使用 CSV 在 D3 中嵌套数据后制作组条形图
【发布时间】:2021-02-12 10:12:50
【问题描述】:

我对 D3 不是很熟悉,并且在嵌套特定数据后,我正在为创建组条形图的概念而苦苦挣扎。我试图创建的分组条形图基本上应该是这样的。分隔的栏应指示宿舍,每个颜色条将指示宿舍学生数量的学年。我的问题是如何将嵌套数据中的值基本上用作学生学年的条形高度,如何将数据按宿舍划分,如果您注意到我的控制台仅输出有值的学年,如果学年不在宿舍,则不输出值 0。我只是在努力理解 D3,我想知道如何使用嵌套数据来创建分组条形图。

这只是我希望条形图外观的一般概述。这些值显然会有所不同,只是一般的 SketchUp。

这是使用 d3.nest() 后数据的控制台输出。如果您注意到,没有显示值为 0 的“Sophomore”键。我不知道在输出到图表时是否会有所不同。

0:
key: "Davis Hall"
    values: Array(3)
         0: {key: "Freshman", value: 1}
         1: {key: "Junior", value: 2}
         2: {key: "Senior", value: 2}
         length: 3
     __proto__: Array(0)
__proto__: Object
1:
key: "Jameson Hall"
   values: Array(3)
       0: {key: "Sophomore", value: 1}
       1: {key: "Junior", value: 3}
       2: {key: "Senior", value: 1}
       length: 3
   __proto__: Array(0)
__proto__: Object

以下是我如何使用 D3.Nest 嵌套 CSV 数据并使用计数

d3.csv("./data/studentresidences.csv", function(data){
    var studentBuildings = d3.nest()
        .key(function(r) { return r.Residence; })
        .key(function(s) { return s.Schoolyear; })
        .rollup(function(a) { return a.length; })
        .entries(data)
        console.log(studentBuildings);
});

这是 CSV

Name, Residence, ID, Schoolyear, Major
Bill Thornton, Jameson Hall, 11123, Sophomore, Mathematics
Savannah Lipscombe, Davis Hall, 11231, Freshman, Biology
Jay Price, Jameson Hall, 12222, Senior, Business
Hassan Abdullah, Jameson Hall, 11111, Junior, Mechanical Engineering
Jo Park, Davis Hall, 22123, Junior, Political Science
Arnold Allen, Jameson Hall, 12314, Junior, Psychology
Anthony Daniels, Davis Hall,15125, Senior, Aerospace Engineering
Josephine Alvarez, Davis Hall,11512, Junior, Chemistry
Cynthia Blackman, Davis Hall,66142, Senior, Computer Science
Sophie Aspen, Jameson Hall,111221, Junior, English

【问题讨论】:

  • 你为什么要删除昨天的your question?由于您要求的是堆叠条形图,而现在要求的是分组条形图,看起来您对方向不满意 - 但删除问题也会阻止其他人从中受益
  • 我的错,我真的以为我应该做一个堆叠的条形图,结果我需要一个分组的。
  • 没问题,感谢您重新打开它。现在,到目前为止,您尝试过什么?您当前的汇总提供了专业的数量,而不是唯一的数字 - 还是您不再需要它?
  • 所以在这种情况下,不再需要专业,而是我需要条形图中的大一、大二等总人数。当前的汇总应该给出这个
  • 好的,到目前为止你尝试了什么?你有什么可以和我们分享的尝试吗?也许是有用或没用的教程或在线示例?

标签: javascript csv d3.js bar-chart


【解决方案1】:

考虑以下问题。你的开始很好,但你需要有两个 x 轴。一个将整个领域划分为每个住宅的相等位置,另一个则占用该住宅区域并每年划分。

您可以轻松地使用x.bandwidth() 来获取该区域的大小。

const dataString = `Name, Residence, ID, Schoolyear, Major
Bill Thornton, Davis Hall, 11123, Sophomore, Mathematics
Savannah Lipscombe, Jameson Hall, 11231, Freshman, Biology
Jay Price, Davis Hall, 12222, Senior, Business
Hassan Abdullah, Arthur Hall, 11111, Junior, Mechanical Engineering
John Doe, Arthur Hall, 11112, Junior, Mechanical Engineering
Jo Park, Reed Hall, 22123, Freshman, Political Science`.replace(/, /g, ",");

const unique = array => array.filter((v, i) => array.indexOf(v) === i);

const data = d3.csvParse(dataString);
const years = unique(data.map(d => d.Schoolyear));

var groupedData = d3.nest()
  .key(d => d.Residence)
  .key(d => d.Schoolyear)
  .rollup(v => v.length)
  .entries(data)
console.log(groupedData);

const svg = d3.select("svg"),
  margin = {
    top: 35,
    left: 35,
    bottom: 0,
    right: 0
  },
  width = +svg.attr("width") - margin.left - margin.right,
  height = +svg.attr("height") - margin.top - margin.bottom;

const x = d3.scaleBand()
  .range([margin.left, width - margin.right])
  // The residences
  .domain(groupedData.map(d => d.key))
  .padding(0.1);

const subX = d3.scaleBand()
  .range([0, x.bandwidth()])
  .domain(years)
  .padding(0.05);

// Calculate the nested max
const max = d3.max(
  groupedData,
  d => d3.max(d.values, e => e.value)
);
const y = d3.scaleLinear()
  .domain([0, max])
  .range([height - margin.bottom, margin.top]);

const z = d3.scaleOrdinal()
  .range(["steelblue", "darkorange", "lightblue"])
  .domain(years);

const xAxis = svg.append("g")
  .attr("transform", `translate(0,${height - margin.bottom})`)
  .attr("class", "x-axis")

const yAxis = svg.append("g")
  .attr("transform", `translate(${margin.left},0)`)
  .attr("class", "y-axis")

svg.selectAll(".y-axis")
  .call(d3.axisLeft(y)
    .ticks(null, "s"))

const bargroups = svg.selectAll("g.bargroup")
  .data(groupedData, d => d.key)

bargroups.exit().remove()

const bars = bargroups.enter()
  .append("g")
  .classed("bargroup", true)
  .merge(bargroups)
  .attr("transform", d => `translate(${x(d.key)}, 0)`)
  .selectAll("rect")
  .data(d => d.values, e => e.key);

bars.exit().remove()

bars.enter()
  .append("rect")
  .attr("width", subX.bandwidth())
  .merge(bars)
  .attr("x", d => subX(d.key))
  .attr("y", d => y(d.value))
  .attr("height", d => height - y(d.value))
  .attr("fill", d => z(d.key))

// Draw the main axis labels
xAxis
  .call(d3.axisBottom(x)
    .tickSize(0)
    .tickPadding(24));

// For every tick, add the year labels
xAxis.selectAll(".tick")
  .each(function() {
    d3.select(this)
      .selectAll(".year-tick")
      .data(years)
      .enter()
      .append("text")
      .classed("year-tick", true)
      .attr("fill", "currentColor")
      .attr("text-anchor", "middle")
      .attr("y", (d, i) => i % 2 === 0 ? 3 : 12)
      .attr("dy", "0.71em")
      .attr("x", d => subX(d) - (x.bandwidth() / 2))
      .attr("dx", d => subX.bandwidth() / 2)
      .text(d => d);
  });
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
<svg width="700" height="300"></svg>

【讨论】:

  • 我怎样才能让它看起来像这个例子,在每个关联栏下方都有年份名称stackoverflow.com/questions/37812922/…
  • 我已经更新了我的答案。只需将文本节点添加到每个刻度,从主刻度复制样式,并使用辅助 x 轴定位它们
猜你喜欢
  • 1970-01-01
  • 2016-03-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-12-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多