ScottPlotのインストール方法や使い方については、こちらの記事に記載しましたが、よく使いそうなグラフについて簡単に描画できるよう関数化(メソッド化)してみました。
引数にScottPlotのコントロールと描画したいデータを渡すと、簡単に描画してくれます。
後から手を加えやすいよう、必要最小限のプロパティを使っていますので、用途に応じてカスタマイズしてお使いください。
Contents
グラフ(チャート)の種類
この関数(メソッド)を使えば、次のグラフ(チャート)が描画できます。



サンプルプログラム
サンプルプログラムを作りましたので、そのソースコードを元にポイントを解説していきたいと思います。
画面レイアウト
チャート1~チャート3までタブで分かれていて、合計12個のScotPlotコントロールを張り付けています。
描画ボタンをクリックすると、全てのチャートが描画されるようになっています。

サンプルのダウンロード場所
サンプルプログラムのソースは下記からダウンロードできます。
今回は Nuget で取得した ScottPlot 4.0.44 のライブラリも同梱していますので、任意のフォルダに解凍し、Visual Stduio 2019 でプロジェクトを開き、ビルドできると思います。
関数(メソッド)の使い方
グラフ描画はDrowから始まるメソッド名にしました。
チャート(グラフ)名 | 関数(メソッド)名 | 内容 |
---|---|---|
折れ線グラフ | DrawLine | 単一の折れ線グラフを描画 |
折れ線グラフ(複数) | DrawLine | 複数の折れ線グラフを描画 |
散布図 | DrawScatt | 散布図を描画 |
円グラフ | DrawPie | 円グラフを描画 |
縦棒グラフ | DrawColumn | 縦棒グラフを描画 |
横棒グラフ | DrawBar | 横棒グラフを描画 |
棒グラフ(グルーピング) | DrawGroupColumn | 複数の棒グラフをグルーピングして描画 |
積み上げグラフ | DrawStack | 積み上げグラフを描画 |
レーダーチャート | DrawRadar | レーダーチャートを描画 |
箱ひげ図 | DrawPopulations | 箱ひげ図とベルカーブを同時描画 |
散布図と回帰直線 | DrawRegression | 散布図と回帰直線を同時描画 |
ヒストグラム | DrawHistgram | ヒストグラムを描画 |
第一引数にコントロールを、第二引数にタイトルを、第三引数以降に描画データ(プロットデータ)を渡します。
例えば、コントロールに “uxChart1” という名前を付けて、xs にX方向のデータ、ysにY方向のデータが格納されていると仮定すると
1 2 |
//グラフの描画 DrawLine(uxChart1,"折れ線グラフ",xs, ys); |
という具合です。
第三引数のプロットデータについては、大きく分けて2つの形式があります。
折れ線や棒グラフ、円グラフ、散布図は引数にプロットデータの配列を渡す仕様ですが、複数の折れ線グラフ、レーダーチャート、グルーピングした棒グラフ、積み上げグラフは複数の項目をグルーピングする形になるため、タプルをリスト形式で渡すようにしました。
詳しくはソースコードを見て頂くとして、ここでは簡単にポイントだけ説明しておきます。
単独の折れ線グラフ、散布図、散布図と回帰直線、箱ひげ図、ヒストグラム
これらはプロットデータを配列データとして、1つまたは2つ引数に渡します。
例えば、折れ線グラフの場合は次の様になります。
1 |
DrawLine(uxChart1,"折れ線グラフ",xs, ys); |
縦棒グラフ、横棒グラフ
縦棒グラフ、横棒グラフともプロットデータとして2つ渡すのは折れ線や散布図と同じですが、横軸がdouble型配列ではなく、文字列配列になっているところが異なる点です。
1 2 |
//棒グラフ DrawBar(uxChart6, "横棒グラフ", labels, values); |
円グラフ
円グラフは、ラベルと対応する値の配列を描画データとして渡します。
1 2 3 4 5 6 |
//円グラフのデータ double[] values = { 778, 43, 283, 76, 184 }; string[] labels = { "C#", "JAVA", "Python", "F#", "PHP" }; //円グラフの描画 DrawPie(uxChart4, "円グラフ", labels, values); |
複数の折れ線グラフ
タプルのリスト形式で描画データを指定します。
タプルで、凡例タイトル(legend)、X座標の配列、y座標の配列を1まとまりにして、リストに追加していき、そのリストを引数に渡します。
1 2 3 4 5 6 |
List<(string legend, double[] xs, double[] ys)> linedata = new List<(string legend, double[] xs, double[] ys)>(); linedata.Add(("legend1", xs, ys1)); linedata.Add(("legend2", xs, ys2)); linedata.Add(("legend3", xs, ys3)); DrawLine(uxChart2, "折れ線グラフ(複数)", linedata); |
縦棒グラフ(グルーピング)、積み上げグラフ、レーダーチャート
これらは複数の値をグループ化して、まとめて表示するグラフであるため、タプルのリスト形式でプロットデータを設定します。
グループ化が少し分かりづらいかもしれませんが、項目名と内訳と考えてもらえれば分かりやすいかと思います。

ScottPlot をそのまま使う場合、少し面倒な値の渡し方をする必要があるので、項目名と内訳という考え方でプロットデータをセットすれば良いようにしています。
1 2 3 4 5 6 7 8 9 10 11 |
//グルーピングのデータ作成 string[] group = { "コア数", "クロック数", "スレッド数", "キャッシュ", "価格" }; List<(string, double[])> datas = new List<(string, double[])>(); datas.Add(("Core-i7", new double[] { 8, 3.6, 16, 64, 70 })); datas.Add(("Core-i5", new double[] { 6, 2.8, 12, 32, 50 })); datas.Add(("Core-i3", new double[] { 4, 2.0, 8, 16, 30 })); datas.Add(("Pentium", new double[] { 2, 1.8, 4, 8, 10 })); datas.Add(("Celeron", new double[] { 2, 1.5, 4, 8, 5 })); //棒グラフ(グルーピング) DrawGroupColumn(uxChart1, "グループ", group, datas); |
このサンプルソース上では group という変数名を使っていますが、明細(detail) とか、内訳(breakdown) という変数名の方が良かったかもしれません。
ソースコード
サンプルプロジェクトをダウンロード&解凍したあと、プロジェクトをVisual Studioで開くと、次のレイアウトが表示されます。
先ほども申しましたが、タブページが3つあって、それぞれに ScottPlot のコントロールを4つづつ張り付けています。

サンプルプログラムのXAMLのソースコードは次の様になっています。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 |
<Window x:Class="ScotPlotTest.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:local="clr-namespace:ScotPlotTest" mc:Ignorable="d" Title="MainWindow" Height="450" Width="1320"> <Grid> <TabControl> <TabItem Header="チャート1"> <Grid> <WpfPlot x:Name="uxChart1" HorizontalAlignment="Left" Height="315" Margin="27,53,0,0" VerticalAlignment="Top" Width="300"/> <WpfPlot x:Name="uxChart2" HorizontalAlignment="Left" Height="315" Margin="345,53,0,0" VerticalAlignment="Top" Width="300"/> <WpfPlot x:Name="uxChart3" HorizontalAlignment="Left" Height="315" Margin="664,53,0,0" VerticalAlignment="Top" Width="300"/> <WpfPlot x:Name="uxChart4" HorizontalAlignment="Left" Height="315" Margin="987,53,0,0" VerticalAlignment="Top" Width="300"/> <Button Content="描画" HorizontalAlignment="Left" Margin="1212,10,0,0" VerticalAlignment="Top" Width="75" Click="Button_Click" Height="21"/> </Grid> </TabItem> <TabItem Header="チャート2"> <Grid> <Button Content="描画" HorizontalAlignment="Left" Margin="1212,10,0,0" VerticalAlignment="Top" Width="75" Click="Button_Click"/> <WpfPlot x:Name="uxChart5" HorizontalAlignment="Left" Height="315" Margin="27,53,0,0" VerticalAlignment="Top" Width="300"/> <WpfPlot x:Name="uxChart6" HorizontalAlignment="Left" Height="315" Margin="345,53,0,0" VerticalAlignment="Top" Width="300"/> <WpfPlot x:Name="uxChart7" HorizontalAlignment="Left" Height="315" Margin="664,53,0,0" VerticalAlignment="Top" Width="300"/> <WpfPlot x:Name="uxChart8" HorizontalAlignment="Left" Height="315" Margin="987,53,0,0" VerticalAlignment="Top" Width="300"/> </Grid> </TabItem> <TabItem Header="チャート3"> <Grid> <Button Content="描画" HorizontalAlignment="Left" Margin="1212,10,0,0" VerticalAlignment="Top" Width="75" Click="Button_Click"/> <WpfPlot x:Name="uxChart9" HorizontalAlignment="Left" Height="315" Margin="27,53,0,0" VerticalAlignment="Top" Width="300"/> <WpfPlot x:Name="uxChart10" HorizontalAlignment="Left" Height="315" Margin="345,53,0,0" VerticalAlignment="Top" Width="300"/> <WpfPlot x:Name="uxChart11" HorizontalAlignment="Left" Height="315" Margin="664,53,0,0" VerticalAlignment="Top" Width="300"/> <WpfPlot x:Name="uxChart12" HorizontalAlignment="Left" Height="315" Margin="987,53,0,0" VerticalAlignment="Top" Width="300"/> </Grid> </TabItem> </TabControl> </Grid> </Window> |
次にC#のソースコードを見てみましょう。
ソースを読み解く上で、ScottPlotの描画手順の全体像を知っていると理解が深まりますので、もしScottPlotが初めての方は、こちらの記事も是非お読み下さい。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 |
using ScottPlot; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows; using System.Windows.Controls; using System.Windows.Data; using System.Windows.Documents; using System.Windows.Input; using System.Windows.Media; using System.Windows.Media.Imaging; using System.Windows.Navigation; using System.Windows.Shapes; namespace ScotPlotTest { /// <summary> /// MainWindow.xaml の相互作用ロジック /// </summary> public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); } private void Button_Click(object sender, RoutedEventArgs e) { Random rand = new Random(); //折れ線グラフのデータ作成 double[] xs = Enumerable.Range(0, 100).Select(i => (double)i).ToArray(); double[] ys = Enumerable.Range(0, 100).Select(i => (double)(i + rand.Next(0,100) * ((rand.Next(1,2) == 1) ? 1 : -1))).ToArray(); double[] ys1 = Enumerable.Range(0, 100).Select(i => Math.Sin(i * 0.1)).ToArray(); double[] ys2 = Enumerable.Range(0, 100).Select(i => 2 + Math.Cos(i * 0.1)).ToArray(); double[] ys3 = Enumerable.Range(0, 100).Select(i => 4 + Math.Sin(i * 0.1) * Math.Cos(i * 0.1)).ToArray(); //グラフの描画 DrawLine(uxChart1,"折れ線グラフ",xs, ys); List<(string legend, double[] xs, double[] ys)> linedata = new List<(string legend, double[] xs, double[] ys)>(); linedata.Add(("legend1", xs, ys1)); linedata.Add(("legend2", xs, ys2)); linedata.Add(("legend3", xs, ys3)); DrawLine(uxChart2, "折れ線グラフ(複数)", linedata); //散布図 DrawScatt(uxChart3, "散布図", xs, ys); //円グラフ double[] values = { 778, 43, 283, 76, 184 }; string[] labels = { "C#", "JAVA", "Python", "F#", "PHP" }; DrawPie(uxChart4, "円グラフ", labels, values); //縦棒グラフ DrawColumn(uxChart5, "縦棒グラフ", labels, values); //横棒グラフ DrawBar(uxChart6, "横棒グラフ", labels, values); //グルーピングのデータ作成 string[] items = { "コア数", "クロック数", "スレッド数", "キャッシュ", "価格" }; List<(string, double[])> datas = new List<(string, double[])>(); datas.Add(("Core-i7", new double[] { 8, 3.6, 16, 64, 70 })); datas.Add(("Core-i5", new double[] { 6, 2.8, 12, 32, 50 })); datas.Add(("Core-i3", new double[] { 4, 2.0, 8, 16, 30 })); datas.Add(("Pentium", new double[] { 2, 1.8, 4, 8, 10 })); datas.Add(("Celeron", new double[] { 2, 1.5, 4, 8, 5 })); //棒グラフ(グルーピング) DrawGroupColumn(uxChart7, "グループ", items, datas); //積み上げグラフ DrawStack(uxChart8, "積み上げ", items, datas); //レーダーチャート DrawRadar(uxChart9, "レーダー", items, datas); //箱ひげ図 DrawPopulations(uxChart10, "箱ひげ", ys); //散布図と回帰直線 DrawRegression(uxChart11, "回帰", xs, ys); ///ヒストグラム DrawHistgram(uxChart12, "ヒストグラム", ys,20); } /// <summary> /// 折れ線グラフ /// </summary> /// <param name="chart"></param> /// <param name="title"></param> /// <param name="xs"></param> /// <param name="ys"></param> private void DrawLine(WpfPlot chart, string title, double[] xs,double[] ys) { chart.plt.Clear(); chart.plt.Title(title); chart.plt.PlotSignalXY(xs,ys); chart.Render(); } /// <summary> /// 折れ線グラフ(複数) /// </summary> /// <param name="chart"></param> /// <param name="title"></param> /// <param name="datas"></param> private void DrawLine(WpfPlot chart, string title, List<(string legend,double[] xs, double[] ys)> datas) { chart.plt.Clear(); chart.plt.Title(title); foreach (var data in datas) { chart.plt.PlotSignalXY(data.xs, data.ys, label: data.legend); } chart.plt.Legend(location: legendLocation.upperRight); chart.Render(); } /// <summary> /// 散布図 /// </summary> /// <param name="chart"></param> /// <param name="title"></param> /// <param name="xs"></param> /// <param name="ys"></param> private void DrawScatt(WpfPlot chart,string title, double[] xs, double[] ys) { chart.plt.Clear(); chart.plt.Title(title); chart.plt.PlotScatter(xs, ys, lineWidth: 0); chart.Render(); } /// <summary> /// 円グラフ /// </summary> /// <param name="chart"></param> /// <param name="title"></param> /// <param name="labels"></param> /// <param name="values"></param> private void DrawPie(WpfPlot chart, string title, string[] labels,double[] values) { chart.plt.Clear(); chart.plt.Title(title); chart.plt.PlotPie(values, labels); chart.plt.Grid(false); chart.plt.Frame(false); chart.plt.Ticks(false, false); chart.Render(); } /// <summary> /// 縦棒グラフ /// </summary> /// <param name="chart"></param> /// <param name="title"></param> /// <param name="labels"></param> /// <param name="ys"></param> private void DrawColumn(WpfPlot chart, string title, string[] labels, double[] ys) { chart.plt.Clear(); chart.plt.Title(title); chart.plt.PlotBar(DataGen.Consecutive(ys.Length),ys); chart.plt.XTicks(labels); chart.Render(); } /// <summary> /// 横棒グラフ /// </summary> /// <param name="chart"></param> /// <param name="title"></param> /// <param name="labels"></param> /// <param name="ys"></param> private void DrawBar(WpfPlot chart, string title, string[] labels, double[] ys) { chart.plt.Clear(); chart.plt.Title(title); chart.plt.PlotBar(DataGen.Consecutive(ys.Length), ys,horizontal:true); chart.plt.YTicks(labels); chart.Render(); } /// <summary> /// 箱ひげ図 /// </summary> /// <param name="chart"></param> /// <param name="title"></param> /// <param name="ys"></param> private void DrawPopulations(WpfPlot chart, string title, double[] ys) { chart.plt.Clear(); chart.plt.Title(title); chart.plt.PlotPopulations(new ScottPlot.Statistics.Population(ys)); chart.plt.Ticks(displayTicksX: false); chart.Render(); } /// <summary> /// 散布図と回帰直線 /// </summary> /// <param name="chart"></param> /// <param name="title"></param> /// <param name="xs"></param> /// <param name="ys"></param> private void DrawRegression(WpfPlot chart,string title, double[] xs, double[] ys) { var model = new ScottPlot.Statistics.LinearRegressionLine(xs, ys); chart.plt.Clear(); chart.plt.Title((title != "") ? title : "Y = {model.slope:0.0000}x + {model.offset:0.0}\nR² = {model.rSquared:0.0000}"); chart.plt.PlotScatter(xs, ys, lineWidth: 0); chart.plt.PlotLine(model.slope, model.offset, (xs.Min(), xs.Max()), lineWidth: 2); chart.Render(); } /// <summary> /// 縦棒グラフ(グループ) /// </summary> /// <param name="chart"></param> /// <param name="title"></param> /// <param name="labels"></param> /// <param name="values"></param> private void DrawGroupColumn(WpfPlot chart, string title, string[] labels, List<(string legend,double[] ys)> values) { chart.plt.Clear(); chart.plt.Title(title); var datas = Enumerable.Range(0, values[0].ys.Length).Select(y => Enumerable.Range(0, values.Count).Select(x => values[x].ys[y]).ToArray()).ToArray(); chart.plt.PlotBarGroups(values.Select(i => i.legend).ToArray(), labels, datas); chart.plt.Legend(location: legendLocation.upperRight); chart.Render(); } /// <summary> /// 積み上げグラフ /// </summary> /// <param name="chart"></param> /// <param name="title"></param> /// <param name="labels"></param> /// <param name="values"></param> private void DrawStack(WpfPlot chart, string title, string[] labels, List<(string legend, double[] ys)> values) { //チャートエリアのクリア chart.plt.Clear(); //タイトルの設定 chart.plt.Title(title); //X軸のデータを生成 var x = Enumerable.Range(0, labels.Length).Select(i => (double)i).ToArray(); //積み上げ用配列の初期化と合計計算 var sum = values.Select(i => i.ys.Sum()).ToArray(); //積み上げグラフ作成(トップから順に描画) for(int n = 0;n < values.Count;n ++) { chart.plt.PlotBar(x, sum.ToArray(), label: labels[n]); Enumerable.Range(0, sum.Length).Select(i => sum[i] = sum[i] - values[i].ys[n]).ToArray(); } //凡例と軸の設定 chart.plt.Legend(location: legendLocation.upperRight); chart.plt.XTicks(values.Select(i=>i.legend).ToArray()); //レンダリング chart.Render(); } /// <summary> /// レーダーチャート /// </summary> /// <param name="chart"></param> /// <param name="title"></param> /// <param name="labels"></param> /// <param name="values"></param> private void DrawRadar(WpfPlot chart, string title, string[] labels, List<(string legend, double[] ys)> values) { chart.plt.Clear(); chart.plt.Title(title); double[,] plots = new double[values.Count,values[0].ys.Length]; Enumerable.Range(0, plots.GetLength(0)).Select(i => Enumerable.Range(0, plots.GetLength(1)).Select(j => plots[i, j] = values[i].ys[j]).ToArray()).ToArray(); chart.plt.PlotRadar(plots,labels,values.Select(i => i.legend).ToArray()); chart.plt.Legend(location: legendLocation.upperRight); chart.Render(); } /// <summary> /// ヒストグラム /// </summary> /// <param name="chart"></param> /// <param name="title"></param> /// <param name="ys"></param> /// <param name="backet"></param> private void DrawHistgram(WpfPlot chart, string title, double[] ys,int backet = 10) { var hist = new ScottPlot.Statistics.Histogram(ys,binCount:backet); chart.plt.Clear(); chart.plt.Title(title); chart.plt.PlotBar(hist.bins, hist.counts, barWidth: hist.binSize, outlineWidth: 0); chart.Render(); } // https://swharden.com/scottplot/cookbooks/4.0.40/#plottypes-bar-bar-plot-quickstart } } |
ソースの解説(ポイント)
ソースコードを見て頂くと使い方は分かると思いますので、ポイントだけ解説しておきます。
ScottPlotの基本形は簡単で、次の様になります。
1 2 3 4 5 6 7 8 |
//コントロールのインスタンスを生成 WpfPlot chart = new WpfPlot(); //タイトルの設定 chart.plt.Title(title); //データを渡して折れ線グラフを作成 chart.plt.PlotSignalXY(xs,ys); //画面に表示 chart.Render(); |
関数(メソッド)では、それぞれのグラフ(チャート)を書く上で必要最小限の記述しかしていないので、みなさんが必要と思われる機能(このソースコードで不足している機能)を継ぎ足してご利用下さい。
積み上げグラフについて
この中で一番ややこしいのが積み上げグラフです。
ScottPlotには積み上げグラフ専用メソッドが有りませんので、通常の縦棒グラフを重ねて表現する必要があります。
積み上げグラフの場合、全ての値の合計が一番高い棒になるので、まずそれを作成します。
そこから、順に積み上げる値を引いては棒グラフを描画するという作業を繰り返し、いちばん高い棒グラフから順に小さな棒グラフを重ねています。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
private void DrawStack(WpfPlot chart, string title, string[] labels, List<(string legend, double[] ys)> values) { //チャートエリアのクリア chart.plt.Clear(); //タイトルの設定 chart.plt.Title(title); //X軸のデータを生成 var x = Enumerable.Range(0, labels.Length).Select(i => (double)i).ToArray(); //積み上げ用配列の初期化と合計計算 //var sum = new double[values[0].ys.Length]; //Enumerable.Range(0, values.Count).Select(i => Enumerable.Range(0, sum.Length).Select(j => sum[j] = sum[j] + values[i].ys[j]).ToArray()).ToArray(); var sum = values.Select(i => i.ys.Sum()).ToArray(); //積み上げグラフ作成(トップから順に描画) for(int n = 0;n < values.Count;n ++) { chart.plt.PlotBar(x, sum.ToArray(), label: labels[n]); Enumerable.Range(0, sum.Length).Select(i => sum[i] = sum[i] - values[i].ys[n]).ToArray(); } //凡例と軸の設定 chart.plt.Legend(location: legendLocation.upperRight); chart.plt.XTicks(values.Select(i=>i.legend).ToArray()); //レンダリング chart.Render(); } |
まとめ
今回はよく使うグラフ(チャート)を、ScottPlotで簡単に描画するための関数(メソッド)について解説しました。
例えばグラフの色を引数に指定するとか、線の太さや種類を指定するなどは、ScottPlotの Plot~メソッドに引数があるので、それを使えば簡単に実現できます。
みなさんが必要な機能を随時継ぎ足して、使いやすい様にカスタマイズしていただければ幸いです。