VBAでグラフをいじくる

VBAでグラフを操る

Excelグラフのオブジェクトモデルを探る

次のような表からグラフを作成し、いろいろいじくり回してみた。

f:id:akashi_keirin:20180127221014j:plain

f:id:akashi_keirin:20180127221029j:plain

これが元のグラフ。それぞれの選手の連対時決まり手を元に積み上げ横棒グラフを作ってみた。

んで、次のコードでこのグラフを加工してみた。

リスト1 標準モジュール
Public Sub testGraph()
  Dim Sh As Worksheet
  Set Sh = ActiveSheet
  Dim targetGraph As ChartObject
  Set targetGraph = Sh.ChartObjects(1)
  Dim i As Integer
  With targetGraph.Chart
    .ChartType = xlBarStacked
    With .Axes(xlCategory)
      .ReversePlotOrder = True    '……(1)軸を反転させる'
      .Crosses = xlMaximum     '……(2)横軸との交点を「最大項目」に'
    End With
    .ChartGroups(1).GapWidth = 20    '……(3)グラフの棒と棒の間隔'
    With .PlotArea
      .InsideHeight = 140    '……(4)プロットエリア内部の高さ'
      .InsideWidth = 280    '……(5)プロットエリア内部の幅'
      With .Format.Line    '……(6)プロットエリアの枠線'
        .ForeColor.RGB = vbBlack    '……(7)枠線の色'
        .Weight = 1.5    '……(8)枠線の太さ'
      End With
    End With
    For i = 1 To .SeriesCollection.Count
      With .SeriesCollection(i).Format    '……(9)データ系列の書式'
        .Fill.ForeColor.RGB = vbBlack    '……(10)塗りつぶしの色'
        .Fill.BackColor.RGB = vbWhite
        .Fill.Patterned (i - 1) * 5 + 1    '……(11)塗りつぶしのパターン'
        .Line.Visible = msoTrue
        .Line.ForeColor.RGB = vbBlack    '……(12)枠線の色'
        .Line.Weight = 1    '……(13)枠線の太さ'
      End With
    Next
  End With
End Sub

まずは(1)と(2)の

With targetGraph.Chart.Axes(xlCategory)
  .ReversePlotOrder = True    '……(1)軸を反転させる'
  .Crosses = xlMaximum     '……(2)横軸との交点を「最大項目」に'
End With

分かりやすいようにWithで括った上位オブジェクトを補って記す。targetGraphは埋め込みグラフオブジェクトを表すChartObject型の変数。コイツを便宜的に最上位オブジェクトとして説明する。以下同様に。

何をしているのかはコードの中のコメントに記してあるので、実行後どうなっているのかを示す。

f:id:akashi_keirin:20180127221043j:plain

まず(1)でこうなって、

f:id:akashi_keirin:20180127221102j:plain

(2)でこうなる。

横棒グラフにしたときは、項目が上下逆になってしまうので、その現象への対応。

ちなみに、Axesメソッドの引数に「xlCategory」を指定するとタテ軸、「xlValue」にするとヨコ軸を指すっぽい。

(3)の

targetGraph.Chart.ChartGroups(1).GapWidth = 20    '……(3)グラフの棒と棒の間隔'

「20」の単位は%。

コイツを実行すると、

f:id:akashi_keirin:20180127221113j:plain

こうなる。

(4)から(8)の

With targetGraph.Chart.PlotArea
  .InsideHeight = 140    '……(4)プロットエリア内部の高さ'
  .InsideWidth = 280    '……(5)プロットエリア内部の幅'
  With .Format.Line    '……(6)プロットエリアの枠線'
    .ForeColor.RGB = vbBlack    '……(7)枠線の色'
   .Weight = 1.5    '……(8)枠線の太さ'
  End With
End With

(4)、(5)でプロットエリアの大きさを決め、(6)で処理対象をプロットエリアの枠線に切り替えて(7)で枠線の色を黒に。

f:id:akashi_keirin:20180127221127j:plain

最後に(8)で枠線の太さを設定する。

f:id:akashi_keirin:20180127221139j:plain

(9)から(13)の

For i = 1 To .SeriesCollection.Count
  With .SeriesCollection(i).Format    '……(9)データ系列の書式'
    .Fill.ForeColor.RGB = vbBlack    '……(10)塗りつぶしの色'
    .Fill.BackColor.RGB = vbWhite
    .Fill.Patterned (i - 1) * 5 + 1    '……(11)塗りつぶしのパターン'
    .Line.Visible = msoTrue
    .Line.ForeColor.RGB = vbBlack    '……(12)枠線の色'
    .Line.Weight = 1    '……(13)枠線の太さ'
  End With
Next

では、Forループを使ってSeriesCollectionコレクションからそれぞれのSeriesオブジェクトにアクセスする。Seriesオブジェクトというのは、データ系列のことみたい。

1回目のループでは、グラフの中では「先行」のところ。山賀選手しか持っていないw

(9)でデータ系列の書式にアクセスし、(10)からの2行で前景色を黒、背景色を白に指定しているので、

f:id:akashi_keirin:20180127221200j:plain

まずはこうなる。

で、(11)で塗りつぶしのパターンを指定。Patternedメソッドに渡す引数の指定はテキトーです。この場合は「1」が渡ることになるので、「msoPattern5Percent」、すなわち「前景色5%」を指定することになる。

f:id:akashi_keirin:20180127221225j:plain

こうなる。

(12)では、枠線の色を黒に指定する。

f:id:akashi_keirin:20180127221245j:plain

こうなる。

あとは(13)で枠線の太さを「1」にする。

これをSeriesCollectionの要素数だけ繰り返すと、全ての系列について書式を変更することになる。

f:id:akashi_keirin:20180127221254j:plain

こんな感じ。

まとめ

オブジェクトブラウザーで調べたり、マクロ記録をしてみたりして上記のコードを作った。

その結果、グラフまわりのオブジェクト構造は、およそ

Worksheet
  ┗━[ChartObjects]ChartObject
        ┗━Chart┳[ChartGroups]ChartGroup
               ┣PlotArea━Format━Line
               ┗[SeriesCollection]Series━Format┳Fill
                                               ┗Line

こんな感じなんだろうな、ということが分かった。間違えているかも知れんけど。

まあ、そもそもグラフ自体をほぼやったことがなかったので、これからだんだん分かってくるかも知れない。