Comprendre le message d’erreur « Dépendance circulaire détectée » et le corriger

Proposé par André Meyer-Roussilhon

27 avril 2021

Daxologie | Hep Daxy !

CALCULATE | dépendance circulaire | erreur

Restez à l'écoute, abonnez-vous à la newsletter (2 fois / mois)

4 + 2 =

Présentation du scénario

Dans ce scénario, j’étudie les variations journalières (intraday) d’une action. L’objectif est de compter le nombre de jours où la variation est inférieure à 1%, à 2% , à 3% etc., en tenant compte du volume d’actions échangées (<1 million ou >1 million) :

Pour cela je dispose d’une table ASML demo et de mesures me précisant :

  • La date (c’est une colonne)
  • Un index (colonne indiquant un numéro unique pour chaque ligne de la table)
  • Le plus bas (mesure _bas)
  • Le plus haut (mesure _haut)
  • Le volume (mesure _vol)
  • Le nombre de jours (mesure définie par COUNT(‘ASML demo’[Date]))
  • La variation intraday (mesure définie par ([_haut] – [_bas]) / [_bas])

Pour créer le segment volumétrie, je crée cette fois-ci une colonne définie par

volumétrie = 
IF(
    [_vol] > 1000000,
    ">1M",
    "<1M"
)

Jusque là pas de message d’erreur.

Pour créer l’axe X (horizontale) de mon graphique, je dois également créer une colonne (la mesure ne permet pas de créer cet axe) : il s’agit de multiplier la variation par 100 et de prendre l’arrondi supérieur. C’est l’amplitude de variation que vous voyez sur le graphique. La première idée est donc :

groupe variation = 
"<" & CEILING( [_variation intraday] *100 , 1 ) &"%"

C’est à ce moment que l’erreur liée à la dépendance circulaire apparaît.

Pourquoi une erreur liée à la dépendance circulaire ?

La dépendance circulaire, comme son nom l’indique, survient lorsque qu’une colonne B fait référence lors de son calcul à une colonne A, qui elle-même fait référence à la colonne B.

Ce phénomène ne se produit que parce que les deux calculs sont des colonnes ! Une dépendance circulaire n’est pas possible avec une mesure.

(Notez qu’il existe aussi des cas plus rares de dépendance entre deux tables, dans certaines conditions)

Pourtant, dans la formule

"<" & CEILING( [_variation intraday] *100 , 1 ) &"%"

Je ne fais pas référence à une autre colonne !

Et c’est que vous ne devez pas oublier trois règles fondamentales du DAX : tout d’abord, première règle, lors de l’appel d’une mesure dans une formule (ici la mesure _variation intraday), un CALCULATE est toujours implicitement ajouté.

Deuxième règle fondamentale : lorsqu’il est appelé dans un contexte de ligne, CALCULATE déclenche une transition de contexte. Ici, parce que nous sommes en train de créer une colonne, nous sommes bien dans un contexte de ligne.

Troisième règle fondamentale : une transition de contexte consiste à transformer un contexte de ligne en un ensemble de filtres équivalents, et concrètement, à filtrer chacune des autres colonnes de la table.

La boucle est bouclée ! La transition de contexte déclenchée par le CALCULATE implicite dû à l’appel de la mesure _variation intraday fait bien référence aux autres colonnes de la table, et par conséquent à la colonne volumétrie. Mais la colonne volumétrie elle-même fait appel à la mesure _vol : celle-ci introduit donc un CALCULATE implicite et une transition de contexte, qui fait référence à la colonne groupe variation.

En définitive, et de manière implicite, la dépendance circulaire vient donc du fait que groupe variation fait référence à volumétrie qui fait elle-même référence à groupe variation

Mais alors comment s’en sortir ?

La première façon d’éviter cette erreur est d’éviter de créer des colonnes ! Créer des mesures le plus souvent possible est la quatrième règle fondamentale du DAX, et vous ne devez recourir aux colonnes que dans des cas bien précis (dont ceux proposés dans ce scénario).

Dans le cas où la formule doit être une colonne, il faut donc s’arranger pour que le CALCULATE implicite ne déclenche pas une transition de contexte sur toutes les colonnes de la table. Or, et c’est là le secret, si une colonne de votre table permet d’identifier de manière unique chaque ligne, DAX n’aura pas besoin de filtrer toutes les colonnes dans le cadre d’une transition de contexte.

Dans notre scénario, deux colonnes répondent à cette condition : la date et l’index (notez que ce dernier peut être ajouté à l’aide de Power Query).

Je vais donc réécrire la formule de groupe variation, et écrire explicitement le CALCULATE et son filtre, en faisant appel à la fonction ALLEXCEPT, qui enlève tous les filtres sauf celui de la colonne indiquée :

groupe variation = 
"<" &
CALCULATE(
    CEILING([_variation intraday]*100,1),
    ALLEXCEPT('ASML demo', 'ASML demo'[Index])
)
&"%"

Conclusion

N’oubliez pas les quatre règles fondamentales du DAX :

  • L’appel d’une mesure ajoute un CALCULATE implicite
  • Dans un contexte de ligne, CALCULATE déclenche une transition de contexte
  • Une transition de contexte pose un filtre sur toutes les colonnes de la table
  • Ne créez des colonnes que lorsque vous n’avez pas le choix

Et pour ce qui concerne la dépendance circulaire, dans le cadre de la création d’une colonne, le motif explicite CALCULATE (ALLEXCEPT()) est recommandé dès que vous faite appel à une mesure, c’est-à-dire très souvent.

Post-scriptum

Une erreur de débutant consisterait à créer la formule suivante sous forme d’une colonne :

En effet, le filtre ‘ASML demo'[Volume] > 1500000 est traduit par DAX en

FILTER(
    ALL(ASML demo) , 
    'ASML demo'[Volume] > 1500000)
)

C’est le fait que la fonction ALL porte sur toute la table qui génère l’erreur. Là encore, utiliser ALLEXCEPT permet de régler le problème :

Mais rappelons-le, ici, l’erreur principale c’est de vouloir faire de cette formule une colonne : c’est clairement sous forme d’une mesure qu’il faut faire ce calcul.

Articles associés :

Le DAX : maîtriser l’analyse et la modélisation de données dans Power BI

Le DAX : maîtriser l’analyse et la modélisation de données dans Power BI

Le troisième livre que je consacre à Power BI sort demain 14 avril : 328 pages entièrement dédiées au DAX, les concepts-clés (et en particulier le contexte d’évaluation), CALCULATE, la modification du modèle physique, l’analyse temporelle, etc., 328 pages également accompagnées d’exercices pratiques, corrigés et commentés (à la fois pour Power BI et pour Excel).

Une étude du contexte de filtre

Le contexte de filtre est assurément le cœur du DAX, le langage d’analyse de Power BI et de Power Pivot dans Excel. Comprendre le contexte de filtre, c’est comprendre 90% du DAX : ce n’est pas moi qui le dis, mais les deux sommités mondiales sur ce langage (Marco et Alberto, de SQLBI). Dans ce billet, je vous propose de regarder une formule et de commenter le contexte de filtre et ses évolutions.

Construire et lire une moyenne mobile dans Power BI

Construire et lire une moyenne mobile dans Power BI

Dans ce billet, je vous propose une étude très poussée de la moyenne mobile et de sa mise en œuvre dans Power BI. La moyenne mobile est un outil primordial pour « lire » les données, en particulier lorsque les variations sont importantes, mais aussi un outil prédictif. Et notamment, tout un pan des stratégies d’investissement repose sur la lecture de ces moyennes