Google Spreadsheetの時系列データから散布図を自動生成してGoogle Driveに保存するGASスクリプト
こんにちは、えぬ(@nmukineer)です!
Google SpreadSheetで管理している体重データを、定期的にグラフ化して画像付きツイートしたいなーと思って作ってみました。
今回はGoogle SpreadSheetの時系列データから任意の日時範囲で散布図を作成し、Google Driveに画像として保存するGASスクリプトを書いてみました。
処理の流れ
処理の流れを簡単に書くと以下のようになります。
- データ参照
- 時系列データを保管しているシートを参照します。ここでは範囲を絞らず、シート内の全データを取得します
- 全データを取得したら、指定した範囲にデータを切り取ります。
- 一時シート作成
- ①で切り出したデータを、同一スプレッドシートの別シートに記録します。このシートはグラフ作成のために一時的に作成されるものであり、⑤で削除されます。
- グラフ作成
- ②で作成したデータに対してグラフを作成します。
- グラフ画像保存
- ③で作成したグラフを画像として所定のGoogle Driveのフォルダに保存します。
- 一時シート削除
- ④で画像として保存したため②で作成したシートは不要になりました。削除します。
スプレッドシートの準備
Google Drive上にスプレッドシートを新規作成します。
今回は、体重や体脂肪率をスプレッドシート上で管理しているという想定で、「体重」と「体脂肪率」というシートを作成しておきます。
また、「体重」シートには、こちらのように適当にダミーで日時と体重データを入れておきます。上から日時が古い順に並んでいます。
GASスクリプトの作成
プロジェクトを作成
プロジェクトの作成方法についてはこちらの記事を参考にしてください。
スクリプトを作成
こちらが今回作成したスクリプトです。参考までにスクリプト内にコメントしております。
//スクリプトプロパティに事前に登録しておく
const FOLDER_ID = PropertiesService.getScriptProperties().getProperty('FOLDER_ID');
const SPREADSHEET_ID = PropertiesService.getScriptProperties().getProperty('SPREADSHEET_ID');
//スプレッドシートのシート名
const SHEET_NAME = {
weight: "体重",
fat: "体脂肪率",
temp: "temp"
}
//Date型を日付文字列に変換する関数
const dateText = date => `${date.getFullYear()}年${date.getMonth() + 1}月${date.getDate()}日`;
//配列を転置する関数
const transpose = a => a[0].map((_, c) => a.map(r => r[c]));
//グラフを作成する関数
//期間(from, to): Date
//key: シート名(キー)
function createGraph(from, to, key) {
const sheetName = SHEET_NAME[key];
const activeSheet = SpreadsheetApp.openById(SPREADSHEET_ID);
const sheet = activeSheet.getSheetByName(sheetName);
const values = sheet.getDataRange().getValues();
const tValues = transpose(values);
//from, toのそれぞれのIndexを探す
const fromIndex = tValues[0].findIndex(elem => elem >= from);
const toIndex = tValues[0].findIndex(elem => elem >= to);
//取得したfrom, toの範囲にデータを限定する
const tempArray = values.slice(fromIndex, toIndex + 1)
//ヘッダー追加
tempArray.unshift(["日時", SHEET_NAME[key]])
//一時シート作成(重複しないようにシート名にタイムスタンプをつける)
let newSheet = activeSheet.insertSheet();
const tempName = `${SHEET_NAME.temp}${Date.parse(new Date())}`
newSheet.setName(tempName);
//一時シートに記録
tempArray.forEach(function(row) {
newSheet.appendRow(row);
});
//散布図作成
const range = newSheet.getRange(1, 1, values.length, values[0].length);
let chart = newSheet.newChart()
.addRange(range)
.asScatterChart()
.setNumHeaders(1)
.setYAxisRange(60, 80)
.setPosition(1,4,0,0)
.setOption("title", `${SHEET_NAME[key]}推移: ${dateText(from)}~${dateText(to)}`)
.build();
newSheet.insertChart(chart);
//折れ線グラフをドライブに保存
const graph = newSheet.getCharts();
const graphImg = graph[0].getBlob();
const folder = DriveApp.getFolderById(FOLDER_ID);
const file = folder.createFile(graphImg.setName(tempName));
const fileId = file.getId();
//シートの削除
const sheet2 = activeSheet.getSheetByName(tempName);
activeSheet.deleteSheet(sheet2);
return fileId;
}
//テスト用関数。こっちを実行する。
function test() {
const endDate = "2022/10/20";
const dateRange = 7;
const to = new Date(endDate);
let from = new Date(endDate);
from.setDate(from.getDate() - dateRange);
const graphId = createGraph(from, to, 'weight');
console.log(graphId);
}
実行してみる
テスト実行用に用意したtest
を実行してみます。成功したら、生成されたグラフのファイルIDがログに表示されるはずです!
じゃん!
きました!Google DriveはファイルIDがわかれば、
https://drive.google.com/file/d/<ファイルID>
とすることでアクセスすることが可能です(アクセス権限があるGoogleアカウントのみ)。
これをGoogle Driveで開いてみます!
どん!
見事にできてました。Google Drive上のどこにあるかは、スクリプト上で「FOLDER_ID」というスクリプトプロパティに登録したフォルダに生成されています。
今回は「マイドライブ⇒GAS用⇒graphs」というフォルダのIDをFOLDER_IDに設定したため、ちゃんとフォルダ内に画像が保存されていました。
まとめ
今回はGASを使ってスプレッドシートの時系列データから任意の範囲をグラフ化し画像として保存するスクリプトを書いてみました!
決まった日時に画像を生成してTwitterに投稿するようにしておけば自動的に日々の変化を発信していけますね!
お読みいただきありがとうございました!