【问题标题】:Manipulating Spreadsheet data for visualization操作电子表格数据以进行可视化
【发布时间】:2015-08-25 14:30:38
【问题描述】:

我刚开始学习 Google Apps 脚本/JavaScript,想知道如何重塑、操作来自 Google 电子表格的多维数据。我读过一些像this one 这样的帖子,说GAS 在数据操作方面不灵活。但是这篇文章有点过时了,所以我想知道 GAS 功能是否有任何新的更改/添加。

下面是开始的功能代码。它可以成功绘制出下面的图表。但我真正想要的是:

  1. 按“工作日”(dayOfWeek(toDate(A))) 和“项目”(column B) 分组
  2. 使用“项目”作为过滤器

    .

我尝试使用PIVOT BGROUP BY dayOfWeek(toDate(A)),,但它返回了One or more participants failed to draw()× 错误消息或意外格式。

<html>
  <head>
    <title>
      Test
    </title>
    <!--Load the AJAX API-->
    <script type="text/javascript" src="https://www.google.com/jsapi"></script>
    <script type="text/javascript">
      google.load('visualization', '1', {'packages': ['table', 'controls', 'corechart']});
      google.setOnLoadCallback(initialize);

      function initialize() {

              var url = 'https://docs.google.com/spreadsheets/d/1_mSbT87MVWOiX2cfKX_x3dgTnToY5ulCWeGGCVn13iQ/gviz/tq?sheet=Sheet1&tq='   

              var queryStringDaily = encodeURIComponent("SELECT dayOfWeek(toDate(A)), sum(C), sum(D), sum(E), sum(F), sum(G), sum(H) GROUP BY dayOfWeek(toDate(A)) LABEL dayOfWeek(toDate(A)) 'Weekday' " ); 

              var queryDaily = new google.visualization.Query(url+ queryStringDaily);
              queryDaily.send(drawDaily);
      }

      function drawDaily(dailyTicket) {

                //prepare data
                var dailyTicket_table = dailyTicket.getDataTable(firstRowIsHeader = true); 

                // Create a dashboard.
                var dashboard = new google.visualization.Dashboard(
                    document.getElementById('dashboard_div2'));

                // Create a filter
                var categoryFilter = new google.visualization.ControlWrapper({
                  'controlType': 'CategoryFilter',
                  'containerId': 'filter_div2',
                  'options': {
                    'filterColumnLabel': 'Weekday'
                  }
                });

                //create chart
                var dailyChart = new google.visualization.ChartWrapper({
                  'chartType': 'LineChart',
                  'containerId': 'current_day',
                  'options': {
                    'title': 'Tickets by Rep, Item, and Weekday',
                    'legend': {position: 'right'},
                    //reformat x-axis tickmarks
                    'hAxis': {'viewWindow': {'min': 1.5, 'max': 6.5},
                              'ticks': [//{v: 1, f: 'Sunday'}, 
                                        {v: 2, f: 'Monday'}, 
                                        {v: 3, f: 'Tuesday'}, 
                                        {v: 4, f: 'Wednesday'}, 
                                        {v: 5, f: 'Thursday'}, 
                                        {v: 6, f: 'Friday'}, 
                                        //{v: 7, f: 'Saturday'}
                                        ] 
                            },                    
                  }
                });

                // bind charts and controls to dashboard 
                dashboard.bind(categoryFilter, dailyChart); 

                // Draw the dashboard.
                dashboard.draw(dailyTicket_table);

      }


    </script>
  </head>

  <body>
    <!--Div that will hold the dashboard-->
    <div id="dashboard_div2"></div>
    <!--Divs that will hold each control and chart-->
    <div id="filter_div2"></div>
    <div id="current_day" style="align: center; width: 500px; height: 250px;"></div>

  </body>
</html>

【问题讨论】:

    标签: javascript google-apps-script google-sheets google-visualization


    【解决方案1】:

    您可以添加多个过滤器。要使用您的源数据执行此操作:

    1. 您需要SELECT 附加文本列B 并将其包含在GROUP BY 和可选的LABEL 语句中。

      var queryStringDaily = encodeURIComponent("SELECT B, dayOfWeek(toDate(A)), sum(C),
                sum(D), sum(E), sum(F), sum(G), sum(H)
                GROUP BY dayOfWeek(toDate(A)), B
                LABEL dayOfWeek(toDate(A)) 'Weekday', B 'Issue' ");
      

      请注意,我们首先有B。如果我们不这样做,我们会收到您提到的错误。这是因为LineChart 需要一个标签列,然后是相关序列的列。将文本列移动到 SELECT 的开头可以避开错误。

    2. 为“问题”添加过滤器。

      var issueFilter = new google.visualization.ControlWrapper({
        'controlType': 'CategoryFilter',
        'containerId': 'issue-div',
        'options': {
          'filterColumnLabel': 'Issue'
        }
      });
      
    3. 将新过滤器绑定到仪表板。

      dashboard.bind(issueFilter, dailyChart);
      

    就是这样!

    ...不,不是。因为Issue 是我们的第一列,所以它被选为主轴,这不是很有用。

    此时您的挑战是选择与您的数据相匹配的适当可视化 - 因为 LineChart 没有。

    注意:这个 sn-p 是可运行的。

    google.load('visualization', '1', {
      'packages': ['table', 'controls', 'corechart']
    });
    google.setOnLoadCallback(initialize);
    
    function initialize() {
    
      var url = 'https://docs.google.com/spreadsheets/d/1_mSbT87MVWOiX2cfKX_x3dgTnToY5ulCWeGGCVn13iQ/gviz/tq?sheet=Sheet1&tq='
    
      var queryStringDaily = encodeURIComponent("SELECT B, dayOfWeek(toDate(A)), sum(C), sum(D), sum(E), sum(F), sum(G), sum(H) GROUP BY dayOfWeek(toDate(A)),B LABEL dayOfWeek(toDate(A)) 'Weekday', B 'Issue' ");
    
      var queryDaily = new google.visualization.Query(url + queryStringDaily);
      queryDaily.send(drawDaily);
    }
    
    function drawDaily(dailyTicket) {
    
      //prepare data
      var dailyTicket_table = dailyTicket.getDataTable(firstRowIsHeader = true);
      console.log(JSON.stringify(dailyTicket_table).replace(/\\"/g,"'").replace(/"/g,''));
    
      // Create a dashboard.
      var dashboard = new google.visualization.Dashboard(
        document.getElementById('dashboard-div'));
    
      // Create a filter
      var issueFilter = new google.visualization.ControlWrapper({
        'controlType': 'CategoryFilter',
        'containerId': 'issue-div',
        'options': {
          'filterColumnLabel': 'Issue'
        }
      });
    
      var categoryFilter = new google.visualization.ControlWrapper({
        'controlType': 'CategoryFilter',
        'containerId': 'weekday-div',
        'options': {
          'filterColumnLabel': 'Weekday'
        }
      });
    
      //create chart
      var dailyChart = new google.visualization.ChartWrapper({
        'chartType': 'LineChart',
        'containerId': 'linechart-div',
        'options': {
          'title': 'Tickets by Rep, Item, and Weekday',
          'legend': { position: 'right'},
          //reformat x-axis tickmarks
          'hAxis': {
            'viewWindow': { 'min': 1.5, 'max': 6.5},
            'ticks': [ 
              //{v: 1, f: 'Sunday'}, 
              { v: 2, f: 'Monday' },
              { v: 3, f: 'Tuesday' },
              { v: 4, f: 'Wednesday'},
              { v: 5, f: 'Thursday' },
              { v: 6, f: 'Friday' },
              //{v: 7, f: 'Saturday'}
            ]
          },
        }
      });
    
      // bind charts and controls to dashboard 
      dashboard.bind(issueFilter, dailyChart);
      dashboard.bind(categoryFilter, dailyChart);
    
      // Draw the dashboard.
      dashboard.draw(dailyTicket_table);
    
    }
    <html>
      <head>
        <title>
          Test
        </title>
        <!--Load the AJAX API-->
        <script type="text/javascript" src="https://www.google.com/jsapi"></script>
    
      </head>
    
      <body>
        <!--Div that will hold the dashboard-->
        <div id="dashboard-div">
          <div id="control-div">
            <div id="issue-div">
            </div>
            <div id="weekday-div">
            </div>
          </div>
          <div id="charts-div">
            <div id="linechart-div" style="align: center; width: 500px; height: 250px;">
            </div>
          </div>
        </div>    
    
      </body>
    </html>

    【讨论】:

    • 如果所有其他方法都失败并且您无法使用 GQL (developers.google.com/chart/interactive/docs/querylanguage) 构建查询,您始终可以使用 javascript 获取整个数据范围和过滤器/组。
    • 注意,Zig - 这是我最常使用的技术。
    • @Mogsdad,非常感谢您的建议。我受到您的 cmets 的启发,并通过使用 columnChart 重新解决了这个问题。如上所述,我认为它在一定程度上解决了我的问题,如果您认为代码可以进一步改进,我会全力以赴。提前致谢!
    • 嗨,@Mogsdad。还有一个问题:您是否知道如何按月按周对数据集进行分组?所以轴是“第 1 周”和“第 2 周”等? Google Query Language 文档似乎没有这个选项。 developers.google.com/chart/interactive/docs/… 如果你愿意,我可以创建另一个问题帖子。非常感谢。
    • 知道了。谢谢,莫格达德!
    【解决方案2】:

    我想我今天早上有一个顿悟的时刻。在从其他帖子中学习和借用代码后(在脚本下面注明),我能够制作出我想要的图表。

    1. 正如@Mogsdad 所建议的,我将B 列(问题)移到“SELECT”项的开头,然后将此列用于注释和过滤。注释文本疯狂地出现在每个条形上方,但我可以通过将 annotated.textStyle 的字体大小设置为 0 来隐藏它们。
    2. 我还自定义了工具提示,因此工作日(数字格式)不会显示。

    我认为这是解决我的问题的方法。如果您有更好的建议,我将不胜感激。

    <html>
      <head>
        <title>
          Test
        </title>
        <!--Load the AJAX API-->
        <script type="text/javascript" src="https://www.google.com/jsapi"></script>
        <script type="text/javascript">
          google.load('visualization', '1', {'packages': ['table', 'controls', 'corechart']});
          google.setOnLoadCallback(initialize);
    
          function initialize() {
    
                  var url = 'https://docs.google.com/spreadsheets/d/1_mSbT87MVWOiX2cfKX_x3dgTnToY5ulCWeGGCVn13iQ/gviz/tq?sheet=Sheet1&tq='   
                  
                  var queryStringDaily = encodeURIComponent("SELECT B, dayOfWeek(toDate(A)), sum(C), sum(D), sum(E), sum(F), sum(G), sum(H) GROUP BY dayOfWeek(toDate(A)), B LABEL dayOfWeek(toDate(A)) 'Weekday' , B '{role: \"annotation\"}' " ); 
    
                  var queryDaily = new google.visualization.Query(url+ queryStringDaily);
                  queryDaily.send(drawDaily);
          }
    
          function drawDaily(dailyTicket) {
    
                    //prepare data
                    var dailyTicket_table = dailyTicket.getDataTable(firstRowIsHeader = true); 
                    
                    //NEW!!! create tooltip
                    //inspired by http://stackoverflow.com/questions/17924826/add-tooltips-to-a-google-line-chart-with-multiple-data-series-with-simplified
                    var columns = [2]; // jump to the value columns
                    for (var i = 2; i < dailyTicket_table.getNumberOfColumns(); i++) { 
                        columns.push(i);
                        columns.push({
                            type: 'string',
                            properties: {
                                role: 'tooltip'
                            },
                            calc: (function (j) {
                                return function (dt, row) {
                                    return dt.getColumnLabel(j)  //+ ': Weekday:' + dt.getValue(row, 1) 
                                    + ' Tickets:' + dt.getValue(row, j)
                                } 
                            })(i) 
                        });
    
                        columns.push({sourceColumn: 0,
                            //calc: getValueAt.bind(undefined, 1)
                            type: "string",
                            role: "annotation",
                            label: "Issue"} );
                    }
                    columns = [1].concat(columns);
    
                    var view = new google.visualization.DataView(dailyTicket_table);
                    view.setColumns(columns)
    
                    // Create dashboard.
                    var dashboard = new google.visualization.Dashboard(
                        document.getElementById('dashboard_div2'));
    
                    // Create filter
                    var issueFilter = new google.visualization.ControlWrapper({
                      'controlType': 'CategoryFilter',
                      'containerId': 'issue-div',
                      'options': {
                        'filterColumnLabel': 'Issue',
                        'ui': {
                        'allowMultiple': false,
                        'allowNone': false, 
                        }
                      },
                      //Set default filter value
                      'state': {'selectedValues': [dailyTicket_table.getValue(1, 1)]}
                    });
    
                    //create chart
                    var dailyChart = new google.visualization.ChartWrapper({
                      'chartType': 'ColumnChart',
                      'containerId': 'current_day',
                      'options': {
                          'legend': {position: 'right'},
                          //Set the fontsize of labels so they don't show up crazily
                          'annotations': {textStyle: {'fontsize': 0},
                                         //use 'line' style so to remove the line pointer
                                          style: 'line'},
                          'hAxis': {'viewWindow': {'min': 1.5, 'max': 6.5},
                                    'ticks': [//{v: 1, f: 'Sunday'}, 
                                              {v: 2, f: 'Monday'}, 
                                              {v: 3, f: 'Tuesday'}, 
                                              {v: 4, f: 'Wednesday'}, 
                                              {v: 5, f: 'Thursday'}, 
                                              {v: 6, f: 'Friday'}, 
                                              //{v: 7, f: 'Saturday'}
                                              ] 
                                   },  
                      }
                    });
    
                    // bind charts and controls to dashboard 
                    dashboard.bind(issueFilter, dailyChart);
    
                    // Draw the dashboard.
                    dashboard.draw(view);
          }
    
        </script>
      </head>
    
      <body>
        <!--Div that will hold the dashboard-->
        <div id="dashboard_div2"></div>
        <!--Divs that will hold each control and chart-->
        <div id="filter_div2"></div>
        <div id="issue-div"></div>
        <div id="current_day" style="align: center; width: 1100px; height: 500px;"></div>
    
      </body>
    </html>

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多