Traducir el blog

Rendimiento de las macros VBA

🔝To translate this blog post to your language, select it in the top left Google box.


Mientras diseño un mapa del mundo me he encontrado con la tarea de calcular la localización de cada país en el mapa mundial.

Cada vez que cambia el zoom o el scroll del mapa tengo que recalcular la posición de los países, por lo que el algoritmo de cálculo debe ser eficiente y con un rendimiento máximo para que ese cálculo no interfiera en el manejo del mapa.

Explicaré por qué utilizar una matriz para recopilar datos de las formas de lo países y escribir en la matriz en lugar de escribir directamente en un rango de celdas de la hoja de trabajo.

En estos artículos encontrarás más información de las matrices  (array) y de las formas (shapes):

Este consejo de optimización del código VBA permite mejorar el rendimiento, reduciendo el tiempo de ejecución entre 10 y 100 veces.

Este artículo en inglés es muy relevante:

Chip Pearson comenta que:

La transferencia de datos entre celdas de la hoja de cálculo y variables de VBA es una operación costosa en tiempo de ejecución, por lo que debe reducirse lo más posible. Puede aumentar considerablemente el rendimiento de su aplicación Excel pasando matrices de datos a la hoja de cálculo, y viceversa, en una sola operación en lugar de una celda cada vez. Si necesita realizar cálculos extensos sobre datos en VBA, debe transferir todos los valores de la hoja de trabajo a una matriz, hacer los cálculos en la matriz y luego escribir la matriz nuevamente en la hoja de trabajo. Esto mantiene al mínimo la cantidad de veces que se transfieren datos entre la hoja de trabajo y VBA. Es mucho más eficaz transferir en una única instrucción una matriz de 100 valores a la hoja de cálculo que transferir cada uno de los 100 elementos separadamente en una celda diferente.

Con esta técnica de cargar la matriz y escribirla en las celdas una sola vez, he conseguido tiempos de ejecución de menos de medio segundo, cuando un bucle para escribir separadamente en las celdas no baja de 60 segundos.


Como se aprende practicando, os dejo un ejemplo con las dos macros, la lenta y la rápida.


Cómo guardar las formas de los países en una tabla

El problema es que en la hoja 'Mapa' hay formas (shapes) de 240 países que hay que guardar en una tabla de la hoja 'Fronteras', para lo que hace falta una macro que escriba en la tabla algunas de las propiedades de las 240 formas, lo que se hace con un bucle de dos maneras diferentes.

Las propiedades de las formas se guardan en la tabla "TablaFronteras" en las 5 primeras columnas, el resto de columnas se calculan con fórmulas que hay que mantener.

Normalmente se programa la macro lenta si no se conoce la técnica de la macro rápida, que mejora el rendimiento al usar matrices (arrays). A continuación explicaré la diferencia principal entre estas dos macros.


Macro lenta

Se escribe cada celda dentro de un bucle a la vez que se leen las propiedades de cada una de las formas (shapes) de cada país del mapa. Este método es ineficiente pues consume mucho tiempo escribir celdas individualmente, pues las macros VBA y Excel son dos mundos separados y el interfaz de conexión entre ellos no está optimizado internamente.


Macro rápida

Con un bucle se escriben las propiedades de cada forma (shape) de los países en una matriz (array) bidimensional, que se copia en el rango de celdas de la tabla con una única instrucción, lo que mejora su rendimiento pues es el método más eficiente.

La única instrucción que copia la matriz en el rango está optimizada internamente para pasar valores entre VBA y la hoja de cálculo.


Vídeo para mejorar el rendimiento

En este vídeo explico cómo usar las dos macros y calcular su rendimiento.


Descarga el archivo con las macros

Descarga la versión 2.0 desde uno de estos enlaces:

Las macros del archivo descargado están bloqueadas por defecto. Para desbloquear las macros debes modificar las Propiedades del archivo siguiendo estas instrucciones:

Las macros de Internet están bloqueadas de forma predeterminada en Office - Deploy Office | Microsoft Learn

Abre el archivo y presiona el botón: Habilitar edición cuando aparezca el aviso de VISTA PROTEGIDA.

Presiona el botón: Habilitar contenido cuando aparezca la ADVERTENCIA DE SEGURIDAD Las macros se han deshabilitado o se deshabilitó parte del contenido activo.

Las hojas no están protegidas, y no está protegido el proyecto VBA, por lo que puedes estudiar y analizar el código de las macros.

ATENCIÓN: Se puede modificar este libro de Excel respetando esta licencia:

Creative Commons — Atribución-NoComercial-CompartirIgual 3.0 No portada — CC BY-NC-SA 3.0


Rendimiento y escalabilidad de las macros

Con el archivo descargado los tiempos de ejecución son mucho más rápidos que en el vídeo pues es un ejemplo reducido.

  • Macro lenta: >0,6 segundos
  • Macro rápida: <0,05 segundos

El rendimiento es de más de 1 a 10 con matrices.

Los tiempos en el vídeo son con el archivo que estoy diseñando ¡es el caso real!:

  • Macro lenta: >60 segundos
  • Macro rápida: <0,5 segundos

El rendimiento es de más de 1 a 100 con matrices.

La macro lenta se ejecuta en 0,6 segundos en un archivo reducido, pero ese tiempo es de 60 segundos en el archivo real del vídeo. El escalado empeora el tiempo en un factor de 100.

La macro rápida se ejecuta en 0,05 segundos en un archivo reducido, y en 0,5 segundos en el archivo real del vídeo. El escalado solo empeora el tiempo en un factor de 10, siendo razonables los 0,5 segundos que es mejor tiempo para la macro rápida que el mejor tiempo de la macro lenta en un archivo reducido.

A veces no tenemos en cuenta que el rendimiento de los algoritmos no optimizados empeora con el escalado de las aplicaciones.

Una macro que parece rápida y eficaz se vuelve lenta y torpe cuando las hojas de cálculo crecen, pues no están optimizadas para el escalado y el rendimiento óptimo, que hay que tener en cuenta desde la primera versión del algoritmo si no queremos encontrarnos sorpresas desagradables cuando el proyecto crezca.

Para la aplicación que estoy desarrollando de un Mapa del mundo es importante que funcione en todo tipo de máquinas, también en las lentas con versiones antiguas de Excel.

Los tiempos de la macro rápida en mi viejo portátil con Excel 2010 corriendo en Windows 7 son similares a los de mi nuevo portátil con Excel para Microsoft 365 en Windows 11. La macro lenta tiene un rendimiento un 100% inferior en el viejo portátil.


Actualización de las macros

En la versión 2.0 he incluido varias macros más de este hilo:

Me ayudaron desinteresadamente los grandes maestros Héctor Miguel y Macro Antonio a mejorar el rendimiento de las macros:

  • GuardarFronterasLento en el MóduloFronteras por Pedro Wave.
    • Mejor tiempo: 0,53 segundos.
    • En un bucle recorre cada forma (shape) y guarda sus propiedades en la tabla.
  • getShapesListInWorksheet en el MóduloHM por Héctor Miguel Orozco Díaz.
    • Mejor tiempo: 0,21 segundos.
    • La UDF getShapePropertie se copia en la tabla y se pegan sus valores.
    • No usa bucles, ya que son sustituidos por: With Worksheets("Fronteras").[A2].Resize(n) 
  • GuardarFronterasMA en el MóduloMA por Macro Antonio.
    • Mejor tiempo: 0,24 segundos.
    • Guarda en una matriz (array) las propiedades de las formas (shapes).
    • Redimensiona la matriz con todas las columnas de la tabla, incluidas las que tienen fórmulas.
    • Cambia el tamaño de la tabla y copia las fórmulas en las 4 columnas de la derecha.
    • Es lenta porque tiene que desproteger la hoja 'Fronteras' y volver a protegerla.
  • GuardarFronterasRápido en el MóduloFronteras por Pedro Wave.
    • Mejor tiempo: 0,03 segundos.
    • Guarda en una matriz (array) las propiedades de las formas (shapes).
    • Copia la matriz en la tabla con una sola instrucción.
  • GuardarFronteras en el MóduloFronteras por Macro Antonio.
    • Mejor tiempo: 0,01 segundos.
    • Guarda en una matriz (array) las propiedades de las formas (shapes).
    • Copia la matriz en la tabla con una sola instrucción.
    • La macro está muy optimizada para reducir al máximo el tiempo de ejecución.

Todas las adaptaciones y cambios de macros son de mi responsabilidad si, por alguna circunstancia que se me escapa, empeoraron su rendimiento.

Esta última macro es óptima pues mejora el rendimiento hasta 1.000 veces en el prototipo real de un mapa mundial que publicaré próximamente.

Pronto publicaré un mapa completo del mundo con todas las funciones y características que voy publicando estas últimas semanas aquí:

Puntero al mapa de África

🔝To translate this blog post to your language, select it in the top left Google box.


Cuando diseñé el Juego de mapas en Excel del artículo anterior, me quedé con las ganas de pasar el ratón por encima del mapa e ir viendo qué país estaba debajo del cursor, sin necesidad de hacer clic en el mapa con el botón izquierdo del ratón.

En esta imagen animada puedes comprobar que ya lo he conseguido, gracias a la ayuda recibida en este foro de Excel al que recomiendo que te registres (no cobro comisión):



Cuando descargues este mapa podrás estudiar los países de África pasando el "puntero" del ratón por encima del mapa.

🕸️ Aprenderás datos de los países africanos obtenidos con Power Query.

🐭 Dale con el ratón a la celda D4 y cambiarás el modo de visualización de los datos en el mapa:

🌍 En modo "globo" los datos siguen al "puntero".

🛩️ En modo "avión" el nombre del país sigue al "puntero".

🏚 En modo "casa" los datos no siguen al "puntero".

📌 En modo "chincheta" los datos están fijos y no se usa el "puntero".

🗣️ Dale a la cabeza parlante en la celda D5 para escuchar el nombre de los países.

♻️ Si algo no funciona reinicia el mapa dando a la celda E19, con lo que también se actualizarán los datos de África con Power Query y se maximizará el mapa mediante un zoom automático.


Puntero al mapa

He creado un "puntero" virtual que sigue al puntero del ratón en todos los movimientos sobre la hoja de cálculo 'Mapa'.

El "puntero" es un círculo pequeño creado desde la cinta de opciones: Insertar > Formas > Formas básicas > Elipse, a la que se le ha dado la misma altura que anchura de 0,2 cm para crear el círculo. A esta forma del "puntero" la denomino: F_Puntero 

Al "puntero" virtual le sigue, como un perrito faldero, una "imagen  dinámica" de un rango de celdas capturada con la cámara de Excel (información aquí), con lo que se consigue mostrar dinámicamente el contenido del rango de celdas en un "Objeto Volante Identificado - OVI", por lo que no se puede clasificar como OVNI. A esta "imagen dinámica" la denomino: F_País =$C$2:$C$5

En el rango C2:C5 debe estar el texto y la bandera.

Con el "texto dinámico" se muestra el nombre del país y opcionalmente su población actual, con un estilo de WordArt para que el texto destaque en el mapa. A este "texto dinámico" lo denomino: F_Texto

La "bandera" es una imagen dinámica capturada con la cámara de Excel. A esta "bandera" la denomino: F_Bandera =miBandera, que muestra la bandera de un país a partir de la columna I de la hoja 'Fronteras'.



ATENCIÓN: La imagen de arriba es de una versión anterior en la que esas dos formas estaban en la hoja 'Mapa'. En la nueva versión se han movido a la hoja 'Fronteras' el "texto dinámico" (F_Texto) y la "bandera dinámica" (F_Bandera), con el texto sin solapar con la bandera.

IMPORTANTE: El orden de las formas es muy importante para conseguir el efecto de capas de dibujo en el mapa, y que las formas (shapes) sean activadas adecuadamente.

El "puntero" (F_Puntero) debe estar al frente del resto de formas y así pasará por encima de las demás capas del mapa.

La "etiqueta" (F_Etiqueta_Mapa) es la segunda capa, situada en la esquina superior izquierda de la hoja, con lo que se obtienen las coordenadas X e Y en el mapa, escuchando el evento: F_Etiqueta_Mapa_MouseMove

La "imagen dinámica" (F_País) es la tercera capa.

Después de la imagen F_Copyright está ordenada cada "forma de país", intentado que los países pequeños estén por encima de los grandes, y así poder seleccionarlos con seguridad.


Países debajo del Puntero

Para identificar cada país he tenido que renombrar cada "forma de país", por ejemplo Zimbabue, detectando las fronteras de cada país. Es un paso importante que hay que hacer al menos una vez. Es tedioso pero es determinante para conseguir el objetivo del mapa, que es identificar el país que está debajo del "puntero" del ratón.

El cálculo de la distancia a la forma (shape) de un país al "puntero virtual" se hace con la fórmula de la columna "Distancia" de la tabla en la hoja 'Fronteras', solamente si el puntero está dentro de la forma rectangular.

En la imagen solamente aparece la Distancia del "puntero virtual" a Argelia porque es el país que más cerca está en el momento de la captura de la imagen de la hoja.

NOTA: Si hay varios países cerca, se calcula el valor mínimo de la Distancia.

Para detectar las fronteras de un país, el método del "puntero virtual" no es tan preciso como el puntero del ratón sobre una forma (shape), ya que Excel nativamente es capaz de detectar el contorno de la forma del país.

Con el cálculo de la Distancia empeora la precisión, pues es una forma rectangular en la que caben los contornos de otros países, y hasta sus aguas jurisdiccionales, por lo que al pasar el "puntero virtual" por los mares y océanos se puede llegar a detectar qué país es el más cercano...

Para obtener correctamente las coordenadas he incluido un Zoom automático, con el que se ve todo el continente de África. La macro: ZoomRangoMapa se ejecuta si el mapa es demasiado grande y se mueve el puntero por el mapa, o cuando el mapa es muy pequeño y se reinicia el mapa haciendo clic en la celda E19, con lo que se maximiza al tamaño de la hoja 'Mapa'.


Truco para alinear los punteros virtual y real

Cuando me propuse pasar el ratón por encima del mapa, el puntero del ratón se desviaba hacia la izquierda del "puntero virtual", aunque éste se veía centrado horizontalmente con el puntero del ratón. 🙀

Investigué en Google y no encontré nada. 😿

¡Hasta que se me ocurrió la solución! 😻

La desviación se producía porque en la etiqueta que permite escuchar eventos de movimiento del ratón, y que está por encima del mapa, llamada: F_Etiqueta_Mapa, la propiedad MousePointer valía: 0-fmMousePointerDefault

La lista de punteros de ratón está explicada aquí: VBA - MousePointer (propiedad)

El puntero del ratón por defecto es una flecha apuntando hacia arriba a la izquierda pero, cuando se pasa por encima del "puntero virtual" que tiene asignada la macro: ColorearPaís, el puntero es una mano con el dedo índice hacia arriba, como si fuera a hacer clic sobre el "puntero virtual".

Observa en la imagen de arriba ¡que la punta de la flecha y la punta del dedo índice no coinciden horizontalmente!

¡Son unos pocos pixeles pero suficientes para tocar la moral del apuntador! 😾

Aquí está el TRUCO: La solución era usar siempre el mismo puntero del ratón: ¡la mano! 👆

O sea, en F_Etiqueta_Mapa la propiedad MousePointer con valor: 3 - fmMousePointerIBeam

¡Y asunto resuelto! 👏👏👏

Ese valor del MousePointer es la misma mano que se usa para mostrar dónde está el cursor cuando se hace clic con el ratón en un objeto con macro asignada, por lo que ahora ya coinciden las coordenadas de la mano que se mueve por la etiqueta.

Y ahora, cuando saco a pasear al ratón,

¡me sigue como un perrito faldero! 🐕


Consultar datos de África con Power Query

En la hoja 'Datos' se cargan los datos de África, una vez transformados con Power Query.

Los datos de la capital del país; moneda; idioma; forma de gobierno, superficie, población y PIB per cápita se extraen con la consulta a dos páginas Web, la primera para obtener la población actual en tiempo real, y la segunda para obtener el resto de datos:

Poblacion de África 2023 (countrymeters.info)

Anexo:Países de África - Wikipedia, la enciclopedia libre

El problema principal con el que me he topado ha sido que los nombres de los países no son iguales en esas páginas, siendo peor en Wikipedia, pues detrás de los nombres hay caracteres ocultos, por lo que no se pueden combinar las dos consultas a no ser que los nombres sean iguales.

En la columna A de esta imagen Egipto tiene un LARGO de 8 con los caracteres ocultos, cuando su LARGO es 6.

Los caracteres sobrantes son: Unicode 8203 (hexadecimal: 200B) 

Es un espacio de ancho cero que mete la Wikipedia, ¿con qué motivo?

Este carácter Unicode detrás de los nombres de los países impedía combinar las dos consultas, una a la Wikipedia y otra a CountryMeters, pues no coinciden los nombres de los países con los espacios ocultos de ancho cero.

Este es el código para quitar ese carácter Unicode en el último PASO APLICADO a la consulta en Power Query: Datos África

Esto demuestra que los caracteres sin importancia son los que más guerra dan, pues son difíciles de limpiar. La limpieza proporcionada por defecto por Power Query no elimina ciertos caracteres Unicode.

En versiones antiguas de Excel el mapa funciona aunque no actualiza los datos si no está instalado el complemento de Power Query, que se puede descargar aquí:

Download Power Query from Official Microsoft Download Center


Videotutorial del mapa de África

Este videotutorial lo hice con una versión anterior, que aún no cargaba datos de los países con Power Query, pero creo que seguirá sirviendo para explicar su funcionamiento.

Selecciona los subtítulos en tu idioma para entender el vídeo.


Descarga el mapa de África

Este mapa ha sido probado en versiones de Excel 2010, 2016, 2021 y Excel para Microsoft 365. Si me das feedback con los bugs que encuentres, y que seguro que se me han escapado, igual mejora el mapa.

Descarga la versión 9.6 desde uno de estos enlaces:

Las macros del archivo descargado están bloqueadas por defecto. Para desbloquear las macros debes modificar las Propiedades del archivo siguiendo estas instrucciones:

Las macros de Internet están bloqueadas de forma predeterminada en Office - Deploy Office | Microsoft Learn

Abre el archivo y presiona el botón: Habilitar edición cuando aparezca el aviso de VISTA PROTEGIDA.

Presiona el botón: Habilitar contenido cuando aparezca la ADVERTENCIA DE SEGURIDAD Las macros se han deshabilitado o se deshabilitó parte del contenido activo.

Si aparece una ventana para elegir el tipo de acceso, selecciona el modo Anónimo.

Las hojas están protegidas sin contraseña y no está protegido el proyecto VBA, por lo que puedes estudiar y analizar el código de las macros.

AVISO: Si se desprotege la hoja 'Mapa' ¡no se debe volver a proteger manualmente!, ya que este mapa se ha diseñado pensando en protegerlo totalmente del usuario, sin estar protegido de las macros, con esta instrucción:

Sheets("Mapa").Protect DrawingObjects:=True, Contents:=True, Scenarios:=True, UserInterfaceOnly:=True

Este último parámetro, que protege la hoja únicamente del usuario, es imposible de poner si se protegen las hojas manualmente.

Se ha protegido el mapa así para que las imágenes (shapes) de los países no puedan ser modificadas ni movidas por el usuario final y tampoco puedan ser cambiadas las formas del "puntero virtual" ni las formas que comienzan por F_ (abreviatura de Formas).

ATENCIÓN: Se puede modificar este libro de Excel respetando esta licencia:

Creative Commons — Atribución-NoComercial-CompartirIgual 3.0 No portada — CC BY-NC-SA 3.0


Zoom al mapa de África

A partir de la versión 9.5 he introducido una interesante mejora para ver el detalle del mapa haciendo Zoom.

Con el zoom puedo aumentar el detalle del mapa y seguir pasando el "puntero" por encima de los países, sin necesidad de maximizar el mapa, y permitiendo el desplazamiento (scroll) horizontal y vertical del mapa.

Para hacer zoom en Excel con el ratón usa la rueda del ratón. Presiona la tecla Control mientras giras la rueda hacia adelante o hacia atrás para ampliar o disminuir el zoom respectivamente.


Pronto publicaré un mapa completo del mundo con todas las funciones y características que voy publicando estas últimas semanas aquí:

Mi lista de blogs