Find everything you need to get certified on Fabric—skills challenges, live sessions, exam prep, role guidance, and more. Get started
Hi all,
I am new to the D3.js visual in PowerBI and can't seem to get it to work. I have followed the tutorial the best I know how without any luck. Here is the tutorial I am referring to: https://azurebi-docs.jppp.org/powerbi-visuals/d3js.html?tabs=docs%2Cdocs-open
I have an animated multiple line chart: the lines are the different ids in my dataset, the animation is based off of a timestamp column in which the datapoints (and the connecting lines) display based on each datapoint's timestamp. There is a replay button to replay the animation.
My data has the following columns: id, left, top, timestamp. One id may have multiple rows. y-axis is left, x-axis is top.
I also have a background image for the plotArea.
This is what i have so far in the D3.JS editor:
var margin = {top: 20, right: 30, bottom: 50, left: 40},
width = pbi.width - margin.left - margin.right,
height = pbi.height - margin.top - margin.bottom;
var x = d3.scaleLinear()
.domain([0, 1800])
.range([margin.left, width - margin.right]).clamp(true);
var y = d3.scaleLinear()
.domain([0, 1200])
.range([margin.top, height - margin.bottom]).clamp(true);
var svg = d3.select("#chart")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom);
var plotAreaWidth = pbi.width - margin.left - margin.right;
var plotAreaHeight = pbi.height - margin.top - margin.bottom;
var plotArea = svg.append("g")
.attr("class", "plot-area")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
plotArea.append("image")
.attr("xlink:href", "backdrop.png")
.attr("width", plotAreaWidth)
.attr("height", plotAreaHeight);
svg.append("g")
.attr("transform", "translate(0," + (height - margin.bottom) + ")")
.call(d3.axisBottom(x).ticks(4).tickSizeOuter(0))
.call(function(g) { g.select(".domain").remove(); })
.call(function(g) { g.selectAll(".tick line").clone()
.attr("y2", -height)
.attr("stroke-opacity", 0.1); })
.append("text")
.attr("x", width - 4)
.attr("y", -4)
.attr("font-weight", "bold")
.attr("text-anchor", "end")
.attr("fill", "currentColor")
.text("Top");
svg.append("g")
.attr("transform", "translate(" + margin.left + ",0)")
.call(d3.axisLeft(y).ticks(6).tickSizeOuter(0))
.call(function(g) { g.select(".domain").remove(); })
.call(function(g) { g.selectAll(".tick line").clone()
.attr("x2", width)
.attr("stroke-opacity", 0.1); })
.append("text")
.attr("x", 4)
.attr("y", margin.top - 10)
.attr("font-weight", "bold")
.attr("text-anchor", "start")
.attr("fill", "currentColor")
.text("Left");
var loadChart = function(){
pbi.dsv(function(data){
data.sort(function(a, b) { return new Date(a.timestamp) - new Date(b.timestamp); });
var ids = Array.from(new Set(data.map(function(d) { return d.id; })));
var color = d3.scaleOrdinal()
.domain(ids)
.range(d3.schemeCategory10);
ids.forEach(function(id) {
var idData = data.filter(function(d) { return d.id === id; });
var lineData = idData; // Include all data points for the line
plotArea.append("path")
.datum(lineData)
.attr("fill", "none")
.attr("stroke", color(id))
.attr("stroke-width", 2.5)
.attr("stroke-linejoin", "round")
.attr("stroke-linecap", "round")
.attr("d", d3.line()
.x(function(d) { return x(d.top); })
.y(function(d) { return y(d.left); }));
});
data.forEach(function(d, i) {
setTimeout(function() {
plotArea.append("circle")
.attr("cx", x(d.top))
.attr("cy", y(d.left))
.attr("r", 4)
.attr("fill", "steelblue")
.on("mouseover", function() {
d3.select(this.nextSibling).style("visibility", "visible");
})
.on("mouseout", function() {
d3.select(this.nextSibling).style("visibility", "hidden");
});
plotArea.append("text")
.attr("x", x(d.top))
.attr("y", y(d.left) - 10)
.attr("text-anchor", "middle")
.text(d.timestamp.toLocaleString())
.attr("fill", "black")
.style("visibility", "hidden");
ids.forEach(function(id) {
var idData = data.filter(function(item) { return item.id === id && item.timestamp <= d.timestamp; });
var lineData = idData; // Include all data points for the line
plotArea.select('path[stroke="' + color(id) + '"]')
.datum(lineData)
.attr("d", d3.line()
.x(function(d) { return x(d.top); })
.y(function(d) { return y(d.left); }));
});
}, i * 100);
});
});
}
loadChart();
var replayButton = d3.select("body").append("button").attr("id", "replay-button").text("Replay");
replayButton.on("click", function() {
d3.select("#chart").selectAll("*").remove(); // Clear the chart
drawConnectedScatterplot(data);
});
I have tried different variations and have tried simplifying it by focusing on simply getting a line chart to display but i can't get it to work, nothing gets generated at all - all i see is a blank placeholder.
This is the html version that works as expected:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Connected Scatterplot</title>
<script src="https://d3js.org/d3.v7.min.js"></script>
</head>
<body>
<div id="chart"></div>
<script>
function drawConnectedScatterplot(data) {
// Sort the data based on the timestamp
data.sort(function(a, b) { return a.timestamp - b.timestamp; });
var width = 600;
var height = 400;
var margin = { top: 20, right: 30, bottom: 50, left: 40 };
var x = d3.scaleLinear()
.domain([0, 1800])
.range([margin.left, width - margin.right]).clamp(true);
var y = d3.scaleLinear()
.domain([0, 1200])
.range([margin.top, height - margin.bottom]).clamp(true);
var svg = d3.select("#chart").append("svg")
.attr("width", width)
.attr("height", height);
var plotAreaWidth = width - margin.left - margin.right;
var plotAreaHeight = height - margin.top - margin.bottom;
var plotArea = svg.append("g")
.attr("class", "plot-area")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
// Append background image to the plot area
plotArea.append("image")
.attr("xlink:href", "backdrop.png")
.attr("width", plotAreaWidth)
.attr("height", plotAreaHeight);
svg.append("g")
.attr("transform", "translate(0," + (height - margin.bottom) + ")")
.call(d3.axisBottom(x).ticks(4).tickSizeOuter(0))
.call(function(g) { g.select(".domain").remove(); })
.call(function(g) { g.selectAll(".tick line").clone()
.attr("y2", -height)
.attr("stroke-opacity", 0.1); })
.append("text")
.attr("x", width - 4)
.attr("y", -4)
.attr("font-weight", "bold")
.attr("text-anchor", "end")
.attr("fill", "currentColor")
.text("Top");
svg.append("g")
.attr("transform", "translate(" + margin.left + ",0)")
.call(d3.axisLeft(y).ticks(6).tickSizeOuter(0))
.call(function(g) { g.select(".domain").remove(); })
.call(function(g) { g.selectAll(".tick line").clone()
.attr("x2", width)
.attr("stroke-opacity", 0.1); })
.append("text")
.attr("x", 4)
.attr("y", margin.top - 10)
.attr("font-weight", "bold")
.attr("text-anchor", "start")
.attr("fill", "currentColor")
.text("Left");
var ids = Array.from(new Set(data.map(function(d) { return d.id; })));
var color = d3.scaleOrdinal()
.domain(ids)
.range(d3.schemeCategory10);
ids.forEach(function(id) {
var idData = data.filter(function(d) { return d.id === id; });
var lineData = idData; // Include all data points for the line
plotArea.append("path")
.datum(lineData)
.attr("fill", "none")
.attr("stroke", color(id))
.attr("stroke-width", 2.5)
.attr("stroke-linejoin", "round")
.attr("stroke-linecap", "round")
.attr("d", d3.line()
.x(function(d) { return x(d.top); })
.y(function(d) { return y(d.left); }));
});
data.forEach(function(d, i) {
setTimeout(function() {
plotArea.append("circle")
.attr("cx", x(d.top))
.attr("cy", y(d.left))
.attr("r", 4)
.attr("fill", "steelblue")
.on("mouseover", function() {
d3.select(this.nextSibling).style("visibility", "visible");
})
.on("mouseout", function() {
d3.select(this.nextSibling).style("visibility", "hidden");
});
plotArea.append("text")
.attr("x", x(d.top))
.attr("y", y(d.left) - 10)
.attr("text-anchor", "middle")
.text(d.timestamp.toLocaleString())
.attr("fill", "black")
.style("visibility", "hidden");
ids.forEach(function(id) {
var idData = data.filter(function(item) { return item.id === id && item.timestamp <= d.timestamp; });
var lineData = idData; // Include all data points for the line
plotArea.select('path[stroke="' + color(id) + '"]')
.datum(lineData)
.attr("d", d3.line()
.x(function(d) { return x(d.top); })
.y(function(d) { return y(d.left); }));
});
}, i * 100);
});
}
var data = [
{ id: "ID1", left: 744, top: 987, timestamp: new Date("2024-01-01T05:00:00") },
{ id: "ID1", left: 828, top: 938, timestamp: new Date("2024-01-01T10:00:00") },
{ id: "ID1", left: 886, top: 883, timestamp: new Date("2024-01-01T11:00:00") },
{ id: "ID1", left: 940, top: 734, timestamp: new Date("2024-01-01T12:00:00") },
{ id: "ID1", left: 997, top: 638, timestamp: new Date("2024-01-01T13:00:00") },
{ id: "ID1", left: 1056, top: 577, timestamp: new Date("2024-01-01T14:00:00") },
{ id: "ID1", left: 1101, top: 516, timestamp: new Date("2024-01-01T15:00:00") },
{ id: "ID1", left: 1146, top: 473, timestamp: new Date("2024-01-01T16:00:00") },
{ id: "ID1", left: 1179, top: 411, timestamp: new Date("2024-01-01T17:00:00") },
{ id: "ID1", left: 1212, top: 372, timestamp: new Date("2024-01-01T18:00:00") },
{ id: "ID2", left: 1417, top: 312, timestamp: new Date("2024-01-01T06:00:00") },
{ id: "ID2", left: 1436, top: 330, timestamp: new Date("2024-01-01T11:30:00") },
{ id: "ID2", left: 1448, top: 355, timestamp: new Date("2024-01-01T12:45:00") },
{ id: "ID2", left: 1445, top: 386, timestamp: new Date("2024-01-01T13:30:00") },
{ id: "ID2", left: 1444, top: 420, timestamp: new Date("2024-01-01T14:15:00") },
{ id: "ID2", left: 1430, top: 467, timestamp: new Date("2024-01-01T15:00:00") },
{ id: "ID2", left: 1414, top: 512, timestamp: new Date("2024-01-01T15:45:00") },
{ id: "ID2", left: 1392, top: 573, timestamp: new Date("2024-01-01T16:30:00") },
{ id: "ID2", left: 1363, top: 628, timestamp: new Date("2024-01-01T17:15:00") },
{ id: "ID2", left: 1318, top: 699, timestamp: new Date("2024-01-01T18:00:00") }
];
drawConnectedScatterplot(data);
var replayButton = d3.select("body").append("button").attr("id", "replay-button").text("Replay");
replayButton.on("click", function() {
d3.select("#chart").selectAll("*").remove(); // Clear the chart
drawConnectedScatterplot(data);
});
</script>
</body>
</html>
Since i am in powerbi desktop im finding it excessively difficult to find the issue/s since i can't debug as i would in the browser.
Any guidance on how to get it to work is much appeciated!
Solved! Go to Solution.
HI @Anonymous,
I'd like to suggest you to check the d3.js visual official support page to know the usage and the limitations at the first:
Power BI D3.js Visual - Azure BI (jppp.org)
Regards,
Xiaoxin Sheng
HI @Anonymous,
I'd like to suggest you to check the d3.js visual official support page to know the usage and the limitations at the first:
Power BI D3.js Visual - Azure BI (jppp.org)
Regards,
Xiaoxin Sheng
Check out the September 2024 Power BI update to learn about new features.
Learn from experts, get hands-on experience, and win awesome prizes.
User | Count |
---|---|
43 | |
4 | |
4 | |
3 | |
3 |