【问题标题】:d3 x scale and labels at the bottomd3 x 底部的刻度和标签
【发布时间】:2021-12-22 23:08:57
【问题描述】:

我正在尝试构建一个垂直向下钻取条形图。我指的是这个链接https://observablehq.com/@d3/hierarchical-bar-chart。链接中的图表是水平条形图,但我正在构建垂直条形图。我已设法构建图表,但 xAxis 定位存在问题。我正在尝试像我们在普通条形图中所做的那样将其定位,但它似乎无法正常工作。我的代码和图像如下所示。

从图像中可以看出,xAxis 和标签位于顶部。我想要它在底部。我使用过 d3.axisBottom,但它似乎不起作用。

代码

var margin = { top: 30, right: 50, bottom: 30, left: 50 },
  width = 400 - margin.left - margin.right,
  height = 250 - margin.top - margin.bottom;

var y:any = d3.scaleLinear()
  .range([height, 0]);

var x = d3.scaleBand()
  .range([0, width])
//   .domain(flare.map(function(d) { return d.name; }))
  // .padding(0.2);

var barWidth = 25;

var color:any = d3.scaleOrdinal()
  .range(["steelblue"]);

var duration = 750,
  delay = 25;

var yAxis:any = d3.axisLeft(y);

var xAxis:any = d3.axisBottom(x);


var svg: any = d3.select("#Area")
  .append("svg")
  .attr('preserveAspectRatio', 'xMinYMin meet')
  .attr(
    'viewBox',
    '0 0 ' +
    (width + margin.left + margin.right) +
    ' ' +
    (height + margin.top + margin.bottom)
  )
  .append("g")
  .attr("transform",
    "translate(" + margin.left + "," + margin.top + ")")

svg.append("rect")
  .attr("class", "background")
  .attr("width", width + margin.left + margin.right)
  .attr("height", height)
  .on("click", up);

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

svg.append("g")
  .attr("class", "x axis")
  .append("line")
  .attr("x1", "100%")
  .call(d3.axisBottom(x));

  


var root = d3.hierarchy(flare)
  .sum(d => d['size']);
y.domain([0, root.value]).nice();
down(root, 0);

function down(d, i) {
  if (!d.children) return;
  var end = duration + d.children.length * delay;

  // 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(p => 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", color(true));

  // Update the y-scale domain.
  y.domain([0, d3.max(d.children, d => d['value'])]).nice();

  // Update the y-axis.
  svg.selectAll(".y.axis").transition()
    .duration(duration)
    .call(yAxis);

  // 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((d, i) => i * delay)
    .attr("transform", (d, i) => `translate(${barWidth * i * 1.2 + 5}, 0)`);

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

  // Transition entering rects to the new y-scale.
  enterTransition.select("rect")
    .attr("height", d => height - y(d['value']))
    .attr("width", barWidth)
    .attr("y", d => y(d['value']))
    .attr("x", d => x(d['data'].name))
    .attr("width", barWidth)
    .style("fill", d => color(!!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 y-scale.
  exitTransition.selectAll("rect")
    .attr("height", d => height - y(d['value']))
    .attr("width", barWidth)
    .attr("y", d => y(d['value']))
    .attr("x", d => x(d['data'].name))
    .attr("width", barWidth)

  // Rebind the current node to the background.
  svg.select(".background")
    .datum(d)
    .transition()
    .duration(end);

  d.index = i;
}

function up(d) {
  if (!d.parent) return;
  var end = duration + d.children.length * delay;

  // 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", (d, i) => `translate(${barWidth * i * 1.2 + 5}, 0)`)
    .style("opacity", 1e-6);

  // Color the bars as appropriate.
  // Exiting nodes will obscure the parent bar, so hide it.
  enter.select("rect")
    .style("fill", d => color(!!d['children']))
    .filter(p => p === d)
    .style("fill-opacity", 1e-6);

  // Update the y-scale domain.
  y.domain([0, d3.max(d.parent.children, d => d['value'])]).nice();

  // Update the y-axis.
  svg.selectAll(".y.axis").transition()
    .duration(duration)
    .call(yAxis);

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

  // Transition entering rects to the new y-scale.
  // When the entering parent rect is done, make it visible!
  enterTransition.select("rect")
    .attr("height", d => height - y(d['value']))
    .attr("width", barWidth)
    .attr("y", d => y(d['value']))
    .attr("x", d => x(d['data'].name))
    .attr("width", barWidth)
    .on("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((d, i) => 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("height", d => height - y(d['value']))
    .attr("width", barWidth)
    .attr("y", d => y(d['value']))
    .attr("x", d => x(d['data'].name))
    .style("fill", color(true));

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

  // Rebind the current parent to the background.
  svg.select(".background")
    .datum(d.parent)
    .transition()
    .duration(end);
}

// Creates a set of bars for the given data node, at the specified index.
function bar(d) {
  var bar = svg.insert("g", ".x.axis")
    .attr("class", "enter")
    .attr("transform", "translate(0,0)")
    .selectAll("g")
    .data(d.children)
    .enter().append("g")
    .style("cursor", d => !d['children'] ? null : "pointer")
    .on("click", down);
  bar.append("rect")
    .attr("height", d => height - y(d['value']))
    .attr("width", barWidth)
    .attr("y", d =>  y(d['value']))
    .attr("x", d => x(d['data'].name))
  bar.append("text")
    .attr("x", -15)
    .attr("y", -barWidth / 2)
    .attr("dx", ".35em")
    .attr("transform", "rotate(90)")
    .style("text-anchor", "end")
    .text(d => d['data'].name);
  return bar;
}

// A stateful closure for stacking bars horizontally.
function stack(i) {
  var y0 = 0;
  return function (d) {
    var ty = `translate(${barWidth * i * 1.2 + 5}, ${y0})`;
    y0 += y(d.value);
    return ty;
  };
}

【问题讨论】:

    标签: javascript d3.js data-visualization


    【解决方案1】:

    axisBottom 只是指示刻度和标签的方向,您仍然需要将其移动到位。

    改变这个:

    svg.append("g")
      .attr("class", "x axis")
      .append("line")
      .attr("x1", "100%")
      .call(d3.axisBottom(x));
    

    收件人:

    svg.append('g')
        .attr('class','x axis')
        .attr('transform','translate(0,' + height + ')') // Move the axis to the bottom
        .call(d3.axisBottom(x))
        .append("line")
        .attr("x1", "100%")
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-07-21
      • 2021-02-06
      • 2012-03-14
      • 1970-01-01
      • 2018-02-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多