javascript - 获取条形图中每个 y 轴的唯一最大值

标签 javascript d3.js

在我下面的代码中,我附加了多个 svg 元素并从中获取了 3 个不同的图表。

我遇到的问题是,从每个 y 轴的 y.domain() 评估的最大值是我所有数据的最大值。

是否有一些聪明的方法来获取每个 svg 的最大值并将其设置为每个 y 轴的最大值,或者我是否必须制作 3 个不同的 y 尺度?

代码如下:

var data = [
	{category: "Apples", total: 10, goal: 8},
	{category: "Oranges", total: 20, goal: 18},
	{category: "Bananas", total: 20, goal: 25},
];

chart(data);

function chart(result) {

	var margin = {bottom: 25, right: 25, top: 25, left: 25},
		width = 180 - margin.left - margin.right,
		height = 230 - margin.top - margin.bottom;

	var svg = d3.select("#chart").selectAll("svg")
		.data(result)
	.enter().append("svg")
		.attr("width", width)
		.attr("height", height)

	var x = d3.scaleBand()
		.range([margin.left, width - margin.right])
		.domain(["Total", "Goal"])
		.padding(.1)
		.paddingOuter(.2)

	var y = d3.scaleLinear()
		.range([height - margin.bottom, margin.top])
		.domain([0, d3.max(result, d => Math.max(d.total, d.goal))]).nice()

	var xAxis = g => g
		.attr("transform", "translate(0," + (height - margin.bottom) + ")")
		.call(d3.axisBottom(x).tickSizeOuter(0))
	
	var yAxis = g => g
		.attr("transform", "translate(" + margin.left + ",0)")
		.call(d3.axisLeft(y))

	svg.append("g")
		.attr("class", "x-axis")
		.call(xAxis);

	svg.append("g")
		.attr("class", "y-axis")
		.call(yAxis);
		
	var total = svg.append("rect")
		.attr("fill", "steelblue")
		.attr("width", x.bandwidth())
		.attr("x", x("Total"))
		.attr("y", function() {
			var d = d3.select(this.parentNode).datum()
			return y(d.total)
		})
		.attr("height", function() {
			var d = d3.select(this.parentNode).datum()
			return y(0) - y(d.total)
		})

	var goal = svg.append("rect")
		.attr("fill", "orange")
		.attr("width", x.bandwidth())
		.attr("x", x("Goal"))
		.attr("y", function() {
			var d = d3.select(this.parentNode).datum()
			return y(d.goal)
		})
		.attr("height", function() {
			var d = d3.select(this.parentNode).datum()
			return y(0) - y(d.goal)
		})

	var text = svg.append("text")
		.attr("dx", width / 2)
		.attr("dy", 15)
		.attr("text-anchor", "middle")
		.text(function() {
			return d3.select(this.parentNode).datum().category
		})
}
<meta charset ="utf-8">
<script src="https://d3js.org/d3.v5.min.js "></script>

<div id="chart"></div>

最佳答案

我认为这里最好的想法是重构您的代码,以根据您传递给它的数据创建特定的 SVG。但是,鉴于您现在拥有的代码, 惯用的 D3 解决方案正在使用 local variables .

实际上,根据 Mike Bostock 的说法...

For instance, when rendering small multiples of time-series data, you might want the same x-scale for all charts but distinct y-scales to compare the relative performance of each metric.

...局部变量是您具体情况的解决方案!

所以,您只需要设置本地...

var local = d3.local();

svg.each(function(d) {
    var y = local.set(this, d3.scaleLinear()
      .range([height - margin.bottom, margin.top])
      .domain([0, Math.max(d.total, d.goal)]).nice())
});

... 并使用它来创建轴和条。例如:

.attr("y", function(d) {
    return local.get(this)(d.total);
})

请记住,您不需要 var d = d3.select(this.parentNode).datum() 来获取数据!

这是您的代码,其中包含这些更改:

var data = [{
    category: "Apples",
    total: 10,
    goal: 8
  },
  {
    category: "Oranges",
    total: 20,
    goal: 18
  },
  {
    category: "Bananas",
    total: 20,
    goal: 25
  },
];

var local = d3.local();

chart(data);

function chart(result) {

  var margin = {
      bottom: 25,
      right: 25,
      top: 25,
      left: 25
    },
    width = 180 - margin.left - margin.right,
    height = 230 - margin.top - margin.bottom;

  var svg = d3.select("#chart").selectAll("svg")
    .data(result)
    .enter().append("svg")
    .attr("width", width)
    .attr("height", height)

  var x = d3.scaleBand()
    .range([margin.left, width - margin.right])
    .domain(["Total", "Goal"])
    .padding(.1)
    .paddingOuter(.2);

  svg.each(function(d) {
    var y = local.set(this, d3.scaleLinear()
      .range([height - margin.bottom, margin.top])
      .domain([0, Math.max(d.total, d.goal)]).nice())
  });

  var xAxis = g => g
    .attr("transform", "translate(0," + (height - margin.bottom) + ")")
    .call(d3.axisBottom(x).tickSizeOuter(0))



  svg.append("g")
    .attr("class", "x-axis")
    .call(xAxis);

  svg.each(function() {
    var y = local.get(this);
    var yAxis = g => g
      .attr("transform", "translate(" + margin.left + ",0)")
      .call(d3.axisLeft(y));
    d3.select(this).append("g")
      .attr("class", "y-axis")
      .call(yAxis);
  })

  var total = svg.append("rect")
    .attr("fill", "steelblue")
    .attr("width", x.bandwidth())
    .attr("x", x("Total"))
    .attr("y", function(d) {
      return local.get(this)(d.total);
    })
    .attr("height", function(d) {
      return local.get(this)(0) - local.get(this)(d.total)
    })

  var goal = svg.append("rect")
    .attr("fill", "orange")
    .attr("width", x.bandwidth())
    .attr("x", x("Goal"))
    .attr("y", function(d) {
      return local.get(this)(d.goal)
    })
    .attr("height", function(d) {
      return local.get(this)(0) - local.get(this)(d.goal)
    })

  var text = svg.append("text")
    .attr("dx", width / 2)
    .attr("dy", 15)
    .attr("text-anchor", "middle")
    .text(function() {
      return d3.select(this.parentNode).datum().category
    })
}
<meta charset="utf-8">
<script src="https://d3js.org/d3.v5.min.js "></script>

<div id="chart"></div>

关于javascript - 获取条形图中每个 y 轴的唯一最大值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52555845/

相关文章:

javascript - 外部接口(interface)和 swfobject.js 问题

angularjs - 如何使用 angularjs-nvd3-directives 避免内存泄漏

php - 为什么从mysql数据库读取数据,直方图不显示

d3.js 无法可视化大型数据集

Javascript 通过 Id 获取元素并设置值

javascript - Angularjs:ng-if通过比较字符串显示内容

javascript - Jest - 如何模拟函数中的方法

javascript - jQuery - 解析 DOM 并创建树结构(复合模式)

javascript - 强制引导 d3.js 添加边缘标签

javascript - 显示工具提示时 d3.event 的 x 和 y 坐标不正确