Arthur Graus...•Add external libraries (f.e. D3.js, jQuery, Angular, React) •Develop in Visual...
Transcript of Arthur Graus...•Add external libraries (f.e. D3.js, jQuery, Angular, React) •Develop in Visual...
Gebruikersdag 2018
Ontwikkel Custom Visuals met D3.jsArthur Graus
Arthur GrausPower BI Trainer | Consultant | [email protected]://www.arthurgraus.nl
.PBIXQ
uery
DAX
Dataset
Report
ODATA RESTHTML
OLEDB MDX SQL
Publish
PowerView
PowerPivot
PowerQuery
DA
X
DA
X
https://d3js.org/
https://github.com/agmgraus/socialnetworkgraph/
• Install Power BI Visual Tools CLI (pbiviz)
• Create new visual project
• Add external libraries (f.e. D3.js, jQuery, Angular, React)
• Develop in Visual Studio Code
• Test/ debug
• Build and package
• Import in Power BI Report
Demo: HelloWorld Custom Visual
<svg width="200" height="200"><circle cx="30" cy="30" r="20" fill="green"/><circle x="70" cy="70" r="20" fill="purple"/><circle cx="110" cy="100" r="20" fill="red"/>
</svg>
var people = [
{ "x_axis": 30, "y_axis": 30, "radius": 20, "color" : "green" …},
{ "x_axis": 70, "y_axis": 70, "radius": 20, "color" : "purple" …},
{ "x_axis": 110, "y_axis": 100, "radius": 20, "color" : "red“s…}];
var svgContainer = d3.select("body").append("svg")
.attr("width", 200)
.attr("height", 200);
var circles = svgContainer.selectAll("circle") .data(people)
circles.enter().append("circle");
circles.attr("cx", function (d) { return d.x_axis; })
.attr("cy", function (d) { return d.y_axis; })
.attr("r", function (d) { return d.radius; })
.style("fill", function(d) { return d.color; });
circles.exit().remove();
var people = [
{ "x_axis": 30, "y_axis": 30, "radius": 40, "color" : "green" },
{ "x_axis": 70, "y_axis": 70, "radius": 20, "color" : "black"},
{ "x_axis": 110, "y_axis": 100, "radius": 20, "color" : "red"}];
var circles = svgContainer.selectAll("circle") .data(people)
circles.enter().append("circle");
circles.attr("cx", function (d) { return d.x_axis; })
.attr("cy", function (d) { return d.y_axis; })
.attr("r", function (d) { return d.radius; })
.style("fill", function(d) { return d.color; });
circles.exit().remove();
<svg width="200" height="200"><circle cx="30" cy="30" r="20" fill="green"/><circle cx="70" cy="70" r="20" fill="purple"/><circle cx="110" cy="100" r="20" fill="red"/>
</svg>
40black
var people = [
{ "x_axis": 30, "y_axis": 30, "radius": 40, "color" : "green" },
{ "x_axis": 70, "y_axis": 70, "radius": 20, "color" : "black"},
{ "x_axis": 110, "y_axis": 100, "radius": 20, "color" : "red"}];
var circles = svgContainer.selectAll("circle") .data(people);
circles.enter().append("circle");
circles.attr("cx", function (d) { return d.x_axis; })
.attr("cy", function (d) { return d.y_axis; })
.attr("r", function (d) { return d.radius; })
.style("fill", function(d) { return d.color; });
circles.exit().remove();
<svg width="200" height="200"><circle cx="30" cy="30" r="40" fill="green"/><circle cx="70" cy="70" r="20" fill="black"/><circle cx="110" cy="100" r="20" fill="red"/>
</svg>
Demo 01: D3.js Data Binding in action
//A Create Circles (Databinding)...
//B Create Force Simulationthis.simulation = this.d3.forceSimulation();
//C Define forcesthis.simulation
// keep entire simulation balanced around screen center.force('center_nodes', this.d3.forceCenter(this.width / 2, this.height / 2))// avoid collision with padding.force('collision', this.d3.forceCollide(function (d) {return d.r + 5; })
.radius(function (d: any) {return (d.r) * 1.5}));
//D Bind Model Data: Nodesthis.simulation
.nodes(this.people);
//E Register events this.simulation
//each tick all the forces are executed and the x and y positions updated.on('tick', () => { this.circles.attr('cx', function (d) { return d.x; })
.attr('cy', function (d) { return d.y; });})
//simulation is finished.on('end', () => {this.showDebugInfo('Simulation finished, alpha < alphaMin');
});
let people = [{
id: 1,name: "The big boss",color: "Red",r: 50
},{
id: 2,name: "John",color: "Green",r: 30
},{
id: 3,name: "Julia",color: "Yellow",r: 20
},
{id: 4,name: "Mike",color: "Blue",r: 25
},{
id: 5,name: "Jessica",color: "Purple",r: 20
},{
id: 6,name: "Steven",color: "Black",r: 30
}];
Demo 02: Force Layout: Nodes
this.simulation.nodes(this.people);
this.simulation.force('center_nodes', this.d3.forceCenter(this.width / 2, this.height / 2)).force('push_them_apart', this.d3.forceManyBody().strength(100)).force('collision_detect', this.d3.forceCollide()
.radius(function (d: any) {return (d.r) * 1.5}))
.force("link_nodes_together", this.d3.forceLink().links(this.connections).distance(function (d) {
return (d.source.r + d.target.r) * 1.5 }) );
this.simulation.on('tick', () => {this.circles.attr('cx', function (d) { return d.x; })
.attr('cy', function (d) { return d.y; });
this.lines.attr("x1", function (d) {return d.source.x;}).attr("y1", function (d) {return d.source.y;}).attr("x2", function (d) {return d.target.x;}).attr("y2", function (d) {return d.target.y;});
})
let connections = [
{
source: this.people[0],
target: this.people[1]
}, {
source: this.people[0],
target: this.people[2]
}, {
source: this.people[0],
target: this.people[3]
}, {
source: this.people[3],
target: this.people[4]
}, {
source: this.people[3],
target: this.people[5]
}
];
Demo 03: Force Simulation: Nodes + Links
capabilites.json:
"dataRoles": [{
"displayNameKey": "Visual_Source",
"name": "SourceName",
"kind": "Grouping",
"displayName": "Source: Name (required)"
},{
"displayNameKey": "Visual_Target",
"name": "TargetName",
"kind": "Grouping",
"displayName": "Target: Name (required)"
},
...
{
"displayNameKey": "Visual_SourceSize",
"name": "SourceSize",
"kind": "Measure",
"displayName": "Source: Size"
},{
"displayNameKey": "Visual_TargetSize",
"name": "TargetSize",
"kind": "Measure",
"displayName": "Target: Size"
}]
Data View Mappings Documentation
capabilites.json:
"dataViewMappings": [{ "table": {
"rows": {
"select": [
{"for": { "in": "SourceName"}},
{"for": { "in": "SourceSize"}},
{"for": { "in": "SourceColor"}},
{"for": { "in": "TargetName"}},
{"for": { "in": "TargetSize"}},
{"for": { "in": "TargetColor"}}
]
}
}
}]
table.columns:"0": {
"roles": {"SourceName": true},
"type": {...},
"displayName": "ManagerName",
"queryName": "Employees.ManagerName",...
},
"1": {
"roles": {"TargetName": true},
"type": {...},
"displayName": "EmployeeName",
"queryName": "Employees.EmployeeName",
...
},
"2": {
"roles": {"SourceColor": true},
"type": {...},
"displayName": "ManagerDepartment",
"queryName": "Employees.ManagerDepartment",...
},...
table.rows:[
[
null,
"Paul",
null,
"Board",
null,
220000
],
[
"Evy",
"Carleen",
"HR",
"HR",
80000,
45000
]...]
let people = [{
id: 1,name: "Paul",color: "Red",r: 50
},{
id: 2,name: "Evy",color: "Green",r: 30
},{
id: 3,name: "Carleen",color: "Green",r: 16
},
{
];
let connections = [
{
source: null,
target: this.people[0]
}, {
source: this.people[1],
target: this.people[2]
}, {
}, {
source:
target:
}, {
source:
target:
}
];
Demo 04: DataView
Demo 05: Social Network Graph
Gebruikersdag 2018
Bedankt!Vergeet nietde evaluatie in tevullen!Scan de QR code.