Excel VBA を使ってグラフを描く
素人、グラフに挑戦する
ExcelVBAでグラフを描く
実は、今までほとんどExcelでグラフを使ったことがなかったのである。
まったくグラフを使うことがなかったわけではないが、ずーっと前に誰かが作ったグラフをちょこちょこっといじくる程度で乗りきっていたのである。
ところが、なぜか職場では Excelができる人認定されている私は、
Excelができる=グラフもバリバリ
という魔の方程式のせいで、
アンタ、Excel得意やからグラフを用いたデータ分析なんかもチョチョイのチョイやろ?
と、やけに軽々しく
データ分析&見栄え良く加工する業務
を割り当てられたのであった(´・ω・`)
グラフの種類を概観するマクロ
ずーっと前に、『Excel VBAでデータ分析』(川上恭子著)という本を購入していたのを思い出して引っ張り出してみた。
その本によると、
118ページ
新しくグラフシートを追加して、そのシートにグラフだけを表示します。
ソースコード
Sub グラフシートに作成() 'グラフシートにマーカー付折れ線グラフを作成' With Charts.Add .ChartType = xlLineMarkers .SetSourceData Source:=Sheets("Sheet1").Range("A3:G8") End With End Sub
とあった。
ぱっと見た感じ、単にグラフを描くだけなら、
- ChartsコレクションにAddしたら、(たぶん)新しいChartオブジェクトが得られ、
- 1.で得られたChartオブジェクトのChartTypeプロパティにグラフの種類をセットして、
- SetDataSourceメソッドでグラフ化する元データを指定する
という流れだけっぽい。
とりあえずこれだけなら素人の私にもできそうだ。
前掲書の119ページには、
グラフの種類
ChartTypeプロパティに設定する定数を以下のように指定すると、グラフの種類を変更できます。また定数には値を指定することもできます。
ChartTypeプロパティ グラフ 定数 値 集合縦棒 xlColumnClustered 51 積み上げ縦棒 xlColumnStacked 52 100%積み上げ縦棒 xlColumnStacked100 53 3-D集合縦棒 xl3DColumnClustered 54 3-D積み上げ縦棒 xl3DColumnStacked 55 3-D100%積み上げ縦棒 xl3DColumnStacked100 56 3-D縦棒 xl3DColumn -4100 集合横棒 xlBarClustered 57 3-D集合横棒 xl3DBarClustered 60 折れ線 xlLine 4 マーカー付き折れ線 xlLineMarkers 65 円 xlPie 5 補助円グラフ付き円 xlPieOfPie 68 補助縦棒グラフ付き円 xlBarOfPie 71 3-D円 xl3 DPie -4102 ドーナツ xlDoughnut -4120 面 xlArea 1 積み上げ面 xlAreaStacked 76 3-D面 xl3DArea -4098 散布図 xlXYScatter -4169 バブル xlBubble 15 株価チャート(高値-安値-終値) xlStockHLC 88 レーダー xlRadar -4151 マーカー付きレーダー xlRadarMarkers 81
とあり、ChartTypeプロパティに渡す値を変えれば、同じデータからいろんなグラフが作れそうだ。
ちなみに、オブジェクトブラウザーで見てみると、
これらの定数は、「XLChartType列挙体」のメンバのようだ。【→参考】
とりあえずやってみる
まずは、単純に、引数としてグラフの種類を表す定数と、グラフ化する元データの範囲を与えたら、新しいシートにサクッとグラフを作ってくれるマクロを作ってみる。
リスト1 標準モジュール
Public Function createGraph(ByVal typeOfGraph As String, _ ByVal sourceRange As Range) As Boolean If getGraphType(typeOfGraph) = 0 Then '……(*)' createGraph = False Exit Function End If With Charts.Add .ChartType = getGraphType(typeOfGraph) '……(*)' .SetSourceData Source:=sourceRange End With createGraph = True End Function
引数typeOfGraphがString型であること、あと(*)の
getGraphType(typeOfGraph)
がナゾだと思う。getGraphTypeというのは自作Functionなんだから仕方がない。
あと、なんでSubじゃなくてFunctionにしているのか、についても後述する。
引数でグラフの種類と元データの範囲を受け取って、それをもとにグラフを新規作成する、というだけのマクロ。もちろん、単独でこのプロシージャを呼び出しても動かない。次のgetGraphTypeが必要になる。
リスト2 標準モジュール
Private Function getGraphType(ByVal typeOfGraph As String) As XlChartType Select Case typeOfGraph Case "集合縦棒" getGraphType = xlColumnClustered Case "積み上げ縦棒" getGraphType = xlColumnStacked Case "100%積み上げ縦棒" getGraphType = xlColumnStacked100 Case "3-D集合縦棒" getGraphType = xl3DColumnClustered Case "3-D積み上げ縦棒" getGraphType = xl3DColumnStacked Case "3-D100%積み上げ縦棒" getGraphType = xl3DColumnStacked100 Case "3-D縦棒" getGraphType = xl3DColumn Case "集合横棒" getGraphType = xlBarClustered Case "3-D集合横棒" getGraphType = xl3DBarClustered Case "折れ線" getGraphType = xlLine Case "マーカー付き折れ線" getGraphType = xlLineMarkers Case "円" getGraphType = xlPie Case "補助円グラフ付き円" getGraphType = xlPieOfPie Case "補助縦棒グラフ付き円" getGraphType = xlBarOfPie Case "3-D円" getGraphType = xl3DPie Case "ドーナツ" getGraphType = xlDoughnut Case "面" getGraphType = xlArea Case "積み上げ面" getGraphType = xlAreaStacked Case "3-D面" getGraphType = xl3DArea Case "散布図" getGraphType = xlXYScatter Case "バブル" getGraphType = xlBubble Case "株価チャート(高値-安値-終値)" getGraphType = xlStockHLC Case "レーダー" getGraphType = xlRadar Case "塗りつぶしレーダー" getGraphType = xlRadarFilled Case "マーカー付きレーダー" getGraphType = xlRadarMarkers Case Else '……(*)' Call makeUserSick("すまん、そのグラフの種類には対応しとらんわwww") getGraphType = 0 End Select End Function
すっげータテ長ですまん。見たら分かると思うけど、グラフの種類名を引数として渡したら、その名前に応じた定数を返すようにした。
データの入力規則のリストに名前を登録しといたら、それを選ぶだけで良いようにしたのだ。
一見、コードを書くのが死ぬほどメンドクサそうに見えると思うけれど、返り値の型を「XLChartType型」にしているので、それほどでもなかった。
ただ、XLChartTypeのメンバ全てに対応するのはちょっと数が多すぎて嫌になるので、基本的には、前掲書の119ページの表に載っていたものだけに対応した(追加したのは「マーカー付きレーダー」だけです)。
その関係で、選から漏れたグラフの種類を指定された場合には、ユーザーを軽く煽ってから、「0」を返すことにした。
要するに、対応していないグラフの種類とか、間違った名前を指定されたら、リスト1の
If typeOfGraph = 0 Then createGraph = False: Exit Function
の条件式がTrueになるので、返り値Falseを持って呼び出し元へ帰る、ということになる。
グラフを描いてみる
ワークシートを、
こんなふうに作っておく。
A2セルには、データの入力規則で、特定のグラフの種類名しか入力できないように指定しておく。
んで、C1:H6にグラフの元データを準備した。
いちいちVBEから呼び出すのもメンドウなので、呼び出し用のコマンドボタンも置いておく。
エントリポイントのコードは次の通り。
リスト3 標準モジュール
Public Sub testCreateGraph() Dim Sh As Worksheet Set Sh = ThisWorkbook.Worksheets("Main") With Sh If Not createGraph(typeOfGraph:=.Range("A2").Value, _ sourceRange:=.Range("C1:H6")) Then '……(*)' Call makeUserSick("すまん、グラフ描けんかったわwww") End If End With End Sub
グラフの種類の指定がおかしかったら、リスト1の先頭で撥ねられて、Falseを持って帰ってくるので、(*)のところで
Call makeUserSick("すまん、グラフ描けんかったわwww")
が実行される。
グラフの種類の指定が正しければ、createGraphの中身が実行されてグラフが追加されることになる。
実行結果
この状態で実行してみる。A2セルには、「集合縦棒」が入っている。
ほれ、このとおり。
A2セルには「折れ線」。
ほれ、このとおり。
A2セルには「マーカー付きレーダー」。
ほれ、このとおり。
A2セルには入力規則で制限を掛けているので、通常おかしなグラフの種類名が渡るはずはないが、ムリヤリリスト1の引数typeOfGraphにデタラメな文字列を与えてみると、
Public Sub testCreateGraph() Dim Sh As Worksheet Set Sh = ThisWorkbook.Worksheets("Main") With Sh If Not createGraph(typeOfGraph:="ち~んw", _ '……(*)' sourceRange:=.Range("C1:H6")) Then Call makeUserSick("すまん、グラフ描けんかったわwww") End If End With End Sub
無事、グラフが作成されずに、煽られるだけ、となりますw
おわりに
現状、ボタンを押したらいきなり新規シートにグラフを作成する、という乱暴なものになっている。
Chartオブジェクト関係のオブジェクトモデルをもっとちゃんと理解して、もう少し使い勝手の良いものにしないといけないなあ。