【VBAでグラフ作成】ChartオブジェクトとChartObjectオブジェクトの違いを解説

VBAでエクセル作業を自動化していると、時々グラフも一緒に作成してしまいたいケースもあるかと思います。

初めてのときは色々と調べながらコーディングすると思うのですが、グラフについてはあまり良い解説記事が見つかりません。

また、私としては
非推奨のコーディング
を紹介している記事が大半です。
※最後にいまいちな例として紹介します。

VBAでグラフ作成するときは、

  • ChartObjectオブジェクト
  • Chartオブジェクト

という紛らわしい2つのオブジェクトがあり、理解を妨げてきます。

この2つの違いの解説を交えながら、スマートな記述方法を紹介したいと思います。

ChartObjectオブジェクトとChartオブジェクトの関係性

いきなり見本コードから始めると混乱の元となるため、最初に2つのオブジェクトの関係性を紹介します。

埋め込みグラフを作成した場合、

  1. まずWorksheetオブジェクトがあり、
  2. その下にChartObjectオブジェクトがあり、
  3. その下にChartオブジェクトがあります。

理解の妨げになるのは、このChartObjectオブジェクトです。
このChartObjectオブジェクトって一体なんやねん!?って話です。

f:id:hamahiro881477:20200812174550p:image

このChartObjectオブジェクトはコンテナ(箱)と覚えてください。

Worksheetの中に、いきなりグラフ(Chartオブジェクト)を入れることができないので、一旦コンテナ(箱)を作るのです。

実際このようなプログラムを書いて実行すると、白い枠ができます。

Sub Container()
   Dim ChartObj As ChartObject 'ChartObjectオブジェクト
   'コンテナのSet
   Set ChartObj = ActiveSheet.ChartObjects.Add(120, 10, 400, 200)
End Sub
f:id:hamahiro881477:20200812195127j:plain

この白い枠がChartObjectオブジェクトの正体です。

このChartObjectオブジェクトに対して、Chartオブジェクトをセットすると、白い枠の中にグラフが描かれます。
なお、ChartObjectオブジェクトは枠のため、枠の位置や大きさを指定できます。

推奨コーディング

私が推奨するコーディングを紹介します。

f:id:hamahiro881477:20200812181436j:plain

私の推奨するコーディングでは、
①ChartObjectオブジェクトをセットし、
②Chartオブジェクトをセットします。

Sub MakeGraphOne()
   Dim ChartObj As ChartObject 'ChartObjectオブジェクト
   Dim ChartOne As Chart 'Chartオブジェクト

   'コンテナのSet
   Set ChartObj = ActiveSheet.ChartObjects.Add(120, 10, 400, 200) '左位置, 上位置, 幅, 高さ
   'コンテナ内のChartをSet
   Set ChartOne = ChartObj.Chart

   'Chartのプロパティを指定
   With ChartOne
      .SetSourceData Source:=Cells(2, 1).Resize(5, 2) 'グラフの参照データを指定
      .ChartType =xlColumnClustered 'グラフの種類の指定
      .HasTitle = True 'グラフタイトル有
      .ChartTitle.Text = "テスト" 'グラフタイトルの指定
   End With
End Sub
  1. Set ChartObj=…の部分でコンテナを作成し、
  2. Set ChartOne = ChartObj.Chartで作成したコンテナに対してグラフを作成します。

あとは、Chartオブジェクト(ChartOne)に各種プロパティを設定して、グラフの形式を自由に変更しています。

f:id:hamahiro881477:20200812195143j:plain

実行すると、上図のような縦棒グラフが作成されます。

コンテナ(箱)の位置指定

コンテナの説明で、「ChartObjectオブジェクトは枠のため、枠の位置や大きさを指定できます」と書きました。
ここまでの見本コードではコンテナの位置を数値で書きましたが、これをセルの位置で指定することもできます。
例えば、C1セル~I10セルの範囲を指定すると、下図のようにグラフの位置がセルの位置とピッタリ一致します。 

f:id:hamahiro881477:20200812195154j:plain

セルで指定するための、見本コードは次のようになります。

Sub MakeGraphTwo()
   Dim ChartObj As ChartObject
   Dim ChartOne As Chart
   Dim RngGraph As Range

   'コンテナ用のRangeをSet
   Set RngGraph = Cells(1, 3).Resize(10, 7)

   'コンテナのSet
   Set ChartObj = ActiveSheet.ChartObjects.Add(RngGraph.Left, RngGraph.Top, RngGraph.Width, RngGraph.Height) 'RngGraphの位置を指定

   'コンテナ内のChartをSet
   Set ChartOne = ChartObj.Chart

   'Chartのプロパティを指定
   With ChartOne
      .SetSourceData Source:=Cells(2, 1).Resize(5, 2) 'グラフの参照データを指定
      .ChartType = xlColumnClustered 'グラフの種類の指定
      .HasTitle = True 'グラフタイトル有
      .ChartTitle.Text = "テスト" 'グラフタイトルの指定
   End With
End Sub

ポイントはRngGraphというRangeオブジェクトを使用している点です。
RangeオブジェクトのLeft、Top、Width、Heightを使用することで、グラフを張り付けたい範囲の位置情報を取得しています。
そして、その情報をコンテナをセットするときに使うことで、セルとピッタリ一致した位置に埋め込みグラフを作成しています。

複数グラフ作成

先ほどのコンテナの位置指定が真価を発揮するのは、複数のグラフを一度に作成するときです。

やってみるとわかるのですが、位置を指定せずにグラフを複数作成すると、同じ場所にグラフが重なって作成されてしまいます。
位置を指定するRangeオブジェクトを変数を用いてずらすことで、複数のグラフを重ならないで表示することができます。

f:id:hamahiro881477:20200812195209j:plain
Sub MakeGraphThree()
   Dim ChartObj As ChartObject
   Dim ChartOne As Chart
   Dim RngGraph As Range
   Dim intI As Integer

   For intI = 1 To 2
      'コンテナ用のRangeをSet
      Set RngGraph = Cells(intI * 10 - 9, 3).Resize(10, 7)

      'コンテナのSet
      Set ChartObj = ActiveSheet.ChartObjects.Add(RngGraph.Left, RngGraph.Top, RngGraph.Width, RngGraph.Height) 'RngGraphの位置を指定

      'コンテナ内のChartをSet
      Set ChartOne = ChartObj.Chart

      'Chartのプロパティを指定
      With ChartOne
         .SetSourceData Source:=Cells(intI * 5 - 3, 1).Resize(5, 2) 'グラフの参照データを指定
         .ChartType = xlColumnClustered 'グラフの種類の指定
         .HasTitle = True 'グラフタイトル有
         .ChartTitle.Text = "テスト" 'グラフタイトルの指定
      End With
   Next intI
End Sub

RngGraphの範囲と、SetSoureDataの範囲にintIを入れることで複数のグラフを同時に作成できるように変更しています。

非推奨コーディング

 反対に私が非推奨としているコーディング方法を紹介します。

f:id:hamahiro881477:20200812190025j:plain

非推奨するコーディングでは、
①Chartオブジェクトを作り、
②ChartObjectオブジェクトのプロパティを指定します。

Sub BadExample()
   'いきなりChartオブジェクトを作成(AddChart)
   With ActiveSheet.Shapes.AddChart.Chart
      .SetSourceData Source:=Cells(2, 1).Resize(5, 2)
      .ChartType = xlColumnClustered
   End With

   'インデックス1のコンテナを指定
   With ActiveSheet.ChartObjects(1) '複数のグラフを作るときはインデックスを増やさないといけない
      'コンテナの位置指定s
      .Left = 120
      .Top = 0
      .Width = 400
      .Height = 200
   End With
End Sub

このやり方ではAddChartメソッドを使用してオブジェクトを作成し、そのChartプロパティを取得しています。

そして、グラフの位置とサイズを指定するために、ChartObjects(1)を取得して位置指定しています。

グラフの作成自体はできるのですが、1つ問題点があります。
それは、元々シート上にグラフがあるとインデックスがずれることです。

見本コードではChartObjectオブジェクトのインデックス1を指定して、グラフの位置とサイズを指定しています。

元々シート上にグラフがなければ問題ないのですが、もしグラフがあるとインデックス1は元々存在するグラフとなってしまいます。
そのため、目的と異なるグラフの位置を変更してしまいます。

この問題があるため、一度コンテナをセットしてからChartオブジェクトをセットするやり方をお勧めします。

最後に

今回はわかりにくいオブジェクトに絞って解説しましたが、グラフのプロパティについてもっと知りたいことがあればコメントしてください。

他の「VBA」の記事はこちらからどうぞ