代码之家  ›  专栏  ›  技术社区  ›  Travis J

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

  •  0
  • Travis J  · 技术社区  · 6 年前

    下面是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个月的选择组?

    1 回复  |  直到 6 年前
        1
  •  2
  •   MPanzeri    5 年前

    天哪有一个更简单的选择。。。

    使用7天:

        step: 'day',
        stepmode: 'backward',
        count: 7,
        label: '1w'
    
        2
  •  1
  •   Travis J    6 年前

    显然这不是内置的。如果它是,或者在某个时候成为内置的,请在这里的评论或其他答案中指出。

    我唯一能确定可行的方法是使用 .on('plotly_relayout', function () { ,从范围选择器按钮获取参数(这似乎是有限的,只有一个“开始”和“结束”日期,如果有更好的方法来确定来源,请让我知道,我将在这里更新),然后大致基于此按周对日期进行分类,并调整绘图中的x和y值。

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

    这里发生了很多事。基本上,它将遍历一组日期来创建星期日箱,其中将保存每周数据(注意,它仍然缺少显示更新,以显示它是从开始日期开始的一周)。一旦它有了箱子,它就把每个箱子范围内的日期加起来。然后它使用 restyle . 如果选定的范围不是6米,则它将使用备份数据的a片,因为plotly会就地修改数组,因此,如果每次使用备份时没有备份副本和单个副本,则它将覆盖数据。

    请参阅下面的工作演示。

    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>