使用 Google 表格和幻灯片将大数据转化为数据洞见

市面上有很多工具可供数据科学家用来进行大数据分析,但归根结底,您还是不得不证明这些结果值得管理层吗?纸质或数据库中的大量数字很难向关键的利益相关方展示。此中级 Google Apps 脚本 Codelab 利用一对 Google 的开发者平台 G SuiteGoogle Cloud Platform (GCP) 帮助您完成最后一公里。

借助 Google Cloud 的开发者工具,您可以执行深入的数据分析,然后将这些结果放入电子表格中,然后使用这些数据生成幻灯片演示,从而为将结果传递给管理提供更合适的阶段。本 Codelab 介绍了 GCP 的 BigQuery API(作为 Apps 脚本高级服务)以及适用于 Google 表格Google 幻灯片内置 Apps 脚本服务

动机/先进艺术

此 Codelab 中的示例应用的灵感源自于以下这些代码示例...

虽然 Slides API Codelab 示例应用也提供 BigQuery 和幻灯片,但与这个 Codelab 的示例应用不同,以下几个方面:

  • Node.js 应用与 Apps 脚本应用
  • 在我们使用 Apps 脚本服务时使用 REST API
  • 使用 Google 云端硬盘,但不使用 Google 表格,而此应用使用 Google 表格,但不使用 Google 云端硬盘

在此 Codelab 中,我们希望将尽可能多的技术整合到一个应用中,同时以更接近于真实使用场景的方式展示 Google Cloud 中的功能和 API。我们的目标是激励您发挥想象力,并考虑利用 GCP 和 G Suite 为您的单位或客户解决棘手的问题。

学习内容

  • 如何将 Google Apps 脚本与多项 Google (GCP &G Suite) 服务搭配使用
  • 如何使用 Google BigQuery 执行大数据分析
  • 如何创建 Google 表格并在其中填充数据
  • 如何在 Google 表格中创建新图表
  • 如何将图表和数据从 Google 表格转移到 Google 幻灯片演示文稿

您需要满足的条件

  • 互联网和网络浏览器的访问权限
  • Google 帐号(G Suite 帐号可能需要管理员批准)
  • JavaScript 基本技能
  • 了解 Apps 脚本开发可能有所帮助,但并非必须

您将如何使用此 Codelab/教程?

仔细阅读,信息仅供技术同事参考 尽可能阅读,并尝试尽可能多的练习 无论去海水还是玩高水准,我都要完成整个 Codelab

您如何评价使用 G Suite 开发者工具和 API 的体验?

新手水平 中等水平 熟练水平

您如何评价 Apps 脚本的使用体验?

新手水平 中等水平 熟练水平

您对使用 GCP 开发者工具和 API 的体验有何评价?

新手 中级 熟练

现在,您已经了解了此 Codelab 的主题,接下来要做什么呢?

  1. 获取现有的 Apps Script-BigQuery 示例并使其正常运行
  2. 通过此示例,了解如何向 BigQuery 发送查询并获取其结果
  3. 创建 Google 表格并将 BigQuery 中的结果填充到其中
  4. 稍微修改一下代码,对返回的数据和添加到表格中的数据略微更改
  5. 使用 Apps 脚本中的表格服务为 BigQuery 中的数据创建图表
  6. 使用幻灯片服务新建幻灯片演示文稿
  7. 为所有新的幻灯片幻灯片自动创建的默认标题幻灯片,添加标题和副标题
  8. 使用数据表格创建新幻灯片,然后将工作表的数据单元格导入到其中
  9. 再添加一张新幻灯片,然后将电子表格图表添加到其中

首先介绍 Apps 脚本、BigQuery、表格和幻灯片的一些背景信息。

Google Apps 脚本和 BigQuery

Google Apps 脚本是 G Suite 开发平台,其运行级别比 Google REST API 更高。它是一种无服务器的开发和应用托管环境,可供各种开发者技能水平使用。简而言之,“Apps 脚本”是一种用于 G Suite 自动化、扩展程序和集成的无服务器 JavaScript 运行时。

它是与 JavaScript 类似的服务器端 JavaScript,但专注于与 G Suite 和其他 Google 服务紧密集成,而不是快速异步事件驱动型应用托管。它还具有开发环境,与您习惯的开发环境完全不同。使用 Apps 脚本,您可以:

  • 在基于浏览器的代码编辑器中开发,但如果使用 clasp(Apps 脚本的命令行部署工具),则可以选择在本地进行开发
  • 使用专门的 JavaScript 版本自定义代码,以访问 G Suite 和其他 Google 服务或外部服务(通过 Apps 脚本 URLfetchJdbc 服务访问)
  • 可以避免编写授权代码,因为 Apps 脚本会为您处理
  • 无需托管您的应用,应用会在云端的 Google 服务器上运行

注意:大多数情况下,此 Codelab 不涵盖此 Codelab。我们提供了大量在线资源来帮助您解决此问题。官方文档中也提供了快速入门概览教程视频。最后,别忘了完成 Apps 脚本入门 Codelab,该 Codelab 应该在开始本 Codelab 之前完成。

Apps 脚本与其他 Google 技术通过以下两种方式集成:

  • 内置服务/原生服务
  • 高级服务

内置服务提供了可用于访问 G Suite 或 Google 商品数据的高级方法或其他有用的实用程序方法。高级服务是 G Suite 或 Google REST API 的瘦封装容器。高级服务提供 REST API 的完整覆盖范围,通常比内置服务做得更多,但需要更多的代码复杂度(同时仍比 REST API 本身更易于使用)。必须先为脚本项目启用高级服务,然后才能使用该服务。

我们建议开发者尽可能使用内置服务,因为与高级服务相比,这些服务使用起来更便捷,而且需要做更多工作。不过,一些 Google API 不具备内置服务,因此高级服务可能是唯一选择。Google BigQuery 就是一个示例...我们不提供内置的服务,但提供了 BigQuery 高级服务(是否比服务要好?)如果您刚开始接触 BigQuery,它是一种 GCP 服务,让您可以对超大型数据资料(例如,数 TB 的数据顺序)执行简单(或复杂)查询,同时仍可在数秒内提供结果。

通过 Apps 脚本访问 Google 表格和幻灯片

与 BigQuery 不同,Google 表格和幻灯片都内置服务(以及高级服务,这些服务仅供您访问 API 中的功能)。在跳转到代码之前,请先查看内置表格幻灯片服务的文档。当然,我们还提供了高级服务的文档;这两个版本分别适用于表格幻灯片

简介

我们要开始学习此 Codelab 并完成第一个任务。事实上,完成本文中的操作后,整个 Codelab 就完成了一半。这些部分分解为若干子部分,您需要执行以下所有操作:

  • 启动新的 Google Apps 脚本项目
  • 启用对 BigQuery 高级服务的访问权限
  • 转到开发编辑器,然后输入应用源代码
  • 完成应用授权流程 (OAuth2)
  • 运行向 BigQuery 发送请求的应用
  • 查看基于 BigQuery 结果创建的全新 Google 表格

初始设置

  1. a) 转到 script.google.com 创建新的 Apps 脚本项目。G Suite 产品线各不相同,您创建新项目的方式可能会有所不同,具体取决于您使用的版本。如果您刚刚使用自己的 Gmail 帐号,且刚开始开发项目,则会看到空白屏幕,并且您会看到创建第一个项目的按钮:


b) 否则,您可能会看到所有项目,左上角有一个大大的 +New 按钮,因此请点击该按钮。



c) 如果以上选项均不符合,您的屏幕可能如下所示。如果是这种情况,请找到左上角的汉堡式菜单图标,然后选择 +New script



d) 如果您更喜欢命令行,您的工具是 clasp,具体而言,您将运行 clasp create 命令。

e) 创建新脚本项目的最后一种方法是直接转到快捷方式链接:https://script.google.com/create

  1. 无论使用哪种方法启动新项目,关键在于您都应该被放入 Apps 脚本编辑器,该屏幕如下所示:


  2. 点击 File > Save,并为项目命名。
  3. 接下来,您需要创建 Google Cloud Console 项目才能运行 BigQuery 查询。
  1. 创建一个新项目,为其命名,选择结算帐号,然后点击创建
  1. 项目创建完成后,页面右上角会显示通知。点击 Create Project: <Project Name> 条目以打开项目。
  2. 点击左上角的菜单图标 ,然后导航到 APIs & Services; Credentials。点击 OAuth 同意屏幕标签页(直接链接)。
  3. Application name 字段中,输入“Big Data Codelab”,然后点击底部的保存按钮。
  4. 点击右上角的三点状图标 展开菜单,然后选择项目设置直接链接)。
  5. 复制项目编号下列出的值。(有一个单独的字段 Product ID,稍后我们会在 Codelab 中使用)。
  6. 返回 App Script Editor,点击 Resources > Cloud Platform project
  7. 在文本框中输入项目编号,然后点击 Set Project。出现提示时,点击确认
  8. 完成后,点击关闭按钮关闭对话框。
  9. 现在您已经有了新的项目设置,接下来需要启用 BigQuery 高级服务,因此请下拉资源 -> 高级 Google 服务并为 BigQuery API 启用


  10. 底部说明“这些服务还必须在“Google Cloud Platform API 信息中心”中启用,因此请点击该链接,在“开发者控制台”或“devconsole”上打开另一个浏览器标签页。
  11. 在 DevConsole 中,点击顶部的 + 启用 API 和服务按钮,搜索“bigquery”,选择 BigQuery API(不是 BigQuery Data Transfer API),然后点击启用将其开启。请将此浏览器标签页保持打开状态。

    注意:启用此 API 后,您可能会在本页面上看到一条说明,如“如需使用此 API,您需要创建凭据...”,但目前无需担心— Apps 脚本会为您处理此步骤。


  12. 返回代码编辑器浏览器标签页,您仍然处于“高级 Google 服务”菜单,因此请点击确定关闭该对话框,使您留在代码编辑器中。点击顶部的项目名称,然后随意命名,即“BigQuery demo”(BigQuery 演示)或类似名称(我们称之为“最后一公里”)。

现在,您可以输入应用代码,完成授权流程,并开始运行此应用的首个版本。

上传并运行应用

  1. 复制下方框中的代码,将其粘贴在代码编辑器中的所有内容:
// Filename for data results
var QUERY_NAME = "Most common words in all of Shakespeare's works";
// Replace this value with your Google Cloud API project ID
var PROJECT_ID = '';
if (!PROJECT_ID) throw Error('Project ID is required in setup');

/**
 * Runs a BigQuery query; puts results into Sheet. You must enable
 * the BigQuery advanced service before you can run this code.
 * @see http://developers.google.com/apps-script/advanced/bigquery#run_query
 * @see http://github.com/googleworkspace/apps-script-samples/blob/main/advanced/bigquery.gs
 *
 * @returns {Spreadsheet} Returns a spreadsheet with BigQuery results
 * @see http://developers.google.com/apps-script/reference/spreadsheet/spreadsheet
 */
function runQuery() {
  // Replace sample with your own BigQuery query.
  var request = {
    query:
        'SELECT ' +
            'LOWER(word) AS word, ' +
            'SUM(word_count) AS count ' +
        'FROM [bigquery-public-data:samples.shakespeare] ' +
        'GROUP BY word ' +
        'ORDER BY count ' +
        'DESC LIMIT 10'
  };
  var queryResults = BigQuery.Jobs.query(request, PROJECT_ID);
  var jobId = queryResults.jobReference.jobId;

  // Wait for BQ job completion (with exponential backoff).
  var sleepTimeMs = 500;
  while (!queryResults.jobComplete) {
    Utilities.sleep(sleepTimeMs);
    sleepTimeMs *= 2;
    queryResults = BigQuery.Jobs.getQueryResults(PROJECT_ID, jobId);
  }

  // Get all results from BigQuery.
  var rows = queryResults.rows;
  while (queryResults.pageToken) {
    queryResults = BigQuery.Jobs.getQueryResults(PROJECT_ID, jobId, {
      pageToken: queryResults.pageToken
    });
    rows = rows.concat(queryResults.rows);
  }

  // Return null if no data returned.
  if (!rows) {
    return Logger.log('No rows returned.');
  }

  // Create the new results spreadsheet.
  var spreadsheet = SpreadsheetApp.create(QUERY_NAME);
  var sheet = spreadsheet.getActiveSheet();

  // Add headers to Sheet.
  var headers = queryResults.schema.fields.map(function(field) {
    return field.name.toUpperCase();
  });
  sheet.appendRow(headers);

  // Append the results.
  var data = new Array(rows.length);
  for (var i = 0; i < rows.length; i++) {
    var cols = rows[i].f;
    data[i] = new Array(cols.length);
    for (var j = 0; j < cols.length; j++) {
      data[i][j] = cols[j].v;
    }
  }

  // Start storing data in row 2, col 1
  var START_ROW = 2;      // skip header row
  var START_COL = 1;
  sheet.getRange(START_ROW, START_COL, rows.length, headers.length).setValues(data);

  Logger.log('Results spreadsheet created: %s', spreadsheet.getUrl());
}


现在,保存刚刚创建的文件,但是将其从 Code.gs 重命名为 bq-sheets-slides.js。此代码有什么作用?我们已经说过,它查询 BigQuery 并将结果写入新的 Google 表格中,但这个查询是什么呢?您可以在 runQuery() 的顶部附近看到它:

SELECT
    LOWER(word) AS word,
    SUM(word_count) AS count
FROM [bigquery-public-data:samples.shakespeare]
GROUP BY word
ORDER BY count
DESC LIMIT 10


此查询会浏览莎士比亚的作品(属于 BigQuery' 公开数据集),并从他的所有作品中排名前 10 位的字词(按热门程度降序排列)。想象一下,如果以手动方式完成这项工作,有趣(而非)有趣,您大概也清楚 BigQuery 有多实用。

  1. 我们几乎尚未准备好尝试此功能。如以下代码段所示,您需要提供有效的项目 ID,以便我们将其加入到应用代码中。要获取该文件,请返回包含开发者控制台页面的浏览器窗口或标签页。(我们曾要求您保持打开状态,记得吗?)
  2. Google 帐号头像的左上角是下拉菜单选择器 ()。点击它并选择项目设置。您将看到项目名称、ID 和编号。复制项目 ID,并将 bq-sheets-slides.js 顶部的 PROJECT_ID 变量设置为您从开发者控制台获取的值。注意:如果菜单选择器变得粘滞且无法使用,请重新加载页面。
  3. if 语句的作用是防止应用在没有项目 ID 的情况下继续运行。添加文件后,保存文件并运行代码,具体方法是:转到菜单栏,选择 Run > Run Function > runQuery,点击 Review Permissions 对话框,此应用未经验证,下方是一个动画 GIF(用于其他应用),说明接下来的几个步骤:
  4. 申请审核权限后,系统会向您显示一个新的对话框,如上所示。选择将运行脚本的正确 Google 帐号,选择高级,向下滚动,然后点击“转到您的项目名称(不安全)”,以转到 OAuth2 应用授权屏幕。(请详细了解验证流程,了解下文中的 OAuth 授权对话框为何会显示该屏幕)。在本教程中,当您深入执行任务 3 时,会再次看到此对话框,并请求用户授予创建和管理 Google 幻灯片演示文稿的权限。
  5. 点击 OAuth2 对话框窗口中的允许后,脚本就会开始运行...您会在顶部看到一个浅黄色的对话框。它运行得非常快,所以您可能注意到它正在运行或执行完毕了。

  6. 该对话框一旦关闭就会消失,因此如果您找不到它,它也许已经完成,因此请转到您的 Google 云端硬盘 (drive.google.com),找到名为“Fake<ph type="x-smartling-void-element"><br /></ph>“莎士比亚作品中所有常见字词”或分配给 QUERY_NAME 变量的任何内容的新 Google 表格:

  7. 打开电子表格后,您应该会看到 10 行字词,并且这些字词的总数以降序排列:

任务 1 摘要

识别出刚刚发生的情况... 您运行了部分代码,以查询莎士比亚的作品(并非大量数据,但肯定比您简单地看每部剧本中的每一个单词都多得多,需要管理这些单词的计数,然后按出现次数降序排序)。您不仅请求了 BigQuery 代表您执行此操作,还能够使用 Google 表格的 Apps 脚本中的内置服务将这些数据放入其中,以方便使用。

您在上面粘贴的 bq-sheets-slides.js(我们选择的文件名)PROJECT_ID(应该具有实际项目 ID 的 PROJECT_ID 除外)的代码可以在此 Codelab 的 GitHub 代码库 (github.com/googlecodelabs/bigquery-sheets-slides) 的 step1 文件夹中找到。代码的灵感来自于“BigQuery 高级服务”页面中的原始示例,该示例运行的查询略有不同...莎士比亚最常用的包含 10 个或更多字符的字词。您还可以在其 GitHub 代码库中查看该示例。

如果您对其他查询感兴趣,则可以尝试使用莎士比亚的作品或其他公开数据表格。请查看此网页此网页。无论使用哪种查询,您都可以始终先在 BigQuery 控制台中测试该查询,然后再在 Apps 脚本中运行该查询。开发者可以访问 bigquery.cloud.google.com 使用 BigQuery 的界面。例如,以下是使用 BigQuery 界面的查询示例:

上述步骤利用了 Apps 脚本的代码编辑器,不过您也可以选择通过命令行在本地开发。您可以创建一个名为 bq-sheets-slides.js 的脚本,将上面的代码粘贴到其中,然后使用 clasp push 命令将其上传到 Google。(如果您之前未填写此内容,我们再次为您提供了 clasp 的链接及其使用方法。)

runQuery() 的用途是与 BigQuery 通信并将其结果发送到 Google 表格。现在,我们需要使用这些数据制作一个图表。为此,我们来创建一个名为 createColumnChart() 的新函数,该函数会调用 Google 表格的 newChart() 方法。

  1. 创建图表。将 createColumnChart() 下面精选的正文添加到 bq-sheets-slides.js 之后,紧接在 runQuery() 之后。它会获取包含数据的工作表,并请求一个包含所有数据的柱形图。数据范围从单元格 A2 开始,因为第一行包含列标题,而不是数据。
/**
 * Uses spreadsheet data to create columnar chart.
 * @param {Spreadsheet} Spreadsheet containing results data
 * @returns {EmbeddedChart} visualizing the results
 * @see http://developers.google.com/apps-script/reference/spreadsheet/embedded-chart
 */
function createColumnChart(spreadsheet) {
  // Retrieve the populated (first and only) Sheet.
  var sheet = spreadsheet.getSheets()[0];
  // Data range in Sheet is from cell A2 to B11
  var START_CELL = 'A2';  // skip header row
  var END_CELL = 'B11';
  // Place chart on Sheet starting on cell E5.
  var START_ROW = 5;      // row 5
  var START_COL = 5;      // col E
  var OFFSET = 0;

  // Create & place chart on the Sheet using above params.
  var chart = sheet.newChart()
     .setChartType(Charts.ChartType.COLUMN)
     .addRange(sheet.getRange(START_CELL + ':' + END_CELL))
     .setPosition(START_ROW, START_COL, OFFSET, OFFSET)
     .build();
  sheet.insertChart(chart);
}
  1. 返回电子表格。在上方,createColumnChart() 需要电子表格对象,因此需要更新 runQuery() 以返回 spreadsheet 对象,以便我们将其传递给 createColumnChart()。记录 Google 表格的成功创建后,在 runQuery() 的末尾紧接着日志行后面返回 spreadsheet 对象:
  Logger.log('Results spreadsheet created: %s', spreadsheet.getUrl());

  // NEW: Return the spreadsheet object for later use.
  return spreadsheet;
}
  1. 驾驶 createBigQueryPresentation() 函数。对 BigQuery 和图表创建功能进行逻辑隔离是一个好主意。现在,我们创建一个 createBigQueryPresentation() 函数来驱动应用,同时调用 runQuery()createColumnChart()。添加的代码应如下所示:
/**
 * Runs a BigQuery query, adds data and a chart in a Sheet.
 */
function createBigQueryPresentation() {
  var spreadsheet = runQuery();
  createColumnChart(spreadsheet);
}
  1. 提高代码的可重用性。您在上面执行了两个重要步骤:返回电子表格对象和创建驱动函数。如果某个同事想要重复使用runQuery()的网址,但不想记录该网址,该怎么办?为了使 runQuery() 更容易被常规使用,我们需要移动该日志行。迁移地图的最佳位置?如果猜错了 createBigQueryPresentation(),那就错了!移动日志行后,它应如下所示:
/**
 * Runs a BigQuery query, adds data and a chart in a Sheet.
 */
function createBigQueryPresentation() {
  var spreadsheet = runQuery();
  Logger.log('Results spreadsheet created: %s', spreadsheet.getUrl()); // MOVED HERE
  createColumnChart(spreadsheet);
}

进行上述上述更改后(同样,除了 PROJECT_ID 之外),您的 bq-sheets-slides.js 现在应如下所示(并且也可在 GitHub 代码库的 step2 文件夹中找到):

// Filename for data results
var QUERY_NAME = "Most common words in all of Shakespeare's works";
// Replace this value with your Google Cloud API project ID
var PROJECT_ID = '';
if (!PROJECT_ID) throw Error('Project ID is required in setup');

/**
 * Runs a BigQuery query; puts results into Sheet. You must enable
 * the BigQuery advanced service before you can run this code.
 * @see http://developers.google.com/apps-script/advanced/bigquery#run_query
 * @see http://github.com/googleworkspace/apps-script-samples/blob/main/advanced/bigquery.gs
 *
 * @returns {Sheet} Returns a sheet with results
 * @see http://developers.google.com/apps-script/reference/spreadsheet/sheet
 */
function runQuery() {
  // Replace sample with your own BigQuery query.
  var request = {
    query:
        'SELECT ' +
            'LOWER(word) AS word, ' +
            'SUM(word_count) AS count ' +
        'FROM [bigquery-public-data:samples.shakespeare] ' +
        'GROUP BY word ' +
        'ORDER BY count ' +
        'DESC LIMIT 10'
  };
  var queryResults = BigQuery.Jobs.query(request, PROJECT_ID);
  var jobId = queryResults.jobReference.jobId;

  // Wait for BQ job completion (with exponential backoff).
  var sleepTimeMs = 500;
  while (!queryResults.jobComplete) {
    Utilities.sleep(sleepTimeMs);
    sleepTimeMs *= 2;
    queryResults = BigQuery.Jobs.getQueryResults(PROJECT_ID, jobId);
  }

  // Get all results from BigQuery.
  var rows = queryResults.rows;
  while (queryResults.pageToken) {
    queryResults = BigQuery.Jobs.getQueryResults(PROJECT_ID, jobId, {
      pageToken: queryResults.pageToken
    });
    rows = rows.concat(queryResults.rows);
  }

  // Return null if no data returned.
  if (!rows) {
    return Logger.log('No rows returned.');
  }

  // Create the new results spreadsheet.
  var spreadsheet = SpreadsheetApp.create(QUERY_NAME);
  var sheet = spreadsheet.getActiveSheet();

  // Add headers to Sheet.
  var headers = queryResults.schema.fields.map(function(field) {
    return field.name.toUpperCase();
  });
  sheet.appendRow(headers);

  // Append the results.
  var data = new Array(rows.length);
  for (var i = 0; i < rows.length; i++) {
    var cols = rows[i].f;
    data[i] = new Array(cols.length);
    for (var j = 0; j < cols.length; j++) {
      data[i][j] = cols[j].v;
    }
  }

  // Start storing data in row 2, col 1
  var START_ROW = 2;      // skip header row
  var START_COL = 1;
  sheet.getRange(START_ROW, START_COL, rows.length, headers.length).setValues(data);

  // Return the spreadsheet object for later use.
  return spreadsheet;
}

/**
 * Uses spreadsheet data to create columnar chart.
 * @param {Spreadsheet} Spreadsheet containing results data
 * @returns {EmbeddedChart} visualizing the results
 * @see http://developers.google.com/apps-script/reference/spreadsheet/embedded-chart
 */
function createColumnChart(spreadsheet) {
  // Retrieve the populated (first and only) Sheet.
  var sheet = spreadsheet.getSheets()[0];
  // Data range in Sheet is from cell A2 to B11
  var START_CELL = 'A2';  // skip header row
  var END_CELL = 'B11';
  // Place chart on Sheet starting on cell E5.
  var START_ROW = 5;      // row 5
  var START_COL = 5;      // col E
  var OFFSET = 0;

  // Create & place chart on the Sheet using above params.
  var chart = sheet.newChart()
     .setChartType(Charts.ChartType.COLUMN)
     .addRange(sheet.getRange(START_CELL + ':' + END_CELL))
     .setPosition(START_ROW, START_COL, OFFSET, OFFSET)
     .build();
  sheet.insertChart(chart);
}

/**
 * Runs a BigQuery query, adds data and a chart in a Sheet.
 */
function createBigQueryPresentation() {
  var spreadsheet = runQuery();
  Logger.log('Results spreadsheet created: %s', spreadsheet.getUrl());
  createColumnChart(spreadsheet);
}

保存文件,然后在代码编辑器顶部,执行 createBigQueryPresentation()(而不是 runQuery())。运行该应用后,您会获得另一张 Google 表格,但这次,工作表中的数据旁边会显示图表:

在此 Codelab 的最后一部分,您需要创建一个新的 Google 幻灯片演示文稿,在标题幻灯片中填写标题和副标题,然后添加 2 个新幻灯片,每个数据单元格对应一个,图表对应一个。

  1. 创建幻灯片。该幻灯片的所有工作都将在 createSlidePresentation() 进行,我们将在 createColumnChart()之后立即将其添加到 bq-sheets-slides.js 中。我们先来创建新的幻灯片,然后为所有新演示文稿的默认幻灯片添加标题和副标题。
/**
 * Create presentation with spreadsheet data & chart
 * @param {Spreadsheet} Spreadsheet with results data
 * @param {EmbeddedChart} Sheets chart to embed on slide
 * @returns {Presentation} Slide deck with results
 */
function createSlidePresentation(spreadsheet, chart) {
  // Create the new presentation.
  var deck = SlidesApp.create(QUERY_NAME);

  // Populate the title slide.
  var [title, subtitle] = deck.getSlides()[0].getPageElements();
  title.asShape().getText().setText(QUERY_NAME);
  subtitle.asShape().getText().setText('via GCP and G Suite APIs:\n' +
    'Google Apps Script, BigQuery, Sheets, Slides');
  1. 添加数据表createSlidePresentation() 中的下一步是将 Google 表格中的单元格数据导入新的幻灯片。请将此代码段添加到函数中:
  // Data range to copy is from cell A1 to B11
  var START_CELL = 'A1';  // include header row
  var END_CELL = 'B11';
  // Add the table slide and insert an empty table on it of
  // the dimensions of the data range; fails if Sheet empty.
  var tableSlide = deck.appendSlide(SlidesApp.PredefinedLayout.BLANK);
  var sheetValues = spreadsheet.getSheets()[0].getRange(
      START_CELL + ':' + END_CELL).getValues();
  var table = tableSlide.insertTable(sheetValues.length, sheetValues[0].length);

  // Populate the table with spreadsheet data.
  for (var i = 0; i < sheetValues.length; i++) {
    for (var j = 0; j < sheetValues[0].length; j++) {
      table.getCell(i, j).getText().setText(String(sheetValues[i][j]));
    }
  }
  1. 导入图表createSlidePresentation() 中的最后一步是再创建一张幻灯片,从我们的电子表格导入图表,然后返回 Presentation 对象。将以下最终代码段添加到该函数中:
  // Add a chart slide and insert the chart on it.
  var chartSlide = deck.appendSlide(SlidesApp.PredefinedLayout.BLANK);
  chartSlide.insertSheetsChart(chart);

  // Return the presentation object for later use.
  return deck;
}
  1. 退货图表。现在,我们的最终函数现已完成,让我们再次检查它的签名。是,createSlidePresentation() 需要电子表格和图表对象。我们已调整 runQuery() 以返回 Spreadsheet 对象,但现在我们需要对 createColumnChart() 进行类似的更改,才能返回图表 (EmbeddedChart) 对象。返回应用中的代码,在 createColumnChart() 的末尾添加最后一行,以添加代码:
  // NEW: Return chart object for later use
  return chart;
}
  1. 更新 createBigQueryPresentation()。由于 createColumnChart() 会返回图表,因此我们需要将该图表保存到变量中,然后将电子表格和图表同时传递到 createSlidePresentation()由于我们记录的是新创建的电子表格的网址,因此我们也将记录新幻灯片演示文稿的网址。更新您的 createBigQueryPresentation(),如下所示:
/**
 * Runs a BigQuery query, adds data and a chart in a Sheet,
 * and adds the data and chart to a new slide presentation.
 */
function createBigQueryPresentation() {
  var spreadsheet = runQuery();
  Logger.log('Results spreadsheet created: %s', spreadsheet.getUrl());
  var chart = createColumnChart(spreadsheet); // UPDATED
  var deck = createSlidePresentation(spreadsheet, chart); // NEW
  Logger.log('Results slide deck created: %s', deck.getUrl()); // NEW
}
  1. 再次保存并运行 createBigQueryPresentation()。不过在执行前,您识别出应用还需要再获得一组权限,才能查看和管理您的 Google 幻灯片演示文稿。一旦您授予此权限,它就会像以前一样运行。
  2. 现在,除了创建的工作表之外,您还应创建一个新的 Google 幻灯片演示文稿,其中包含 3 张幻灯片(标题、数据表、数据图表),如下所示:

恭喜!您现在已经创建了一个应用,该应用通过执行查询 Google BigQuery 请求来查询其中一个公开数据集,利用 Google Cloud 的两面,创建新的 Google 表格来存储结果,根据刚刚检索到的数据添加图表,最后在电子表格中创建包含结果和图表的 Google 幻灯片演示文稿。

从技术上来说,这是你们的努力。大体而言,您不仅完成了大数据分析,还能够向利益相关方展示所有的代码,所有这些工作都是自动进行的。我们希望此示例能够帮助您对项目进行个性化设置。在此 Codelab 结束时,我们将提供一些有关如何进一步增强此示例应用的建议。

在完成上述最终任务(PROJECT_ID 除外)后的上述变更之后,您的 bq-sheets-slides.js 现在应如下所示(也可在 GitHub 代码库中的 final 文件夹中找到):

bq-sheets-slides.js

/**
 * Copyright 2018 Google LLC
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at apache.org/licenses/LICENSE-2.0.
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

// Filename for data results
var QUERY_NAME = "Most common words in all of Shakespeare's works";
// Replace this value with your Google Cloud API project ID
var PROJECT_ID = '';
if (!PROJECT_ID) throw Error('Project ID is required in setup');

/**
 * Runs a BigQuery query; puts results into Sheet. You must enable
 * the BigQuery advanced service before you can run this code.
 * @see http://developers.google.com/apps-script/advanced/bigquery#run_query
 * @see http://github.com/googleworkspace/apps-script-samples/blob/main/advanced/bigquery.gs
 *
 * @returns {Spreadsheet} Returns a spreadsheet with BigQuery results
 * @see http://developers.google.com/apps-script/reference/spreadsheet/spreadsheet
 */
function runQuery() {
  // Replace sample with your own BigQuery query.
  var request = {
    query:
        'SELECT ' +
            'LOWER(word) AS word, ' +
            'SUM(word_count) AS count ' +
        'FROM [bigquery-public-data:samples.shakespeare] ' +
        'GROUP BY word ' +
        'ORDER BY count ' +
        'DESC LIMIT 10'
  };
  var queryResults = BigQuery.Jobs.query(request, PROJECT_ID);
  var jobId = queryResults.jobReference.jobId;

  // Wait for BQ job completion (with exponential backoff).
  var sleepTimeMs = 500;
  while (!queryResults.jobComplete) {
    Utilities.sleep(sleepTimeMs);
    sleepTimeMs *= 2;
    queryResults = BigQuery.Jobs.getQueryResults(PROJECT_ID, jobId);
  }

  // Get all results from BigQuery.
  var rows = queryResults.rows;
  while (queryResults.pageToken) {
    queryResults = BigQuery.Jobs.getQueryResults(PROJECT_ID, jobId, {
      pageToken: queryResults.pageToken
    });
    rows = rows.concat(queryResults.rows);
  }

  // Return null if no data returned.
  if (!rows) {
    return Logger.log('No rows returned.');
  }

  // Create the new results spreadsheet.
  var spreadsheet = SpreadsheetApp.create(QUERY_NAME);
  var sheet = spreadsheet.getActiveSheet();

  // Add headers to Sheet.
  var headers = queryResults.schema.fields.map(function(field) {
    return field.name.toUpperCase();
  });
  sheet.appendRow(headers);

  // Append the results.
  var data = new Array(rows.length);
  for (var i = 0; i < rows.length; i++) {
    var cols = rows[i].f;
    data[i] = new Array(cols.length);
    for (var j = 0; j < cols.length; j++) {
      data[i][j] = cols[j].v;
    }
  }

  // Start storing data in row 2, col 1
  var START_ROW = 2;      // skip header row
  var START_COL = 1;
  sheet.getRange(START_ROW, START_COL, rows.length, headers.length).setValues(data);

  // Return the spreadsheet object for later use.
  return spreadsheet;
}

/**
 * Uses spreadsheet data to create columnar chart.
 * @param {Spreadsheet} Spreadsheet containing results data
 * @returns {EmbeddedChart} visualizing the results
 * @see http://developers.google.com/apps-script/reference/spreadsheet/embedded-chart
 */
function createColumnChart(spreadsheet) {
  // Retrieve the populated (first and only) Sheet.
  var sheet = spreadsheet.getSheets()[0];
  // Data range in Sheet is from cell A2 to B11
  var START_CELL = 'A2';  // skip header row
  var END_CELL = 'B11';
  // Place chart on Sheet starting on cell E5.
  var START_ROW = 5;      // row 5
  var START_COL = 5;      // col E
  var OFFSET = 0;

  // Create & place chart on the Sheet using above params.
  var chart = sheet.newChart()
     .setChartType(Charts.ChartType.COLUMN)
     .addRange(sheet.getRange(START_CELL + ':' + END_CELL))
     .setPosition(START_ROW, START_COL, OFFSET, OFFSET)
     .build();
  sheet.insertChart(chart);

  // Return the chart object for later use.
  return chart;
}

/**
 * Create presentation with spreadsheet data & chart
 * @param {Spreadsheet} Spreadsheet with results data
 * @param {EmbeddedChart} Sheets chart to embed on slide
 * @returns {Presentation} Returns a slide deck with results
 * @see http://developers.google.com/apps-script/reference/slides/presentation
 */
function createSlidePresentation(spreadsheet, chart) {
  // Create the new presentation.
  var deck = SlidesApp.create(QUERY_NAME);

  // Populate the title slide.
  var [title, subtitle] = deck.getSlides()[0].getPageElements();
  title.asShape().getText().setText(QUERY_NAME);
  subtitle.asShape().getText().setText('via GCP and G Suite APIs:\n' +
    'Google Apps Script, BigQuery, Sheets, Slides');

  // Data range to copy is from cell A1 to B11
  var START_CELL = 'A1';  // include header row
  var END_CELL = 'B11';
  // Add the table slide and insert an empty table on it of
  // the dimensions of the data range; fails if Sheet empty.
  var tableSlide = deck.appendSlide(SlidesApp.PredefinedLayout.BLANK);
  var sheetValues = spreadsheet.getSheets()[0].getRange(
      START_CELL + ':' + END_CELL).getValues();
  var table = tableSlide.insertTable(sheetValues.length, sheetValues[0].length);

  // Populate the table with spreadsheet data.
  for (var i = 0; i < sheetValues.length; i++) {
    for (var j = 0; j < sheetValues[0].length; j++) {
      table.getCell(i, j).getText().setText(String(sheetValues[i][j]));
    }
  }

  // Add a chart slide and insert the chart on it.
  var chartSlide = deck.appendSlide(SlidesApp.PredefinedLayout.BLANK);
  chartSlide.insertSheetsChart(chart);

  // Return the presentation object for later use.
  return deck;
}

/**
 * Runs a BigQuery query, adds data and a chart in a Sheet,
 * and adds the data and chart to a new slide presentation.
 */
function createBigQueryPresentation() {
  var spreadsheet = runQuery();
  Logger.log('Results spreadsheet created: %s', spreadsheet.getUrl());
  var chart = createColumnChart(spreadsheet);
  var deck = createSlidePresentation(spreadsheet, chart);
  Logger.log('Results slide deck created: %s', deck.getUrl());
}

在本 Codelab 中,不扮演任何角色的是本 Codelab 中的第二个文件,即 Apps 脚本清单文件 appsscript.json。要访问此代码,请转到代码编辑器浏览器标签页,然后从顶部的菜单中选择查看 &gt 显示清单文件。内容应如下所示:

appsscript.json

{
  "timeZone": "America/Los_Angeles",
  "dependencies": {
    "enabledAdvancedServices": [{
      "userSymbol": "BigQuery",
      "serviceId": "bigquery",
      "version": "v2"
    }]
  },
  "exceptionLogging": "STACKDRIVER"
}

清单文件是一个系统级配置文件,Apps 脚本可使用它来了解应用可用的执行环境。不涵盖此 Codelab 的内容,但您可以学习此 Codelab 的功能。

下面提供了一些其他资源,可帮助您更深入地了解此 Codelab 中涵盖的材料,并探索以编程方式访问 Google 开发者工具的其他方式。我们的目标是使此 Codelab 与代码库保持同步。

此应用的资源

文档

  • 其他 Google(应用)密钥?(Apps 脚本简介视频
  • 通过电子表格访问 Google 地图?!?(视频
  • Google Apps 脚本视频库
  • Launchpad Online 系列视频(前身...)
  • G Suite Dev Show 视频系列

其他 Codelab

入门级

中级

参考应用

下面是各种“代码挑战”,您可以通过不同方式增强或增强我们在此 Codelab 中构建的示例。这份列表当然没有详尽无遗,但应该可以提供一些灵感,让您了解如何进一步改进。

  • 应用。不希望使用 JavaScript 或 Apps 脚本施加的限制吗?将此应用移植到您喜爱的 REST API(适用于 Google BigQuery、表格和幻灯片的编程语言)中。
  • BigQuery。尝试使用不同的查询找出莎士比亚数据集...也许可以找到你感兴趣的查询。您可以在原始的 Apps 脚本 BigQuery 示例应用中找到其他示例查询。
  • BigQuery。尝试使用 BigQuery 的一些其他公开数据集...或许能找到一个可能更有意义的数据集。
  • BigQuery。之前我们提到过,您可以对莎士比亚作品或其他公开数据表尝试其他查询,现在想转告此网页此网页
  • 表格。尝试使用其他图表类型
  • 表格 & BigQuery。翻转表格...也许您在某处的电子表格中整理了大型数据集。2016 年,BigQuery 团队推出了一项功能,允许开发者使用表格作为数据源(有关详情,请参阅一篇博文两篇博文)。
  • 幻灯片。在生成的演示文稿中添加其他幻灯片,例如与大数据分析相关的图片或其他素材资源。请查看幻灯片内置服务指南,以便快速上手。
  • G Suite。查找通过 Apps 脚本使用的其他 G Suite 或 Google 内置服务(即Gmail、Google 云端硬盘、日历、文档、地图、Google Analytics(分析)、YouTube 以及其他高级服务。如需了解详情,请参阅内置服务和高级服务的参考概览