Επισήμανση σημείων δεδομένων σε απεικονίσεις του Power BI
Αυτό το άρθρο περιγράφει τον τρόπο επισήμανσης δεδομένων σε απεικονίσεις Power BI.
Από προεπιλογή, όταν επιλέγεται ένα στοιχείο, ο values
πίνακας στο dataView
αντικείμενο φιλτράρεται ώστε να εμφανίζει μόνο τις επιλεγμένες τιμές. Όταν ο πίνακας values
φιλτράρεται, όλες οι άλλες απεικονίσεις στη σελίδα εμφανίζουν μόνο τα επιλεγμένα δεδομένα.
Εάν ορίσετε την supportsHighlight
ιδιότητα στο αρχείο σας capabilities.json
σε true
, θα έχει ως αποτέλεσμα τον πλήρη μη φιλτραρισμένο values
πίνακα μαζί με έναν highlights
πίνακα. Ο highlights
πίνακας έχει το ίδιο μήκος με τον πίνακα τιμών και τυχόν μη επιλεγμένες τιμές ορίζονται σε null
. Με ενεργοποιημένη αυτήν την ιδιότητα, επισημαίνονται τα κατάλληλα δεδομένα στην απεικόνιση συγκρίνοντας τον values
πίνακα με τον highlights
πίνακα.
Στο παράδειγμα, παρατηρήστε ότι:
- Χωρίς υποστήριξη επισήμανσης, η επιλογή είναι η μοναδική τιμή στον
values
πίνακα και η μοναδική γραμμή που παρουσιάζεται στην προβολή δεδομένων. - Με την υποστήριξη επισήμανσης, όλες οι τιμές βρίσκονται στον
values
πίνακα. Οhighlights
πίνακας περιέχει μιαnull
τιμή για στοιχεία που δεν έχουν επισημανθεί. Όλες οι ράβδοι εμφανίζονται στην προβολή δεδομένων και η επισημασμένη γραμμή έχει διαφορετικό χρώμα.
Μπορεί επίσης να υπάρχουν πολλές επιλογές και μερικές επισημάνσεις. Οι επισημασμένες τιμές παρουσιάζονται στην προβολή δεδομένων.
Σημείωμα
Η αντιστοίχιση προβολής δεδομένων πίνακα δεν υποστηρίζει τη δυνατότητα επισημάνσεων.
Επισήμανση σημείων δεδομένων με αντιστοίχιση προβολής κατηγορικών δεδομένων
Για απεικονίσεις με αντιστοίχιση προβολής κατηγορικών δεδομένων, προσθέστε "supportsHighlight": true
στο capabilities.json
αρχείο. Για παράδειγμα:
{
"dataRoles": [
{
"displayName": "Category",
"name": "category",
"kind": "Grouping"
},
{
"displayName": "Value",
"name": "value",
"kind": "Measure"
}
],
"dataViewMappings": [
{
"categorical": {
"categories": {
"for": {
"in": "category"
}
},
"values": {
"for": {
"in": "value"
}
}
}
}
],
"supportsHighlight": true
}
Αφού καταργήσετε τον περιττό κώδικα, ο προεπιλεγμένος πηγαίος κώδικας απεικόνισης μοιάζει με το ακόλουθο παράδειγμα:
"use strict";
// ... default imports list
import { FormattingSettingsService } from "powerbi-visuals-utils-formattingmodel";
import DataViewCategorical = powerbi.DataViewCategorical;
import DataViewCategoryColumn = powerbi.DataViewCategoryColumn;
import PrimitiveValue = powerbi.PrimitiveValue;
import DataViewValueColumn = powerbi.DataViewValueColumn;
import { VisualFormattingSettingsModel } from "./settings";
export class Visual implements IVisual {
private target: HTMLElement;
private formattingSettings: VisualFormattingSettingsModel;
private formattingSettingsService: FormattingSettingsService;
constructor(options: VisualConstructorOptions) {
console.log('Visual constructor', options);
this.formattingSettingsService = new FormattingSettingsService();
this.target = options.element;
this.host = options.host;
}
public update(options: VisualUpdateOptions) {
this.formattingSettings = this.formattingSettingsService.populateFormattingSettingsModel(VisualFormattingSettingsModel, options.dataViews);
console.log('Visual update', options);
}
// Returns properties pane formatting model content hierarchies, properties and latest formatting values, Then populate properties pane.
// This method is called once every time we open properties pane or when the user edit any format property.
public getFormattingModel(): powerbi.visuals.FormattingModel {
return this.formattingSettingsService.buildFormattingModel(this.formattingSettings);
}
}
Εισαγάγετε τις απαιτούμενες διασυνδέσεις για την επεξεργασία δεδομένων από το Power BI:
import DataViewCategorical = powerbi.DataViewCategorical;
import DataViewCategoryColumn = powerbi.DataViewCategoryColumn;
import PrimitiveValue = powerbi.PrimitiveValue;
import DataViewValueColumn = powerbi.DataViewValueColumn;
Δημιουργήστε το ριζικό div
στοιχείο για τις τιμές κατηγορίας:
export class Visual implements IVisual {
private target: HTMLElement;
private formattingSettings: VisualFormattingSettingsModel;
private formattingSettingsService: FormattingSettingsService;
private div: HTMLDivElement; // new property
constructor(options: VisualConstructorOptions) {
console.log('Visual constructor', options);
this.formattingSettingsService = new FormattingSettingsService();
this.target = options.element;
this.host = options.host;
// create div element
this.div = document.createElement("div");
this.div.classList.add("vertical");
this.target.appendChild(this.div);
}
// ...
}
Διαγράψτε τα περιεχόμενα των στοιχείων div πριν από την απόδοση νέων δεδομένων:
// ...
public update(options: VisualUpdateOptions) {
this.formattingSettings = this.formattingSettingsService.populateFormattingSettingsModel(VisualFormattingSettingsModel, options.dataViews);
console.log('Visual update', options);
while (this.div.firstChild) {
this.div.removeChild(this.div.firstChild);
}
// ...
}
Λάβετε τις κατηγορίες και μετρήστε τιμές από το dataView
αντικείμενο:
public update(options: VisualUpdateOptions) {
this.formattingSettings = this.formattingSettingsService.populateFormattingSettingsModel(VisualFormattingSettingsModel, options.dataViews);
console.log('Visual update', options);
while (this.div.firstChild) {
this.div.removeChild(this.div.firstChild);
}
const dataView: DataView = options.dataViews[0];
const categoricalDataView: DataViewCategorical = dataView.categorical;
const categories: DataViewCategoryColumn = categoricalDataView.categories[0];
const categoryValues = categories.values;
const measures: DataViewValueColumn = categoricalDataView.values[0];
const measureValues = measures.values;
const measureHighlights = measures.highlights;
// ...
}
Όπου το categoryValues
είναι ένας πίνακας τιμών κατηγορίας, measureValues
το είναι ένας πίνακας μετρήσεων και measureHighlights
το είναι τα τμήματα τιμών που επισημαίνονται.
Σημείωμα
Εάν οι τιμές της measureHighlights
ιδιότητας είναι μικρότερες από τις τιμές της categoryValues
ιδιότητας, τότε η τιμή επισημάνθηκε μερικώς.
Απαριθμήστε τον categoryValues
πίνακα και λάβετε αντίστοιχες τιμές και επισημάνσεις:
// ...
const measureHighlights = measures.highlights;
categoryValues.forEach((category: PrimitiveValue, index: number) => {
const measureValue = measureValues[index];
const measureHighlight = measureHighlights && measureHighlights[index] ? measureHighlights[index] : null;
console.log(category, measureValue, measureHighlight);
});
Δημιουργία div
και p
στοιχεία για την εμφάνιση και απεικόνιση τιμών προβολής δεδομένων στην απεικόνιση DOM:
categoryValues.forEach((category: PrimitiveValue, index: number) => {
const measureValue = measureValues[index];
const measureHighlight = measureHighlights && measureHighlights[index] ? measureHighlights[index] : null;
console.log(category, measureValue, measureHighlight);
// div element. it contains elements to display values and visualize value as progress bar
let div = document.createElement("div");
div.classList.add("horizontal");
this.div.appendChild(div);
// div element to visualize value of measure
let barValue = document.createElement("div");
barValue.style.width = +measureValue * 10 + "px";
barValue.style.display = "flex";
barValue.classList.add("value");
// element to display category value
let bp = document.createElement("p");
bp.innerText = category.toString();
// div element to visualize highlight of measure
let barHighlight = document.createElement("div");
barHighlight.classList.add("highlight")
barHighlight.style.backgroundColor = "blue";
barHighlight.style.width = +measureHighlight * 10 + "px";
// element to display highlighted value of measure
let p = document.createElement("p");
p.innerText = `${measureHighlight}/${measureValue}`;
barHighlight.appendChild(bp);
div.appendChild(barValue);
barValue.appendChild(barHighlight);
div.appendChild(p);
});
Εφαρμόστε τα απαιτούμενα στυλ στοιχείων για χρήση flexbox
και καθορίστε τα χρώματα για στοιχεία div:
div.vertical {
display: flex;
flex-direction: column;
}
div.horizontal {
display: flex;
flex-direction: row;
}
div.highlight {
background-color: blue
}
div.value {
background-color: red;
display: flex;
}
Το αποτέλεσμα είναι η ακόλουθη προβολή της απεικόνισης:
Επισήμανση σημείων δεδομένων με αντιστοίχιση προβολής δεδομένων μήτρας
Για απεικονίσεις με αντιστοίχιση προβολής δεδομένων μήτρας, προσθέστε "supportsHighlight": true
στο capabilities.json
αρχείο. Για παράδειγμα:
{
"dataRoles": [
{
"displayName": "Columns",
"name": "columns",
"kind": "Grouping"
},
{
"displayName": "Rows",
"name": "rows",
"kind": "Grouping"
},
{
"displayName": "Value",
"name": "value",
"kind": "Measure"
}
],
"dataViewMappings": [
{
"matrix": {
"columns": {
"for": {
"in": "columns"
}
},
"rows": {
"for": {
"in": "rows"
}
},
"values": {
"for": {
"in": "value"
}
}
}
}
],
"supportsHighlight": true
}
Το δείγμα δεδομένων για τη δημιουργία μιας ιεραρχίας για αντιστοίχιση προβολής δεδομένων μήτρας:
Γραμμή1 | Γραμμή2 | Γραμμή3 | Στήλη1 | Στήλη2 | Στήλη3 | Τιμές |
---|---|---|---|---|---|---|
R1 | R11 | R111 | C1 | C11 | C111 | 1 |
R1 | R11 | R112 | C1 | C11 | C112 | 2 |
R1 | R11 | R113 | C1 | C11 | C113 | 3 |
R1 | R12 | R121 | C1 | C12 | C121 | 4 |
R1 | R12 | R122 | C1 | C12 | C122 | 5 |
R1 | R12 | R123 | C1 | C12 | C123 | 6 |
R1 | R13 | R131 | C1 | C13 | C131 | 7 |
R1 | R13 | R132 | C1 | C13 | C132 | 8 |
R1 | R13 | R133 | C1 | C13 | C133 | 9 |
R2 | R21 | R211 | C2 | C21 | C211 | 10 |
R2 | R21 | R212 | C2 | C21 | C212 | 11 |
R2 | R21 | R213 | C2 | C21 | C213 | 12 |
R2 | R22 | R221 | C2 | C22 | C221 | 13 |
R2 | R22 | R222 | C2 | C22 | C222 | 14 |
R2 | R22 | R223 | C2 | C22 | C223 | 16 |
R2 | R23 | R231 | C2 | C23 | C231 | 17 |
R2 | R23 | R232 | C2 | C23 | C232 | 18 |
R2 | R23 | R233 | C2 | C23 | C233 | 19 |
Δημιουργήστε το προεπιλεγμένο έργο απεικόνισης και εφαρμόστε το δείγμα του capabilities.json
αρχείου.
Αφού καταργήσετε τον περιττό κώδικα, ο προεπιλεγμένος πηγαίος κώδικας απεικόνισης μοιάζει με το ακόλουθο παράδειγμα:
"use strict";
// ... default imports
import { FormattingSettingsService } from "powerbi-visuals-utils-formattingmodel";
import { VisualFormattingSettingsModel } from "./settings";
export class Visual implements IVisual {
private target: HTMLElement;
private formattingSettings: VisualFormattingSettingsModel;
private formattingSettingsService: FormattingSettingsService;
constructor(options: VisualConstructorOptions) {
console.log('Visual constructor', options);
this.formattingSettingsService = new FormattingSettingsService();
this.target = options.element;
this.host = options.host;
}
public update(options: VisualUpdateOptions) {
this.formattingSettings = this.formattingSettingsService.populateFormattingSettingsModel(VisualFormattingSettingsModel, options.dataViews);
console.log('Visual update', options);
}
/**
* Returns properties pane formatting model content hierarchies, properties and latest formatting values, Then populate properties pane.
* This method is called once every time we open properties pane or when the user edit any format property.
*/
public getFormattingModel(): powerbi.visuals.FormattingModel {
return this.formattingSettingsService.buildFormattingModel(this.formattingSettings);
}
}
Εισαγάγετε τις απαιτούμενες διασυνδέσεις για την επεξεργασία δεδομένων από το Power BI:
import DataViewMatrix = powerbi.DataViewMatrix;
import DataViewMatrixNode = powerbi.DataViewMatrixNode;
import DataViewHierarchyLevel = powerbi.DataViewHierarchyLevel;
Δημιουργήστε δύο div
στοιχεία για τη διάταξη απεικόνισης:
constructor(options: VisualConstructorOptions) {
// ...
this.rowsDiv = document.createElement("div");
this.target.appendChild(this.rowsDiv);
this.colsDiv = document.createElement("div");
this.target.appendChild(this.colsDiv);
this.target.style.overflowY = "auto";
}
Ελέγξτε τα δεδομένα στη update
μέθοδο για να εξασφαλίσετε ότι η απεικόνιση λαμβάνει δεδομένα:
public update(options: VisualUpdateOptions) {
this.formattingSettings = this.formattingSettingsService.populateFormattingSettingsModel(VisualFormattingSettingsModel, options.dataViews);
console.log('Visual update', options);
const dataView: DataView = options.dataViews[0];
const matrixDataView: DataViewMatrix = dataView.matrix;
if (!matrixDataView ||
!matrixDataView.columns ||
!matrixDataView.rows ) {
return
}
// ...
}
Καταργήστε τα περιεχόμενα των στοιχείων πριν από την div
απόδοση νέων δεδομένων:
public update(options: VisualUpdateOptions) {
// ...
// remove old elements
// to better performance use D3js pattern:
// https://d3js.org/#enter-exit
while (this.rowsDiv.firstChild) {
this.rowsDiv.removeChild(this.rowsDiv.firstChild);
}
const prow = document.createElement("p");
prow.innerText = "Rows";
this.rowsDiv.appendChild(prow);
while (this.colsDiv.firstChild) {
this.colsDiv.removeChild(this.colsDiv.firstChild);
}
const pcol = document.createElement("p");
pcol.innerText = "Columns";
this.colsDiv.appendChild(pcol);
// ...
}
Δημιουργήστε τη treeWalker
συνάρτηση για να διανείμετε τη δομή δεδομένων μήτρας:
public update(options: VisualUpdateOptions) {
// ...
const treeWalker = (matrixNode: DataViewMatrixNode, index: number, levels: DataViewHierarchyLevel[], div: HTMLDivElement) => {
}
// ...
}
Όπου matrixNode
το είναι ο τρέχων κόμβος, levels
το είναι στήλες μετα-δεδομένων αυτού του επιπέδου ιεραρχίας, div
- γονικό στοιχείο για θυγατρικά στοιχεία HTML.
Το treeWalker
είναι η επαναλαμβανόμενη συνάρτηση, χρειάζεται να δημιουργήσετε div
το στοιχείο και p
για το κείμενο ως κεφαλίδα και καλέστε τη συνάρτηση για θυγατρικά στοιχεία του κόμβου:
public update(options: VisualUpdateOptions) {
// ...
const treeWalker = (matrixNode: DataViewMatrixNode, index: number, levels: DataViewHierarchyLevel[], div: HTMLDivElement) => {
// ...
if (matrixNode.children) {
const childDiv = document.createElement("div");
childDiv.classList.add("vertical");
div.appendChild(childDiv);
const p = document.createElement("p");
const level = levels[matrixNode.level]; // get current level column metadata from current node
p.innerText = level.sources[level.sources.length - 1].displayName; // get column name from metadata
childDiv.appendChild(p); // add paragraph element to div element
matrixNode.children.forEach((node, index) => treeWalker(node, levels, childDiv, ++levelIndex));
}
}
// ...
}
Καλέστε τη συνάρτηση για ριζικά στοιχεία της στήλης και γραμμής της δομής προβολής δεδομένων μήτρας:
public update(options: VisualUpdateOptions) {
// ...
const treeWalker = (matrixNode: DataViewMatrixNode, index: number, levels: DataViewHierarchyLevel[], div: HTMLDivElement) => {
// ...
}
// ...
// remove old elements
// ...
// ...
const rowRoot: DataViewMatrixNode = matrixDataView.rows.root;
rowRoot.children.forEach((node) => treeWalker(node, matrixDataView.rows.levels, this.rowsDiv));
const colRoot = matrixDataView.columns.root;
colRoot.children.forEach((node) => treeWalker(node, matrixDataView.columns.levels, this.colsDiv));
}
Δημιουργία selectionID για κόμβους και δημιουργία κουμπιών για την εμφάνιση κόδων:
public update(options: VisualUpdateOptions) {
// ...
const treeWalker = (matrixNode: DataViewMatrixNode, index: number, levels: DataViewHierarchyLevel[], div: HTMLDivElement) => {
const selectionID: ISelectionID = this.host.createSelectionIdBuilder()
.withMatrixNode(matrixNode, levels)
.createSelectionId();
let nodeBlock = document.createElement("button");
nodeBlock.innerText = matrixNode.value.toString();
nodeBlock.addEventListener("click", (event) => {
// call select method in the selection manager
this.selectionManager.select(selectionID);
});
nodeBlock.addEventListener("contextmenu", (event) => {
// call showContextMenu method to display context menu on the visual
this.selectionManager.showContextMenu(selectionID, {
x: event.clientX,
y: event.clientY
});
event.preventDefault();
});
// ...
}
// ...
}
Το κύριο βήμα της επισήμανσης είναι η δημιουργία ενός άλλου πίνακα τιμών.
Το αντικείμενο του τερματικού κόμβου έχει δύο ιδιότητες για τον πίνακα τιμών, την τιμή και την επισήμανση:
JSON.stringify(options.dataViews[0].matrix.rows.root.children[0].children[0].children[0], null, " ");
{
"level": 2,
"levelValues": [
{
"value": "R233",
"levelSourceIndex": 0
}
],
"value": "R233",
"identity": {
"identityIndex": 2
},
"values": {
"0": {
"value": null,
"highlight": null
},
"1": {
"value": 19,
"highlight": 19
}
}
}
Όπου value
αντιπροσωπεύει την τιμή του κόμβου χωρίς εφαρμογή μιας επιλογής από την άλλη απεικόνιση, highlight
υποδεικνύει ποιο τμήμα των δεδομένων έχει επισημανθεί.
Σημείωμα
Εάν η τιμή του highlight
είναι μικρότερη από την τιμή του value
, τότε value
επισημάνθηκε μερικώς.
Προσθέστε κώδικα για να επεξεργαστείτε τον values
πίνακα του κόμβου, εάν παρουσιάζεται:
public update(options: VisualUpdateOptions) {
// ...
const treeWalker = (matrixNode: DataViewMatrixNode, index: number, levels: DataViewHierarchyLevel[], div: HTMLDivElement) => {
// ...
if (matrixNode.values) {
const sumOfValues = Object.keys(matrixNode.values) // get key property of object (value are 0 to N)
.map(key => +matrixNode.values[key].value) // convert key property to number
.reduce((prev, curr) => prev + curr) // sum of values
let sumOfHighlights = sumOfValues;
sumOfHighlights = Object.keys(matrixNode.values) // get key property of object (value are 0 to N)
.map(key => matrixNode.values[key].highlight ? +matrixNode.values[key].highlight : null ) // convert key property to number if it exists
.reduce((prev, curr) => curr ? prev + curr : null) // convert key property to number
// create div container for value and highlighted value
const vals = document.createElement("div");
vals.classList.add("vertical")
vals.classList.replace("vertical", "horizontal");
// create paragraph element for label
const highlighted = document.createElement("p");
// Display complete value and highlighted value
highlighted.innerText = `${sumOfHighlights}/${sumOfValues}`;
// create div container for value
const valueDiv = document.createElement("div");
valueDiv.style.width = sumOfValues * 10 + "px";
valueDiv.classList.add("value");
// create div container for highlighted values
const highlightsDiv = document.createElement("div");
highlightsDiv.style.width = sumOfHighlights * 10 + "px";
highlightsDiv.classList.add("highlight");
valueDiv.appendChild(highlightsDiv);
// append button and paragraph to div containers to parent div
vals.appendChild(nodeBlock);
vals.appendChild(valueDiv);
vals.appendChild(highlighted);
div.appendChild(vals);
} else {
div.appendChild(nodeBlock);
}
if (matrixNode.children) {
// ...
}
}
// ...
}
Το αποτέλεσμα είναι μια απεικόνιση με κουμπιά και τιμές, όπως highlighted value/default value
.