TL;DR — チャートはデータを保存しません — Range への参照 を保存します。各系列の
.Valuesは=Sheet1!$B$2:$B$13のような数式なので、チャートはその参照と同じだけしか正しくなりえません。埋め込み チャートはws.ChartObjects.Add(left, top, width, height)で作り、その.Chartを取得し、.ChartTypeを設定し、.SetSourceData Source:=Range(...)で一度にデータを結び付けます。噛みついてくるのは 2 つ: 埋め込みチャートはChartObjectsに住みます(Chartsではありません。あちらはチャートシートです)。 そして、先に古いものを削除しない限り、マクロの再実行は重複したチャートを積み上げます。
Dim co As ChartObject, ch As Chart
Set co = Worksheets("Report").ChartObjects.Add( _
Left:=300, Top:=20, Width:=420, Height:=260)
Set ch = co.Chart ' ChartObject は枠、.Chart がチャート本体
ch.ChartType = xlColumnClustered
ch.SetSourceData Source:=Worksheets("Data").Range("A1:B13") ' 範囲全体を一度に結び付ける
ch.HasTitle = True
ch.ChartTitle.Text = "Monthly Sales"
VBA でのチャート作りは簡単そうに見えます — 2 回目の実行でチャートが 2 つ見つかるまで、あるいは 1 回目の実行で棒が間違った列を描くまでは。どちらも同じ誤解から来ていて、どちらの直し方も同じ考えです。チャートはあなたのデータを含んでいるのではなく、それを指しているのです。 どの系列も、数式として書かれた範囲への 参照 を持っています。データを動かし、行を挿入し、別の場所で元データを作り直しても、チャートは命じられた場所を指し続け、間違ったセルを忠実に描きます。「チャートは Range に結び付いた 1 つのビューだ」と握った瞬間、API は面倒であることをやめ、2 つの古典的なバグは自明になります。
この記事で学べること
- 考え方の軸 — チャートはデータのコピーではなく、Range への参照を持つ
- 2 つの入れ物:埋め込みの
ChartObjectsと、Chartsの中のチャートシート SetSourceDataで一度にチャートを作ってデータを結び付けるSeriesCollectionで手作業で系列を追加・制御する- 再実行での重複チャートの罠と、古いチャートの消し方
- チャートがデータを追いかけるよう、元データを Table に結び付ける
考え方の軸:チャートは Range を指す
範囲をチャートにするとき、Excel は数値をチャートにコピーしません。系列ごとに、その範囲を参照する数式 を保存します — セルの数式が他のセルを参照するのとまったく同じです。それは読み戻せます。
Debug.Print ch.SeriesCollection(1).Formula
' =SERIES("Sales",Data!$A$2:$A$13,Data!$B$2:$B$13,1)
この SERIES(...) 数式が、チャートについてのすべての真実です。名前、X 値への参照、Y 値への参照です。チャートは、それらの参照に対する 1 つのライブビューです。だからこそ「チャートが間違ったデータを表示する」がこれほどよくあるのです — チャートが間違っているのではなく、その参照が、あなたの思うものをもう持っていないセルを指しているのです。そしてこれが、本記事の最後で扱う恒久的な直し方が、$B$2:$B$13 で凍りつく代わりに参照にデータを追いかけさせることである理由です。
2 つの入れ物:ChartObjects とチャートシート
Excel にはチャートの住まいが 2 つあり、それらを取り違えることが、チャートのマクロを最初につまずかせます。埋め込み チャートはワークシート上に浮かび、そのシートの ChartObjects コレクションに住みます。チャートシート はチャートだけからなる 1 枚のタブで、ブックの Charts コレクションに住みます。
' 埋め込み:ChartObject は枠/入れ物、その .Chart がチャート本体
Dim co As ChartObject
Set co = Worksheets("Report").ChartObjects.Add(300, 20, 420, 260)
co.Chart.ChartType = xlLine ' プロパティは co ではなく .Chart に設定する
' チャートシート:それ自体が 1 枚のタブ
Dim ch As Chart
Set ch = ThisWorkbook.Charts.Add
人に 1 時間を払わせる微妙な点はこれです。埋め込みチャートでは、ChartObjects.Add が 枠(ChartObject)を渡し、実際に書式を設定するチャートは co.Chart です。チャートが埋め込みなのに Charts(1) に手を伸ばすとエラーになります。Charts はチャートシートしか持たないからです。ほとんどのレポートはワークシート上にあるので、ChartObjects のほうをずっと多く使うことになります — 枠とチャートという 2 層の区別だけ、覚えておきましょう。
SetSourceData で一度にチャートを作ってデータを結び付ける
きれいなやり方はこうです。枠を追加し、.Chart を取得し、種類を設定し、SetSourceData で元データ全体を 1 回の呼び出しで結び付ける。
Dim co As ChartObject, ch As Chart
Set co = Worksheets("Report").ChartObjects.Add(300, 20, 420, 260)
Set ch = co.Chart
ch.ChartType = xlColumnClustered
ch.SetSourceData Source:=Worksheets("Data").Range("A1:B13")
SetSourceData は、ブロック全体 — 見出し・分類項目・値 — を Excel に手渡し、系列を割り出させます。範囲を選んでチャートのボタンを押すのと、まさに同じです。これはほぼつねに望みどおりの動作で、系列を 1 つずつ組み立てるより行数もミスも少なくなります。範囲に見出し行と分類項目の列を含めれば、チャートは自分でラベルを付けます。.ChartType は前でも後でも設定できます — よく使う値は xlColumnClustered、xlLine、xlPie、xlXYScatter です。
SeriesCollection で手作業で系列を追加・制御する
精密な制御が要るとき — 一度に 1 系列、連続しない場所からの値、独自の名前 — は、SeriesCollection を通して系列を追加します。
Dim s As Series
Set s = ch.SeriesCollection.NewSeries
s.Name = "2026"
s.XValues = Worksheets("Data").Range("A2:A13")
s.Values = Worksheets("Data").Range("B2:B13")
どの系列も、あの SERIES(...) 数式にそのまま対応する 3 つの部分を持ちます。.Name、.XValues(分類項目のラベル)、.Values(数値)です。2 つ目の系列はもう一度 NewSeries で追加し、削除は ch.SeriesCollection(2).Delete です。.Values に範囲を設定することは、系列の数式に参照を書き込むことと同じです — これが間違ったデータのバグの背後にある仕組みであり、安定した元データに結び付けることが効いてくる理由です。
重複チャートの罠と、古いチャートの消去
12 回実行すると 12 個のチャートを生むバグがこれです。ChartObjects.Add は つねに新しいものを 1 つ追加します。前回のチャートを再利用することは決してないので、無人のマクロは黙ってコピーを積み上げます。作る前に、シートの既存のチャートを消しましょう。
Dim co As ChartObject
For Each co In Worksheets("Report").ChartObjects
co.Delete ' 先に前回のチャートを削除する
Next co
' ...これで新しいチャートを作る
ChartObjects をループして 1 つずつ Delete し、きれいな状態からチャートを作ります — 繰り返しの作成すべてに使うのと同じ コレクション の規律です。特定の 1 つのチャートを残して更新したいなら、名前を付け(co.Name = "chtSales")、次の実行でその名前で引き、新しい枠を追加する代わりに SetSourceData をもう一度呼びます。どちらにせよ、意図して決めましょう。新しく作るのか、その場で更新するのか — 何も考えずに追加してはいけません。
チャートがデータを追いかけるよう、元データを Table に結び付ける
さて、間違ったデータのバグへの恒久的な直し方です。系列は参照なので、A1:B13 に結び付いたチャートは 13 行で凍りつきます — 月を 1 つ追加すると、新しい点はチャートの外です。代わりに元データを Table に結び付ければ、参照はデータとともに伸びます。
' チャートの元データは Table の範囲 -> 新しい行が自動的に現れる
ch.SetSourceData Source:=Worksheets("Data").ListObjects("tblSales").Range
元データが ListObject のとき、行を追加すると Table が伸び、Table は系列が参照する範囲を伸ばし、チャートは新しい点とともに描き直されます — コードも、SetSourceData のやり直しも要りません。これは ピボット を最新に保つのと同じ一手であり、Table がまず作る価値のある土台である理由です。ピボットとチャートを一度そこに向ければ、両方が自己更新します。チャートを画像として渡すには、co.Chart.Export "C:\Reports\sales.png" がディスクに直接 PNG を書き出します。
ExcelMaster の活用
完成したレポートまで届いてしまうチャートのミスは、静かなものです。誰も削除しなかった 2 つ目のチャート、前四半期の範囲をまだ指している系列、SetSourceData がずれたブロックを受け取ったせいで間違った列を描く棒。どれもきれいに描画されます — ただ、間違った絵を見せるだけです。
ExcelMaster は、その 3 つすべてに痛い目を見た人のようにチャートを作ります。「月次の売上を地域別にチャートにして」と頼めば、描く前に古い ChartObjects を消し、新しい行が自ら現れるよう元データを Table に結び付け、系列を手配線する代わりに SetSourceData でブロック全体を使い、枠とチャートの区別につまずくのではなく co.Chart を通して書式を設定します。あなたはほしい絵を説明するだけ。データが伸びてもチャートが真実を語り続けるよう参照を配線するのは、それがやります。
よくある質問
VBA でチャートを作成するには?
埋め込みチャートを ChartObjects.Add で追加し、その種類とデータを .Chart を通して設定します。Set co = ws.ChartObjects.Add(300, 20, 420, 260)、Set ch = co.Chart、ch.ChartType = xlColumnClustered、ch.SetSourceData Source:=Range("A1:B13") です。ChartObject が枠で、その .Chart が書式を設定するチャートです。SetSourceData は範囲全体を 1 回の呼び出しで結び付けます。
VBA のチャートが間違ったデータを描画するのはなぜ?
チャートは範囲のコピーではなく、範囲への参照を持つからです — 各系列の .Values は =Sheet1!$B$2:$B$13 のような数式です。データが動いたり、行が挿入されたり、元データが別の場所で作り直されたりすると、参照はまだ古いセルを指し、チャートはそれを描きます。SetSourceData で結び付け直すか、参照がデータを追いかけるよう元データを Table に向けましょう。
VBA の ChartObjects と Charts の違いは?
ChartObjects は、シート上に浮かぶ 埋め込み チャートの、ワークシートのコレクションです。各 ChartObject は枠で、その .Chart が実際のチャートです。Charts は チャートシート の、ブックのコレクションです — チャートだけからなるタブです。チャートが埋め込みなのに Charts(1) に手を伸ばすとエラーになります。代わりに ws.ChartObjects(1).Chart を使いましょう。
VBA でチャートに系列を追加するには?
SeriesCollection.NewSeries を使い、その各部を設定します。Set s = ch.SeriesCollection.NewSeries、s.Name = "2026"、s.XValues = Range("A2:A13")、s.Values = Range("B2:B13") です。さらに追加するにはもう一度 NewSeries、削除は ch.SeriesCollection(2).Delete です。単純なチャートなら、範囲全体への SetSourceData のほうが、手作業で系列を追加するより簡単です。
VBA で重複したチャートが作られるのを止めるには?
ChartObjects.Add はつねに新しいチャートを追加するので、マクロを再実行するとコピーが積み上がります。作る前に、既存のものを削除します。For Each co In ws.ChartObjects: co.Delete: Next co です。特定のチャートを残して更新したいなら、名前を付け(co.Name = "chtSales")、次の実行でその名前で見つけ、新しい枠を追加する代わりに SetSourceData をもう一度呼びます。
検証環境
検証環境: Excel 365 (Windows 11), VBA 7.1 — 最終確認 2026-09-02.
関連ガイド: VBA Pivot Table · VBA Table · VBA Range · VBA Collection · VBA Worksheet
