【问题标题】:How to use quantile color scale in bar graph with drill-down?如何在具有向下钻取的条形图中使用分位数色标?
【发布时间】:2016-10-07 18:23:28
【问题描述】:

我正在使用以下脚本生成具有向下钻取功能的条形图。 (来源:http://mbostock.github.io/d3/talk/20111116/bar-hierarchy.html)。

我想要做的是 - 我希望条形图根据数据呈现不同的颜色深浅(几乎是这个问题所要求的 - D3.js: Changing the color of the bar depending on the value)。除了,在我的情况下......图表是水平的而不是静态的,所以答案可能会有所不同。

所以理想情况下,在父节点和除子节点之外的所有子节点上,它会根据数据显示不同深浅的蓝色,一旦向下钻取到最后,剩余的条将是灰色的。

我最近开始使用 d3,不知道从哪里开始。我试过 向z 的颜色范围添加不同的颜色,但这不起作用。

任何帮助将不胜感激!谢谢。

注意:在我的情况下,我假设.. 在转换之后,要么所有节点都通向子节点,要么没有节点通向子节点。基本上,图表中不会有条形图,有些会进一步向下钻取,而有些则不会。这个假设是基于我想用我的图表显示的数据类型。

<script>

    var m = [80, 160, 0, 160], // top right bottom left
        w = 1280 - m[1] - m[3], // width
        h = 800 - m[0] - m[2], // height
        x = d3.scale.linear().range([0, w]),
        y = 25, // bar height
        z = d3.scale.ordinal().range(["steelblue", "#aaa"]); // bar color

    var hierarchy = d3.layout.partition()
        .value(function(d) { return d.size; });

    var xAxis = d3.svg.axis()
        .scale(x)
        .orient("top");

    var svg = d3.select("body").append("svg:svg")
        .attr("width", w + m[1] + m[3])
        .attr("height", h + m[0] + m[2])
      .append("svg:g")
        .attr("transform", "translate(" + m[3] + "," + m[0] + ")");

    svg.append("svg:rect")
        .attr("class", "background")
        .attr("width", w)
        .attr("height", h)
        .on("click", up);

    svg.append("svg:g")
        .attr("class", "x axis");

    svg.append("svg:g")
        .attr("class", "y axis")
      .append("svg:line")
        .attr("y1", "100%");

    d3.json("flare.json", function(root) {
      hierarchy.nodes(root);
      x.domain([0, root.value]).nice();
      down(root, 0);
    });

    function down(d, i) {
      if (!d.children || this.__transition__) return;
      var duration = d3.event && d3.event.altKey ? 7500 : 750,
          delay = duration / d.children.length;

      // Mark any currently-displayed bars as exiting.
      var exit = svg.selectAll(".enter").attr("class", "exit");

      // Entering nodes immediately obscure the clicked-on bar, so hide it.
      exit.selectAll("rect").filter(function(p) { return p === d; })
          .style("fill-opacity", 1e-6);

      // Enter the new bars for the clicked-on data.
      // Per above, entering bars are immediately visible.
      var enter = bar(d)
          .attr("transform", stack(i))
          .style("opacity", 1);

      // Have the text fade-in, even though the bars are visible.
      // Color the bars as parents; they will fade to children if appropriate.
      enter.select("text").style("fill-opacity", 1e-6);
      enter.select("rect").style("fill", z(true));

      // Update the x-scale domain.
      x.domain([0, d3.max(d.children, function(d) { return d.value; })]).nice();

      // Update the x-axis.
      svg.selectAll(".x.axis").transition()
          .duration(duration)
          .call(xAxis);

      // Transition entering bars to their new position.
      var enterTransition = enter.transition()
          .duration(duration)
          .delay(function(d, i) { return i * delay; })
          .attr("transform", function(d, i) { return "translate(0," + y * i * 1.2 + ")"; });

      // Transition entering text.
      enterTransition.select("text").style("fill-opacity", 1);

      // Transition entering rects to the new x-scale.
      enterTransition.select("rect")
          .attr("width", function(d) { return x(d.value); })
          .style("fill", function(d) { return z(!!d.children); });

      // Transition exiting bars to fade out.
      var exitTransition = exit.transition()
          .duration(duration)
          .style("opacity", 1e-6)
          .remove();

      // Transition exiting bars to the new x-scale.
      exitTransition.selectAll("rect").attr("width", function(d) { return x(d.value); });

      // Rebind the current node to the background.
      svg.select(".background").data([d]).transition().duration(duration * 2); d.index = i;
    }

    function up(d) {
      if (!d.parent || this.__transition__) return;
      var duration = d3.event && d3.event.altKey ? 7500 : 750,
          delay = duration / d.children.length;

      // Mark any currently-displayed bars as exiting.
      var exit = svg.selectAll(".enter").attr("class", "exit");

      // Enter the new bars for the clicked-on data's parent.
      var enter = bar(d.parent)
          .attr("transform", function(d, i) { return "translate(0," + y * i * 1.2 + ")"; })
          .style("opacity", 1e-6);

      // Color the bars as appropriate.
      // Exiting nodes will obscure the parent bar, so hide it.
      enter.select("rect")
          .style("fill", function(d) { return z(!!d.children); })
        .filter(function(p) { return p === d; })
          .style("fill-opacity", 1e-6);

      // Update the x-scale domain.
      x.domain([0, d3.max(d.parent.children, function(d) { return d.value; })]).nice();

      // Update the x-axis.
      svg.selectAll(".x.axis").transition()
          .duration(duration * 2)
          .call(xAxis);

      // Transition entering bars to fade in over the full duration.
      var enterTransition = enter.transition()
          .duration(duration * 2)
          .style("opacity", 1);

      // Transition entering rects to the new x-scale.
      // When the entering parent rect is done, make it visible!
      enterTransition.select("rect")
          .attr("width", function(d) { return x(d.value); })
          .each("end", function(p) { if (p === d) d3.select(this).style("fill-opacity", null); });

      // Transition exiting bars to the parent's position.
      var exitTransition = exit.selectAll("g").transition()
          .duration(duration)
          .delay(function(d, i) { return i * delay; })
          .attr("transform", stack(d.index));

      // Transition exiting text to fade out.
      exitTransition.select("text")
          .style("fill-opacity", 1e-6);

      // Transition exiting rects to the new scale and fade to parent color.
      exitTransition.select("rect")
          .attr("width", function(d) { return x(d.value); })
          .style("fill", z(true));

      // Remove exiting nodes when the last child has finished transitioning.
      exit.transition().duration(duration * 2).remove();

      // Rebind the current parent to the background.
      svg.select(".background").data([d.parent]).transition().duration(duration * 2);
    }

    // Creates a set of bars for the given data node, at the specified index.
    function bar(d) {
      var bar = svg.insert("svg:g", ".y.axis")
          .attr("class", "enter")
          .attr("transform", "translate(0,5)")
        .selectAll("g")
          .data(d.children)
        .enter().append("svg:g")
          .style("cursor", function(d) { return !d.children ? null : "pointer"; })
          .on("click", down);

      bar.append("svg:text")
          .attr("x", -6)
          .attr("y", y / 2)
          .attr("dy", ".35em")
          .attr("text-anchor", "end")
          .text(function(d) { return d.name; });

      bar.append("svg:rect")
          .attr("width", function(d) { return x(d.value); })
          .attr("height", y);

      return bar;
    }

    // A stateful closure for stacking bars horizontally.
    function stack(i) {
      var x0 = 0;
      return function(d) {
        var tx = "translate(" + x0 + "," + y * i * 1.2 + ")";
        x0 += x(d.value);
        return tx;
      };
    }

</script>

【问题讨论】:

  • 你能做一个我们可以看的运行例子吗,比如一个jsfiddle?另外,我只是想澄清一下,您正在寻找完全基于数据的 1 种颜色的不同色调?
  • @Fallenreaper 这是一个小提琴(jsfiddle.net/af9gqqth),是的,我确实想要一种颜色的不同色调(基于数据),直到我一直深入到图表中......其中案例 1 的颜色可以很好地向用户显示他们已完成向下钻取。
  • @Fallenreaper 你可以看看这个配色方案,例如,他们使用蓝色 - ibm.com/developerworks/library/…
  • 你想要什么样的颜色中断,你是在寻找一个连续的比例还是像你的答案中链接的第一个答案那样离散的。
  • @NicE 我想要一个像这样的连续的,例如 - ibm.com/developerworks/library/…

标签: javascript d3.js


【解决方案1】:

您可以创建一个新比例来处理颜色的“阴影”,

var shades = d3.scale.sqrt()
.domain([your domain])
.clamp(true)
.range([your range]);

并创建一个变量来控制向下钻取的“深度”,因此当您要为条形着色时,您只需使用 d3.lab (Doc) 设置颜色“阴影”的级别,像这样:

   function fill(d) {
      var c = d3.lab(colorScale(d.barAttr));
      c.l = shades(d.depth);
      return c; 
   }

【讨论】:

  • 你能在 jfiddle 中显示这个吗? jsfiddle.net/af9gqqth
  • 您好,我不是很喜欢 jsfiddle,但在这里,link,为了简单起见,我选择随机化色调级别(这样很容易看到),我希望这会对你有所帮助......
  • 嗨,这很有帮助...但是我有一个问题...当我尝试向上移动到图表中的父节点时,在过渡时,一些条形图一开始是黑色的然后更改为蓝色阴影。无论如何我们可以在过渡/动画中隐藏黑色吗?
  • 当然,我忘了更新 up 函数中的填充(我留下了一个 console.log,对不起),[jfiddle] (jsfiddle.net/af9gqqth/4),一切都是随机的,所以我把选择颜色的部分留给你......如果你想检查的话,更改是在 js 的第 188 行进行的。
【解决方案2】:

使用与您发布的链接中的第二个相同的代码,您可以添加(省略号表示与小提琴中的代码相比没有任何变化):

//initialize the scale
var colors = ["#ffffd9", "#edf8b1", "#c7e9b4", "#7fcdbb", "#41b6c4", "#1d91c0", "#225ea8", "#253494", "#081d58"];

var colorScale = d3.scale.quantile() 

那么在d3读取数据的时候,需要加上一个域和一个范围。这假设任何条的所有最大值都在根节点的子节点中(即在最初显示的条中)。

d3.json(..., function(root) {
  ...
  colorScale.domain([0, colors.length - 1,d3.max(root.children, function(d) {
    return d.value;
  })]).range(colors);
 ...
});

然后,您可以使用colorScale 根据转换期间的值对条形图进行着色。这是我修改的行:

enter.select("rect").style("fill", colorScale(d.value));
    ...
    enterTransition.select("rect")
        .attr("width", function(d) {
          return x(d.value);
        })
        .style("fill", function(d) {
            if(!d.children) return "#aaa";
          return colorScale(d.value);
        });
    ...
    enter.select("rect")
        .style("fill", function(d) {
          return colorScale(d.value);
        })
        .filter(function(p) {
          return p === d;
        })
        .style("fill-opacity", 1e-6);
    ...
    exitTransition.select("rect")
        .attr("width", function(d) {
          return x(d.value);
        })
        .style("fill", colorScale(d.value));

这是一个有效的小提琴:https://jsfiddle.net/f640v0yj/2/

【讨论】:

  • 在根级别,小提琴中的所有条都具有相同的颜色....根据数据,它们应该是不同的阴影。
  • 好吧,我在你的问题的评论中问过,你说这就是你想要的(超过 100 000 深蓝色,50 000 到 100 000 浅蓝色等)...
猜你喜欢
  • 2023-04-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多