Megosztás a következőn keresztül:


A hierarchikus identitásszűrők API-ja Power BI-vizualizációkban

A Hierarchia identitásszűrő API lehetővé teszi a Mátrix DataView-leképezést használó vizualizációk számára, hogy egyszerre több mező adatait szűrik a hierarchiastruktúrát használó adatpontok alapján.

Ez az API a következő helyzetekben hasznos:

  • Hierarchiák szűrése adatpontok alapján
  • Olyan egyéni vizualizációk, amelyek szemantikai modelleket használnak csoporttal a kulcsokon

Feljegyzés

A hierarchia identitásszűrő API az API 5.9.0-s verziójából érhető el

A szűrőfelület a következő kódban jelenik meg:

interface IHierarchyIdentityFilter<IdentityType> extends IFilter {
    target: IHierarchyIdentityFilterTarget;
    hierarchyData: IHierarchyIdentityFilterNode<IdentityType>[];
}
  • $schema: https://powerbi.com/product/schema#hierarchyIdentity (az IFiltertől örökölt)

  • filterType: FilterType.HierarchyIdentity (az IFiltertől örökölt)

  • cél: A lekérdezés releváns oszlopainak tömbje. Jelenleg csak egyetlen szerepkör támogatott; ezért a cél nem szükséges, és üresnek kell lennie.

  • hierarchyData: a hierarchiafában kijelölt és nem kijelölt elemek, amelyek mindegyike IHierarchyIdentityFilterNode<IdentityType> egyetlen értékkijelölést jelöl.

type IHierarchyIdentityFilterTarget = IQueryNameTarget[]

interface IQueryNameTarget {
    queryName: string;
}
  • queryName: a lekérdezés forrásoszlopának lekérdezésneve. A következőből származik: DataViewMetadataColumn
interface IHierarchyIdentityFilterNode<IdentityType> {
    identity: IdentityType;
    children?: IHierarchyIdentityFilterNode<IdentityType>[];
    operator: HierarchyFilterNodeOperators;
}
  • identitás: A DataView csomóponti identitása. A IdentityTypeCustomVisualOpaqueIdentity

  • gyermekek: Az aktuális kijelölés szempontjából releváns csomóponti gyermekek listája

  • operátor: A fa egyetlen objektumának operátora. Az operátor a következő három lehetőség egyike lehet:

    type HierarchyFilterNodeOperators = "Selected" | "NotSelected" | "Inherited";
    
    • Kiválasztva: az érték explicit módon van kiválasztva.

    • NotSelected: az érték explicit módon nincs kiválasztva.

    • Öröklött: az értékválasztás a hierarchia szülőértékének megfelelően van megadva, vagy alapértelmezett érték, ha ez a gyökérérték.

A hierarchia identitásszűrőjének meghatározásakor tartsa szem előtt az alábbi szabályokat:

  • Vegye át az identitásokat a DataView-ból.
  • Minden identitásútvonalnak érvényes elérési útnak kell lennie a DataView-ban.
  • Minden levélnek a Kijelölt vagy a NotSelected operátorral kell rendelkeznie.
  • Az identitások összehasonlításához használja a függvényt ICustomVisualsOpaqueUtils.compareCustomVisualOpaqueIdentities .
  • Az identitások a következő mezők módosításait (például mezők hozzáadását vagy eltávolítását) módosíthatják. A Power BI hozzárendeli a frissített identitásokat a meglévő filter.hierarchyData-hoz.

A Hierarchia identitásszűrő API használata

Az alábbi kód egy példa a hierarchia identitásszűrő API egyéni vizualizációkban való használatára:

import { IHierarchyIdentityFilterTarget, IHierarchyIdentityFilterNode, HierarchyIdentityFilter } from "powerbi-models"

const target: IHierarchyIdentityFilterTarget = [];

const hierarchyData: IHierarchyIdentityFilterNode<CustomVisualOpaqueIdentity>[] = [
    {
        identity: {...},
        operator: "Selected",
        children: [
            {
                identity: {...},
                operator: "NotSelected"
            }
        ]
    },
    {
        identity: {...},
        operator: "Inherited",
        children: [
            {
                identity: {...},
                operator: "Selected"
            }
        ]
    }
];

const filter = new HierarchyIdentityFilter(target, hierarchyData).toJSON();

A szűrő alkalmazásához használja az applyJsonFilter API-hívást:

this.host.applyJsonFilter(filter, "general", "filter", action);

Az aktív JSON-szűrő visszaállításához használja a jsonFilters "VisualUpdateOptions" tulajdonságot:

export interface VisualUpdateOptions extends extensibility.VisualUpdateOptions {
   //...
   jsonFilters?: IFilter[];
}

A HierarchyIdnetity szűrő csak hierarchikusan kapcsolódó mezők esetén támogatott. Alapértelmezés szerint a Power BI nem ellenőrzi, hogy a mezők hierarchikusan kapcsolódnak-e.

A hierarchikusan kapcsolódó ellenőrzés aktiválásához adja hozzá az "areHierarchicallyRelated" tulajdonságot a megfelelő szerepkörfeltételhez a capabilities.json fájlban:

"dataViewMappings": [
    {
         "conditions": [
             {
                  "Rows": {
                      "min": 1,
                      "areHierarchicallyRelated": true <------ NEW ------>
                  },
                  "Value": {
                  "min": 0
                  }
            }
        ],
        ...
    }
]

A mezők hierarchikusan kapcsolódnak a következő feltételek teljesülése esetén:

  • Nincs belefoglalt kapcsolati él sok-sok számossághoz, és nem ConceptualNavigationBehavior.Weakis.

  • A szűrő összes mezője az elérési úton található.

  • Az elérési út minden kapcsolata azonos irányban vagy kétirányú.

  • A kapcsolat iránya megegyezik az egy-többhöz vagy kétirányúhoz tartozó számossággal.

Példa hierarchiakapcsolatokra

Például a következő entitáskapcsolatra tekintettel:

A szűrő kétirányú jellegét bemutató ábra.

  • Az A, B hierarchikusan kapcsolódik: igaz
  • A B, C hierarchikusan kapcsolódik: igaz
  • Az A, B, C hierarchikusan kapcsolódóak: igaz
  • A, C, E hierarchikusan kapcsolódóak: igaz (A --> E --> C)
  • A, B, E hierarchikusan kapcsolódóak: igaz (B --> A --> E)
  • Az A, B, C, E hierarchikusan kapcsolódóak: igaz (B --> A --> E --> C)
  • Az A, B, C, D hierarchikusan kapcsolódnak: hamis (3. szabály megszegése)
  • A C, D hierarchikusan kapcsolódik: igaz
  • A B, C, D hierarchikusan összefügg: hamis (3. szabály megszegése)
  • Az A, C, D, E hierarchikusan kapcsolódóak: hamis (3. szabály megsértése)

Feljegyzés

  • Ha ezek az érvényesítések engedélyezve vannak, és a mezők nem hierarchikusan kapcsolódnak, a vizualizáció nem jelenik meg, és hibaüzenet jelenik meg:

    Képernyőkép a vizualizációról, amelyen az érvényesítések nem tölthetőek be, mert a mezők nem hierarchikusan kapcsolódnak egymáshoz. A hibaüzenetben az áll, hogy

    Képernyőkép az ellenőrzés engedélyezésekor megjelenő hibaüzenetről, és a mezők nem hierarchikusan kapcsolódnak egymáshoz. Az üzenet azt jelzi, hogy

  • Ha ezek az érvényesítések le vannak tiltva, és a szűrővizualizáció olyan szűrőt alkalmaz, amely nem hierarchikusan kapcsolódó mezőkhöz kapcsolódó csomópontokat tartalmaz, előfordulhat, hogy más vizualizációk nem jelennek meg megfelelően a mértékek használatakor:

    Képernyőkép a vizualizációról, amelyen az érvényesítések nem tölthetőek be, mert a mezők nem hierarchikusan kapcsolódnak egymáshoz. A hibaüzenet azt jelzi, hogy

    Képernyőkép a hibaüzenetről, amikor az ellenőrzés le van tiltva, és a mezők nem hierarchikusan kapcsolódnak egymáshoz. Az üzenetben az áll, hogy

Példakód a hierarchia adatfának az új kijelölés utáni frissítéséhez

Az alábbi kód bemutatja, hogyan frissítheti a fát egy hierarchyData új kijelölés után:

type CompareIdentitiesFunc = (id1: CustomVisualOpaqueIdentity, id2: CustomVisualOpaqueIdentity) => boolean;
/**
* Updates the filter tree following a new node selection.
* Prunes irrelevant branches after node insertion/removal if necessary.
* @param path Identities path to the selected node.
* @param treeNodes Array of IHierarchyIdentityFilterNode representing a valid filter tree.
* @param compareIdentities Compare function for CustomVisualOpaqueIdentity to determine equality. Pass the ICustomVisualsOpaqueUtils.compareCustomVisualOpaqueIdentities function.
* @returns A valid filter tree after the update
*/

function updateFilterTreeOnNodeSelection(
   path: CustomVisualOpaqueIdentity[],
   treeNodes: IHierarchyIdentityFilterNode<CustomVisualOpaqueIdentity>[],
   compareIdentities: CompareIdentitiesFunc
): IHierarchyIdentityFilterNode<CustomVisualOpaqueIdentity>[] {
    if (!path) return treeNodes;
    const root: IHierarchyIdentityFilterNode<CustomVisualOpaqueIdentity> = {
        identity: null,
        children: treeNodes || [],
        operator: 'Inherited',
    };
    let currentNodesLevel = root.children;
    let isClosestSelectedParentSelected = root.operator === 'Selected';
    let parents: { node: IHierarchyIdentityFilterNode<CustomVisualOpaqueIdentity>, index: number }[] = [{ node: root, index: -1 }];
    let shouldFixTree = false;
    path.forEach((identity, level) => {
        const index = currentNodesLevel.findIndex((node) => compareIdentities(node.identity, identity));
        const isLastNodeInPath = level === path.length - 1
        if (index === -1) {
           const newNode: IHierarchyIdentityFilterNode<CustomVisualOpaqueIdentity> = {
               identity,
               children: [],
               operator: isLastNodeInPath ? (isClosestSelectedParentSelected ? 'NotSelected' : 'Selected') : 'Inherited',
           };
           currentNodesLevel.push(newNode);
           currentNodesLevel = newNode.children;
           if (newNode.operator !== 'Inherited') {
              isClosestSelectedParentSelected = newNode.operator === 'Selected';
           }
        } else {
            const currentNode = currentNodesLevel[index];
            if (isLastNodeInPath) {
               const partial = currentNode.children && currentNode.children.length;
               if (partial) {
                  /**
                   * The selected node has subtree.
                   * Therefore, selecting this node should lead to one of the following scenarios:
                   * 1. The node should have Selected operator and its subtree should be pruned.
                   * 2. The node and its subtree should be pruned form the tree and the tree should be fixed.
                   */
                   // The subtree should be always pruned.
                   currentNode.children = [];
                   if (currentNode.operator === 'NotSelected' || (currentNode.operator === 'Inherited' && isClosestSelectedParentSelected )) {
                      /**
                       * 1. The selected node has NotSelected operator.
                       * 2. The selected node has Inherited operator, and its parent has Slected operator.
                       * In both cases the node should be pruned from the tree and the tree shoud be fixed.
                       */
                      currentNode.operator = 'Inherited'; // to ensure it will be pruned
                      parents.push({ node: currentNode, index });
                      shouldFixTree = true;
                  } else {
                     /**
                      * 1. The selected node has Selected operator.
                      * 2. The selected node has Inherited operator, but its parent doesn't have Selected operator.
                      * In both cases the node should stay with Selected operator pruned from the tree and the tree should be fixed.
                      * Note that, node with Selected oprator and parent with Selector operator is not valid state.
                      */
                      currentNode.operator = 'Selected';
                  }
              } else {
                  // Leaf node. The node should be pruned from the tree and the tree should be fixed.
                  currentNode.operator = 'Inherited'; // to ensure it will be pruned
                  parents.push({ node: currentNode, index });
                  shouldFixTree = true;
                 }
             } else {
                 // If it's not the last noded in path we just continue traversing the tree
                 currentNode.children = currentNode.children || [];
                 currentNodesLevel = currentNode.children
                 if (currentNode.operator !== 'Inherited') {
                     isClosestSelectedParentSelected = currentNode.operator === 'Selected';
                     // We only care about the closet parent with Selected/NotSelected operator and its children
                     parents = [];
                  }
                  parents.push({ node: currentNode, index });
                }
           }
    });
    // Prune brnaches with Inherited leaf
    if (shouldFixTree) {
       for (let i = parents.length - 1; i >= 1; i--) {
           // Normalize to empty array
           parents[i].node.children = parents[i].node.children || [];
           if (!parents[i].node.children.length && (parents[i].node.operator === 'Inherited')) {
              // Remove the node from its parent children array
              removeElement(parents[i - 1].node.children, parents[i].index);
           } else {
               // Node has children or Selected/NotSelected operator
               break;
         }
      }
   }
   return root.children;
}
/**
* Removes an element from the array without preserving order.
* @param arr - The array from which to remove the element.
* @param index - The index of the element to be removed.
*/
function removeElement(arr: any[], index: number): void {
    if (!arr || !arr.length || index < 0 || index >= arr.length) return;
    arr[index] = arr[arr.length - 1];
    arr.pop();
}

Szempontok és korlátozások

  • Ez a szűrő csak mátrix dataView-leképezés esetén támogatott.

  • A vizualizációnak csak egy csoportosítási adatszerepkört kell tartalmaznia.

  • A Hierarchia identitásszűrő típusát használó vizualizációknak csak egy ilyen típusú szűrőt kell alkalmazniuk.