クイックノート

ちょっとした発見・アイデアから知識の発掘を

【GAS】時系列を図解するスライドを自動生成

ある一連のできごとを図解する場合、
時系列に沿って出来事を並べると前後の関係が一目瞭然になります。

また、単に順に並べるだけではなく、
出来事と出来事の間の時間を視覚的なスペースとして表現すれば、
より正確に時間の流れを説明することができます。

下の図は、出来事が生じた年を点の位置で表現しています。
「AAAA」と「BBBB」
「CCCC」と「DDDD」
の間はどちらも同じ7年の間が空いていますが、
図でも同じ間隔が空くように配置されています。

f:id:u874072e:20191004141724p:plain
年によって位置をずらした図

問題は、このような図を手で作るとなると結構手間がかかるということです。

まず、手作業で正確な位置に図形を移動させるのは至難の業です。
きわめて正確なマウス捌きが要求されることになります。

一応、座標を指定して図形を移動させることもできますが、
一つ一つの図形に座標を設定していくのも中々に骨が折れます。

そこで、このスライド作成作業を自動化してみましょう。

自動生成の流れ

下のように時間と出来事を並べたデータを用意して、
このデータをもとに時系列を図示したスライドを生成します。

f:id:u874072e:20191004144813p:plain
時系列のデータファイル

自動生成では、上のデータを読み込んで、
順にふさわしい位置に出来事を配置していきます。

GASのコード

以下ではデータを読み込んで、
自動的に図を生成するGASのコードを紹介します。

関数

データの読み込み

まずは、Google スプレッドシートから、
図のもととなるデータを取得します。

データを取得するシート名をDATA_SHEETで指定します。

var DATA_SHEET = "データ領域"
function load_data(){
  var ss = SpreadsheetApp.getActive()
  var s = ss.getSheetByName(DATA_SHEET)
  
  var row = s.getLastRow()
  var col = s.getLastColumn()
  
  var X = s.getRange(1, 1,row,col).getValues()
  return(X)
}

読み込んだデータは二次元配列として保持します。
二次元配列から列を取り出せるようにしておくと便利なので、
列を取り出す関数getColumnを定義しておきます。

function getColumn(array,col){
  var ans = []
  for(var i=0;i<array.length;i++){
    ans.push(array[i][col])
  }
  return ans
}

まっさらなスライドの生成

図形を配置していく前に、
その土台となるスライドを生成します。

デフォルトでは、タイトル領域などが最初から配置されていますが、
今回は、まっさらなスライドに図形を配置していきたいので、
clear_pageでページの要素を全て削除しています。

function clear_page(slide){
  var els = slide.getPageElements()
  for(var i=0;i<els.length;i++){
    els[i].remove()
  }
}

function slide_initialize(){
  var pres = SlidesApp.create("自動生成された年表")
  var slides = pres.getSlides()
  var sl = slides[0]
  clear_page(sl)
  return [pres,sl]
}

図形の位置計算

データに含まれる時間に応じて、
いい感じの位置に図形を配置するための位置を計算します。

基本的には、一番古い出来事と、一番新しい出来事が、
スライドの両端にくるようにして、
後はそれぞれの時間に応じて相対的に配置します。

function rel_position(x,start,end){
  var max_x = Math.max.apply([],x)
  var min_x = Math.min.apply([],x)
  var ans = []
  Logger.log(max_x)
  for(var i=0;i<x.length;i++){
    ans.push((x[i]-min_x)/(max_x-min_x) * (end-start) + start)
  }
  return ans
}

図の自動生成

上で定義した関数を利用して、図を自動生成します。
少しいじることで様々なバリエーションの図が生成できます。

箱型の時系列

ひとつめは下のような箱を時系列にそって並べたものです。
箱の中に出来事の名前を表示しています。

f:id:u874072e:20191004151928p:plain
箱型の時系列

function chro_box() {
  var X = load_data()
  var [pres, sl] = slide_initialize()

  var years = getColumn(X,0).map(Number)
  var pos = rel_position(years,50,pres.getPageWidth()-100)
  for(var i=0;i<X.length;i++){
    var text = X[i][1]
    var rect = sl.insertShape(SlidesApp.ShapeType.RECTANGLE,pos[i],50,50,30)
    
    rect.getText().setText(text).getTextStyle().setForegroundColor("#FFFFFF")
    rect.getFill().setSolidFill("#004ea8")
    rect.getBorder().setTransparent()
  }
}

点型の時系列

次は、箱の代わりに小さい丸、点を並べて時系列を図示してみます。
出来事の名前は点の上にテキストボックスで配置しています。

f:id:u874072e:20191004152228p:plain
点型の時系列

function chro_dot() {
  var X = load_data()
  var [pres, sl] = slide_initialize()

  var years = getColumn(X,0).map(Number)
  var pos = rel_position(years,50,pres.getPageWidth()-50)
  for(var i=0;i<X.length;i++){
    var text = X[i][1]
    var rect = sl.insertShape(SlidesApp.ShapeType.ELLIPSE,pos[i],50,10,10)
    var tbox = sl.insertShape(SlidesApp.ShapeType.TEXT_BOX,pos[i]-15,20,200,30)
    
    tbox.getText().setText(text)
    rect.getFill().setSolidFill("#004ea8")
    rect.getBorder().setTransparent()
  }
}

点型の時系列+時間

最後に、冒頭で示した点の時系列に、
時間も表示したものを生成します。

f:id:u874072e:20191004141724p:plain
点型の時系列+時間

function chro_dot_with_year() {
  var X = load_data()
  var [pres, sl] = slide_initialize()

  var years = getColumn(X,0).map(Number)
  var pos = rel_position(years,50,pres.getPageWidth()-50)
  for(var i=0;i<X.length;i++){
    var text = X[i][1]
    var rect = sl.insertShape(SlidesApp.ShapeType.ELLIPSE,pos[i],50,10,10)
    var tbox = sl.insertShape(SlidesApp.ShapeType.TEXT_BOX,pos[i]-15,20,200,30)
    sl.insertShape(SlidesApp.ShapeType.TEXT_BOX,pos[i]-15,80,200,30).getText().setText(years[i])
    
    tbox.getText().setText(text)
    rect.getFill().setSolidFill("#004ea8")
    rect.getBorder().setTransparent()
  }
}

まとめ

手作業では微調整がとても面倒な、
時系列の図解スライドをGASで自動生成する方法を紹介しました。

これを応用すれば、ガートナーのハイプサイクルのように、
グラフ上に大量の点と文字を配置した図も一発でつくれそうです。

プライバシーポリシー