前回までの取り組みで、PowerShellスクリプトを使ってCSVデータから棒グラフと円グラフの画像データが生成できるようになった。だが、グラフの種類ごとにPowerShellスクリプトが用意されている。今回は、これを統合して1つのスクリプトにする。

→連載「PowerShell Core入門 - 基本コマンドの使い方」の過去回はこちらを参照。

csv2barchart.ps1とcsv2piechart.ps1の差分を調べる

前回までに、棒グラフと円グラフを作成するPowerShellスクリプトを作成した。目的は達成しているわけだが、このままだと「似たようなPowerShellのコードがいろんなファイルに存在する」という状況が生まれる。これではメンテナンスが面倒になるので、共通部分を取り出して1つの汎用的なPowerShellスクリプトファイルにまとめたい。

まずは、作成した2つのPowerShellスクリプトファイル(csv2barchart.ps1、csv2piechart.ps1)の違いを調査する。差分は以下の通りだ。

--- csv2barchart.ps1        2023-05-30 10:11:11.408891800 +0900
+++ csv2piechart.ps1        2023-05-30 10:11:11.408891800 +0900
@@ -59,7 +59,7 @@
                        'height':'$Height'};

         // 初期化およびチャートの生成
-        var chart = new google.visualization.BarChart(document.getElementById('chart_div'));
+        var chart = new google.visualization.PieChart(document.getElementById('chart_div'));

         // チャートイメージをbase64エンコードされたPNG画像データとして出力
         google.visualization.events.addListener(chart, 'ready', function () {

実際には上記のようにGoogle Charts APIのインスタンスの生成部分の処理が違うだけで、ほかはまったく同じだ。これなら単一のファイルにまとめた方がメンテナンス的にも良い。

汎用的なcsv2chart.ps1を作る

今回の目的に合わせた「csv2chart.ps1」は次の通りだ。

#!/usr/bin/env pwsh

#========================================================================
# 引数を処理
#   -CSVFile パス             グラフのCSVデータファイルパス
#   -PNGFile パス             生成するPNG画像のファイルパス
#   -OutFile パス             中間生成されるHTMLファイルパス
#   -GraphTitle タイトル        グラフのタイトル
#   -Width 幅                        生成するPNG画像の幅
#   -Height 高さ              生成するPNG画像の高さ
#   -Type グラフ種類             生成するグラフの種類
#========================================================================
Param(
    [Parameter(Mandatory=$true)][String]$CSVFile,
    [String]$PNGFile = (Get-Location).ToString() + '\out.png',
    [String]$OutFile = (Get-Location).ToString() + '\out.html',
    [String]$GraphTitle = 'グラフ',
    [Int]$Width = 2000,
    [Int]$Height = 1200,
    [ValidateSet('Bar','Pie')]$GraphType = 'Bar'
)

#========================================================================
# 気温データを取得
#========================================================================
$CsvData = Import-Csv $CSVFile -Header 1,2
# ヘッダを変数に格納
foreach     ($Row in $CsvData) {
    $CsvHeader1 = $Row.1
    $CsvHeader2 = $Row.2
    break
}

#========================================================================
# Google Charts用HTMLの用意
#========================================================================
$GoogleChartsHTML1 = @"
<html>
  <head>
    <script type="text/javascript" src="https://www.gstatic.com/charts/loader.js"></script>
    <script type="text/javascript">
      // Google Visualization APIおよびコアチャートパッケージを読み込み
      google.charts.load('current', {'packages':['corechart']});

      // Google Visualization API読み込み完了後に実行
      google.charts.setOnLoadCallback(drawChart);
      function drawChart() {
        // データテーブルを作成
        var data = new google.visualization.DataTable();
        data.addColumn('string', '');
        data.addColumn('number', '$CsvHeader2');
        data.addRows([
"@

$GoogleChartsHTML2 = @"
        ]);

        // チャートオプションを設定
        var options = {'title':'$GraphTitle',
                       'width':'$Width',
                       'height':'$Height'};

        // 初期化およびチャートの生成
        var chart = new google.visualization.${GraphType}Chart(document.getElementById('chart_div'));

        // チャートイメージをbase64エンコードされたPNG画像データとして出力
        google.visualization.events.addListener(chart, 'ready', function () {
          document.getElementById('chart_base64').innerHTML = chart.getImageURI();
        });

        // チャートを描画
        chart.draw(data, options);
      }
    </script>
  </head>
  <body>
    <div id="chart_div"></div>
    <div id="chart_base64"></div>
  </body>
</html>
"@

#========================================================================
# CSVデータをGoogle Chartsで使える形式へ加工
#========================================================================
$GraphData = ""
$FirstLineIs = $true
foreach     ($Row in $CsvData) {
    if ($FirstLineIs) {
            $FirstLineIs = $false
            continue
    }

    $GraphData = $GraphData + "['" + $Row.1 + "'," + $Row.2 + "],"
}
$GraphData = $GraphData.trim(",")

#========================================================================
# Google Charts用のHTMLを出力
#========================================================================
$GoogleChartsHTML1                                  > $OutFile
$GraphData                                          >>$OutFile
$GoogleChartsHTML2                                  >>$OutFile

#========================================================================
# WebDriver起動
#========================================================================
webdriver_edge_start.ps1

#========================================================================
# Microsoft EdgeでGoogle Charts用のHTMLをオープン
#========================================================================
$FileURL = "file:///" + $OutFile.Replace('\','/')

'Microsoft Edgeでグラフを描画します。'
Set-SeUrl -Url $FileURL

#========================================================================
# 描画されたグラフをBase64エンコードされたPNGデータとして取得
#========================================================================
'描画したグラフをBase64エンコードされたPNGデータとして取得します。'
$Element = Get-SeElement -By XPath -Value '//*[@id="chart_base64"]'
$Base64 = $Element.Text -replace 'data:image/png;base64,',''

#========================================================================
# Base64エンコードデータをデコードしてファイルへ保存
#========================================================================
'Base64エンコードされたPNGデータをデコードして保存します。'
$Bytes = [Convert]::FromBase64String($Base64)
[IO.File]::WriteAllBytes($PNGFile, $Bytes)

#========================================================================
# WebDriverを終了
#========================================================================
webdriver_edge_stop.ps1

#========================================================================
# 作業用の一時ファイルを削除
#========================================================================
Remove-Item $OutFile

書き換えた部分を見て行こう。まず、csv2chart.ps1は複数の形態のグラフをレンダリングできるようにする必要があるので、パラメータでグラフ形式を指定できるようにする。「-GraphType グラフスタイル」のように指定できるようにすればよい。

Param(
    [Parameter(Mandatory=$true)][String]$CSVFile,
    [String]$PNGFile = (Get-Location).ToString() + '\out.png',
    [String]$OutFile = (Get-Location).ToString() + '\out.html',
    [String]$GraphTitle = 'グラフ',
    [Int]$Width = 2000,
    [Int]$Height = 1200,
    [ValidateSet('Bar','Pie')]$GraphType = 'Bar'
)

上記のようにパラメータを追加すると、-GraphTypeに指定できる文字列が「Bar」か「Pie」のどちらかになる。デフォルト値は「Bar」に設定したので、指定がないと棒グラフとして処理される。この2つは補完対象にもなるし、これ以外の文字列はエラーとして処理される。

このようにPowerShellの引数処理機能であるparam()はとても強力で扱いやすい。ちょっと書くだけで、パラメータに必要な処理も含めて全て良い塩梅に処理してくれるようになる。

そしてGoogle Charts APIを使っている部分の処理を次のように書き換えている。

$GoogleChartsHTML2 = @"
        ]);

        // チャートオプションを設定
        var options = {'title':'$GraphTitle',
                       'width':'$Width',
                       'height':'$Height'};

        // 初期化およびチャートの生成
        var chart = new google.visualization.${GraphType}Chart(document.getElementById('chart_div'));

        // チャートイメージをbase64エンコードされたPNG画像データとして出力
        google.visualization.events.addListener(chart, 'ready', function () {
          document.getElementById('chart_base64').innerHTML = chart.getImageURI();
        });

        // チャートを描画
        chart.draw(data, options);
      }
    </script>
  </head>
  <body>
    <div id="chart_div"></div>
    <div id="chart_base64"></div>
  </body>
</html>
"@

具体的には次の部分が書き換えられている。

        var chart = new google.visualization.${GraphType}Chart(document.getElementById('chart_div'));

BarChart()とPieChart()というインスタンスの生成部分のみが異なっているので、この部分を${GraphType}Chartのように書くことで、HTMLファイルが生成された段階でBarChart()かPieChart()かのどちらかになるようにしている。

コンストラクタで使われているのと別の名前をパラメータで指定できるようにする場合には、ここの処理をifで切り分けるなど、もう少し処理を加える必要がある。

実行して動作を確認する

この記事は
Members+会員の方のみ御覧いただけます

ログイン/無料会員登録

会員サービスの詳細はこちら