I'm trying to create a multi line chart with dual y axes , I've tried running the code in powerbi d3.js visual , but is not yielding any visual. I'm not understanding where I've made the mistake
I want to create a multi line chart , where x axes has the time , one y axes is force , another y axes is temperature.Time should be in the format HH:MM:SS on the x axes
This is the base chart I've created using html enter image description here
So for each metal , I need to plot the line for force and a line for temperature for each time interval ,the result line chart format should be somewhat like in the image enter image description here
Dummy Data:
Metal | Force | Temperature | Time |
---|---|---|---|
Silver | 55 | 22 | 15:30:01 |
Copper | 43 | 67 | 15:30:01 |
gold | 61 | 99 | 15:30:01 |
diamond | 31 | 47 | 15:30:01 |
indium | 88 | 19 | 15:30:01 |
Silver | 51 | 61 | 15:30:02 |
Copper | 37 | 26 | 15:30:02 |
gold | 49 | 81 | 15:30:02 |
diamond | 26 | 41 | 15:30:02 |
indium | 15 | 15:30:02 | |
Silver | 34 | 77 | 15:30:03 |
Copper | 93 | 58 | 15:30:03 |
gold | 29 | 36 | 15:30:03 |
diamond | 64 | 57 | 15:30:03 |
indium | 72 | 15:30:03 |
Below is the code. When I run the code I'm getting a blank space as in the image
var margin = { top: 20, right: 20, bottom: 30, left: 40 },
width = pbi.width - margin.left - margin.right,
height = pbi.height - margin.top - margin.bottom;
var parseTime = d3.time.format("%H:%M:%S").parse;
// Scales
var x = d3.time.scale().range([0, width]);
var y = d3.scale.linear().range([height, 0]);
// Axis
var xAxis = d3.svg.axis().scale(x).orient("bottom").ticks(d3.time.seconds, 1).tickFormat(d3.time.format("%H:%M:%S"));
var yAxis = d3.svg.axis().scale(y).orient("left");
// Line generators
var lineForce = d3.svg.line()
.x(function(d) { return x(d.Time); })
.y(function(d) { return y(d.Force); });
var lineTemp = d3.svg.line()
.x(function(d) { return x(d.Time); })
.y(function(d) { return y(d.Temperature); });
var svg = d3.select("#chart")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
pbi.dsv(function(data) {
// Convert Time to Date object and parse Force and Temperature as numbers
data.forEach(function(d) {
d.Time = parseTime(d.Time);
d.Force = +d.Force;
d.Temperature = d.Temperature ? +d.Temperature : null; // Handle null values
});
var metals = Array.from(new Set(data.map(function(d) { return d.Metal; })));
var colorScale = d3.scale.category10()
.domain(metals);
x.domain(d3.extent(data, function(d) { return d.Time; })); // Use extent for min and max
y.domain([0, d3.max(data, function(d) { return Math.max(d.Force, d.Temperature || 0); })]); // Combined domain, handling nulls
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis)
.append("text")
.attr("x", width / 2)
.attr("y", margin.bottom - 10)
.attr("fill", "#000")
.attr("text-anchor", "middle")
.text("Time");
svg.append("g")
.attr("class", "y axis")
.call(yAxis)
.append("text")
.attr("transform", "rotate(-90)")
.attr("y", -margin.left + 10)
.attr("x", -height / 2)
.attr("dy", "0.71em")
.attr("text-anchor", "middle")
.text("Force/Temperature"); // Combined axis label
metals.forEach(function(metal) {
var metalData = data.filter(function(d) { return d.Metal === metal; });
svg.append("path")
.datum(metalData.filter(function(d) { return d.Force !== null; }))
.attr("fill", "none")
.attr("stroke", colorScale(metal))
.attr("class", "line-force " + metal)
.attr("stroke-width", 1.5)
.attr("d", lineForce);
svg.append("path")
.datum(metalData.filter(function(d) { return d.Temperature !== null; }))
.attr("fill", "none")
.attr("stroke", colorScale(metal + "-temp"))
.attr("class", "line-temp " + metal)
.attr("stroke-width", 1.5)
.attr("d", lineTemp);
});
});