如何在plotly.js中按周对值进行分组

时间:2018-07-31 20:11:25

标签: javascript aggregate plotly.js

下面显示的是一个时间序列条形图,在plotly.js中带有一个范围选择器。

在其中,我试图找出如何按周对值进行分组,但似乎无法实现这一点。更改时间范围选择时,plotly.js中是否有设置按周将其分组?我似乎无法弄清楚是否有可能。

这是他们提供的主要文档页面,我尝试了许多与完成此操作有关的设置,但无法弄清。

var days = (function(start,count){
  var days = [];
  var MSday = 1000 * 60 * 60 * 24;
  for(var i = 0; i < count; i++){
    days.push(new Date(+start + i*MSday));
  }
  return days;
})(new Date(2018,0,1),100);

function vals(){
  var vals = [];
  for(var i = 0; i < 100; i++){
    vals.push((Math.random() * 2 * i) | 0);
  }
  return vals;
}

var selectorOptions = {
  buttons: [{
    step: 'month',
    stepmode: 'backward',
    count: 1,
    label: '1m'
  }, {
    step: 'month',
    stepmode: 'backward',
    count: 6,
    label: '6m'
  }, {
    step: 'year',
    stepmode: 'todate',
    count: 1,
    label: 'YTD'
  }, {
    step: 'year',
    stepmode: 'backward',
    count: 1,
    label: '1y'
  }, {
    step: 'all',
  }],
};

var trace1 = {
  x: days,
  y: vals(),
  type: 'bar',
  name: 'Trace 1'
};

var trace2 = {
  x: days,
  y: vals(),
  type: 'bar',
  name: 'Trace 2'
};

var data = [trace1, trace2];

var layout = {
  title: 'Bar Demo',
  barmode: 'group',
  xaxis: {
    rangeselector: selectorOptions
  }
};

Plotly.newPlot('myDiv', data, layout);
<script src="https://cdn.plot.ly/plotly-latest.min.js"></script>
<div id="myDiv"><!-- Plotly chart will be drawn inside this DIV --></div>

如何在图表上按周而不是按天创建6个月的选择组?

2 个答案:

答案 0 :(得分:2)

布莱米!有一个更简单的选择...

使用7天:

    step: 'day',
    stepmode: 'backward',
    count: 7,
    label: '1w'

答案 1 :(得分:1)

显然这不是内置的。如果它是内置的或在某个时候内置的,请在注释或其他答案中指出。

我唯一确定可行的选择是使用.on('plotly_relayout', function () {进入中继事件,并从范围选择器按钮中获取参数(似乎有限制,如果有确定原点的更好方法,也请让我知道,我将在此处进行更新),然后大致基于此来按周对日期进行分类并调整图中的x和y值。

这只是作为概念证明的基本实现。在生产中使用它需要对代码进行重构,以在设计和页面实现方面与现有数据结构一起使用。

这里发生了很多事情。基本上,它将遍历日期集以创建将包含每周数据的星期天框(请注意,它仍然缺少显示更新以显示它是从开始日期开始的一周)。一旦有了垃圾箱,它将对每个垃圾箱范围内的日期进行求和。然后,它使用restyle替换数据集。如果选择的范围不是6m,则它将使用一部分备份数据,因为会按计划修改阵列,因此,如果没有备份副本,则每次备份时都会覆盖一个副本,因此它将覆盖数据。使用。

请参见下面的有效演示。

function sum(array){
	return array.reduce(function(sum,curr){
  	return sum + curr;
  },0);
};
Date.MSday = 1000 * 60 * 60 * 24;
Date.prototype.floor = function(){
	return new Date(this.getFullYear(),this.getMonth(),this.getDate());
}
Date.prototype.addDays = function(days){
	var time = +this - +this.floor();
  var addedDays = new Date(+this.floor() + Date.MSday*days);
  return new Date(+addedDays + time);
}

function weeksFromDates(datesArray, valsArray){
	var lastDay = datesArray[datesArray.length -1];
	var firstDay = datesArray[0];
  var dayOfWeek = firstDay.getDay();
  var firstSunday = firstDay.addDays(-dayOfWeek);
  var sundays = [];
  var currentSunday = firstSunday;
  while(currentSunday < lastDay){
  	sundays.push(currentSunday);
    currentSunday = currentSunday.addDays(7);
  }
  currentSunday = currentSunday.addDays(7);
  sundays.push(currentSunday);
  
  var valSets = [];
  
  var n = 0;
  for(var i = 1; i < sundays.length; i++){
  	var last = sundays[i-1];
    var next = sundays[i];
    var theseVals = [];
    for(; n < datesArray.length && last <= datesArray[n] && next > datesArray[n]; n++){
      theseVals.push(valsArray[n]);
    }
  	valSets.push(sum(theseVals));
  }
  sundays.pop();
  return {x: sundays, y: valSets};
}

var MSday = 1000 * 60 * 60 * 24;
var days = (function(start,count){
  var days = [];
  for(var i = 0; i < count; i++){
    days.push(new Date(+start + i*MSday));
  }
  return days;
})(new Date(2018,0,1),100);

function vals(){
  var vals = [];
  for(var i = 0; i < 100; i++){
    vals.push((Math.random() * 2 * i) | 0);
  }
  return vals;
}

var selectorOptions = {
  buttons: [{
    step: 'month',
    stepmode: 'backward',
    count: 1,
    label: '1m'
  }, {
    step: 'month',
    stepmode: 'backward',
    count: 6,
    label: '6m'
  }, {
    step: 'year',
    stepmode: 'todate',
    count: 1,
    label: 'YTD'
  }, {
    step: 'year',
    stepmode: 'backward',
    count: 1,
    label: '1y'
  }, {
    step: 'all',
  }],
};

var trace1 = {
  x: days,
  y: vals(),
  type: 'bar',
  name: 'Trace 1',
  orientation: 'v'
};

var trace2 = {
  x: days,
  y: vals(),
  type: 'bar',
  name: 'Trace 2',
  orientation: 'v'
};

var data = [trace1, trace2];
var dataBackup = $.extend(true,{},data);

var layout = {
  title: 'Bar Demo',
  barmode: 'group',
  xaxis: {
    rangeselector: selectorOptions
  }
};

Plotly.newPlot('myDiv', data, layout);
$('#myDiv').on('plotly_relayout', function () {
    var lower = new Date(arguments[1]['xaxis.range[0]']);
    var upper = new Date(arguments[1]['xaxis.range[1]']);
    var dayRange = (+upper - +lower) / MSday;
    if( dayRange < 190 && dayRange > 170 ){
        //6m
        for(var n = 0; n < data.length; n++){
        var weekly = weeksFromDates(dataBackup[n].x,dataBackup[n].y);
        Plotly.restyle('myDiv',{x:[weekly.x],y: [weekly.y]},n);
        }
    }else{
      for(var n = 0; n < data.length; n++){
        Plotly.restyle('myDiv',{x:[dataBackup[n].x.slice()],y: [dataBackup[n].y.slice()]},n);
        }
    }
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdn.plot.ly/plotly-latest.min.js"></script>
<div id="myDiv"><!-- Plotly chart will be drawn inside this DIV --></div>