Este contenido fue traducido mediante IA y no ha sido revisado por un editor humano. Las imágenes y los gráficos permanecen en su idioma original.
Puntos clave
- Punto clave 1. Las funciones DAX definidas por el usuario (o UDF de DAX) son una buena forma de centralizar la lógica de los Cálculos Visuales, manteniéndola en el modelo.
- Punto clave 2. Las funciones DAX específicas de los Cálculos Visuales se pueden usar dentro de las UDF de DAX y funcionarán si se llaman desde Cálculos Visuales.
- Punto clave 3. El tipo del parámetro ‘passing mode’ es importante si usas tus parámetros dentro de expresiones que modifican el Contexto Visual de evaluación.
Este resumen lo ha elaborado el autor, no una IA.
UDF de DAX para reutilizar Cálculos Visuales
Las funciones DAX definidas por el usuario (UDF de DAX) junto con los Cálculos Visuales han sido dos nuevas características recientes e importantes para quienes trabajan con DAX. Los Cálculos Visuales llegaron primero y una de las desventajas más señaladas era que se definían en cada Visual y, por tanto, no era posible reutilizar la lógica entre Visuales o Report diferentes. Las UDF de DAX se presentaron en versión preliminar pública en septiembre de 2025 y permiten encapsular lógica DAX, incluido DAX que solo puede usarse en Cálculos Visuales. Por tanto, ahora es posible centralizar la lógica de los Cálculos Visuales en las UDF de DAX.
En este artículo, mostraremos cómo resolver un caso de uso con Cálculos Visuales y, después, cómo trasladar esa lógica a las UDF de DAX para poder reutilizarla en otros Visuales. En general, es un proceso bastante sencillo, pero como suele ocurrir, hay algunos detalles que debes tener en cuenta.
Configuración del eje: haz que la línea de un gráfico combinado siempre quede por encima de las columnas
Hay casos en los que queremos ajustar los valores máximo y mínimo del eje para que el gráfico sea más fácil de entender. En la mayoría de los casos, no se pueden codificar los valores de forma fija porque necesitamos que sean dinámicos. Desde hace tiempo, es posible vincular el valor a una medida. Sin embargo, puede que no queramos crear medidas “de usar y tirar” que no aportan valor analítico en nuestro modelo semántico. Aquí es donde los Cálculos Visuales brillan. Para este tipo de cálculos, todos los datos que necesitamos ya están en el Visual y el DAX es mucho más sencillo, porque no necesitamos considerar el contexto de filtro sombra y factores similares.
Al vincular los valores máximo y mínimo del eje a Cálculos Visuales, queremos conseguir lo siguiente:

El primer detalle importante que debes tener en cuenta es que, para el eje o los títulos, cuando se vinculan a un Cálculo Visual, el valor que se usa es el de la fila de total general. Para obtener el valor deseado en esa fila, puede que necesites modificar el Contexto Visual del cálculo, usando las funciones COLLAPSE o EXPAND (puedes leer más al respecto aquí).
NOTA
Al crear un Cálculo Visual para definir el valor máximo o mínimo de un eje, el valor que se usará será el del total general.
Consideraciones generales sobre el caso de uso
Para garantizar que la línea siempre aparezca por encima de las columnas en un gráfico combinado, necesitamos modificar el máximo del eje Y principal y los valores máximo y mínimo del eje Y secundario. Para lograrlo, también necesitaremos dos parámetros adicionales que se usarán en dos o más de estos Cálculos Visuales: uno para añadir un margen alrededor de los valores máximos y mínimos encontrados en el gráfico, y otro para definir el porcentaje del eje vertical que corresponde al gráfico de líneas. Estos dos parámetros se podrían codificar de forma fija en cada cálculo, pero eso dificultaría el mantenimiento. Un enfoque mejor es crear Cálculos Visuales ocultos con estos valores codificados de forma fija, para poder reutilizarlos en los tres Cálculos Visuales que queremos hacer. Si estos valores de configuración deben centralizarse, los dos parámetros se pueden añadir al Visual como medidas normales y después ocultarlos una vez creado el primer Cálculo Visual.
Los Cálculos Visuales no son extremadamente difíciles, pero sí requieren algo de reflexión. Para hacerlo un poco más fácil, estas dos imágenes nos ayudarán a deducir las expresiones DAX. Con fines ilustrativos, estamos considerando un caso de uso en el que todos los valores son positivos. Esta implementación se puede mejorar para que el margen sea más proporcional y para contemplar valores negativos, pero para mayor claridad hemos mantenido el ejemplo lo más simple posible.


Todos los cálculos Visuales se crearán como ocultos, ya que solo queremos usarlos para la configuración del eje. De forma predeterminada, se crean como visibles, así que tendrás que ocultarlos haciendo clic en el pequeño icono del ojo junto al nombre del campo en el panel de Visualizaciones que aparece cuando editas Cálculos Visuales.

Añadir parámetros ocultos para reutilizarlos entre Cálculos Visuales
Como se indicó en la sección anterior, añadimos dos Cálculos Visuales o medidas ocultas con el valor del porcentaje de margen (padding) y el valor de linechartWeight. Así:

Máximo del eje principal (Cálculo Visual)
Añadir parámetros ocultos fue la parte fácil. Ahora vamos con mainAxisMax. Para calcularlo, primero tendremos que obtener el valor máximo de cualquiera de las columnas (columnsMax en la imagen). A continuación, necesitaremos ampliarlo un poco para dejar algo de aire entre las columnas y el área del gráfico de líneas (columnsMaxAdj) y, por último, tendremos que añadir todo el espacio asignado al gráfico de líneas, expresado como un porcentaje de la altura total del gráfico. Esto devuelve el valor máximo que se usará para el eje (mainAxisMax).
Una implementación con Cálculos Visuales se ve así:
mainAxisMax =
VAR columnsMax = CALCULATE(MAXX(ROWS,MAX([Sales Amount],[Total Cost])),EXPANDALL(ROWS))
VAR columnsMaxAdj = columnsMax * (1 + [Padding] )
VAR mainAxisMax = columnsMaxAdj / (1 - [LineChartWeight] )
RETURN mainAxisMax
La clave de este cálculo es usar EXPANDALL en el valor columnsMax para obtener el máximo por fila específicamente en la fila de total general. Usar EXPANDALL en lugar de EXPAND hace que el máximo en el total general se calcule sobre la combinación de todos los campos usados para filas. Para una única columna, no hay diferencia, pero si usáramos año y mes, en el total general obtendríamos el máximo entre años, en lugar del máximo por combinación de año y mes, que es lo que necesitamos para este caso de uso. Como extra, este cálculo no hace referencia a los campos usados para filas en absoluto, por lo que funcionará incluso si cambias la granularidad del gráfico con un parámetro de campo.
NOTA
Los Cálculos Visuales siempre tienen en cuenta todos los campos añadidos al Visual, independientemente del estado de subir/bajar de nivel (drill-up/drill-down) del gráfico. Así que, si los meses están colapsados y el gráfico se muestra a nivel de año, el total general del Cálculo Visual no cambiará y la línea ya no quedará por encima de las columnas. Al intercambiar varios campos con un parámetro de campo, de forma predeterminada se mostrarán contraídos, por lo que esto puede provocar un comportamiento inesperado.
Ahora, al hacer clic en el botón fx del máximo del eje, puedes vincular el valor al cálculo Visual, y tomará el valor del total general.

Máximo del eje secundario (cálculo Visual)
El máximo del gráfico de líneas es probablemente el más fácil, ya que solo tenemos que ocuparnos de un poco de margen (y hasta eso puede ser opcional).
secondaryAxisMax =
VAR lineMax = CALCULATE(MAXX(ROWS,[Margin %]),EXPANDALL(ROWS))
VAR lineMaxAdj = lineMax * (1 + [Padding] )
RETURN lineMaxAdj
Mínimo del eje secundario (cálculo Visual)
Ahora, el más complicado de los tres es el mínimo del eje secundario. Para eso, tendremos que calcular la altura real del área del gráfico de líneas, luego calcular la altura de todo el eje secundario usando el parámetro lineChartWeight y, por último, restarla del máximo del eje para encontrar el mínimo del eje. Podríamos reutilizar el cálculo Visual del máximo del eje secundario, pero también podemos recalcularlo con la misma expresión y mantenerlos independientes y, además, un poco más fáciles de entender.
secondaryAxisMin =
VAR LineMax = CALCULATE(MAXX(ROWS,[Margin %]),EXPANDALL(ROWS))
VAR LineMaxAdj = LineMax * (1 + [Padding])
VAR LineMin = CALCULATE(MINX(ROWS,[Margin %]),EXPANDALL(ROWS))
VAR LineMinAdj = LineMin * (1 - [Padding])
VAR LineHeight = LineMaxAdj - LineMinAdj
VAR SecondaryAxisHeight = LineHeight / [LineChartWeight]
VAR SecondaryAxisMin = LineMaxAdj - SecondaryAxisHeight
RETURN SecondaryAxisMin
Si ahora vinculamos los valores máximo y mínimo del eje secundario a los cálculos Visuales ocultos, deberíamos ver algo parecido a esto:

Al menos para la línea, se recomienda encarecidamente añadir etiquetas de datos y ocultar los valores y el título del eje secundario.
Convertir un Cálculo Visual en una UDF de DAX
Los resultados se ven muy bien, pero ¿qué pasa si queremos replicar el mismo efecto en otro lugar del Report o incluso en un Report independiente? Aquí es donde entran las UDF de DAX. Para crear una UDF de DAX, puedes hacerlo desde la Vista de modelo, la Vista de Consulta DAX, la Vista de TMDL y, por supuesto, desde Tabular Editor. Una vez creada la función, se puede llamar desde cualquier lugar del modelo donde se use DAX o, en el caso de Cálculos Visuales, desde cualquier Report conectado a ese modelo. Como cabría esperar, si la función contiene expresiones que solo pueden usarse en Cálculos Visuales, llamarla desde otros lugares producirá un error. Las UDF de DAX se pueden copiar a otros modelos semánticos y funcionarán si no hay referencias explícitas al modelo o a los nombres de los cálculos Visuales.
Al crear cualquier UDF de DAX, debes darle un nombre, especificar los parámetros y, después, proporcionar la expresión que se calculará. Para las UDF de DAX de Cálculos Visuales no hay ninguna diferencia. La lógica del Cálculo Visual mainAxisMax, en una UDF de DAX, quedaría más o menos así:
PrimaryAxisMax =
(
maxColumnExpression : expr,
padding,
lineChartWeight
) =>
VAR ColumnsMax =
CALCULATE(
MAXX(ROWS,maxColumnExpression),
EXPANDALL(ROWS)
)
VAR ColumnsMaxAdj = ColumnsMax * (1 + padding )
VAR MainAxisMax = ColumnsMaxAdj / (1- lineChartWeight )
RETURN MainAxisMax
Y la llamada desde el Cálculo Visual a la UDF de DAX se vería así:
mainAxisMax2 =
PrimaryAxisMax(
MAX([Sales Amount],[Total Cost]),
[Padding],
[LineChartWeight]
)
Y, efectivamente, ambos Cálculos Visuales devuelven los mismos valores:

NOTA
En la versión de Power BI Desktop de noviembre de 2025, IntelliSense todavía no reconoce las UDF de DAX en Cálculos Visuales ni funciones de Cálculos Visuales en las UDF de DAX, pero la sintaxis es válida y funciona como se espera.
La expresión de la UDF de DAX es, efectivamente, muy parecida a la del Cálculo Visual original, pero hay algunos aspectos que comentar.
La primera opción es evitar crear dos argumentos para pasar las medidas Sales Amount y Total Cost (como visualColumn1 y visualColumn2, por ejemplo, porque dejarían de ser medidas). En su lugar, se optó por pasar una expresión que ya devuelve el máximo de ambas. La razón es que quizá queramos usar esta UDF de DAX en escenarios ligeramente distintos cuando tengamos un número diferente de columnas en el Visual. Dado que, en el momento de escribir esto, no hay posibilidad de pasar un número variable de argumentos a las UDF de DAX, esta es la solución alternativa más razonable. Puedes crear un cálculo Visual que precalcule este máximo por fila o hacerlo directamente como una expresión. La forma más compacta de calcular el máximo de tres o más números es usar una tabla anónima como:
MAXX( {[a], [b], [c]}, [Value])
El segundo detalle a considerar es que maxColumnExpression debe ser un argumento con modo de paso “expr”. Esto indica que el valor se evaluará dentro de la expresión en la que se usa, en lugar de pasarse como un valor estático. Esto es lo que ocurriría si no especificaras nada, así que es algo que no debes olvidar.
NOTA
Cualquier parámetro usado dentro de la expresión de cálculo (compute expression) de CALCULATE en una UDF de DAX debe tener modo de paso “expr”. Esto se aplica tanto a Visual Calculations como al DAX convencional. También se aplica a otras funciones que usan CALCULATE internamente, como COLLAPSE y EXPAND cuando no se usan como modificadores de CALCULATE (más información aquí).
La lógica de la Visual Calculation secondaryAxisMax es bastante sencilla y da lugar a una UDF de DAX bastante directa:
SecondaryAxisMax =
(
lineMaxExpression:expr,
padding
) =>
VAR lineMax =
CALCULATE(
MAXX(ROWS,lineMaxExpression),
EXPANDALL(ROWS)
)
VAR lineMaxAdj = lineMax * (1 + padding )
RETURN lineMaxAdj
Además, ambos devuelven los mismos valores:

Aquí, lo único que merece la pena mencionar es que también podríamos tener más de una línea en el gráfico, así que tendremos que pasar una expresión que devuelva el valor máximo de todas ellas para cada fila de la matriz visual.
Ahora, para secondaryAxisMin, la Visual Calculation original era más compleja y, como es lógico, da lugar a una UDF de DAX más compleja, que se ve así:
SecondaryAxisMin =
(
lineMaxExpression: expr,
lineMinExpression: expr,
padding,
lineChartWeight
) =>
VAR LineMax = CALCULATE(MAXX(ROWS,lineMaxExpression),EXPANDALL(ROWS))
VAR LineMaxAdj = LineMax * (1 + padding)
VAR LineMin = CALCULATE(MINX(ROWS,lineMinExpression),EXPANDALL(ROWS))
VAR LineMinAdj = LineMin * (1 - padding)
VAR LineHeight = LineMaxAdj - LineMinAdj
VAR SecondaryAxisHeight = LineHeight / lineChartWeight
VAR SecondaryAxisMin = LineMaxAdj - SecondaryAxisHeight
RETURN SecondaryAxisMin
Y sí, también devuelven los mismos valores:

A estas alturas, ya no queda nada más que señalar. Aun así, podemos señalar que, aunque una sola línea del gráfico podría gestionarse con un único argumento, si queremos que la UDF de DAX funcione con gráficos que tengan más de una línea, tendremos que proporcionar una expresión para MAX y otra para el mínimo. Esperemos que en el futuro se implemente un número variable de parámetros para que estos cálculos también puedan encapsularse en la DAX UDF.
Ten en cuenta también que, para esta DAX UDF más compleja, hemos seguido las convenciones de nomenclatura de SQLBI, usando PascalCase para las variables y camelCase para los parámetros, para que el código sea más legible.
Sobre la reutilización de DAX UDF en Visual Calculations
Desde una perspectiva técnica, las DAX UDF de Visual Calculations parecen ser —por definición— independientes del modelo y, por tanto, buenas candidatas para compartir en daxlib.org o en cualquier repositorio con ese fin. Aun así, como se explica en este artículo, las referencias por su nombre también hacen que la función no sea 100% independiente del modelo; por tanto, las DAX UDF de Visual Calculations que queramos compartir no deberían tener referencias directas a columnas específicas del visual; todas las referencias a columnas deberían pasarse mediante parámetros.
Sin embargo, aunque todas las DAX UDF de daxlib.org son independientes del modelo, esto no significa que puedas usarlas todas en un cálculo visual. Cualquier DAX UDF que necesite una medida, una tabla o una columna del modelo para funcionar no se puede llamar desde un cálculo visual, ya que el cálculo visual no tiene acceso al modelo, solo al visual.
En conclusión
Las DAX UDF proporcionan una forma de centralizar la lógica de las Visual Calculations en el modelo semántico. Todas las funciones de DAX específicas de los cálculos visuales se pueden usar en las UDF, lo que hace que las expresiones de los cálculos visuales sean mucho más compactas.
Además, si no tienen referencias directas a columnas de la matriz visual, incluso se pueden reutilizar en distintos Reports y Visuales.
Eso sí, como con cualquier otra DAX UDF, tenemos que prestar atención a los detalles, como el modo de paso de cada parámetro, y contemplar los distintos escenarios en los que podría usarse la función.