はじめに
「手元にあるCSVやTSVの中身をちょっとグラフで可視化したい」という場面はよくあります。
しかし、以下のような理由で少し手間に感じたことはないでしょうか?
- ExcelがPCに入っていない。
- 業務端末でPython(matplotlib/pandas)などの外部ライブラリをインストールできない
そこで今回は、Windows標準のPowerShellのみを使い、GUIで直感的にCSV/TSVファイルを選んで集計・グラフ描画まで行えるスクリプトを作成しました。追加ソフトのインストールは一切不要です。
主な機能と特徴
-
完全GUI操作
- ファイル選択(CSV / TSV 自動判別)
- グラフ種別選択(縦棒・折れ線・散布図・円グラフ)
- X軸・Y軸の列選択
-
自動集計機能(散布図以外)
- 同じX軸データが複数ある場合、「合計・平均・最大値・最小値・件数」から集計方法を選択可能
-
安全なデータ処理
-
[double]::TryParseを用いた堅牢な数値判定(指数表記や空白セルにも対応) - X軸が数値の場合は数値順、文字列の場合は文字列順で正しく自動ソート
-
実行イメージ(処理の流れ)
スクリプトを実行すると、対話形式でダイアログが表示されます。
- ファイル選択ダイアログ: 可視化したいCSVまたはTSVファイルを選択
-
グラフ種類の選択 (
Out-GridView): 縦棒 / 折れ線 / 散布図 / 円グラフ から選択(適切なデータ型のヒント付き) -
X軸・Y軸の選択 (
Out-GridView): CSVヘッダーからプロットしたい列を選択 -
集計方法の選択 (
Out-GridView): 合計や平均などを選択(※散布図の場合はスキップ) -
グラフ描画ウィンドウの表示:
System.Windows.Forms.DataVisualizationによるグラフが表示される
スクリプト全文
以下のコードを Show-CsvChart.ps1 などの名前で保存してください。
# ウィンドウやダイアログなどのGUI機能を使うための System.Windows.Forms アセンブリを読み込みます。
Add-Type -AssemblyName System.Windows.Forms
# グラフを描画するための DataVisualization(データ視覚化)アセンブリを読み込みます。
Add-Type -AssemblyName System.Windows.Forms.DataVisualization
# ファイルを開くためのダイアログオブジェクトを作成します。
$dialog = New-Object System.Windows.Forms.OpenFileDialog
# ダイアログのタイトルを設定します。
$dialog.Title = "グラフ化するデータ(CSV/TSV)を選択してください"
# 選択可能なファイルの種類を制限するフィルターを設定します。
$dialog.Filter = "データファイル (*.csv;*.tsv)|*.csv;*.tsv|すべてのファイル (*.*)|*.*"
# ダイアログを表示し、ユーザーが「OK」ボタンを押したかどうかを判定します。
if ($dialog.ShowDialog() -eq [System.Windows.Forms.DialogResult]::OK) {
# ユーザーが選択したファイルのパスを変数 $path に格納します。
$path = $dialog.FileName
} else {
# 「OK」以外(キャンセルなど)が押された場合は警告を表示します。
Write-Warning "キャンセルされました。"
# 処理を安全に終了します。
return
}
# 選択されたファイルの拡張子を取得し、小文字に変換します。
$ext = [System.IO.Path]::GetExtension($path).ToLower()
# 拡張子が ".csv" ならカンマ、それ以外ならタブを区切り文字に設定します。
$delimiter = if ($ext -eq ".csv") { "," } else { "`t" }
# ファイルの先頭1行を読み込み、各列の名前の配列を取得します。
$headers = (Import-Csv -Path $path -Delimiter $delimiter -Encoding UTF8 | Select-Object -First 1).psobject.Properties.Name
# 列名が取得できなかった場合の処理です。
if (-not $headers) {
Write-Error "データの列名が取得できませんでした。"
return
}
# グラフの種類と推奨データ型のヒントを定義します。
$graphTypes = @(
[PSCustomObject]@{ "グラフの種類" = "縦棒グラフ"; "X軸の推奨" = "質的変数 (カテゴリ・種類など)"; "Y軸の推奨" = "量的変数"; ChartType = "Column" }
[PSCustomObject]@{ "グラフの種類" = "折れ線グラフ"; "X軸の推奨" = "質的変数 または 量的変数 (時間・連続データなど)"; "Y軸の推奨" = "量的変数"; ChartType = "Line" }
[PSCustomObject]@{ "グラフの種類" = "散布図"; "X軸の推奨" = "量的変数"; "Y軸の推奨" = "量的変数"; ChartType = "Point" }
[PSCustomObject]@{ "グラフの種類" = "円グラフ"; "X軸の推奨" = "質的変数 (カテゴリ・種類など)"; "Y軸の推奨" = "量的変数 (数値・割合データ)"; ChartType = "Pie" }
)
# グラフの種類一覧を表示し、ユーザーに一つ選ばせます。
$selectedGraph = $graphTypes | Out-GridView -Title "【手順1】作成するグラフの種類を選択してください" -OutputMode Single
if (-not $selectedGraph) { return }
# 取得した列名一覧を表示し、X軸に使用する列をユーザーに選ばせます。
$xCol = $headers | Out-GridView -Title "【手順2: X軸】列を選択してください (推奨: $($selectedGraph.'X軸の推奨'))" -OutputMode Single
if (-not $xCol) { return }
# 取得した列名一覧を表示し、Y軸に使用する列をユーザーに選ばせます。
$yCol = $headers | Out-GridView -Title "【手順3: Y軸】列を選択してください (推奨: $($selectedGraph.'Y軸の推奨'))" -OutputMode Single
if (-not $yCol) { return }
# =========================================================================
# 同じX軸のデータがあった場合の「集計方法」を選択させる(散布図以外)
# =========================================================================
$selectedAgg = $null
if ($selectedGraph.ChartType -ne "Point") {
# 用意する集計方法のリスト(合計、平均、最大値、最小値、データ数)を定義します。
$aggregationTypes = @(
[PSCustomObject]@{ "集計方法" = "合計"; "説明" = "同じ項目の数値を足し合わせます"; Method = "Sum" }
[PSCustomObject]@{ "集計方法" = "平均"; "説明" = "同じ項目の数値の平均を出します"; Method = "Average" }
[PSCustomObject]@{ "集計方法" = "最大値"; "説明" = "同じ項目の中で最大の数値を使います"; Method = "Maximum" }
[PSCustomObject]@{ "集計方法" = "最小値"; "説明" = "同じ項目の中で最小の数値を使います"; Method = "Minimum" }
[PSCustomObject]@{ "集計方法" = "データ数"; "説明" = "同じ項目の出現回数(有効データ数)を数えます"; Method = "Count" }
)
# 集計方法の一覧を表示し、ユーザーに選ばせます。
$selectedAgg = $aggregationTypes | Out-GridView -Title "【手順4: 集計方法】同じX軸($xCol)のデータが複数ある場合の処理を選んでください" -OutputMode Single
if (-not $selectedAgg) { return }
}
# =========================================================================
# 対象ファイルのデータ全体を読み込みます。
$data = Import-Csv -Path $path -Delimiter $delimiter -Encoding UTF8
# グラフを表示するためのウィンドウを作成し、幅と高さを設定します。
$form = New-Object System.Windows.Forms.Form
$form.Width = 800; $form.Height = 600
# ウィンドウのタイトルバーに、選択した内容を分かりやすく表示します。
if ($selectedGraph.ChartType -eq "Point") {
# 散布図の場合は集計がないため、そのまま X vs Y と表示します。
$form.Text = "$($selectedGraph.'グラフの種類') ($xCol vs $yCol)"
} else {
# それ以外の場合は、選んだ集計方法もタイトルに含めます。
$form.Text = "$($selectedGraph.'グラフの種類') ($xCol vs $yCol の $($selectedAgg.'集計方法'))"
}
# Chart オブジェクトを作成します。
$chart = New-Object System.Windows.Forms.DataVisualization.Charting.Chart
$chart.Dock = [System.Windows.Forms.DockStyle]::Fill
# プロットエリアを作成し、軸の自動調整などを行います。
$chartArea = New-Object System.Windows.Forms.DataVisualization.Charting.ChartArea
$chartArea.AxisX.LabelStyle.IsStaggered = $false
if ($selectedGraph.ChartType -ne "Point") {
$chartArea.AxisX.Interval = 1
}
$chart.ChartAreas.Add($chartArea)
# データ系列(Series)を作成し、グラフの種類を適用します。
$series = New-Object System.Windows.Forms.DataVisualization.Charting.Series
$series.Name = "Series1"
$series.ChartType = [System.Windows.Forms.DataVisualization.Charting.SeriesChartType]::$($selectedGraph.ChartType)
# 円グラフの場合、値をラベルとして表示します。
if ($selectedGraph.ChartType -eq "Pie") {
$series.IsValueShownAsLabel = $true
}
$chart.Series.Add($series)
# =========================================================================
# データをグラフに追加する処理
# =========================================================================
if ($selectedGraph.ChartType -eq "Point") {
# 【散布図の場合】
foreach ($row in $data) {
$xVal = 0.0
$yVal = 0.0
# 正規表現ではなく TryParse で厳密に数値判定(指数表記等にも対応)
if ([double]::TryParse($row.$xCol, [ref]$xVal) -and [double]::TryParse($row.$yCol, [ref]$yVal)) {
[void]$chart.Series["Series1"].Points.AddXY($xVal, $yVal)
}
}
} else {
# 【縦棒・折れ線・円グラフの場合】
# Y軸が数値であり、X軸が空欄でない有効なデータだけを抽出
$validData = $data | Where-Object {
$dummy = 0.0
[double]::TryParse($_.$yCol, [ref]$dummy) -and (-not [string]::IsNullOrWhiteSpace($_.$xCol))
}
# X軸の名前ごとにグループ化し、さらにX軸の値でソートする
$groupedData = $validData | Group-Object -Property $xCol | Sort-Object {
$parsedX = 0.0
# 数値に変換できるものは数値としてソート、できないものは文字列としてソート
if ([double]::TryParse($_.Name, [ref]$parsedX)) { $parsedX } else { $_.Name }
}
foreach ($group in $groupedData) {
$aggValue = 0.0
# 集計処理
switch ($selectedAgg.Method) {
"Sum" { $aggValue = ($group.Group | Measure-Object -Property $yCol -Sum).Sum }
"Average" { $aggValue = ($group.Group | Measure-Object -Property $yCol -Average).Average }
"Maximum" { $aggValue = ($group.Group | Measure-Object -Property $yCol -Maximum).Maximum }
"Minimum" { $aggValue = ($group.Group | Measure-Object -Property $yCol -Minimum).Minimum }
"Count" { $aggValue = $group.Group.Count }
}
$parsedX = 0.0
# X軸が数値の場合は[double]で渡し、グラフ上の間隔(スケール)を正確に保つ
if ([double]::TryParse($group.Name, [ref]$parsedX)) {
[void]$chart.Series["Series1"].Points.AddXY($parsedX, [double]$aggValue)
} else {
[void]$chart.Series["Series1"].Points.AddXY([string]$group.Name, [double]$aggValue)
}
}
}
# =========================================================================
# データがセットされた Chart オブジェクトをフォームに追加します。
$form.Controls.Add($chart)
# ウィンドウを画面に表示し、閉じるまで待機します。
[void]$form.ShowDialog()
# ウィンドウが閉じられた後、メモリを解放します。
$form.Dispose()
コードの注目ポイント
1. Out-GridView -OutputMode Single による簡易UI
PowerShell標準コマンドレットの Out-GridView に -OutputMode Single を指定することで、ユーザーが一覧から1行選択して「OK」を押すまで待機するGUIセレクタとして利用できます。わざわざ複雑なWindows Formsのリストボックスを組む必要がありません。
2. [double]::TryParse を使った堅牢な型判定
CSVデータはすべて文字列として読み込まれます。
正規表現や単純な型キャスト([double]$val)で判定すると、空文字や指数表記(1.2e+3 など)でエラーになるケースがあります。.NET の [double]::TryParse(string, [ref]double) を使うことで、例外を発生させずに安全に数値判定を行っています。
3. グループ化と型を意識したソート
棒グラフや折れ線グラフでは、X軸が日付やID(数値)の場合と、カテゴリ名(文字列)の場合があります。
ソート時に数値として解釈できる場合は数値順、そうでない場合は五十音/アルファベット順に切り替えることで、意図しない並び順(例: 1, 10, 2, 3...)になるのを防いでいます。
$groupedData = $validData | Group-Object -Property $xCol | Sort-Object {
$parsedX = 0.0
if ([double]::TryParse($_.Name, [ref]$parsedX)) { $parsedX } else { $_.Name }
}
実行環境と注意点
- 対応環境: Windows PowerShell 5.1(Windows 10/11 に標準搭載)
-
文字コード: スクリプト内の
Import-Csvでは-Encoding UTF8を指定しています。Shift-JIS (CP932) のCSVを読み込む場合は、-Encoding Defaultに変更してください。
おわりに
PowerShellは単なるタスク自動化シェルにとどまらず、.NETのGUIや描画コンポーネントを即座に呼び出せる点が大きな強みです。
CSVをサクッと確認したいときの社内ツールや簡易分析スクリプトとして、ぜひ活用してみてください。