🚀The world's best VBA AI has evolved. ExcelMaster is now an autonomous Agent.Read more →
Back to Blog

VBA Chart en Excel — crea un gráfico en código y por qué dibuja los datos equivocados

|

VBA Chart en Excel — crea un gráfico en código y por qué dibuja los datos equivocados

TL;DR — Un gráfico no guarda datos — guarda una referencia a un Range. El .Values de cada serie es una fórmula del tipo =Sheet1!$B$2:$B$13, así que el gráfico es solo tan correcto como esa referencia. Crea un gráfico incrustado con ws.ChartObjects.Add(left, top, width, height), coge su .Chart, fija .ChartType, y enlaza los datos de una sola vez con .SetSourceData Source:=Range(...). Las dos cosas que muerden: los gráficos incrustados viven en ChartObjects (no en Charts, que son hojas de gráfico), y reejecutar la macro apila gráficos duplicados a menos que borres antes los viejos.

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                                   ' el ChartObject es el marco; .Chart es el grafico
ch.ChartType = xlColumnClustered
ch.SetSourceData Source:=Worksheets("Data").Range("A1:B13")   ' enlaza todo el rango de una vez
ch.HasTitle = True
ch.ChartTitle.Text = "Monthly Sales"

Hacer gráficos en VBA parece fácil hasta la segunda ejecución, cuando te encuentras dos gráficos, o la primera, cuando las barras dibujan la columna equivocada. Las dos cosas vienen del mismo malentendido, y la solución para ambas es la misma idea: un gráfico no contiene tus datos — apunta a ellos. Cada serie guarda una referencia a un rango, escrita como una fórmula. Mueve los datos, inserta una fila, reconstruye el origen en otro sitio, y el gráfico sigue apuntando adonde se le dijo, dibujando fielmente las celdas equivocadas. En cuanto retienes «un gráfico es una vista ligada a un Range», la API deja de ser engorrosa y los dos bugs clásicos se vuelven obvios.

Lo que aprenderás

  • El modelo mental — un gráfico guarda una referencia a un Range, no una copia de los datos
  • Los dos contenedores: los ChartObjects incrustados frente a las hojas de gráfico en Charts
  • Crear un gráfico y enlazar los datos de una sola vez con SetSourceData
  • Añadir y controlar series a mano con SeriesCollection
  • La trampa del gráfico duplicado al reejecutar, y cómo limpiar los gráficos viejos
  • Enlazar el origen a una Table para que el gráfico siga a los datos

El modelo mental: un gráfico apunta a un Range

Cuando haces un gráfico de un rango, Excel no copia los números dentro del gráfico. Almacena, para cada serie, una fórmula que referencia el rango — igual que una fórmula de celda referencia otras celdas. Puedes leerla de vuelta:

Debug.Print ch.SeriesCollection(1).Formula
' =SERIES("Sales",Data!$A$2:$A$13,Data!$B$2:$B$13,1)

Esa fórmula SERIES(...) es toda la verdad sobre el gráfico: un nombre, una referencia de valores X, una referencia de valores Y. El gráfico es una vista viva sobre esas referencias. Por eso «mi gráfico muestra los datos equivocados» es tan común — el gráfico no está mal, su referencia está apuntando a celdas que ya no contienen lo que crees. Y por eso la solución duradera, al final de esta guía, es hacer que la referencia siga a los datos en lugar de congelarse en $B$2:$B$13.

Los dos contenedores: ChartObjects frente a hojas de gráfico

Excel tiene dos hogares para los gráficos, y confundirlos es lo primero que hace tropezar a una macro de gráficos. Un gráfico incrustado flota sobre una hoja y vive en la colección ChartObjects de esa hoja; una hoja de gráfico es una pestaña entera que no es más que un gráfico, y vive en la colección Charts del libro:

' Incrustado: un ChartObject es el marco/contenedor; su .Chart es el grafico en si
Dim co As ChartObject
Set co = Worksheets("Report").ChartObjects.Add(300, 20, 420, 260)
co.Chart.ChartType = xlLine        ' fija propiedades en .Chart, no en co

' Hoja de grafico: una pestana propia
Dim ch As Chart
Set ch = ThisWorkbook.Charts.Add

La sutileza que le cuesta una hora a la gente: con un gráfico incrustado, ChartObjects.Add te da el marco (un ChartObject), y el gráfico que de verdad das formato es co.Chart. Echar mano de Charts(1) cuando tu gráfico está incrustado lanza un error, porque Charts solo contiene hojas de gráfico. La mayoría de los informes viven en una hoja de cálculo, así que usarás ChartObjects mucho más a menudo — solo recuerda la división en dos capas marco/gráfico.

Crear un gráfico y enlazar los datos de una sola vez

El patrón limpio es: añade el marco, coge .Chart, fija el tipo, y enlaza todo el origen con SetSourceData en una sola llamada:

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 le entrega a Excel el bloque entero — encabezados, categorías y valores — y lo deja calcular las series, exactamente igual que seleccionar el rango y pulsar el botón de gráfico. Esto es casi siempre lo que quieres; son menos líneas y menos errores que construir las series de una en una. Incluye la fila de encabezado y la columna de categorías en el rango y el gráfico se etiqueta solo. Fija .ChartType antes o después — valores comunes son xlColumnClustered, xlLine, xlPie y xlXYScatter.

Añadir y controlar series a mano

Cuando necesitas control preciso — una serie a la vez, valores de un sitio no contiguo, un nombre personalizado — añade series a través de 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")

Cada serie tiene tres partes que se corresponden directamente con esa fórmula SERIES(...): .Name, .XValues (las etiquetas de categoría) y .Values (los números). Añade una segunda serie con otro NewSeries; quita una con ch.SeriesCollection(2).Delete. Fijar .Values a un rango es lo mismo que escribir la referencia dentro de la fórmula de la serie — que es el mecanismo detrás del bug de los datos equivocados, y la razón de que importe enlazar a un origen estable.

La trampa del gráfico duplicado, y limpiar los gráficos viejos

Aquí está el bug que produce doce gráficos tras doce ejecuciones: ChartObjects.Add siempre añade uno nuevo. Nunca reutiliza el gráfico de la última vez, así que una macro sin vigilancia apila copias en silencio. Limpia los gráficos existentes de la hoja antes de construir:

Dim co As ChartObject
For Each co In Worksheets("Report").ChartObjects
    co.Delete                          ' quita antes los graficos de la ejecucion anterior
Next co
' ...ahora construye el grafico nuevo

Recorre ChartObjects y haz Delete a cada uno, y luego crea tu gráfico desde cero — la misma disciplina de colección que usarías para cualquier construcción repetida. Si prefieres conservar y actualizar un gráfico concreto, ponle nombre (co.Name = "chtSales"), búscalo por ese nombre en la siguiente ejecución, y vuelve a llamar a SetSourceData en lugar de añadir un marco nuevo. Sea como sea, decide a conciencia: construir de cero o actualizar en el sitio, nunca añadir a ciegas.

Enlazar el origen a una Table para que el gráfico siga a los datos

Ahora la solución duradera para el bug de los datos equivocados. Como una serie es una referencia, un gráfico enlazado a A1:B13 se congela en trece filas — añade un mes y el punto nuevo queda fuera del gráfico. Enlaza el origen a una Table en su lugar, y la referencia crece con los datos:

' El origen del grafico es el rango de una Table -> las filas nuevas aparecen solas
ch.SetSourceData Source:=Worksheets("Data").ListObjects("tblSales").Range

Cuando el origen es un ListObject, añadir una fila extiende la Table, la Table extiende el rango que referencia la serie, y el gráfico se redibuja con el punto nuevo — sin código, sin volver a llamar a SetSourceData. Este es el mismo movimiento que mantiene al día una tabla dinámica, y es por lo que una Table es el cimiento que vale la pena construir primero: apunta tus tablas dinámicas y gráficos a ella una vez y ambos se autoactualizan. Para entregar un gráfico como imagen, co.Chart.Export "C:\Reports\sales.png" escribe un PNG directamente en disco.

Cómo ayuda ExcelMaster

Los errores de gráficos que llegan a un informe terminado son silenciosos: el segundo gráfico que nadie borró, la serie que aún apunta al rango del trimestre pasado, las barras que dibujan la columna equivocada porque SetSourceData recibió un bloque que se había desplazado. Cada uno se dibuja limpiamente — solo que muestra la imagen equivocada.

ExcelMaster construye gráficos como alguien al que los tres le han quemado ya. Pídele «haz un gráfico de las ventas mensuales por región», y limpia los ChartObjects viejos antes de dibujar, enlaza el origen a una Table para que las filas nuevas aparezcan solas, usa SetSourceData para el bloque entero en lugar de cablear las series a mano, y da formato a través de co.Chart en lugar de tropezar con la división marco/gráfico. Tú describes la imagen que quieres; él conecta la referencia para que el gráfico siga diciendo la verdad a medida que los datos crecen.

Preguntas frecuentes

¿Cómo creo un gráfico en VBA?

Añade un gráfico incrustado con ChartObjects.Add, y luego fija su tipo y sus datos a través de .Chart: Set co = ws.ChartObjects.Add(300, 20, 420, 260), Set ch = co.Chart, ch.ChartType = xlColumnClustered, ch.SetSourceData Source:=Range("A1:B13"). El ChartObject es el marco y su .Chart es el gráfico al que das formato. SetSourceData enlaza todo el rango en una sola llamada.

¿Por qué mi gráfico de VBA dibuja los datos equivocados?

Porque un gráfico guarda una referencia a un rango, no una copia de él — el .Values de cada serie es una fórmula del tipo =Sheet1!$B$2:$B$13. Si los datos se mueven, se insertan filas, o el origen se reconstruye en otro sitio, la referencia sigue apuntando a las celdas viejas y el gráfico las dibuja. Vuelve a enlazar con SetSourceData, o apunta el origen a una Table para que la referencia siga a los datos.

¿Cuál es la diferencia entre ChartObjects y Charts en VBA?

ChartObjects es la colección de gráficos incrustados de una hoja que flotan sobre ella; cada ChartObject es un marco cuyo .Chart es el gráfico de verdad. Charts es la colección de hojas de gráfico del libro — pestañas que no son más que un gráfico. Echar mano de Charts(1) cuando tu gráfico está incrustado lanza un error; usa ws.ChartObjects(1).Chart en su lugar.

¿Cómo añado una serie a un gráfico en VBA?

Usa SeriesCollection.NewSeries, y luego fija sus partes: Set s = ch.SeriesCollection.NewSeries, s.Name = "2026", s.XValues = Range("A2:A13"), s.Values = Range("B2:B13"). Añade más con otro NewSeries; quita una con ch.SeriesCollection(2).Delete. Para un gráfico sencillo, SetSourceData sobre todo el rango es más fácil que añadir series a mano.

¿Cómo evito que VBA cree gráficos duplicados?

ChartObjects.Add siempre añade un gráfico nuevo, así que reejecutar una macro apila copias. Antes de construir, borra los existentes: For Each co In ws.ChartObjects: co.Delete: Next co. Si quieres conservar y refrescar un gráfico concreto, ponle nombre (co.Name = "chtSales"), búscalo por ese nombre en la siguiente ejecución, y vuelve a llamar a SetSourceData en lugar de añadir un marco nuevo.

Probado en

Probado en: Excel 365 (Windows 11), VBA 7.1 — última verificación el 02/09/2026.

Guías relacionadas: VBA Pivot Table · VBA Table · VBA Range · VBA Collection · VBA Worksheet