この記事では以下のようなグラフをPowerShellで描画する方法について解説しています。
やりたいこと
グラフ作成の自動化です。
Pythonで作ったコードを配布できれば楽なのですが、自職場ではオープンソースなどを自由に導入できないので困難。
そこで、自職場でも使えるPowerShellで、グラフを作成する方法について調べてみました。
PowerShellでのグラフ描画
PowerShellについて
PowerShellはWindowsに標準搭載されているスクリプト言語です。Windowsであれば追加インストールなしですぐに利用を開始できます。なので、配布も容易です。
PowerShellが強力なのは、Windowsの基盤である「.NET Framework」の機能を直接呼び出せる点にあります。これにより、GUIを持つウィンドウアプリケーションやグラフの描画も可能になります。
描画できるグラフの例
今回は例として散布図を作成しますが、System.Windows.Forms.DataVisualization
では以下のような様々な種類のグラフを描画できます。
-
棒グラフ
-
Column
: 一般的な縦棒グラフ -
Bar
: 横棒グラフ
-
-
折れ線グラフ
-
Line
: データ点を直線で結んだ、一般的な折れ線グラフ -
Spline
: データ点を滑らかな曲線で結んだ折れ線グラフ
-
-
散布図
-
Point
: 点でデータをプロットする散布図 -
Bubble
: 散布図の拡張版。第三の要素をバブルの大きさで表現
-
-
円グラフ
-
Pie
: 一般的な円グラフ -
Doughnut
: 中央に穴の開いたドーナツ型の円グラフ
-
-
積み上げグラフ
-
StackedColumn
: 縦棒グラフを積み上げたもの -
StackedBar
: 積み上げグラフの横棒バージョン
-
-
レーダー/ポーラーチャート
-
Radar
: 円周方向にカテゴリ(離散値)をセットし、データをプロット -
Polar
: 円周方向に軸(連続値)をセットし、データをプロット
-
その他にも様々なグラフを描くことができます。詳細はMicroSoftの公式ドキュメントを参照ください。
上記サンプルの描画スクリプト(自分のメモ用)
(全てAIに書いてもらったスクリプトになります)# 棒グラフ系サンプル(Column / Bar)
# 目的: 同じデータを縦棒・横棒で比較表示。横に並べて固定サイズで図示
# 事前準備 ================================================
# 必要なアセンブリの読み込み
Add-Type -AssemblyName System.Windows.Forms
Add-Type -AssemblyName System.Windows.Forms.DataVisualization
# データ準備 ================================================
# グラフにプロットするデータ(カテゴリと値)を定義
$categories = @("A", "B", "C", "D", "E")
$values = @(12, 25, 18, 30, 20)
# フォームの作成(表示用ウィンドウ) ================================================
$form = [System.Windows.Forms.Form] @{
Text = "棒グラフ系"
Width = 900
Height = 400
}
# チャートの作成 ================================================
# チャート全体の作成とフォームへの配置
$chart = [System.Windows.Forms.DataVisualization.Charting.Chart] @{
Width = 860
Height = 320
Left = 20
Top = 20
}
$form.Controls.Add($chart)
# チャート全体のタイトル設定
$mainTitle = [System.Windows.Forms.DataVisualization.Charting.Title] @{
Text = "棒グラフ系"
Font = [System.Drawing.Font]::new("Meiryo", 18, [System.Drawing.FontStyle]::Bold)
}
$chart.Titles.Add($mainTitle)
# チャートエリアの作成 ================================================
# グラフを2つ描画するため、チャートエリアを左右に分割して作成
$areaLeftName = "Area_Left"
$areaRightName = "Area_Right"
$areaLeft = [System.Windows.Forms.DataVisualization.Charting.ChartArea] @{
Name = $areaLeftName
Position = [System.Windows.Forms.DataVisualization.Charting.ElementPosition]::new(5, 24, 42, 72)
}
$areaRight = [System.Windows.Forms.DataVisualization.Charting.ChartArea] @{
Name = $areaRightName
Position = [System.Windows.Forms.DataVisualization.Charting.ElementPosition]::new(53, 24, 42, 72)
}
$chart.ChartAreas.Add($areaLeft)
$chart.ChartAreas.Add($areaRight)
# 各チャートエリアの上に、個別のタイトル(副題)を設定
$subTitleLeft = [System.Windows.Forms.DataVisualization.Charting.Title] @{
Text = "縦棒グラフ(Column)"
Font = [System.Drawing.Font]::new("Meiryo", 12, [System.Drawing.FontStyle]::Bold)
DockedToChartArea = $areaLeftName
IsDockedInsideChartArea = $false
Docking = [System.Windows.Forms.DataVisualization.Charting.Docking]::Top
DockingOffset = 2
}
$subTitleRight = [System.Windows.Forms.DataVisualization.Charting.Title] @{
Text = "横棒グラフ(Bar)"
Font = [System.Drawing.Font]::new("Meiryo", 12, [System.Drawing.FontStyle]::Bold)
DockedToChartArea = $areaRightName
IsDockedInsideChartArea = $false
Docking = [System.Windows.Forms.DataVisualization.Charting.Docking]::Top
DockingOffset = 2
}
$chart.Titles.Add($subTitleLeft)
$chart.Titles.Add($subTitleRight)
# 軸ラベルの設定
$areaLeft.AxisX.Title = "カテゴリ"
$areaLeft.AxisY.Title = "値"
$areaRight.AxisX.Title = "カテゴリ"
$areaRight.AxisY.Title = "値"
# シリーズの作成とデータ投入 ================================================
# シリーズ1: 縦棒グラフ (Column)
$seriesColumn = [System.Windows.Forms.DataVisualization.Charting.Series] @{
Name = "ColumnSeries"
ChartType = [System.Windows.Forms.DataVisualization.Charting.SeriesChartType]::Column
ChartArea = $areaLeftName
}
$chart.Series.Add($seriesColumn)
# シリーズ2: 横棒グラフ (Bar)
$seriesBar = [System.Windows.Forms.DataVisualization.Charting.Series] @{
Name = "BarSeries"
ChartType = [System.Windows.Forms.DataVisualization.Charting.SeriesChartType]::Bar
ChartArea = $areaRightName
}
$chart.Series.Add($seriesBar)
# データの追加(カテゴリと値を1点ずつプロット)
for ($i = 0; $i -lt $categories.Count; $i++) {
$category = $categories[$i]
$value = $values[$i]
# 両方のシリーズに同じデータを追加(出力抑制)
$null = $seriesColumn.Points.AddXY($category, $value)
$null = $seriesBar.Points.AddXY($category, $value)
}
# 出力 ================================================
# フォームの表示(ShowDialogでウィンドウをモーダル表示)
$null = $form.ShowDialog()
# 画像保存
# $chart.SaveImage(".\棒グラフ系_サンプル.png", [System.Windows.Forms.DataVisualization.Charting.ChartImageFormat]::Png)
# 折れ線グラフ系サンプル(Line / Spline)
# 目的: 同じデータを折れ線・スプラインで比較。横に並べ固定サイズで図示
# 事前準備 ================================================
# 必要なアセンブリの読み込み
Add-Type -AssemblyName System.Windows.Forms
Add-Type -AssemblyName System.Windows.Forms.DataVisualization
# データ準備 ================================================
# グラフにプロットするデータ(X軸用の連番と、Y軸用の乱数)を生成
$rand = [System.Random]::new()
$xValues = 1..10
$yValues = @(1..10 | ForEach-Object { 5 + $rand.Next(0, 20) })
# フォームの作成(表示用ウィンドウ) ================================================
$form = [System.Windows.Forms.Form] @{
Text = "折れ線グラフ系"
Width = 900
Height = 400
}
# チャートの作成 ================================================
# チャート全体の作成とフォームへの配置
$chart = [System.Windows.Forms.DataVisualization.Charting.Chart] @{
Width = 860
Height = 320
Left = 20
Top = 20
}
$form.Controls.Add($chart)
# チャート全体のタイトル設定
$mainTitle = [System.Windows.Forms.DataVisualization.Charting.Title] @{
Text = "折れ線グラフ系"
Font = [System.Drawing.Font]::new("Meiryo", 18, [System.Drawing.FontStyle]::Bold)
}
$chart.Titles.Add($mainTitle)
# チャートエリアの作成 ================================================
# グラフを2つ描画するため、チャートエリアを左右に分割して作成
$areaLeftName = "Area_Left"
$areaRightName = "Area_Right"
$areaLeft = [System.Windows.Forms.DataVisualization.Charting.ChartArea] @{
Name = $areaLeftName
Position = [System.Windows.Forms.DataVisualization.Charting.ElementPosition]::new(5, 24, 42, 72)
}
$areaRight = [System.Windows.Forms.DataVisualization.Charting.ChartArea] @{
Name = $areaRightName
Position = [System.Windows.Forms.DataVisualization.Charting.ElementPosition]::new(53, 24, 42, 72)
}
$chart.ChartAreas.Add($areaLeft)
$chart.ChartAreas.Add($areaRight)
# 各チャートエリアの上に、個別のタイトル(副題)を設定
$subTitleLeft = [System.Windows.Forms.DataVisualization.Charting.Title] @{
Text = "折れ線(Line)"
Font = [System.Drawing.Font]::new("Meiryo", 12, [System.Drawing.FontStyle]::Bold)
DockedToChartArea = $areaLeftName
IsDockedInsideChartArea = $false
Docking = [System.Windows.Forms.DataVisualization.Charting.Docking]::Top
DockingOffset = 2
}
$subTitleRight = [System.Windows.Forms.DataVisualization.Charting.Title] @{
Text = "スプライン(Spline)"
Font = [System.Drawing.Font]::new("Meiryo", 12, [System.Drawing.FontStyle]::Bold)
DockedToChartArea = $areaRightName
IsDockedInsideChartArea = $false
Docking = [System.Windows.Forms.DataVisualization.Charting.Docking]::Top
DockingOffset = 2
}
$chart.Titles.Add($subTitleLeft)
$chart.Titles.Add($subTitleRight)
# 軸ラベルの設定
$areaLeft.AxisX.Title = "X"
$areaLeft.AxisY.Title = "Y"
$areaRight.AxisX.Title = "X"
$areaRight.AxisY.Title = "Y"
# シリーズの作成とデータ投入 ================================================
# シリーズ1: 折れ線グラフ (Line)
$seriesLine = [System.Windows.Forms.DataVisualization.Charting.Series] @{
Name = "LineSeries"
ChartType = [System.Windows.Forms.DataVisualization.Charting.SeriesChartType]::Line
ChartArea = $areaLeftName
BorderWidth = 2
MarkerStyle = [System.Windows.Forms.DataVisualization.Charting.MarkerStyle]::Circle
MarkerSize = 7
}
$chart.Series.Add($seriesLine)
# シリーズ2: スプライングラフ (Spline)
$seriesSpline = [System.Windows.Forms.DataVisualization.Charting.Series] @{
Name = "SplineSeries"
ChartType = [System.Windows.Forms.DataVisualization.Charting.SeriesChartType]::Spline
ChartArea = $areaRightName
BorderWidth = 2
MarkerStyle = [System.Windows.Forms.DataVisualization.Charting.MarkerStyle]::Diamond
MarkerSize = 7
}
$chart.Series.Add($seriesSpline)
# データの追加(事前に生成したX/Y値の配列をバインド)
# DataBindXYを使うとループ処理が不要になり、コードが簡潔になる
$seriesLine.Points.DataBindXY($xValues, $yValues)
$seriesSpline.Points.DataBindXY($xValues, $yValues)
# 出力 ================================================
# フォームの表示
$null = $form.ShowDialog()
# 画像保存
# $chart.SaveImage(".\折れ線グラフ系_サンプル.png", [System.Windows.Forms.DataVisualization.Charting.ChartImageFormat]::Png)
# 散布図系サンプル(Point / Bubble)
# 目的: 同じ分布データを散布図・バブルで比較表示。横に並べて固定サイズで図示
# 事前準備 ================================================
# 必要なアセンブリの読み込み
Add-Type -AssemblyName System.Windows.Forms
Add-Type -AssemblyName System.Windows.Forms.DataVisualization
# データ準備 ================================================
# グラフにプロットするデータ(X, Y, バブルサイズ)を生成
$rand = [System.Random]::new()
$points = 1..40 | ForEach-Object {
[PSCustomObject]@{
X = $rand.Next(0, 100)
Y = $rand.Next(0, 100)
Size = $rand.Next(5, 25)
}
}
# フォームの作成(表示用ウィンドウ) ================================================
$form = [System.Windows.Forms.Form] @{
Text = "散布図系"
Width = 900
Height = 400
}
# チャートの作成 ================================================
# チャート全体の作成とフォームへの配置
$chart = [System.Windows.Forms.DataVisualization.Charting.Chart] @{
Width = 860
Height = 320
Left = 20
Top = 20
}
$form.Controls.Add($chart)
# チャート全体のタイトル設定
$mainTitle = [System.Windows.Forms.DataVisualization.Charting.Title] @{
Text = "散布図系"
Font = [System.Drawing.Font]::new("Meiryo", 18, [System.Drawing.FontStyle]::Bold)
}
$chart.Titles.Add($mainTitle)
# チャートエリアの作成 ================================================
# グラフを2つ描画するため、チャートエリアを左右に分割して作成
$areaLeftName = "Area_Left"
$areaRightName = "Area_Right"
$areaLeft = [System.Windows.Forms.DataVisualization.Charting.ChartArea] @{
Name = $areaLeftName
Position = [System.Windows.Forms.DataVisualization.Charting.ElementPosition]::new(5, 24, 42, 72)
}
$areaRight = [System.Windows.Forms.DataVisualization.Charting.ChartArea] @{
Name = $areaRightName
Position = [System.Windows.Forms.DataVisualization.Charting.ElementPosition]::new(53, 24, 42, 72)
}
$chart.ChartAreas.Add($areaLeft)
$chart.ChartAreas.Add($areaRight)
# 各チャートエリアの上に、個別のタイトル(副題)を設定
$subTitleLeft = [System.Windows.Forms.DataVisualization.Charting.Title] @{
Text = "散布図(Point)"
Font = [System.Drawing.Font]::new("Meiryo", 12, [System.Drawing.FontStyle]::Bold)
DockedToChartArea = $areaLeftName
IsDockedInsideChartArea = $false
Docking = [System.Windows.Forms.DataVisualization.Charting.Docking]::Top
DockingOffset = 2
}
$subTitleRight = [System.Windows.Forms.DataVisualization.Charting.Title] @{
Text = "バブル(Bubble)"
Font = [System.Drawing.Font]::new("Meiryo", 12, [System.Drawing.FontStyle]::Bold)
DockedToChartArea = $areaRightName
IsDockedInsideChartArea = $false
Docking = [System.Windows.Forms.DataVisualization.Charting.Docking]::Top
DockingOffset = 2
}
$chart.Titles.Add($subTitleLeft)
$chart.Titles.Add($subTitleRight)
# 軸ラベルの設定
$areaLeft.AxisX.Title = "X"
$areaLeft.AxisY.Title = "Y"
$areaRight.AxisX.Title = "X"
$areaRight.AxisY.Title = "Y"
# バブルチャートのみ、軸の最小値を0、最大値を100に設定
$areaRight.AxisX.Minimum = 0
$areaRight.AxisY.Minimum = 0
$areaRight.AxisX.Maximum = 100
$areaRight.AxisY.Maximum = 100
# シリーズの作成とデータ投入 ================================================
# シリーズ1: 散布図 (Point)
$seriesPoint = [System.Windows.Forms.DataVisualization.Charting.Series] @{
Name = "PointSeries"
ChartType = [System.Windows.Forms.DataVisualization.Charting.SeriesChartType]::Point
ChartArea = $areaLeftName
}
$chart.Series.Add($seriesPoint)
# シリーズ2: バブルチャート (Bubble)
$seriesBubble = [System.Windows.Forms.DataVisualization.Charting.Series] @{
Name = "BubbleSeries"
ChartType = [System.Windows.Forms.DataVisualization.Charting.SeriesChartType]::Bubble
ChartArea = $areaRightName
}
$chart.Series.Add($seriesBubble)
# データの追加
# 散布図はX, Yの2値、バブルはX, Y, Sizeの3値が必要なため、ループで個別に投入
foreach ($p in $points) {
# 散布図 (X, Y)
$null = $seriesPoint.Points.AddXY($p.X, $p.Y)
# バブル (X, Y, バブルサイズ)
# バブルのY値は配列で [Y座標, サイズ] の2つを指定する
$null = $seriesBubble.Points.AddXY($p.X, @($p.Y, $p.Size))
}
# 出力 ================================================
# フォームの表示
$null = $form.ShowDialog()
# 画像保存
# $chart.SaveImage(".\散布図系_サンプル.png", [System.Windows.Forms.DataVisualization.Charting.ChartImageFormat]::Png)
# 円/ドーナツ系サンプル(Pie / Doughnut)
# 目的: 構成比の2表現を並べて比較。横に並べて固定サイズで図示
# 事前準備 ================================================
# 必要なアセンブリの読み込み
Add-Type -AssemblyName System.Windows.Forms
Add-Type -AssemblyName System.Windows.Forms.DataVisualization
# データ準備 ================================================
# グラフにプロットするデータ(ラベルと値)を定義
$labels = @("A", "B", "C", "D")
$values = @(40, 25, 20, 15)
# フォームの作成(表示用ウィンドウ) ================================================
$form = [System.Windows.Forms.Form] @{
Text = "円/ドーナツ系"
Width = 900
Height = 400
}
# チャートの作成 ================================================
# チャート全体の作成とフォームへの配置
$chart = [System.Windows.Forms.DataVisualization.Charting.Chart] @{
Width = 860
Height = 320
Left = 20
Top = 20
}
$form.Controls.Add($chart)
# チャート全体のタイトル設定
$mainTitle = [System.Windows.Forms.DataVisualization.Charting.Title] @{
Text = "円/ドーナツ系"
Font = [System.Drawing.Font]::new("Meiryo", 18, [System.Drawing.FontStyle]::Bold)
}
$chart.Titles.Add($mainTitle)
# チャートエリアの作成 ================================================
# グラフを2つ描画するため、チャートエリアを左右に分割して作成
$areaLeftName = "Area_Left"
$areaRightName = "Area_Right"
$areaLeft = [System.Windows.Forms.DataVisualization.Charting.ChartArea] @{
Name = $areaLeftName
Position = [System.Windows.Forms.DataVisualization.Charting.ElementPosition]::new(5, 24, 42, 72)
}
$areaRight = [System.Windows.Forms.DataVisualization.Charting.ChartArea] @{
Name = $areaRightName
Position = [System.Windows.Forms.DataVisualization.Charting.ElementPosition]::new(53, 24, 42, 72)
}
$chart.ChartAreas.Add($areaLeft)
$chart.ChartAreas.Add($areaRight)
# 各チャートエリアの上に、個別のタイトル(副題)を設定
$subTitleLeft = [System.Windows.Forms.DataVisualization.Charting.Title] @{
Text = "円グラフ(Pie)"
Font = [System.Drawing.Font]::new("Meiryo", 12, [System.Drawing.FontStyle]::Bold)
DockedToChartArea = $areaLeftName
IsDockedInsideChartArea = $false
Docking = [System.Windows.Forms.DataVisualization.Charting.Docking]::Top
DockingOffset = 2
}
$subTitleRight = [System.Windows.Forms.DataVisualization.Charting.Title] @{
Text = "ドーナツ(Doughnut)"
Font = [System.Drawing.Font]::new("Meiryo", 12, [System.Drawing.FontStyle]::Bold)
DockedToChartArea = $areaRightName
IsDockedInsideChartArea = $false
Docking = [System.Windows.Forms.DataVisualization.Charting.Docking]::Top
DockingOffset = 2
}
$chart.Titles.Add($subTitleLeft)
$chart.Titles.Add($subTitleRight)
# シリーズの作成とデータ投入 ================================================
# シリーズ1: 円グラフ (Pie)
$seriesPie = [System.Windows.Forms.DataVisualization.Charting.Series] @{
Name = "PieSeries"
ChartType = [System.Windows.Forms.DataVisualization.Charting.SeriesChartType]::Pie
ChartArea = $areaLeftName
}
$chart.Series.Add($seriesPie)
# シリーズ2: ドーナツグラフ (Doughnut)
$seriesDoughnut = [System.Windows.Forms.DataVisualization.Charting.Series] @{
Name = "DoughnutSeries"
ChartType = [System.Windows.Forms.DataVisualization.Charting.SeriesChartType]::Doughnut
ChartArea = $areaRightName
}
$chart.Series.Add($seriesDoughnut)
# データの追加(X値がラベル、Y値が実際の値となる)
# DataBindXYで一括投入が可能
$seriesPie.Points.DataBindXY($labels, $values)
$seriesDoughnut.Points.DataBindXY($labels, $values)
# 出力 ================================================
# フォームの表示
$null = $form.ShowDialog()
# 画像保存
# $chart.SaveImage(".\円ドーナツ系_サンプル.png", [System.Windows.Forms.DataVisualization.Charting.ChartImageFormat]::Png)
# 積み上げ系サンプル(StackedColumn / StackedBar)
# 目的: 総量と内訳を縦横で比較。横に並べて固定サイズで図示
# 事前準備 ================================================
# 必要なアセンブリの読み込み
Add-Type -AssemblyName System.Windows.Forms
Add-Type -AssemblyName System.Windows.Forms.DataVisualization
# データ準備 ================================================
# グラフにプロットするデータ(カテゴリ、系列名、値)を定義
$categories = @("A", "B", "C", "D")
$seriesNames = @("S1", "S2", "S3")
# 値は (系列 x カテゴリ) の2次元配列で定義
$values = @(
@(10, 15, 20, 12), # Series S1 の値 (A, B, C, D)
@(8, 12, 18, 10), # Series S2 の値 (A, B, C, D)
@(5, 7, 9, 6) # Series S3 の値 (A, B, C, D)
)
# フォームの作成(表示用ウィンドウ) ================================================
$form = [System.Windows.Forms.Form] @{
Text = "積み上げ系"
Width = 900
Height = 400
}
# チャートの作成 ================================================
# チャート全体の作成とフォームへの配置
$chart = [System.Windows.Forms.DataVisualization.Charting.Chart] @{
Width = 860
Height = 320
Left = 20
Top = 20
}
$form.Controls.Add($chart)
# チャート全体のタイトル設定
$mainTitle = [System.Windows.Forms.DataVisualization.Charting.Title] @{
Text = "積み上げ系"
Font = [System.Drawing.Font]::new("Meiryo", 18, [System.Drawing.FontStyle]::Bold)
}
$chart.Titles.Add($mainTitle)
# チャートエリアの作成 ================================================
# グラフを2つ描画するため、チャートエリアを左右に分割して作成
$areaLeftName = "Area_Left"
$areaRightName = "Area_Right"
$areaLeft = [System.Windows.Forms.DataVisualization.Charting.ChartArea] @{
Name = $areaLeftName
Position = [System.Windows.Forms.DataVisualization.Charting.ElementPosition]::new(5, 24, 42, 72)
}
$areaRight = [System.Windows.Forms.DataVisualization.Charting.ChartArea] @{
Name = $areaRightName
Position = [System.Windows.Forms.DataVisualization.Charting.ElementPosition]::new(53, 24, 42, 72)
}
$chart.ChartAreas.Add($areaLeft)
$chart.ChartAreas.Add($areaRight)
# 各チャートエリアの上に、個別のタイトル(副題)を設定
$subTitleLeft = [System.Windows.Forms.DataVisualization.Charting.Title] @{
Text = "縦積み上げ(StackedColumn)"
Font = [System.Drawing.Font]::new("Meiryo", 12, [System.Drawing.FontStyle]::Bold)
DockedToChartArea = $areaLeftName
IsDockedInsideChartArea = $false
Docking = [System.Windows.Forms.DataVisualization.Charting.Docking]::Top
DockingOffset = 2
}
$subTitleRight = [System.Windows.Forms.DataVisualization.Charting.Title] @{
Text = "横積み上げ(StackedBar)"
Font = [System.Drawing.Font]::new("Meiryo", 12, [System.Drawing.FontStyle]::Bold)
DockedToChartArea = $areaRightName
IsDockedInsideChartArea = $false
Docking = [System.Windows.Forms.DataVisualization.Charting.Docking]::Top
DockingOffset = 2
}
$chart.Titles.Add($subTitleLeft)
$chart.Titles.Add($subTitleRight)
# シリーズの作成とデータ投入 ================================================
# --- 縦積み上げグラフのシリーズをすべて作成 ---
foreach ($s in 0..($seriesNames.Count - 1)) {
$seriesColumn = [System.Windows.Forms.DataVisualization.Charting.Series] @{
Name = "Col_" + $seriesNames[$s]
ChartType = [System.Windows.Forms.DataVisualization.Charting.SeriesChartType]::StackedColumn
ChartArea = $areaLeftName
}
$chart.Series.Add($seriesColumn)
# カテゴリの配列と、現在の系列に対応する値の配列をバインド
$seriesColumn.Points.DataBindXY($categories, $values[$s])
}
# --- 横積み上げグラフのシリーズをすべて作成 ---
foreach ($s in 0..($seriesNames.Count - 1)) {
$seriesBar = [System.Windows.Forms.DataVisualization.Charting.Series] @{
Name = "Bar_" + $seriesNames[$s]
ChartType = [System.Windows.Forms.DataVisualization.Charting.SeriesChartType]::StackedBar
ChartArea = $areaRightName
}
$chart.Series.Add($seriesBar)
# カテゴリの配列と、現在の系列に対応する値の配列をバインド
$seriesBar.Points.DataBindXY($categories, $values[$s])
}
# 出力 ================================================
# フォームの表示
$null = $form.ShowDialog()
# 画像保存
# $chart.SaveImage(".\積み上げ系_サンプル.png", [System.Windows.Forms.DataVisualization.Charting.ChartImageFormat]::Png)
# レーダー/ポーラー 同一チャート サンプル
# 目的: 1つのチャート内にレーダー(左)とポーラー(右)を横並びで表示
# 事前準備 ================================================
# 必要なアセンブリの読み込み
Add-Type -AssemblyName System.Windows.Forms
Add-Type -AssemblyName System.Windows.Forms.DataVisualization
# データ準備 ================================================
# レーダーチャート用のデータ(カテゴリと値)を定義
$radarLabels = @("Speed", "Power", "Skill", "Stamina", "Luck")
$radarValues = @(70, 85, 65, 75, 60)
# ポーラーチャート用のデータ(角度と半径)を生成
$polarData = 0..36 | ForEach-Object {
$deg = $_ * 10
$rad = [math]::PI * $deg / 180
[PSCustomObject]@{
Degree = $deg
Radius = 10 + [math]::Sin($rad * 2) * 5
}
}
# フォームの作成(表示用ウィンドウ) ================================================
$form = [System.Windows.Forms.Form] @{
Text = "レーダー/ポーラー"
Width = 900
Height = 400
}
# チャートの作成 ================================================
# チャート全体の作成とフォームへの配置
$chart = [System.Windows.Forms.DataVisualization.Charting.Chart] @{
Width = 860
Height = 320
Left = 20
Top = 20
}
$form.Controls.Add($chart)
# チャート全体のタイトル設定
$mainTitle = [System.Windows.Forms.DataVisualization.Charting.Title] @{
Text = "レーダー / ポーラー"
Font = [System.Drawing.Font]::new("Meiryo", 18, [System.Drawing.FontStyle]::Bold)
}
$chart.Titles.Add($mainTitle)
# チャートエリアの作成 ================================================
# グラフを2つ描画するため、チャートエリアを左右に分割して作成
$areaLeftName = "Area_Left"
$areaRightName = "Area_Right"
$areaLeft = [System.Windows.Forms.DataVisualization.Charting.ChartArea] @{
Name = $areaLeftName
Position = [System.Windows.Forms.DataVisualization.Charting.ElementPosition]::new(5, 24, 42, 72)
}
$areaRight = [System.Windows.Forms.DataVisualization.Charting.ChartArea] @{
Name = $areaRightName
Position = [System.Windows.Forms.DataVisualization.Charting.ElementPosition]::new(53, 24, 42, 72)
}
$chart.ChartAreas.Add($areaLeft)
$chart.ChartAreas.Add($areaRight)
# 各チャートエリアの上に、個別のタイトル(副題)を設定
$subTitleLeft = [System.Windows.Forms.DataVisualization.Charting.Title] @{
Text = "レーダー(面塗り)"
Font = [System.Drawing.Font]::new("Meiryo", 12, [System.Drawing.FontStyle]::Bold)
DockedToChartArea = $areaLeftName
IsDockedInsideChartArea = $false
Docking = [System.Windows.Forms.DataVisualization.Charting.Docking]::Top
DockingOffset = 2
}
$subTitleRight = [System.Windows.Forms.DataVisualization.Charting.Title] @{
Text = "ポーラー(マーカー)"
Font = [System.Drawing.Font]::new("Meiryo", 12, [System.Drawing.FontStyle]::Bold)
DockedToChartArea = $areaRightName
IsDockedInsideChartArea = $false
Docking = [System.Windows.Forms.DataVisualization.Charting.Docking]::Top
DockingOffset = 2
}
$chart.Titles.Add($subTitleLeft)
$chart.Titles.Add($subTitleRight)
# シリーズの作成とデータ投入 ================================================
# シリーズ1: レーダーチャート (Radar)
$seriesRadar = [System.Windows.Forms.DataVisualization.Charting.Series] @{
Name = "RadarArea"
ChartType = [System.Windows.Forms.DataVisualization.Charting.SeriesChartType]::Radar
ChartArea = $areaLeftName
BorderWidth = 2
Color = [System.Drawing.Color]::FromArgb(120, [System.Drawing.Color]::RoyalBlue)
}
$chart.Series.Add($seriesRadar)
$seriesRadar.Points.DataBindXY($radarLabels, $radarValues)
# シリーズ2: ポーラーチャート (Polar)
$seriesPolar = [System.Windows.Forms.DataVisualization.Charting.Series] @{
Name = "PolarMarker"
ChartType = [System.Windows.Forms.DataVisualization.Charting.SeriesChartType]::Polar
ChartArea = $areaRightName
BorderWidth = 2
MarkerStyle = [System.Windows.Forms.DataVisualization.Charting.MarkerStyle]::Circle
MarkerSize = 6
}
$chart.Series.Add($seriesPolar)
# ポーラーチャートはDataSourceバインドを使うとより宣言的に記述できる
$seriesPolar.Points.DataBind($polarData, "Degree", "Radius", $null)
# 出力 ================================================
# フォームの表示
$null = $form.ShowDialog()
# 画像保存
# $chart.SaveImage(".\レーダー_ポーラー_サンプル.png", [System.Windows.Forms.DataVisualization.Charting.ChartImageFormat]::Png)
つくってみよう
それでは、実際にグラフを作成していきましょう。
使用するサンプルデータは、複数のゲームタイトルのスコアや売上をまとめたデータです。
(AIに適当に集めてもらったデータを加工。正確性は未検証)
:
このデータからメタスコアとユーザースコアを取り出し、散布図にプロットしていきます。
最終的に完成したスクリプトはこちら。
完成スクリプト
# 事前準備 ================================================
# 必要なアセンブリの読み込み
Add-Type -AssemblyName System.Windows.Forms
Add-Type -AssemblyName System.Windows.Forms.DataVisualization
# CSVファイルのパス設定
$csvPath = ".\game_sales_dataset.csv"
# CSVファイルからデータを読み込む(UTF-8想定)
$gameData = Import-Csv -Path $csvPath -Encoding UTF8
# フォームの作成(表示用ウィンドウ)
$form = [System.Windows.Forms.Form] @{
Text = "メタスコアとユーザースコアの散布図"
Width = 700
Height = 600
}
# チャートの作成 ================================================
# チャートの作成(固定配置)
$chart = [System.Windows.Forms.DataVisualization.Charting.Chart] @{
Width = $form.ClientSize.Width - 100
Height = $form.ClientSize.Height - 100
Left = 50
Top = 50
}
# タイトルの設定
$title = [System.Windows.Forms.DataVisualization.Charting.Title] @{
Text = "メタスコア vs ユーザースコア"
Font = [System.Drawing.Font]::new("Meiryo UI", 14)
}
# チャートにタイトルを追加
$chart.Titles.Add($title)
# フォームにチャートを追加
$form.Controls.Add($chart)
# チャートエリアの作成 ================================================
# チャートエリアの作成
$chartArea = [System.Windows.Forms.DataVisualization.Charting.ChartArea]::new()
# チャートにチャートエリアを追加
$chart.ChartAreas.Add($chartArea)
# 軸ラベル
$chartArea.AxisX.Title = "メタスコア"
$chartArea.AxisY.Title = "ユーザースコア"
# # シリーズの作成 ================================================
# シリーズの作成
$series = $chart.Series.Add("ゲームデータ")
# シリーズの設定
$series.ChartType = [System.Windows.Forms.DataVisualization.Charting.SeriesChartType]::Point
$series.MarkerStyle = [System.Windows.Forms.DataVisualization.Charting.MarkerStyle]::Circle
$series.MarkerSize = 8
$series.Color = [System.Drawing.Color]::Blue
# データバインドするためのXY配列を生成
# !読み込んだimport-csvで読み込んだデータは文字列であるため、数値に変換する必要がある
$xValues = $gameData.メタスコア | ForEach-Object { [double]$_ }
$yValues = $gameData.ユーザースコア | ForEach-Object { [double]$_ }
# ★データ追加(データバインド)
$series.Points.DataBindXY($xValues, $yValues)
# 出力 ================================================
# フォームの表示(出力抑制)
$null = $form.ShowDialog()
# 画像保存(必要に応じてコメントを外して使用)
# $chart.SaveImage(".\scatter.png", [System.Windows.Forms.DataVisualization.Charting.ChartImageFormat]::Png)
では、このスクリプトを実際の作成の流れに沿って解説していきます。
1.グラフ作成前の事前準備
アセンブリ読み込み
はじめに、グラフ描画に必要となる.NETのライブラリ(アセンブリ)を2つ読み込みます。
今回はフォーム表示に必要なSystem.Windows.Forms
と、グラフ作成に必要なSystem.Windows.Forms.DataVisualization
を読み込みます。
# 必要なアセンブリの読み込み
Add-Type -AssemblyName System.Windows.Forms
Add-Type -AssemblyName System.Windows.Forms.DataVisualization
CSVデータの読み込み
次に、グラフ化したいCSVファイルをImport-Csv
コマンドレットで読み込みます。
今回はあらかじめ指定したパスのCSVファイルを読み込んでいきます。
# CSVファイルからデータを読み込む
$csvPath = ".\game_sales_dataset.csv"
$gameData = Import-Csv -Path $csvPath -Encoding UTF8
フォームの作成
今回はフォーム上にウィンドウ(フォーム)を表示するため、まず土台となるフォームを作成します。ここではウィンドウのタイトルやサイズを指定しています。
# フォームの作成
$form = [System.Windows.Forms.Form] @{
Text = "メタスコアとユーザースコアの散布図"
Width = 700
Height = 600
}
フォームについては前回の記事でも紹介しているので、参考にしてください。
2.グラフの骨格を作る(Chart/ChartArea/Series)
続いて、グラフを構成する主要な3つの要素を作成していきます。
3つの要素は以下の通りです。
-
Chart
: グラフ全体(タイトルや凡例なども含んだコントロール) -
ChartArea
: 軸に囲まれた、データが実際に描画される領域 -
Series
: グラフとして描画される、ひとまとまりのデータ系列(1グループの点群など)
Chartの作成・設定
タイトルなどを含むグラフ領域を作成していきます。
Chartオブジェクトの作成
System.Windows.Forms.DataVisualization.Charting.Chart
クラスにleft
(横方向の位置)やtop
(高さ方向の位置)、width
(幅)やheight
(高さ)などのパラメータを渡して、インスタンスを生成します。
# チャートの作成
$chart = [System.Windows.Forms.DataVisualization.Charting.Chart] @{
Width = $form.ClientSize.Width - 100
Height = $form.ClientSize.Height - 100
Left = 50
Top = 50
}
タイトルの追加
System.Windows.Forms.DataVisualization.Charting.Title
クラスにテキストやフォントを指定して新規オブジェクトを作成し、チャートのタイトルに追加します。
Font
には[System.Drawing.Font]
クラスのオブジェクトを指定します。
追加先はChart自体ではなく、Chartの子要素のTitles
になります。
# タイトルの設定
$title = [System.Windows.Forms.DataVisualization.Charting.Title] @{
Text = "メタスコア vs ユーザースコア"
Font = [System.Drawing.Font]::new("Meiryo UI", 14)
}
# タイトルをチャートに追加
$chart.Titles.Add($title)
親要素への紐づけ
あとは親要素となるフォームへ紐づけるだけです。
他のコントロールと同様、Formの子要素Controls
にAdd
メソッドを使用して追加します。
# フォームにチャートを追加
$form.Controls.Add($chart)
今回はタイトルの追加を行った後に紐づけていますが、順番が前後しても問題ありません。
ここまでの結果

とりあえず、まっさらな領域とタイトルだけが追加されました。
ChartAreaの作成・設定
次に実際にデータがプロットされる領域を定義していきます。
ChartAreaオブジェクトの作成
System.Windows.Forms.DataVisualization.Charting.ChartArea
クラスの新規オブジェクトを作成するだけです。
今回のケースでは引数に何も指定する必要はありません。
# チャートエリアの定義
$chartArea = [System.Windows.Forms.DataVisualization.Charting.ChartArea]::new()
親要素への紐づけ
作成した親要素(Chart
)へ紐づけます。Chartの持つChartAreas
にAdd
でオブジェクトを追加するだけです。
# チャートにチャートエリアを追加
$chart.ChartAreas.Add($chartArea)
軸タイトルの設定
今度は親要素に紐づけた後に設定をいじってみます。
ChartArea
の持つ様々な子要素を設定することで、グラフの見た目などをカスタマイズすることができます。
今回はシンプルに軸ラベルのみ指定します。
# 軸ラベル
$chartArea.AxisX.Title = "メタスコア"
$chartArea.AxisY.Title = "ユーザースコア"
ここまでの結果

…先ほどと何も変わりませんね。
理由は、ChartAreaはプロットする何かしらのデータが設定されないと描画されないためです。
なので、データプロットに関する設定を行っていきます。
Seriesの作成・設定
では、データプロットに直接関わるSeries
の作成を行っていきます。
エクセルのグラフで言うところの「系列」ですね。
Seriesの作成
Series
はこれまでのChart
やChartArea
と作成の仕方が異なります。
# シリーズの作成
$series = $chart.Series.Add("ゲームデータ")
Chart
やChartArea
は[クラス名]::new()
で新規オブジェクトを作成していたのに対し、Series
はChartのもつ子要素Series
にいきなりAdd
メソッドで追加しています。
これはSeries
がインスタンス生成→設定に加え、→データ追加という流れを持つためです。
(あくまでも一般的な書き方なだけであって、先にインスタンスを生成して後からAddすることも可能です)
また、Series
は ChartArea
ではなくChart
の子要素になる点も注意が必要です。
Seriesの設定
先ほどAdd
メソッドを呼び出した際に戻り値を変数に格納しておき、その変数の子要素をいじることでグラフの設定を変えられます。
# シリーズの設定
$series.ChartType = [System.Windows.Forms.DataVisualization.Charting.SeriesChartType]::Point # グラフの種類を散布図に
$series.MarkerStyle = [System.Windows.Forms.DataVisualization.Charting.MarkerStyle]::Circle # マーカーの形を円に
$series.MarkerSize = 8 # マーカーのサイズ
$series.Color = [System.Drawing.Color]::Blue # マーカーの色
ChartType
特に重要な設定が ChartType
です。何を指定したかでグラフの種類が変わってきます。System.Windows.Forms.DataVisualization.Charting.SeriesChartType
クラスの列挙子(::
の後ろに指定する文字)で指定します。
主なグラフの種類と列挙子の対応は以下の通り。
その他のグラフは公式のSeriesChartTypeのページを参照してください。
グラフの種類 | 列挙子 |
---|---|
散布図 | Point |
縦棒グラフ | Column |
横棒グラフ | Bar |
折れ線グラフ | Line |
バブルチャート | Bubble |
円グラフ | Pie |
マーカースタイルなど
MarkerStyle
でマーカーの形、MarkerSize
でマーカーのサイズ、Color
でマーカーの色を指定しています。
後日グラフをカスタマイズするための記事を作成予定なので、本稿では解説を割愛します。
クラス名が長すぎる問題
コード中の[System.Windows.Forms.DataVisualization.Charting.SeriesChartType]
等を見て、「うわ…長っ...」と思った方もいるかも知れません。実はこの手のパラメータは以下のように直接文字列で指定することも可能です。
# シリーズの設定
$series.ChartType = "Point" # グラフの種類を散布図に
$series.MarkerStyle = "Circle" # マーカーの形を円に
$series.Color = "Blue" # マーカーの色
直接文字列を指定すると記述が簡潔になる一方、タイプミスに気付きにくい、入力補完が使えない、コードの意図が読めない場合がある、などのデメリットも存在します。
using namespace
も使えるよ
上記のデメリットを解消しつつ簡潔に記述する方法として、using namespace
があります(PowerShell 5.0以降)
# 必要なアセンブリの読み込み
:
# よく使う名前空間の短縮を宣言
using namespace System.Windows.Forms.DataVisualization.Charting
:
# シリーズの設定
$series.ChartType = [SeriesChartType]::Point # グラフの種類を散布図に
$series.MarkerStyle = [MarkerStyle]::Circle # マーカーの形を円に
using namespace
の後ろにクラスの名前空間(.
で記される住所みたいなもの)を指定することで、指定した名前空間を省いて記述可能になります。
入力補完なども使用でき、安全性と簡潔さを両立させることができます。
Seriesへのデータ投入
ようやくデータをSeriesに投入していきます。
Seriesへのデータ投入の仕方はいくつか選択肢があります。
AddXYで1点ずつ追加
- 1行ずつデータを取り出し、
AddXY
で1点ずつ追加していく方法- シンプルだが、Forなどの制御構文が必須
- 1点ずつ追加するため、データ数が重いと処理が重くなる
DataBindXYで列ごと追加
- X/Y要素となる列を配列として取り出し、
DataBindXY
で列ごと追加する- シンプルで直感的、処理も軽い
- 列を取り出す処理がワンクッションはいる
DataBindにデータ全体を指定
-
DataBind
の際、第一引数でデータ全体を指定し、第二・第三引数でどの列をX/Yにするか設定する- 引数の順番を覚える必要がある
- 第四引数でラベルなどに指定する列を規定することができる
(ツールチップは何故かうまく動作しない。。)
今回はシンプルかつ処理も軽い「DataBindXYで列ごと指定」を採用します。
投入前処理(列の取り出しと変換)
まず最初にデータ全体からXとYに指定する列を取り出します。
# データバインドするためのXY配列を生成
# !読み込んだimport-csvで読み込んだデータは文字列であるため、数値に変換する必要がある
$xValues = $gameData.メタスコア | ForEach-Object { [double]$_ }
$yValues = $gameData.ユーザースコア | ForEach-Object { [double]$_ }
いかにもPowerShellな書き方なので、細かめに解説しておきます。
-
$gameData.メタスコア
:
$gameData
に格納されているのはPSCustomObject
です。PSCustomObjectは.<列名>
で列データを配列として取り出すことができます。 -
|
(パイプライン):
パイプライン前のコマンドで取り出したデータ列を分解し、中の要素をバケツリレーのように一つずつ後ろのコマンドに渡しています。 -
ForEach-Object { }
:
PowerShellでおなじみ「〇〇-Object」シリーズの一つ。渡された要素すべてに{}
内で指定した処理を実行します。 -
[double]$_
:
$_
はパイプラインで渡された一つひとつの要素を指します。変数の前に[double]
を置くことで double型にキャスト(型変換) しています。
以上の処理でDouble型にキャストされた配列が戻り値として取得できるので、それを変数に格納しています。
Seriesへのデータ投入
あとは変換した列データをSeriesに投入するだけです。
# データ追加(データバインド)
$series.Points.DataBindXY($xValues, $yValues)
Seriesの子要素であるPointsのメソッドでデータを投入します。
X列とY列は個別に投入も可能ですが、今回はDataBindXY
でまとめて投入しています。
今回サンプルとして散布図(Point
)を使用していますが、Seriesのデータ群を示すPoints
コレクションとは無関係です。グラフの種類を変えてもPoints
コレクションにデータを投入するのは共通です。
これでグラフを表示する準備が整いました。
グラフ表示
Chartが格納されたFormをShowDialog()
メソッドで画面に表示します。
# フォームの表示
$form.ShowDialog()
出来ました!
以上が基本的なグラフの作り方となります。お疲れ様でした。
3. まとめ
今回は基本的なグラフの書き方を紹介しました。ポイントは
- Chart(グラフ全体)
- ChartArea(データが実際に描画される領域)
- Series(グラフとして描画されるデータ系列)
それぞれの役割と使い方を理解することだと思います。
次回あたりの記事では、見た目の整え方等を紹介したいと考えています。
(多分時間かかるので気長にお待ち下さい。。)