運用 Google 試算表和簡報將大數據轉化為深入分析

市面上有許多工具可供資料科學家執行大數據分析,但最終您還是得向管理階層說明這些結果的合理性,不是嗎?紙上或資料庫中的大量數字,很難向主要利害關係人呈現。這項中階 Google Apps Script 程式碼研究室會運用 Google 的一對開發人員平台 (G SuiteGoogle Cloud Platform (GCP)),協助您完成最後一哩路。

Google Cloud 的開發人員工具可讓您執行深入的資料分析,然後將結果匯入試算表,並根據這些資料產生投影片簡報,以更合適的方式向管理階層呈現結果。本程式碼研究室涵蓋 GCP 的 BigQuery API (做為 Apps Script 進階服務),以及 Google 試算表Google 簡報內建 Apps Script 服務

動機/既有技術

本程式碼研究室中的範例應用程式是參考下列程式碼範例...

雖然 Slides API 程式碼研究室的範例應用程式也提供 BigQuery 和 Slides,但與本程式碼研究室的範例應用程式有幾項差異:

  • Node.js 應用程式與 Apps Script 應用程式的比較
  • 使用 REST API,同時使用 Apps Script 服務
  • 使用 Google 雲端硬碟,但未使用 Google 試算表;這個應用程式使用 Google 試算表,但未使用 Google 雲端硬碟

在本程式碼研究室中,我們希望將盡可能多的技術整合到單一應用程式中,同時展示 Google Cloud 的各項功能和 API,讓您更貼近實際使用情境。我們希望藉此激發您的想像力,並考慮運用 GCP 和 G Suite 解決貴機構或客戶的難題。

課程內容

  • 如何搭配多項 Google (GCP 和 G Suite) 服務使用 Google Apps Script
  • 如何使用 Google BigQuery 執行大數據分析
  • 如何建立 Google 試算表並填入資料
  • 如何在 Google 試算表中建立新圖表
  • 如何將 Google 試算表的圖表和資料轉移到 Google 簡報

軟硬體需求

  • 網路連線和網路瀏覽器
  • Google 帳戶 (G Suite 帳戶可能需要管理員核准)
  • 具備基本 JavaScript 技能
  • 具備 Apps Script 開發知識會有幫助,但並非必要條件

您會如何使用這個程式碼研究室/教學課程?

閱讀內容以瞭解相關資訊,並可能將其轉發給技術同事 盡可能完成內容,並嘗試完成所有練習 無論如何,我都要完成整個程式碼研究室

您對 G Suite 開發人員工具和 API 的體驗滿意嗎?

新手 中級 熟練

您對 Apps Script 的體驗滿意嗎?

新手 中級 熟練

您對 GCP 開發人員工具和 API 的體驗滿意嗎?

新手 中級 熟練

現在您已瞭解本程式碼研究室的主題,接下來要具體做些什麼呢?

  1. 使用現有的 Apps Script-BigQuery 範例並使其正常運作
  2. 從該範例瞭解如何將查詢傳送至 BigQuery 並取得結果
  3. 建立 Google 試算表,並將 BigQuery 的結果填入其中
  4. 稍微修改程式碼,稍微變更傳回並新增至試算表的資料
  5. 使用 Apps Script 中的試算表服務,為 BigQuery 資料建立圖表
  6. 使用 Google 簡報服務建立新的投影片簡報
  7. 為所有新投影片組自動建立的預設標題投影片新增標題和副標題
  8. 建立含有資料表的新投影片,然後將 Google 試算表的資料格匯入其中
  9. 新增另一張投影片,並在其中加入試算表圖表

首先,請先瞭解 Apps Script、BigQuery、試算表和簡報的背景資訊。

Google Apps Script 和 BigQuery

Google Apps Script 是 G Suite 開發平台,運作層級高於 Google REST API。這個無伺服器開發和應用程式代管環境適用於各種程度的開發人員。簡單來說,「Apps Script 是無伺服器 JavaScript 執行階段,可自動化、擴充及整合 G Suite。」

這項技術與 Node.js 類似,都是伺服器端 JavaScript,但著重於與 G Suite 和其他 Google 服務緊密整合,而非快速的非同步事件驅動應用程式代管。此外,開發環境可能與您習慣的環境完全不同。使用 Apps Script,您可以:

  • 在網頁式程式碼編輯器中開發,但如果使用 clasp (Apps Script 的指令列部署工具),則可選擇在本機開發
  • 以專門版本的 JavaScript 編寫程式碼,存取 G Suite 和其他 Google 或外部服務 (透過 Apps Script URLfetchJdbc 服務)
  • 不必編寫授權程式碼,因為 Apps Script 會為您處理
  • 不必代管應用程式,應用程式會存放在雲端中的 Google 伺服器上並在該處執行

注意:本程式碼研究室主要不會教導您 Apps Script,網路上有許多資源可協助您完成這項作業。官方說明文件也提供快速入門導覽課程總覽教學課程影片。最後,別忘了先完成 Apps Script 簡介程式碼研究室,再開始進行本程式碼研究室。

Apps Script 與其他 Google 技術的介面互動方式有兩種:

  • 內建/原生服務
  • 進階服務

內建服務提供高階方法,可用於存取 G Suite 或 Google 產品資料,或存取其他實用公用程式方法。進階服務只是 G Suite 或 Google REST API 的精簡包裝函式。進階服務可完整涵蓋 REST API,通常比內建服務的功能更多,但需要較複雜的程式碼 (不過仍比 REST API 本身更容易使用)。使用進階服務前,也必須為指令碼專案啟用進階服務

如果可以,開發人員應優先使用內建服務,因為內建服務比進階服務更容易使用,且能處理更多繁重的工作。不過,部分 Google API 沒有內建服務,因此進階服務可能是唯一選擇。Google BigQuery 就是其中一例,雖然沒有內建服務,但有 BigQuery 進階服務。(總比沒有服務好,對吧?) 如果您是 BigQuery 新手,這項 GCP 服務可讓您對非常龐大的資料集 (例如數 TB 的資料) 執行簡單 (或複雜) 的查詢,並在幾秒內提供結果。

透過 Apps Script 存取 Google 試算表和簡報

與 BigQuery 不同,Google 試算表和簡報都有內建服務 (以及進階服務,您只會使用進階服務存取 API 專屬功能)。請先參閱內建的 試算表簡報服務說明文件,再開始編寫程式碼。當然,進階服務也有相關文件,請分別參閱 Google 試算表Google 簡報的文件。

簡介

我們將透過第一個工作,在本程式碼研究室中深入探討這個主題。事實上,完成這個步驟後,您就差不多完成整個程式碼研究室的一半內容。這項作業會分成幾個小節,您將完成下列所有事項:

  • 建立新的 Google Apps Script 專案
  • 啟用 BigQuery 進階服務存取權
  • 前往開發編輯器,輸入應用程式原始碼
  • 完成應用程式授權程序 (OAuth2)
  • 執行會將要求傳送至 BigQuery 的應用程式
  • 查看使用 BigQuery 結果建立的全新 Google 試算表

設定

  1. a) 前往 script.google.com 建立新的 Apps Script 專案。G Suite 產品線有許多不同版本,建立新專案的方式可能因版本而異。如果您只是使用 Gmail 帳戶,且是專案開發新手,畫面上會顯示空白畫面,以及建立第一個專案的按鈕:


b) 否則,您可能會在左上角看到所有專案和大型「+New」 按鈕,請點選該按鈕。



c) 如果上述兩種情況都不符合,畫面可能如下所示。如果是,請在左上角尋找漢堡選單圖示,然後選取「+ 新指令碼」



d) 如果您偏好使用指令列,您要使用的工具是 clasp,具體來說,您將執行 clasp create 指令。

e) 建立新指令碼專案的最後一種方式,就是前往捷徑連結:https://script.google.com/create

  1. 無論您使用哪種技術啟動新專案,最終都應該會進入 Apps Script 程式碼編輯器,畫面如下所示:


  2. 依序點選「File」>「Save」,然後為專案命名。
  3. 接著,您需要建立 Google Cloud 控制台專案,才能執行 BigQuery 查詢。
  1. 建立新專案、命名、選取帳單帳戶,然後按一下「建立」
  1. 專案建立完成後,頁面右上角會顯示通知。按一下「建立專案:<專案名稱>」項目,開啟專案。
  2. 按一下左上方的選單圖示 ,然後前往「API 和服務」>「憑證」。按一下「OAuth 同意畫面」分頁 (直接連結)。
  3. 在「Application name」(應用程式名稱) 欄位中輸入「Big Data Codelab」,然後按一下底部的「Save」(儲存) 按鈕。
  4. 按一下右上角的三點圖示展開選單,然後選取「專案設定」 (直接連結)。
  5. 複製「專案編號」下方列出的值。(我們會在程式碼研究室的後續步驟中,使用另一個「產品 ID」欄位)。
  6. 返回 App Script 編輯器,然後依序點選「Resources」>「Cloud Platform project」
  7. 在文字方塊中輸入專案編號,然後按一下「設定專案」。系統提示時,按一下「確認」
  8. 完成後,按一下「關閉」按鈕即可關閉對話方塊。
  9. 現在您已設定新專案,需要啟用 BigQuery 進階服務,因此請下拉「資源」->「進階 Google 服務」,然後將 BigQuery API 的位元開啟


  10. 底部的附註會顯示「必須在『Google Cloud Platform API 資訊主頁』中一併啟用這些服務」,因此請點選該連結,在另一個瀏覽器分頁中開啟開發人員控制台 (簡稱「devconsole」)。
  11. 在開發人員控制台中,按一下頂端的「+ 啟用 API 和服務」按鈕,搜尋「bigquery」,選取 BigQuery API (不是 BigQuery Data Transfer API),然後按一下「啟用」開啟。請保持開啟這個瀏覽器分頁。

    注意:啟用 API 後,您可能會在這個頁面上看到類似「如要使用這個 API,您必須建立憑證...」的附註,但請暫時不必擔心,Apps Script 會為您處理這個步驟。


  12. 返回程式碼編輯器瀏覽器分頁,您仍處於「進階 Google 服務」選單,因此請按一下「確定」關閉對話方塊,然後留在程式碼編輯器中。按一下頂端的專案名稱,然後將專案命名為「BigQuery 試用」或類似名稱 (我們將專案命名為「final mile」)。

現在您已準備好輸入應用程式程式碼、完成授權程序,並讓這個應用程式的第一個版本運作。

上傳並執行應用程式

  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,因此請將您的專案 ID 新增至應用程式程式碼。如要取得這項資訊,請返回開發人員主控台頁面的瀏覽器視窗或分頁。(我們請你保持開啟狀態,還記得嗎?)
  2. 在 Google 帳戶顯示圖片左側的頂端,有一個下拉式選單選取器 ()。按一下並選取「專案設定」。畫面上會顯示專案名稱、ID 和編號。複製專案 ID,並將 bq-sheets-slides.js 頂端的 PROJECT_ID 變數設為您從開發人員控制台取得的值。注意:如果選單選取器無法移動且無法操作,請重新載入頁面。
  3. if 陳述式可防止應用程式在沒有專案 ID 的情況下繼續執行。新增完成後,請儲存檔案,然後依序選取選單列中的「Run」>「Run function」>「runQuery」,點按「Review Permissions」對話方塊中的「This app is unverified」,下方的 GIF 動畫 (適用於其他應用程式) 會說明接下來的幾個步驟:
  4. 要求審查權限後,系統會顯示新的對話方塊,如上圖所示。選擇要執行指令碼的正確 Google 帳戶,選取「進階」,向下捲動,然後按一下「前往 <您的專案名稱> (不安全)」,即可進入 OAuth2 應用程式授權畫面。(請參閱驗證程序一文,進一步瞭解為何這個畫面會出現在您和下方的 OAuth2 授權對話方塊之間。)


    注意:授權應用程式後,您就不必在每次執行時重複這個程序。在本教學課程的「工作 3」之前,您不會再次看到這個對話方塊,要求使用者授權建立及管理 Google 簡報。
  5. 在 OAuth2 對話方塊中按一下「允許」後,指令碼就會開始執行,畫面頂端會顯示淡黃色對話方塊。這項作業的執行速度相當快,因此您可能不會注意到作業正在執行或已完成。

  6. 完成後,該對話方塊就會消失。如果沒有看到,表示作業可能已完成,請前往 Google 雲端硬碟 (drive.google.com),尋找名為「Most common words in all of Shakespeare's works」(莎士比亞所有作品中最常見的字詞) 的新 Google 試算表,或您指派給 QUERY_NAME 變數的名稱:


  7. 開啟試算表,您應該會看到 10 列字詞,以及依遞減順序排序的總計次數:

工作 1 摘要

您剛才執行了一些程式碼,查詢了所有莎士比亞作品 (資料量不算龐大,但肯定比您自己逐字掃描每部戲劇、管理這些字詞的計數,然後依出現次數遞減排序還要多)。您不僅要求 BigQuery 代表您執行這項操作,還能使用 Google 試算表的 Apps Script 內建服務,將資料放入試算表,方便您使用。

您在上方貼上的 bq-sheets-slides.js 程式碼 (我們選擇的檔案名稱) (除了 PROJECT_ID 應具有實際專案 ID 之外),也可以在 github.com/googlecodelabs/bigquery-sheets-slides 的本程式碼研究室 GitHub 存放區中,找到 step1 資料夾。這段程式碼的靈感來自 BigQuery 進階服務頁面中的原始範例,該範例執行的查詢略有不同,目的是找出莎士比亞最常使用的字詞 (長度為 10 個字元以上)。您也可以在 GitHub 存放區中查看該範例。

如要查詢莎士比亞作品或其他公開資料表,請參閱這個網頁這個網頁。無論使用哪種查詢,您一律可以在 BigQuery 控制台中測試查詢,再於 Apps Script 中執行。開發人員可透過 bigquery.cloud.google.com 使用 BigQuery 的使用者介面。舉例來說,以下是使用 BigQuery UI 查詢的樣子:

上述步驟使用 Apps Script 的程式碼編輯器,您也可以選擇透過指令列在本機開發。您也可以建立名為 bq-sheets-slides.js 的指令碼,將上述程式碼貼入其中,然後使用 clasp push 指令上傳至 Google。(如果您先前錯過,這裡再次提供 clasp 的連結和使用方式)。

runQuery() 的用途是與 BigQuery 通訊,並將結果傳送至試算表。現在我們需要使用資料製作圖表。讓我們建立名為 createColumnChart() 的新函式,呼叫 Sheet 的 newChart() 方法來執行這項操作。

  1. 建立圖表。在 runQuery() 後方新增下方顯示的 createColumnChart() 主體。bq-sheets-slides.js取得含有資料的工作表,並要求提供包含所有資料的直條圖。資料範圍從儲存格 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. 讓程式碼更易於重複使用。您已完成上述 2 個重要步驟:傳回試算表物件,以及建立驅動函式。如果同事想重複使用 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 試算表,但這次試算表中的資料旁會顯示圖表:

本程式碼研究室的最後一部分,是建立新的 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 試算表來儲存結果、根據剛擷取的資料新增圖表,以及建立 Google 簡報來呈現結果和試算表中的圖表,充分運用 Google Cloud 的兩端功能。

這就是您在技術上所做的。廣義來說,您已從大數據分析轉為可向利害關係人呈現的內容,而且全都是以程式碼自動完成。希望這個範例能激發您的靈感,並根據自己的專案進行調整。本程式碼研究室結束時,我們會提供一些建議,說明如何進一步強化這個範例應用程式。

完成上述變更後 (再次排除 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());
}

在本程式碼研究室中,「第二個檔案」是 Apps Script 資訊清單檔案 appsscript.json,但不會扮演任何角色。如要存取,請前往程式碼編輯器瀏覽器分頁,然後從頂端選單依序選取「View」>「Show manifest file」。內容應如下所示:

appsscript.json

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

資訊清單檔案是系統層級的設定檔,Apps Script 會根據這個檔案,判斷應用程式可用的執行環境。本程式碼研究室不會涵蓋資訊清單檔案的內容,但您可以瞭解其用途。

下方提供其他資源,協助您深入瞭解本程式碼研究室涵蓋的內容,並探索以程式輔助方式存取 Google 開發人員工具的其他方法。我們會盡量讓本程式碼研究室與存放區保持同步。

這個應用程式的資源

說明文件

其他程式碼研究室

入門

中級

參考應用程式

以下是各種「程式碼挑戰」,您可以透過不同方式,強化或擴增我們在本程式碼研究室中建構的範例。這份清單並非詳盡無遺,但應該能提供一些靈感,協助您採取下一步行動。

  • 應用程式。不想受限於 JavaScript 或 Apps Script 施加的限制嗎?將這個應用程式移植到您慣用的程式設計語言,並使用 Google BigQuery、試算表和簡報的 REST API。
  • BigQuery:請嘗試對莎士比亞資料集使用其他查詢,或許能找到您感興趣的查詢。如需其他查詢範例,請參閱原始的 Apps Script BigQuery 範例應用程式
  • BigQuery:試用其他 BigQuery 公開資料集...或許能找到對您更有意義的資料集。
  • BigQuery:我們稍早提到,您可以嘗試查詢莎士比亞的作品或其他公開資料表,現在想再次分享這個網頁這個網頁
  • 試算表。嘗試其他圖表類型
  • Google 試算表和 BigQuery。反過來想,您可能在某個試算表中擁有大型資料集。2016 年,BigQuery 團隊推出這項功能,讓開發人員能使用試算表做為資料來源 (詳情請參閱第一篇第二篇網誌文章)。
  • 簡報。在生成的簡報中新增其他投影片,例如與大數據分析相關的圖片或其他資產。請參閱這份指南,瞭解如何開始使用簡報內建服務。
  • G Suite。透過 Apps Script 尋找其他 G Suite 或 Google 內建服務的用途,例如 Gmail、Google 雲端硬碟、日曆、文件、地圖、Analytics、YouTube 等,以及其他進階服務。如要瞭解內建和進階服務,請參閱參考資料總覽