【问题标题】:d3 bar chart align bars on ticks for differing number of elementsd3条形图在刻度上为不同数量的元素对齐条形图
【发布时间】:2018-01-28 06:19:21
【问题描述】:

我有一个条形图,它在单击单选按钮时显示 data1.json 或 data2.json。

data1.json 有 9 个元素,data2.json 有 4 个元素。

问题 1:如何进行设置,以便无论数据中有多少对象或条形,条形始终以刻度为中心?

问题 2: 如何将 x 轴降低到您期望的位置?我知道这听起来微不足道,但我尝试了很多方法。

问题 3:我想确保“值”是一个数字,使用

newdata.foreach(function(d) {
      d.value = +d.value;
    })

但我似乎无法像预期的那样遍历“newdata”。

这是github here 和gh-pages demo here。

index.html 文件

<!DOCTYPE html>
<meta charset="utf-8">
<style>
  .bar {
    fill: steelblue;
  }
  .bar:hover {
    fill: brown;
  }
  .axis text {
    font: 10px sans-serif;
  }
  .axis path,
  .axis line {
    fill: none;
    stroke: #000;
    shape-rendering: crispEdges;
  }
</style>

<body>
  <form>
    <input type="radio" name="inputsrc" id="defaultInput" value="default" checked=""><label for="defaultInput">data1.json</label>
    <input type="radio" name="inputsrc" id="updateInput" value="post"><label for="updateInput">data2.json</label>
  </form>
  <svg id="d3newbie-chart" width="600" height="400">
  </svg>
  <script src="https://d3js.org/d3.v4.min.js"></script>

  <script type="text/javascript">
    var outerWidth = 600,
      outerHeight = 400;
    var margin = {
        top: 40,
        right: 30,
        bottom: 30,
        left: 80
      },
      width = outerWidth - margin.left - margin.right,
      height = outerHeight - margin.top - margin.bottom;
    var x = d3.scaleBand()
      .range([0, width]);
    var y = d3.scaleLinear()
      .range([height, 0]);
    var xAxis = d3.axisBottom(x);
    var yAxis = d3.axisLeft(y)
      .ticks(10, "%");
    var chart = d3.select("#d3newbie-chart")
      .attr("width", outerWidth)
      .attr("height", outerHeight)
      .append("g")
      .attr("transform", "translate(" + margin.left + "," + margin.top + ")")
    // x-axis
    chart.append("g")
      .attr("class", "x axis")
      .attr("transform", "translate(0," + height + ")")
      .call(xAxis);

    function defaultFunction() {
      d3.json("data1.json", function(error, newdata) {
        if (error) throw error;
        data = newdata;
        // newdata.foreach(function(d) {
        //   d.value = +d.value;
        // })
        update();
      });
    }
    function updateFunction() {
      d3.json("data2.json", function(error, newdata) {
        if (error) throw error;
        data = newdata;
        update();
      });
    }
    function update(err, newdata) {
      y.domain([0, d3.max(data, function(d) {
        return d.value;
      })]);
      x.domain(data.map(function(d) {
        return d.name
      }));
      // x-axis
      chart.select(".x.axis").remove();
      chart.append("g")
        .attr("class", "x axis")
        .call(xAxis)
        .append("text")
        .attr("transform", "rotate(-90)")
        .attr("y", 6)
        .attr("dy", ".71em")
        .style("text-anchor", "end")
        .text("Frequency");
      // y-axis
      chart.select(".y.axis").remove();
      chart.append("g")
        .attr("class", "y axis")
        .call(yAxis)
        .append("text")
        .attr("transform", "rotate(-90)")
        .attr("y", 6)
        .attr("dy", ".71em")
        .style("text-anchor", "end")
        .text("Frequency");
      var bar = chart.selectAll(".bar")
        .data(data, function(d) {
          return d.name;
        });
      // new data:
      bar.enter().append("rect")
        .attr("class", "bar")
        .attr("x", function(d) {
          return x(d.name);
        })
        .attr("y", function(d) {
          return y(d.value);
        })
        .attr("height", function(d) {
          return height - y(d.value);
        })
        .attr("width", 20);
      // removed data:
      bar.exit().remove();
      // updated data:
      bar.transition()
        .duration(750)
        .attr("y", function(d) {
          return y(d.value);
        })
        .attr("height", function(d) {
          return height - y(d.value);
        });
    };
    document.getElementById("defaultInput")
      .onclick = defaultFunction;
    document.getElementById("updateInput")
      .onclick = updateFunction;
    defaultFunction();
  </script>
</body>

【问题讨论】:

    标签: d3.js alignment bar-chart


    【解决方案1】:

    更新代码:https://jsfiddle.net/5j2nw238/2/

    问题 1: 条形的宽度由 svg 的宽度以及您为 scaleBand 函数 paddingInner、paddingOuter 和其他几个。

    https://github.com/d3/d3-scale/blob/master/README.md#band-scales

    查看描述这些参数的图像。关键是不要像使用.attr("width", 20); 那样对条形的宽度进行硬编码,而是操纵scaleBand 来找到您想要的外观。

    问题 2:

    你用代码正确地做到了这一点

    chart.append("g")
      .attr("class", "x axis")
      .attr("transform", "translate(0," + height + ")")
      .call(xAxis);
    

    但是在更新时,您删除了轴并且没有再次应用转换。无需删除轴并重新创建它,只需使用新域更新轴比例,然后执行chart.select(".x.axis").call(xAxis)。这符合 d3 以数据驱动方式的思维方式。更改您的数据,让 D3 处理 DOM。

    问题 3:

    函数名称是forEach,而不是foreach。另外,您说您想确保该值是一个字符串,但将 + 运算符放在变量之前会将其转换为数字,而不是字符串。

    【讨论】:

    • 精彩的答案,非常感谢。我现在完全理解问题 2 和 3。在 3 中,我实际上确保如果数据是字符串,它将被转换为数字。我需要一点时间来解决问题 1。github 存储库现在反映了这些变化。再次感谢
    • 我现在看到我说我希望该值是一个字符串,我的意思是我希望该字符串是一个数字。
    • 我看到你从 github 中提取了 json,我不知道这是可能的。很有用!我没有设置jsfiddle,因为我不知道如何引入json。太棒了,再次感谢!
    • 不幸的是,当我更新数据时,条形图未与刻度线对齐 shanegibney.github.io/d3-v4-Change-Dataset-JSON 我正在链接到域 .padding([0.5]);在更新函数内部和我使用的条形图上 .attr("width", x.bandwidth());
    • 它正在工作。我不得不更新 .attr("x"... 和 .attr("width", x.bandwidth()) github 已经更新。Github 是最新的演示 shanegibney.github.io/d3-v4-Change-Dataset-JSON 。谢谢
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-02-09
    • 1970-01-01
    相关资源
    最近更新 更多