获取条形图中每个y轴的唯一最大值 [英] Get unique max value for each y-axis in a bar chart

查看:65
本文介绍了获取条形图中每个y轴的唯一最大值的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

In my code below I'm appending multiple svg elements and get 3 different charts from it.

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

The problem I have is that the max value that's evaluated from the y.domain() for each y-axis is the max value from all of my data.

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

Is there some clever way to get the max value for each svg and set that to be the max value for each y-axis or do I have to make 3 different y scales?

代码如下:

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.但是,鉴于您现在拥有的代码, new 惯用的D3解决方案正在使用

I reckon that the best idea here is refactoring your code to create specific SVGs based on the data you pass to it. However, given the code you have right now, a new idiomatic D3 solution is using local variables.

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

Actually, according to Mike Bostock...

例如,当渲染时间序列数据的较小倍数时,您可能希望所有图表使用相同的x比例,但要使用不同的y比例来比较每个指标的相对性能.

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.

...局部变量是您确切情况的解决方案!

... local variables are the solution for your exact case!

因此,您所需要做的就是设置本地...

So, all you need is to set the local...

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())
});

...并获取它来创建轴和条.例如:

... and get it to create the axes and the bars. For instance:

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

请记住,您不需要该var d = d3.select(this.parentNode).datum()即可获取基准!

Have in mind that you don't need that var d = d3.select(this.parentNode).datum() to get the datum!

这是您所做的更改的代码:

Here is your code with those changes:

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>

这篇关于获取条形图中每个y轴的唯一最大值的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆