如何在带有 scaleTime 的条形图中使用 x 和宽度? [英] How to use x and width in a bar chart with scaleTime?

查看:20
本文介绍了如何在带有 scaleTime 的条形图中使用 x 和宽度?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我这里有一个代码笔 - https://codepen.io/anon/pen/xpaYYw?editors=0010

I have a codepen here - https://codepen.io/anon/pen/xpaYYw?editors=0010

它是一个简单的测试图,但日期格式如下.

Its a simple test graph but the date will be formatted like this.

我在 x 轴上有日期,在 y 上有数量

I have dates on the x axis and amounts on the y

如何使用 x 比例来设置条形的宽度和 x 位置.

How can I use the x scale to set the width and x position of the bars.

    layers.selectAll('rect')
      .data(data)
      .enter()
      .append('rect')

      .attr('height', function(d, i) {
        return height - y(d.one);
      })

      .attr('y', function(d, i) {
        return y(d.one);
      })

      .attr('width', function(d, i) {
        return 50;
      })

      .attr('x', function(d, i) {
        return 80*i;
      })

      .style('fill', (d, i) => {
        return colors[i];
      });

推荐答案

你的问题与编程、JavaScript 或 D3 无关...问题是一个基本的 dataviz 概念(这就是为什么我添加了 标签在你的问题):

The problem with your question has nothing to do with programming, or JavaScript, or D3... the problem is a basic dataviz concept (that's why I added the data-visualization tag in your question):

你试图做的不正确!您应该使用带有时间刻度的条形图.时间尺度用于时间序列(其中我们使用点,或由线连接的点).

What you're trying to do is not correct! You should not use bars with a time scale. Time scales are for time series (in which we use dots, or dots connected by lines).

如果您在 x 轴上使用带有时间的条形,则会遇到问题:

If you use bars with time in the x axis you'll face problems:

  1. 定位栏:栏的左边距将始终位于您设置的日期.整个酒吧将在该日期之后
  2. 设置条形的宽度:在实际条形图中,x 轴使用分类变量,宽度没有意义.但在时间尺度上,宽度代表时间.
  1. Positioning the bar: the left margin of the bar will be always at the date you set. The whole bar will lie after that date;
  2. Setting the width of the bar: in a real bar chart, which uses categorical variables for the x axis, the width has no meaning. But in a time scale the width represents time.

但是,为了便于说明,让我们创建带有时间刻度的条形图(尽管这是一个错误选择)...以下是操作方法:

However, just for the sake of explanation, let's create this bar chart with a time scale (despite the fact that this is a wrong choice)... Here is how to do it:

首先,在时间中设置条形的宽度".假设每个条形将有 10 天的宽度:

First, set the "width" of the bars in time. Let's say, each bar will have 10 days of width:

.attr("width", function(d){
    return x(d3.timeDay.offset(d.date, 10)) - x(d.date)
})

然后,将条形的 x 位置设置为当前日期减去其宽度的一半(即,在我们的示例中小于 5 天):

Then, set the x position of the bar to the current date less half its width (that is, less 5 days in our example):

.attr('x', function(d, i) {
    return x(d3.timeDay.offset(d.date, -5));
})

最后别忘了在时间尺度上创建一个padding":

Finally, don't forget to create a "padding" in the time scale:

var x = d3.scaleTime()
  .domain([d3.min(data, function(d) {
    return d3.timeDay.offset(d.date, -10);
  }), d3.max(data, function(d) {
    return d3.timeDay.offset(d.date, 10);
  })])
  .range([0, width]);

以下是包含这些更改的代码:

Here is your code with those changes:

var keys = [];
var legendKeys = [];

var maxVal = [];

var w = 800;
var h = 450;

var margin = {
  top: 30,
  bottom: 40,
  left: 50,
  right: 20,
};

var width = w - margin.left - margin.right;
var height = h - margin.top - margin.bottom;

var colors = ['#FF9A00', '#FFEBB6', '#FFC400', '#B4EDA0', '#FF4436'];

var data = [{
    "one": 4306,
    "two": 2465,
    "three": 2299,
    "four": 988,
    "five": 554,
    "six": 1841,
    "date": "2015-05-31T00:00:00"
  }, {
    "one": 4378,
    "two": 2457,
    "three": 2348,
    "four": 1021,
    "five": 498,
    "six": 1921,
    "date": "2015-06-30T00:00:00"
  }, {
    "one": 3404,
    "two": 2348,
    "three": 1655,
    "four": 809,
    "five": 473,
    "six": 1056,
    "date": "2015-07-31T00:00:00"
  },

];

data.forEach(function(d) {
  d.date = new Date(d.date)
})

for (var i = 0; i < data.length; i++) {
  for (var key in data[i]) {
    if (!data.hasOwnProperty(key) && key !== "date")
      maxVal.push(data[i][key]);
  }
}

var x = d3.scaleTime()
  .domain([d3.min(data, function(d) {
    return d3.timeDay.offset(d.date, -10);
  }), d3.max(data, function(d) {
    return d3.timeDay.offset(d.date, 10);
  })])
  .range([0, width]);

var y = d3.scaleLinear()
  .domain([0, d3.max(maxVal, function(d) {
    return d;
  })])
  .range([height, 0]);

var svg = d3.select('body').append('svg')
  .attr('class', 'chart')
  .attr('width', w)
  .attr('height', h);

var chart = svg.append('g')
  .classed('graph', true)
  .attr('transform', 'translate(' + margin.left + ',' + margin.top + ')');

var layersArea = chart.append('g')
  .attr('class', 'layers');


var layers = layersArea.append('g')
  .attr('class', 'layer');

layers.selectAll('rect')
  .data(data)
  .enter()
  .append('rect')

.attr('height', function(d, i) {
  return height - y(d.one);
})

.attr('y', function(d, i) {
  return y(d.one);
})

// .attr('width', function(d, i) {
//   return 50;
// })

.attr("width", function(d) {
  return x(d3.timeDay.offset(d.date, 10)) - x(d.date)
})

.attr('x', function(d, i) {
  return x(d3.timeDay.offset(d.date, -5));
})

.style('fill', (d, i) => {
  return colors[i];
});

chart.append('g')
  .classed('x axis', true)
  .attr("transform", "translate(0," + height + ")")
  .call(d3.axisBottom(x)
    .tickFormat(d3.timeFormat("%Y-%m-%d")).tickValues(data.map(function(d) {
      return new Date(d.date)
    })));

chart.append('g')
  .classed('y axis', true)
  .call(d3.axisLeft(y)
    .ticks(10));

<script src="https://d3js.org/d3.v4.min.js"></script>

这篇关于如何在带有 scaleTime 的条形图中使用 x 和宽度?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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