I have a stacked bar chart here not cooperating.
For some reason. The part where I have my code update is not working.
At this point the code seems fine but I am just not able to get the transition to occur
Anyone know how to do this?
Thanks!
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>US2016</title>
<!-- d3 and plugins -->
<script src="http://d3js.org/d3.v3.js"></script>
<!-- custom css -->
<style type="text/css">
body {
font: 10px sans-serif;
}
</style>
</head>
<body>
<h2>Random</h4>
<div id="stacked-rep"></div>
<script>
var repColors = ['#403153','#9e7742','#0084ab','#e30513'];
var repColorsLight = ['#e5dae7','#deba96','#c5d7e9','#f6b89f'];
var repCandidates = ["Trump", "Cruz", "Rubio", "Kasich"];
var carnival_colors = ["blue", "lightblue"];
//Width and height
var m = {top: 10, right: 10, bottom: 10, left: 10}, // margins
h = 150 - m.left - m.right, // height
w = 960 - m.top - m.bottom; // width
//Create SVG element
var svg = d3.select("#stacked-rep")
.append("svg")
.attr("width", w)
.attr("height", h);
function cumulChart(id, dataset) {
// Set up stack method
var stack = d3.layout.stack();
//Data, stacked
stack(dataset);
// Set up scales
var xScale = d3.scale.ordinal()
.domain(d3.range(dataset[0].length))
.rangeRoundBands([0, h], 0.2); // This is actually the Y scale (candidates)
var yScale = d3.scale.linear()
.domain([0,
d3.sum(dataset, function(d) {return d[0].y;})*1.2
])
.range([0, w]); // This is actually the X Scale (States)
// Add a group for each row of data
var groups = svg.selectAll("g")
.data(dataset)
.enter()
.append("g")
.classed("g_stacked elements", true)
// .attr("class", "g_stacked elements")
.attr("transform", "translate(" + m.left + ",0)");
// Add a rect for each data value
var rects = groups
.selectAll("rect")
.data(function(d) { return d; });
rects.enter()
.append("rect")
.attr("class", "stacked")
.attr("stacked_state", function(d) { return "st"+ d.state; })
.attr("x", function(d) {
return yScale(d.y0);
})
.attr("y", function(d, i) {
return xScale(i);
})
.attr("width", function(d) {
return yScale(d.y);
})
.attr("height", xScale.rangeBand())
.style("fill", function(d, i) {
if (d.state == 19){
return carnival_colors[1];
}
else {
return carnival_colors[0];
}
})
.style("stroke", function(d, i) {
if (d.state == 19){
return d3.rgb(carnival_colors[1]).darker() ;
}
else {
return d3.rgb(carnival_colors[0]).darker() ;
}
})
/*.on("mouseover", function(d) {
console.log(d.state);
})*/;
// transition
rects.transition() // this is to create animations
.duration(500) // 500 millisecond
.ease("bounce")
.delay(500)
// .attr("class", "stacked")
// .attr("stacked_state", function(d) { return "st"+ d.state; })
.attr("x", function(d) {
return yScale(d.y0);
})
.attr("y", function(d, i) {
return xScale(i);
})
.attr("width", function(d) {
return yScale(d.y);
})
.attr("height", xScale.rangeBand());
};
var data = [
[{
"state": 19,
"x": "Trump1",
"y": 2000
}],
[{
"state": 33,
"x": "Trump2",
"y": 3000
}]
];
cumulChart("#stacked-rep", data);
// create a function to randomize things
function rand_it(x){
return Math.floor((Math.random() * x) + 1);
};
setInterval(function(){
var object = [
[{
"state": 19,
"x": "Trump1",
"y": rand_it(20)
}],
[{
"state": 33,
"x": "Trump2",
"y": rand_it(20)
}]
];
cumulChart("#stacked-rep", object);
console.log(object[0][0].y,"---",object[1][0].y);
}, 3000);
</script>
</body>
</html>
Just figured it out.
The data part was not updating in the function.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>US2016</title>
<!-- d3 and plugins -->
<script src="http://d3js.org/d3.v3.js"></script>
<!-- custom css -->
<style type="text/css">
body {
font: 10px sans-serif;
}
</style>
</head>
<body>
<h2>Random</h4>
<div id="stacked-rep"></div>
<script>
var repColors = ['#403153','#9e7742','#0084ab','#e30513'];
var repColorsLight = ['#e5dae7','#deba96','#c5d7e9','#f6b89f'];
var repCandidates = ["Trump", "Cruz", "Rubio", "Kasich"];
var carnival_colors = ["blue", "lightblue"];
//Width and height
var m = {top: 10, right: 10, bottom: 10, left: 10}, // margins
h = 150 - m.left - m.right, // height
w = 960 - m.top - m.bottom; // width
//Create SVG element
var svg = d3.select("#stacked-rep")
.append("svg")
.attr("width", w)
.attr("height", h);
// Add a group for each row of data
var data = [
[{
"state": 19,
"x": "Trump1",
"y": 2000
}],
[{
"state": 33,
"x": "Trump2",
"y": 3000
}]
];
var groups = svg.selectAll("g")
.data(data)
.enter()
.append("g")
.classed("g_stacked_elements", true)
// .attr("class", "g_stacked elements")
.attr("transform", "translate(" + m.left + ",0)");
function cumulChart(id, dataset) {
// Set up stack method
var stack = d3.layout.stack();
//Data, stacked
stack(dataset);
// console.log("the data sum is:", d3.sum(dataset, function(d) {return d[0].y;}));
// Set up scales
var xScale = d3.scale.ordinal()
.domain(d3.range(dataset[0].length))
.rangeRoundBands([0, h], 0.2); // This is actually the Y scale (candidates)
var yScale = d3.scale.linear()
.domain([0,
d3.sum(dataset, function(d) {return d[0].y;})*1.2])
.range([0, w]); // This is actually the X Scale (States)
// console.log(xScale);
// Add a rect for each data value
groups_w_data = svg.selectAll("g")
.data(data);
var rects = groups_w_data
.selectAll("rect")
.data(function(d) { return d; });
rects.enter()
.append("rect")
.attr("class", "stacked")
.attr("stacked_state", function(d) { return "st"+ d.state; })
.attr("x", function(d) {
return yScale(d.y0);
})
.attr("y", function(d, i) {
return xScale(i);
})
.attr("width", function(d) {
return yScale(d.y);
})
.attr("height", xScale.rangeBand())
.style("fill", function(d, i) {
if (d.state == 19){
return carnival_colors[1];
}
else {
return carnival_colors[0];
}
})
.style("stroke", function(d, i) {
if (d.state == 19){
return d3.rgb(carnival_colors[1]).darker() ;
}
else {
return d3.rgb(carnival_colors[0]).darker() ;
}
})
/*.on("mouseover", function(d) {
console.log(d.state);
})*/;
// transition
rects.transition() // this is to create animations
.duration(500) // 500 millisecond
.ease("bounce")
.delay(500)
// .attr("class", "stacked")
// .attr("stacked_state", function(d) { return "st"+ d.state; })
.attr("x", function(d) {
console.log("This is the X value: ", yScale(d.y0));
return yScale(d.y0);
})
.attr("width", function(d) {
console.log("This is the width value: ", yScale(d.y));
return yScale(d.y);
})
};
cumulChart("#stacked-rep", data);
// create a function to randomize things
function rand_it(x){
return Math.floor((Math.random() * x) + 1);
};
setInterval(function(){
var object = [
[{
"state": 19,
"x": "Trump1",
"y": rand_it(20)
}],
[{
"state": 33,
"x": "Trump2",
"y": rand_it(20)
}]
];
data = object;
cumulChart("#stacked-rep", data);
console.log(object[0][0].y,"---",object[1][0].y);
}, 3000);
</script>
</body>
</html>
Related
I want to create a bubble diagram with a vertical and horizontal line. There is also force simulation applied in order not to allow overlaps of bubbles and text.
The diagram should be responsive within a bootstrap container. But when I resize the window the bubbles move out of the visible field and the alignment with the lines is not correct anymore.
I tried multiple combinations of force stengths, but nothing helped. Here is the jsfiddle: jsfiddle - version 1
I tried removing the force simulation part and then it works, but obviously bubbles will now overlap: jsfiddle without force simulation
Can you help me to setup force simulation?
Code for jsfiddle-1:
<!DOCTYPE html>
<html>
<head>
<title>d3 test bubble</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.4.1/css/bootstrap.min.css">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.4.1/js/bootstrap.min.js"></script>
<script src="https://d3js.org/d3.v7.min.js"></script>
</head>
<body>
<!-- d3.js TEST START-->
<div class="container" id="chart-container" style="margin-top: 8vh; ">
<div id="chart" style="height:80vh; width:80vw"></div>
</div>
<script>
var data = [
{x: 1, y: 1, size: 33, name: "Bubble 1A", link: "https://example.com/bubble1"},
{x: 1, y: 1, size: 33, name: "Bubble 1B", link: "https://example.com/bubble1"},
{x: 100, y: 1, size: 55, name: "Bubble 2", link: "https://example.com/bubble2"},
{x: 250, y: 1, size: 20, name: "Bubble 3", link: "https://example.com/bubble3"},
{x: 1, y: 50, size: 30, name: "Bubble 4A", link: "https://example.com/bubble1"},
{x: 1, y: 50, size: 30, name: "Bubble 4B", link: "https://example.com/bubble1"},
{x: 100, y: 100, size: 40, name: "Bubble 5", link: "https://example.com/bubble2"},
{x: 340, y: 200, size: 50, name: "Bubble 6", link: "https://example.com/bubble3"},
{x: 200, y: 800, size: 10, name: "Bubble 7", link: "https://example.com/bubble3"},
];
let xScale_domain_min = -50.0/340.0 *(d3.max(data, function(d) { return d.x; }));//0;//-50;
let xScale_domain_max_add = 50.0/340.0 *(d3.max(data, function(d) { return d.x; })); //0;//+50;
//let xScale_domain_max = 340;
let xScale_domain_max = (d3.max(data, function(d) { return d.x; }));
console.log("xScale_domain_max");
console.log(xScale_domain_max);
let yScale_domain_min = -55.0/800.0 * (d3.max(data, function(d) { return d.y; }));//0;//-55;
let yScale_domain_max_add = 50.0/800.0 * (d3.max(data, function(d) { return d.y; })); //0;//+50;
//let yScale_domain_max = 800;
let yScale_domain_max = (d3.max(data, function(d) { return d.y; }));
let size_domain_max = 55;
// simulation forces
let force_y = 2;
let force_x = 2;
let force_collide = 0.1;
let alpha_target = 0.0001;
var svg = d3.select("#chart").append("svg")
.attr("width", "100%")
.attr("height", "100%");
var xScale = d3.scaleLinear()
.domain([xScale_domain_min, xScale_domain_max + xScale_domain_max_add])
.range([0, d3.select("#chart").node().getBoundingClientRect().width]);
var yScale = d3.scaleLinear()
.domain([yScale_domain_min, yScale_domain_max + yScale_domain_max_add])
.range([d3.select("#chart").node().getBoundingClientRect().height, 0]);
// bubble size scaler:
let sizeScale_min_factor = 0.005;
let sizeScale_max_factor = 0.05;
var sizeScale = d3.scaleLinear()
.domain([0, size_domain_max])
.range([d3.select("#chart").node().getBoundingClientRect().height * sizeScale_min_factor, d3.select("#chart").node().getBoundingClientRect().height * sizeScale_max_factor]);
// append bubbles:
var bubbles = svg.selectAll("circle")
.data(data)
.enter()
.append("circle")
.attr("cx", function(d) { return xScale(d.x); })
.attr("cy", function(d) { return yScale(d.y); })
.attr("r", function(d) { return sizeScale(d.size); })
.style("fill", "blue")
.on("click", function(d) { window.location.href = d.link; });
// force simulation
var simulation = d3.forceSimulation(data)
.force("x", d3.forceX(function(d) { return xScale(d.x); }).strength(force_x))
.force("y", d3.forceY(function(d) { return yScale(d.y); }).strength(force_y))
.force("collide", d3.forceCollide(function(d) { return sizeScale(d.size) ; }).strength(force_collide))
.on("tick", ticked);
//Start the simulation
simulation.alphaTarget(alpha_target).restart();
function ticked() {
bubbles
.attr("cx", function(d) { return d.x; })
.attr("cy", function(d) { return d.y; });
svg.selectAll("text")
.attr("x", function(d) { return d.x; })
.attr("y", function(d) { return d.y; });
}
bubbles.append("title").text(function(d) { return d.name; });
// append text:
svg.selectAll("text")
.data(data)
.enter()
.append("text")
.text(function(d) { return d.name; })
.attr("x", function(d) { return xScale(d.x); })
.attr("y", function(d) { return yScale(d.y) + 1.4*sizeScale(d.size); })
.attr("text-anchor", "middle")
.attr("fill", "white")
.style("font-size", "10px");
// add horizontally line:
// Calculate the average y-value of the data points
var averageY = (yScale_domain_min + yScale_domain_max + yScale_domain_max_add) / 2.0;
// Append the line to the svg
svg.append("line")
.attr("id", "horizontal-line")
.attr("x1", 0)
.attr("y1", yScale(averageY)) // Use the yScale to position the line based on the average y-value
.attr("x2", d3.select("#chart").node().getBoundingClientRect().width)
.attr("y2", yScale(averageY))
.attr("stroke", "red") // set the color of the line
.attr("stroke-width", 0.3); // set the width of the line
// add vertically line:
// Calculate the average y-value of the data points
var averageX = (xScale_domain_min + xScale_domain_max + xScale_domain_max_add) / 2.0;
// Append the line to the svg
svg.append("line")
.attr("id", "vertical-line")
.attr("x1", xScale(averageX))
.attr("y1", 0) // Use the yScale to position the line based on the average y-value
.attr("x2", xScale(averageX))
.attr("y2", d3.select("#chart").node().getBoundingClientRect().height)
.attr("stroke", "red") // set the color of the line
.attr("stroke-width", 0.3); // set the width of the line
//window.addEventListener("resize", updateChart);
window.addEventListener("resize", function() {
updateChart();
});
function updateChart() {
let xScale_domain_min = -50.0/340.0 *(d3.max(data, function(d) { return d.x; }));//0;//-50;
let xScale_domain_max_add = 50.0/340.0 *(d3.max(data, function(d) { return d.x; })); //0;//+50;
let xScale_domain_max = (d3.max(data, function(d) { return d.x; }));
console.log("xScale_domain_max");
console.log(xScale_domain_max);
let yScale_domain_min = -55.0/800.0 * (d3.max(data, function(d) { return d.y; }));//0;//-55;
let yScale_domain_max_add = 50.0/800.0 * (d3.max(data, function(d) { return d.y; })); //0;//+50;
let yScale_domain_max = (d3.max(data, function(d) { return d.y; }));
// Update the scales and any other elements that need to be changed when the window is resized
xScale.range([0, d3.select("#chart").node().getBoundingClientRect().width]);
xScale.domain([xScale_domain_min, xScale_domain_max + xScale_domain_max_add]);
yScale.range([d3.select("#chart").node().getBoundingClientRect().height, 0]);
yScale.domain([yScale_domain_min, yScale_domain_max + yScale_domain_max_add]);
sizeScale.range([d3.select("#chart").node().getBoundingClientRect().height * sizeScale_min_factor, d3.select("#chart").node().getBoundingClientRect().height * sizeScale_max_factor]);
// Update the position and size of the bubbles
simulation.force("x", d3.forceX(function(d) { return xScale(d.x); }).strength(force_x))
.force("y", d3.forceY(function(d) { return yScale(d.y); }).strength(force_y))
.force("collide", d3.forceCollide(function(d) { return sizeScale(d.size) ; }).strength(force_collide));
// update the width and height of the svg element
svg.attr("width", "100%")
.attr("height", "100%");
bubbles
.attr("cx", function(d) { return xScale(d.x); })
.attr("cy", function(d) { return yScale(d.y); })
.attr("r", function(d) { return sizeScale(d.size); });
svg.selectAll("text")
.attr("x", function(d) { return xScale(d.x); })
.attr("y", function(d) { return yScale(d.y); });
// update line horizontally:
// Recalculate the averageX and averageY
var averageX = (xScale_domain_min + xScale_domain_max + xScale_domain_max_add) / 2.0;
var averageY = (yScale_domain_min + yScale_domain_max + yScale_domain_max_add) / 2.0;
// Update the x1, x2, y1, y2 attributes of the line
svg.select("#horizontal-line")
.attr("y1", yScale(averageY))
.attr("y2", yScale(averageY))
.attr("x2", svg.node().getBoundingClientRect().width);
svg.select("#vertical-line")
.attr("x1", xScale(averageX))
.attr("x2", xScale(averageX))
.attr("y2", svg.node().getBoundingClientRect().height);
simulation.alphaTarget(alpha_target).restart();
}
</script>
</body>
</html>
Code for jsfiddle-2:
<!DOCTYPE html>
<html>
<head>
<title>d3 test bubble</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.4.1/css/bootstrap.min.css">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.4.1/js/bootstrap.min.js"></script>
<script src="https://d3js.org/d3.v7.min.js"></script>
</head>
<body>
<!-- d3.js TEST START-->
<div class="container" id="chart-container" style="margin-top: 8vh; ">
<div id="chart" style="height:80vh; width:80vw"></div>
</div>
<script>
var data = [
{x: 1, y: 1, size: 33, name: "Bubble 1A", link: "https://example.com/bubble1"},
{x: 1, y: 1, size: 33, name: "Bubble 1B", link: "https://example.com/bubble1"},
{x: 100, y: 1, size: 55, name: "Bubble 2", link: "https://example.com/bubble2"},
{x: 250, y: 1, size: 20, name: "Bubble 3", link: "https://example.com/bubble3"},
{x: 1, y: 50, size: 30, name: "Bubble 4A", link: "https://example.com/bubble1"},
{x: 1, y: 50, size: 30, name: "Bubble 4B", link: "https://example.com/bubble1"},
{x: 100, y: 100, size: 40, name: "Bubble 5", link: "https://example.com/bubble2"},
{x: 340, y: 200, size: 50, name: "Bubble 6", link: "https://example.com/bubble3"},
{x: 200, y: 800, size: 10, name: "Bubble 7", link: "https://example.com/bubble3"},
];
let xScale_domain_min = -50.0/340.0 *(d3.max(data, function(d) { return d.x; }));//0;//-50;
let xScale_domain_max_add = 50.0/340.0 *(d3.max(data, function(d) { return d.x; })); //0;//+50;
//let xScale_domain_max = 340;
let xScale_domain_max = (d3.max(data, function(d) { return d.x; }));
console.log("xScale_domain_max");
console.log(xScale_domain_max);
let yScale_domain_min = -55.0/800.0 * (d3.max(data, function(d) { return d.y; }));//0;//-55;
let yScale_domain_max_add = 50.0/800.0 * (d3.max(data, function(d) { return d.y; })); //0;//+50;
//let yScale_domain_max = 800;
let yScale_domain_max = (d3.max(data, function(d) { return d.y; }));
let size_domain_max = 55;
// simulation forces
let force_y = 2;
let force_x = 2;
let force_collide = 0.1;
let alpha_target = 0.0001;
var svg = d3.select("#chart").append("svg")
.attr("width", "100%")
.attr("height", "100%");
var xScale = d3.scaleLinear()
.domain([xScale_domain_min, xScale_domain_max + xScale_domain_max_add])
.range([0, d3.select("#chart").node().getBoundingClientRect().width]);
var yScale = d3.scaleLinear()
.domain([yScale_domain_min, yScale_domain_max + yScale_domain_max_add])
.range([d3.select("#chart").node().getBoundingClientRect().height, 0]);
// bubble size scaler:
let sizeScale_min_factor = 0.005;
let sizeScale_max_factor = 0.05;
var sizeScale = d3.scaleLinear()
.domain([0, size_domain_max])
.range([d3.select("#chart").node().getBoundingClientRect().height * sizeScale_min_factor, d3.select("#chart").node().getBoundingClientRect().height * sizeScale_max_factor]);
// append bubbles:
var bubbles = svg.selectAll("circle")
.data(data)
.enter()
.append("circle")
.attr("cx", function(d) { return xScale(d.x); })
.attr("cy", function(d) { return yScale(d.y); })
.attr("r", function(d) { return sizeScale(d.size); })
.style("fill", "blue")
.on("click", function(d) { window.location.href = d.link; });
bubbles.append("title").text(function(d) { return d.name; });
// append text:
svg.selectAll("text")
.data(data)
.enter()
.append("text")
.text(function(d) { return d.name; })
.attr("x", function(d) { return xScale(d.x); })
.attr("y", function(d) { return yScale(d.y) + 1.4*sizeScale(d.size); })
.attr("text-anchor", "middle")
.attr("fill", "white")
.style("font-size", "10px");
// add horizontally line:
// Calculate the average y-value of the data points
var averageY = (yScale_domain_min + yScale_domain_max + yScale_domain_max_add) / 2.0;
// Append the line to the svg
svg.append("line")
.attr("id", "horizontal-line")
.attr("x1", 0)
.attr("y1", yScale(averageY)) // Use the yScale to position the line based on the average y-value
.attr("x2", d3.select("#chart").node().getBoundingClientRect().width)
.attr("y2", yScale(averageY))
.attr("stroke", "red") // set the color of the line
.attr("stroke-width", 0.3); // set the width of the line
// add vertically line:
// Calculate the average y-value of the data points
var averageX = (xScale_domain_min + xScale_domain_max + xScale_domain_max_add) / 2.0;
// Append the line to the svg
svg.append("line")
.attr("id", "vertical-line")
.attr("x1", xScale(averageX))
.attr("y1", 0) // Use the yScale to position the line based on the average y-value
.attr("x2", xScale(averageX))
.attr("y2", d3.select("#chart").node().getBoundingClientRect().height)
.attr("stroke", "red") // set the color of the line
.attr("stroke-width", 0.3); // set the width of the line
//window.addEventListener("resize", updateChart);
window.addEventListener("resize", function() {
updateChart();
});
function updateChart() {
let xScale_domain_min = -50.0/340.0 *(d3.max(data, function(d) { return d.x; }));//0;//-50;
let xScale_domain_max_add = 50.0/340.0 *(d3.max(data, function(d) { return d.x; })); //0;//+50;
let xScale_domain_max = (d3.max(data, function(d) { return d.x; }));
console.log("xScale_domain_max");
console.log(xScale_domain_max);
let yScale_domain_min = -55.0/800.0 * (d3.max(data, function(d) { return d.y; }));//0;//-55;
let yScale_domain_max_add = 50.0/800.0 * (d3.max(data, function(d) { return d.y; })); //0;//+50;
let yScale_domain_max = (d3.max(data, function(d) { return d.y; }));
// Update the scales and any other elements that need to be changed when the window is resized
xScale.range([0, d3.select("#chart").node().getBoundingClientRect().width]);
xScale.domain([xScale_domain_min, xScale_domain_max + xScale_domain_max_add]);
yScale.range([d3.select("#chart").node().getBoundingClientRect().height, 0]);
yScale.domain([yScale_domain_min, yScale_domain_max + yScale_domain_max_add]);
sizeScale.range([d3.select("#chart").node().getBoundingClientRect().height * sizeScale_min_factor, d3.select("#chart").node().getBoundingClientRect().height * sizeScale_max_factor]);
// update the width and height of the svg element
svg.attr("width", "100%")
.attr("height", "100%");
bubbles
.attr("cx", function(d) { return xScale(d.x); })
.attr("cy", function(d) { return yScale(d.y); })
.attr("r", function(d) { return sizeScale(d.size); });
svg.selectAll("text")
.attr("x", function(d) { return xScale(d.x); })
.attr("y", function(d) { return yScale(d.y); });
// update line horizontally:
// Recalculate the averageX and averageY
var averageX = (xScale_domain_min + xScale_domain_max + xScale_domain_max_add) / 2.0;
var averageY = (yScale_domain_min + yScale_domain_max + yScale_domain_max_add) / 2.0;
// Update the x1, x2, y1, y2 attributes of the line
svg.select("#horizontal-line")
.attr("y1", yScale(averageY))
.attr("y2", yScale(averageY))
.attr("x2", svg.node().getBoundingClientRect().width);
svg.select("#vertical-line")
.attr("x1", xScale(averageX))
.attr("x2", xScale(averageX))
.attr("y2", svg.node().getBoundingClientRect().height);
}
</script>
</body>
</html>
Thanks for reading. I am new to using the d3js library. I want to generate directed and ordered graphs on the x-axis and y-axis. For this I start from a json format where I specify the nodes and their location, as well as the links between them as you can see in the code.
However, I am not getting the links between the nodes rendered based on the json. Any help?
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<title>[D3] Force + Drag + Zoom</title>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<meta name="robots" content="noindex, nofollow">
<meta name="googlebot" content="noindex, nofollow">
<meta name="viewport" content="width=device-width, initial-scale=1">
<script type="text/javascript" src="http://d3js.org/d3.v3.min.js"></script>
<style id="compiled-css" type="text/css">
.node {
fill:#ccc;
stroke: #fff;
stroke-width: 2px;
}
.node-active {
stroke: #555;
stroke-width: 1.5px;
}
.link-active {
stroke-opacity: 1;
}
line {
stroke: rgb(212, 212, 212);
stroke-width: 1px;
shape-rendering: crispEdges;
}
.overlay {
fill: none;
pointer-events: all;
}
.link{
stroke: #ccc;
stroke-width: 4px;
}
svg {
box-sizing: border-box;
border: 1px solid rgb(212, 212, 212);
}
</style>
<body>
<script src="https://d3js.org/d3.v3.min.js" charset="utf-8"></script>
<script>
var width = 960,
height = 500,
resolution = 150,
r = 15;
var graph = {
"nodes": [
{"task": "1", "x": "150", "y": "450"},
{"task": "2", "x": "300", "y": "150"},
{"task": "3", "x": "450", "y": "300"}
],
"links": [
{"source": "1", "target": "2", "value": 3},
{"source": "2", "target": "3", "value": 3},
{"source": "1", "target": "3", "value": 3}
]
}
var margin = {
top: -5,
right: -5,
bottom: -5,
left: -5};
var color = d3.scale.category20();
var force = d3.layout.force()
.charge(-200)
.linkDistance(50)
.size([width + margin.left + margin.right, height + margin.top + margin.bottom]);
var drag = d3.behavior.drag()
.origin(function(d) { return d; })
.on('drag', dragged);
var svg = d3.select('body').append('svg')
.attr('width', width)
.attr('height', height)
.append("g");
var container = svg.append("g");
//force.links(graph.links)
// .start();
svg.selectAll('.vertical')
.data(d3.range(1, width / resolution))
.enter().append('line')
.attr('class', 'vertical')
.attr('x1', function(d) { return d * resolution; })
.attr('y1', 0)
.attr('x2', function(d) { return d * resolution; })
.attr('y2', height);
svg.selectAll('.horizontal')
.data(d3.range(1, height / resolution))
.enter().append('line')
.attr('class', 'horizontal')
.attr('x1', 0)
.attr('y1', function(d) { return d * resolution; })
.attr('x2', width)
.attr('y2', function(d) { return d * resolution; });
var link = container.append("g")
.attr('class', 'link')
.selectAll('.link')
.data(graph.links)
.enter().append('line')
.attr("marker-end", "url(#end)")
.style("stroke-width", function(d) {
return Math.sqrt(d.value);
});
var node = container.append("g")
.attr("class", "node")
.selectAll(".node")
.data(graph.nodes)
.enter().append('circle')
.attr('cx', function(d) { return d.x; })
.attr('cy', function(d) { return d.y; })
.attr('r', r)
.call(drag);
node.append("circle")
.attr("r", function (d) {
return d.weight * 2 + 12;
})
.style("fill", function (d) { return color(1 / d.task); });
force.on("tick", function () {
link.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;
});
/*node.attr("transform", function (d) {
return "translate(" + d.x + "," + d.y + ")";
});*/
});
var linkedByIndex = {};
graph.links.forEach(function (d) {
linkedByIndex[d.source.index + "," + d.target.index] = 1;
});
function isConnected(a, b) {
return linkedByIndex[a.index + "," + b.index] || linkedByIndex[b.index + "," + a.index];
}
node.on("mouseover", function (d) {
node.classed("node-active", function (o) {
thisOpacity = isConnected(d, o) ? true : false;
this.setAttribute('fill-opacity', thisOpacity);
return thisOpacity;
});
link.classed("link-active", function (o) {
return o.source === d || o.target === d ? true : false;
});
d3.select(this).classed("node-active", true);
d3.select(this).select("circle").transition()
.duration(750)
.attr("r", (d.weight * 2 + 12) * 1.5);
})
.on("mouseout", function (d) {
node.classed("node-active", false);
link.classed("link-active", false);
d3.select(this).select("circle").transition()
.duration(750)
.attr("r", d.weight * 2 + 12);
});
function dragged(d) {
var x = d3.event.x,
y = d3.event.y,
gridX = round(Math.max(r, Math.min(width - r, x)), resolution),
gridY = round(Math.max(r, Math.min(height - r, y)), resolution);
d3.select(this).attr('cx', d.x = gridX).attr('cy', d.y = gridY);
}//
function round(p, n) {
return p % n < n / 2 ? p - (p % n) : p + n - (p % n);
}
</script>
</body>
The links between your nodes are not showing up because you didn't specify the x1, x2, y1, and y2 attributes, which are needed to display a line.
There is also a circle that's created incorrectly within a circle, and its attribute r is not correctly defined. The program throws:
Error: attribute r: Expected length, "NaN".
I'm not sure what that is for, so I commented it out. The following code should display the links now:
Update: Now the links will be displayed correctly when you drag!
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<title>[D3] Force + Drag + Zoom</title>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<meta name="robots" content="noindex, nofollow">
<meta name="googlebot" content="noindex, nofollow">
<meta name="viewport" content="width=device-width, initial-scale=1">
<script type="text/javascript" src="http://d3js.org/d3.v3.min.js"></script>
<style id="compiled-css" type="text/css">
.node {
fill:#ccc;
stroke: #fff;
stroke-width: 2px;
}
.node-active {
stroke: #555;
stroke-width: 1.5px;
}
.link-active {
stroke-opacity: 1;
}
line {
stroke: rgb(212, 212, 212);
stroke-width: 1px;
shape-rendering: crispEdges;
}
.overlay {
fill: none;
pointer-events: all;
}
.link{
stroke: #ccc;
stroke-width: 4px;
}
svg {
box-sizing: border-box;
border: 1px solid rgb(212, 212, 212);
}
</style>
<body>
<script src="https://d3js.org/d3.v3.min.js" charset="utf-8"></script>
<script>
var width = 960,
height = 500,
resolution = 150,
r = 15;
var graph = {
"nodes": [
{"task": "1", "x": "150", "y": "450"},
{"task": "2", "x": "300", "y": "150"},
{"task": "3", "x": "450", "y": "300"}
],
"links": [
{"source": "1", "target": "2", "value": 3},
{"source": "2", "target": "3", "value": 3},
{"source": "1", "target": "3", "value": 3}
]
}
var margin = {
top: -5,
right: -5,
bottom: -5,
left: -5
};
var color = d3.scale.category20();
var force = d3.layout.force()
.charge(-200)
.linkDistance(50)
.size([width + margin.left + margin.right, height + margin.top + margin.bottom]);
var drag = d3.behavior.drag()
.origin(function(d) { return d; })
.on('drag', dragged);
var svg = d3.select('body').append('svg')
.attr('width', width)
.attr('height', height)
.append("g");
var container = svg.append("g");
//force.links(graph.links)
// .start();
svg.selectAll('.vertical')
.data(d3.range(1, width / resolution))
.enter().append('line')
.attr('class', 'vertical')
.attr('x1', function(d) { return d * resolution; })
.attr('y1', 0)
.attr('x2', function(d) { return d * resolution; })
.attr('y2', height);
svg.selectAll('.horizontal')
.data(d3.range(1, height / resolution))
.enter().append('line')
.attr('class', 'horizontal')
.attr('x1', 0)
.attr('y1', function(d) { return d * resolution; })
.attr('x2', width)
.attr('y2', function(d) { return d * resolution; });
var link = container.append("g")
.attr('class', 'link')
.selectAll('.link')
.data(graph.links)
.enter().append('line')
.attr("data-source", function (d) {
return d.source;
})
.attr("data-target", function (d) {
return d.target;
})
.attr("x1", function (d) {
for (let node of graph.nodes) {
if (node.task === d.source)
return node.x;
}
})
.attr("x2", function (d) {
for (let node of graph.nodes) {
if (node.task === d.target)
return node.x;
}
})
.attr("y1", function (d) {
for (let node of graph.nodes) {
if (node.task === d.source)
return node.y;
}
})
.attr("y2", function (d) {
for (let node of graph.nodes) {
if (node.task === d.target)
return node.y;
}
})
.attr("marker-end", "url(#end)")
.style("stroke-width", function(d) {
return Math.sqrt(d.value);
});
var node = container.append("g")
.attr("class", "node")
.selectAll(".node")
.data(graph.nodes)
.enter().append('circle')
.attr('cx', function(d) { return d.x; })
.attr('cy', function(d) { return d.y; })
.attr('r', r)
.call(drag);
/*
node.append("circle")
.attr("r", function (d) {
return d.weight * 2 + 12;
})
.style("fill", function (d) { return color(1 / d.task); });
*/ // I'm not sure what this part is for
force.on("tick", function () {
link.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;
});
/*node.attr("transform", function (d) {
return "translate(" + d.x + "," + d.y + ")";
});*/
});
var linkedByIndex = {};
graph.links.forEach(function (d) {
linkedByIndex[d.source.index + "," + d.target.index] = 1;
});
function isConnected(a, b) {
return linkedByIndex[a.index + "," + b.index] || linkedByIndex[b.index + "," + a.index];
}
node.on("mouseover", function (d) {
node.classed("node-active", function (o) {
thisOpacity = isConnected(d, o) ? true : false;
this.setAttribute('fill-opacity', thisOpacity);
return thisOpacity;
});
link.classed("link-active", function (o) {
return o.source === d || o.target === d ? true : false;
});
d3.select(this).classed("node-active", true);
d3.select(this).select("circle").transition()
.duration(750)
.attr("r", (d.weight * 2 + 12) * 1.5);
})
.on("mouseout", function (d) {
node.classed("node-active", false);
link.classed("link-active", false);
d3.select(this).select("circle").transition()
.duration(750)
.attr("r", d.weight * 2 + 12);
});
function dragged(d) {
var x = d3.event.x,
y = d3.event.y,
gridX = round(Math.max(r, Math.min(width - r, x)), resolution),
gridY = round(Math.max(r, Math.min(height - r, y)), resolution);
d3.select(this).attr('cx', d.x = gridX).attr('cy', d.y = gridY);
d3.selectAll(`[data-source='${d.task}']`).attr('x1', d.x).attr('y1', d.y);
d3.selectAll(`[data-target='${d.task}']`).attr('x2', d.x).attr('y2', d.y);
}
function round(p, n) {
return p % n < n / 2 ? p - (p % n) : p + n - (p % n);
}
</script>
</body>
I am a newbie in d3, the following is my input json file,
{
"y_axis_list":["A","B","C","D","E","F","G"],
"Points":[
{
"y": "A",
"x": 10,
"Persona":["link1"]
},
{
"y" : "B",
"x": 20,
"Persona":["link2","link1"]
},
{
"y" : "C",
"x": 30,
"Persona":["link2","link3"]
},
{
"y" : "D",
"x": 40,
"Persona":["link2","link3"]
},
{
"y" : "E",
"x" : 50,
"Persona":["link5","link6"]
},
{
"y" : "F",
"x" : 60,
"Persona":["link7","link8"]
},
{
"y" : "G",
"x" : 70,
"Persona":["link9","link10"]
}
]
}
the following is my code:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge"/>
<title>D3 v4 - linechart</title>
<style>
#graph {
width: 900px;
height: 500px;
}
.tick line {
stroke-dasharray: 2 2 ;
stroke: #ccc;
}
.x{
display: none;
}
.y path{
fill: none;
stroke: none;
/* set the CSS */
}
.line {
fill: none;
stroke: steelblue;
stroke-width: 2px;
}
div.tooltip {
position: absolute;
text-align: center;
width: 60px;
height: 28px;
padding: 2px;
font: 12px sans-serif;
background: lightsteelblue;
border: 0px;
border-radius: 8px;
pointer-events: none;
}
</style>
</head>
<body>
<div id="graph"></div>
<script src="https://d3js.org/d3.v4.min.js"></script>
<script>
!(function(){
"use strict"
var width,height
var chartWidth, chartHeight
var margin
var svg = d3.select("#graph").append("svg")
var axisLayer = svg.append("g").classed("axisLayer", true)
var chartLayer = svg.append("g").classed("chartLayer", true)
var xScale = d3.scaleLinear()
var yScale = d3.scalePoint()
var align = 0
var i=10;
//d3.tsv("data1.tsv", cast, main)
d3.json("http://localhost/newest.json",cast)
//データの方変換
function cast(datafull) {
console.log("got it");
var data=datafull["Points"];enter code here
data.forEach(function(data) {
console.log(data.y);
data.y = data.y;
data.x = +data.x;
});
main(data,datafull);
}
function main(data,datafull) {
console.log("in main");
setSize(data,datafull)
drawAxis()
drawChart(data,datafull)
}
function setSize(data,datafull) {
width = document.querySelector("#graph").clientWidth
height = document.querySelector("#graph").clientHeight
margin = {top:40, left:100, bottom:40, right:0 }
chartWidth = width - (margin.left+margin.right+8)
chartHeight = height - (margin.top+margin.bottom)
svg.attr("width", width).attr("height", height)
axisLayer.attr("width", width).attr("height", height)
chartLayer
.attr("width", chartWidth)
.attr("height", chartHeight)
.attr("transform", "translate("+[margin.left, margin.top]+")")
xScale.domain([0, d3.max(data, function(d) { return d.x; })]).range([0,chartWidth])
yScale.domain(datafull["y_axis_list"]).range([chartHeight, 0]).align(1)
}
function drawChart(data,datafull) {
console.log("in drawChart");
var t = d3.transition()
.duration(4000)
.ease(d3.easeLinear)
.on("start", function(d){ console.log("transiton start") })
.on("end", function(d){ console.log("transiton end") });
// var tooltip = d3.tip().attr('class', 'd3-tip').html(function(d) { return 10; });
var div = d3.select("body").append("div")
.attr("class", "tooltip")
.style("opacity", 0);
var lineGen = d3.line()
.x(function(d) { i=i+50;console.log(i); return xScale(d.x); })
.y(function(d) { return yScale(d.y) })
.curve(d3.curveStepAfter)
var line = chartLayer.selectAll(".line")
.data([data])
line.enter().append("path").classed("line", true)
.merge(line)
.attr("d", lineGen)
.attr("fill", "none")
.attr("stroke", "blue")
.attr("stroke-width","2px")
.attr("stroke-dasharray", function(d){ return this.getTotalLength() })
.attr("stroke-dashoffset", function(d){ return this.getTotalLength() })
chartLayer.selectAll(".line").transition(t)
.attr("stroke-dashoffset", 0)
var img = chartLayer.selectAll('image')
.data(data)
.enter()
.append('image')
.attr("class","logo")
.attr("xlink:href", "http://localhost/whatsapp-logo.jpg" )
.attr("x", function(d,i){ return xScale(d.x+5/2) })
.attr("y", function(d,i){ return yScale(d.y) })
.attr("width", 16)
.attr("height", 16)
.style("opacity",0);
img.transition().delay(4000).duration(500).ease(d3.easeLinear).style("opacity",1);
img.on("mouseover", function(d) {
div.transition()
.duration(200)
.style("opacity", .9);
div.html("Persona people" + "<br/>" + d.x)
.style("left", (d3.event.pageX) + "px")
.style("top", (d3.event.pageY - 28) + "px");
})
.on("mouseout", function(d) {
div.transition()
.duration(500)
.style("opacity", 0);
});
chartLayer.selectAll("circle").classed("circle",true)
.data(data)
.enter().append("circle")
.attr("class", "circle")
.attr("fill","none")
.attr("stroke","black")
.attr("cx", function(d) { return xScale(d.x); })
.attr("cy", function(d) { return yScale(d.y); })
.attr("r", 4)
}
function drawAxis(){
var yAxis = d3.axisLeft(yScale)
.tickSizeInner(-chartWidth)
axisLayer.append("g")
.attr("transform", "translate("+[margin.left, margin.top]+")")
.attr("class", "axis y")
.call(yAxis);
var xAxis = d3.axisBottom(xScale)
axisLayer.append("g")
.attr("class", "axis x")
.attr("transform", "translate("+[margin.left, chartHeight+margin.top]+")")
.call(xAxis);
}
function update(){
}
}());
</script>
</body>
</html>
I want the images given in the persona list to appear in the same line as that of the y coordinate in the json with x-axis changing minutely. The links are the links to images which are to be loaded.
I went through a lot of questions, but I was not able to figure out the method to do that.
My current output is given below.
Now there is one image in each line, I want the number of images in persona list (input json) to appear in each of the corresponding lines.
Rewrite your img variable this way (pay attention to the comments):
var img = chartLayer
.selectAll('g')
.data(data)
.enter()
.append('g') // append g element, here we will be append image as child
.attr("transform", function(d, i) {
var x = xScale(d.x + 5 / 2);
var y = yScale(d.y);
return 'translate(' + x + ', ' + y + ')'
})
.selectAll('image')
.data(function(d) { // here we format data as we need
return d.Persona.map(function(icon, index) {
return {
icon: icon,
tooltipText: d.Text[index] // set tooltip text
}
})
})
.enter()
.append('image') // append image element
.attr("class", "logo")
.attr("xlink:href", function(d) { // set appropriate href attribute
return d.icon;
})
.attr("x", function(d, i) { // move image by index
return 20 * i;
})
.attr("width", 16)
.attr("height", 16)
.style("opacity", 0);
...
img.on("mouseover", function(d) {
div.transition()
.duration(200)
.style("opacity", .9);
div.html("Persona people" + "<br/>" + d.tooltipText) // get tooltip text
.style("left", (d3.event.pageX) + "px")
.style("top", (d3.event.pageY - 28) + "px");
})
...
Look at the working example - https://jsfiddle.net/levsha/og92k0gv/
I am trying to have an standard and inverse bar graph conjoined. The way I went about it currently is creating two separate graphs then going to align the bottom of one and the top of the other. The issue is I can't seem to get them aligned correctly. I'm sure there's a better way to go about this. I thought about parsing one of the data amounts into negative numbers then displaying the positive number on the screen. This direction would involve stacking the bars first and foremost which I can do. I just am not sure how to create the negative space for positive data values, which is why I am doing the two separate graphs.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>D3 Example</title>
<script src="//cdnjs.cloudflare.com/ajax/libs/d3/3.5.5/d3.min.js"></script>
<link href='https://fonts.googleapis.com/css?family=Open+Sans' rel='stylesheet' type='text/css'>
<style>
.axis text {
font-family: 'Open Sans', sans-serif;
font-size: 12pt;
}
.axis .label {
font-size: 20pt;
}
.x.axis path, .x.axis line {
stroke-width:2;
stroke: #EBEBED;
shape-rendering: crispEdges;
}
.x.axis text{ font-weight: 500; transform:translate(0px,14px);stroke:#c7c7c7}
</style>
</head>
<body>
<script>
var outerWidth = 500;
var outerHeight = 120;
var margin = { left: 90, top: 30, right: 30, bottom: 0 };
var barPadding = 0.2;
var xColumn = "date";
var yColumn = "amount";
var colorColumn = "barv";
var layerColumn = colorColumn;
var innerWidth = outerWidth - margin.left - margin.right;
var innerHeight = outerHeight - margin.top - margin.bottom;
var svg = d3.select("body").append("svg")
.attr("width", outerWidth)
.attr("height", outerHeight);
var g = svg.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
var xAxisG = g.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + innerHeight + ")");
var yAxisG = g.append("g")
.attr("class", "y axis");
var xScale = d3.scale.ordinal().rangeBands([0, innerWidth], barPadding);
var yScale = d3.scale.linear().range([innerHeight,0]).nice();
var colorScale = d3.scale.ordinal()
.domain(["top"])
.range([ "#43B365" ])
var xAxis = d3.svg.axis().scale(xScale).orient("bottom")
.outerTickSize(0).ticks(0).tickSize(0);
var yAxis = d3.svg.axis().scale(yScale).orient("left")
.ticks(0)
.outerTickSize(0);
function render(data){
var nested = d3.nest()
.key(function (d){ return d[layerColumn]; })
.entries(data)
var stack = d3.layout.stack()
.y(function (d){ return d[yColumn]; })
.values(function (d){ return d.values; });
var layers = stack(nested);
xScale.domain( data.map( function (d){ return d[xColumn]; }));
yScale.domain([
0,
d3.max(data, function (d){ return d[yColumn]; })
]);
colorScale.domain(layers.map(function (layer){
return layer.key;
}));
xAxisG.call(xAxis);
yAxisG.call(yAxis);
var layerGroups = g.selectAll(".layer").data(layers);
layerGroups.enter().append("g").attr("class", "layer");
layerGroups.exit().remove();
layerGroups.style("fill", function (d){
return colorScale(d.key);
});
var bars = layerGroups.selectAll("rect").data(function (d){
return d.values;
});
bars.enter().append("rect")
bars.exit().remove();
bars
.attr("x", function (d){ return xScale(d[xColumn]); })
.attr("y", function (d){ return yScale(d.y0 + d.y); })
.attr("width", xScale.rangeBand()*.2)
.attr("height", function (d){ return innerHeight - yScale(d.y); })
.attr("ry", 2);
var texty = g.selectAll("text.bar").data(data);
texty.enter().append("text")
.attr("class", "bar")
.attr("text-anchor", "middle")
.attr("x", function(d) { return xScale(d.date); })
.attr("y", function(d) { return yScale(d.amount) - 10; })
.text(function(d) { return d.amount; });
}
var data = [
{
"date": "5/1/16",
"amount": 1098,
"barv": "top"
},
{
"date": "5/8/16",
"amount": 30,
"barv": "top"
},
{
"date": "5/16/16",
"amount": 2504,
"barv": "top"
},
{
"date": "5/24/16",
"amount": 560,
"barv": "top"
}
];
render(data);
//*****SECOND PART
var outerWidth = 500;
var outerHeight = 100;
var margin = { left: 90, top: -10, right: 30, bottom: 40 };
var barPadding = 0.2;
var xColumn = "date";
var yColumn = "amount";
var colorColumn = "barv";
var layerColumn = colorColumn;
var innerWidth = outerWidth - margin.left - margin.right;
var innerHeight = outerHeight - margin.top - margin.bottom;
var svg = d3.select("body").append("svg")
.attr("width", outerWidth)
.attr("height", outerHeight);
var g = svg.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
var xAxisG = g.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + innerHeight + ")");
var yAxisG = g.append("g")
.attr("class", "y axis");
var xScale = d3.scale.ordinal().rangeBands([0, innerWidth], barPadding);
var yScale = d3.scale.linear().range([0,innerHeight]).nice();
var colorScale = d3.scale.ordinal()
.domain(["bot"])
.range(["#DA5A60" ])
var xAxis = d3.svg.axis().scale(xScale).orient("bottom")
.outerTickSize(0).ticks(0).tickSize(0);
var yAxis = d3.svg.axis().scale(yScale).orient("left")
.ticks(0)
.outerTickSize(0);
function renders(data){
var nested = d3.nest()
.key(function (d){ return d[layerColumn]; })
.entries(data)
var stack = d3.layout.stack()
.y(function (d){ return d[yColumn]; })
.values(function (d){ return d.values; });
var layers = stack(nested);
xScale.domain( data.map( function (d){ return d[xColumn]; }));
yScale.domain([
0,
d3.max(data, function (d){ return d[yColumn]; })
]);
colorScale.domain(layers.map(function (layer){
return layer.key;
}));
xAxisG.call(xAxis);
yAxisG.call(yAxis);
var layerGroups = g.selectAll(".layer").data(layers);
layerGroups.enter().append("g").attr("class", "layer");
layerGroups.exit().remove();
layerGroups.style("fill", function (d){
return colorScale(d.key);
});
var bars = layerGroups.selectAll("rect").data(function (d){
return d.values;
});
bars.enter().append("rect")
bars.exit().remove();
bars
.attr("x", function (d){ return xScale(d[xColumn]); })
.attr("y", 0)
.attr("width", xScale.rangeBand()*.2)
.attr("height", function (d){ return yScale(d[yColumn]); })
.attr("ry", 2);
var texty = g.selectAll("text.bar").data(data);
texty.enter().append("text")
.attr("class", "bar")
.attr("text-anchor", "middle")
.attr("x", function(d) { return xScale(d.date); })
.attr("y", function(d) { return yScale(d.amount) - 10; })
.text(function(d) { return d.amount; });
}
var data = [
{
"date": "5/1/16",
"amount": 34,
"barv": "bot"
},
{
"date": "5/8/16",
"amount": 12,
"barv": "bot"
},
{
"date": "5/16/16",
"amount": 47,
"barv": "bot"
},
{
"date": "5/24/16",
"amount": 11,
"barv": "bot"
}
];
renders(data);
</script>
</body>
Here are a few resources I have tried to implement but with no success.
http://jsfiddle.net/philgyford/LjxaV/2/
http://jsfiddle.net/chrisJamesC/tNdJj/4/
http://jsfiddle.net/5hzxegxx/2/
http://bl.ocks.org/larskotthoff/601c66edfb83a11cf2bb
Thanks
UPDATE I updated the code. I was able to figure out the alignment issue and the text appearing. The only issue is the tick labels are not aligned correctly to the bars and there is still space in between graphs.
i'm using d3.js's stacked-to-grouped bar graph. i've modified the example's randomized data generator. and now it's not reading my csv file properly.
the final graph will have:
x-axis determined by date
y-axis determined by hours* or weeks or months
*my naming convention for hours is "dnh".
code below. thanks for your help!:
var data = [];
var dataByDay = [];
d3.csv('data/friday.csv', function(myData) {
// console.log(myData);
return {
date: myData.date,
dnh: +myData.dnh
};
}, function(myData) {
data = myData;
// console.log(myData[0]);
});
function doBarChart() {
var n = 4, // number of layers
m = 30, // number of samples per layer (m will be equal to my x values (time))
stack = d3.layout.stack(),
layers = stack(d3.range(n).map(function() {
return bumpLayer(m, .1);
})),
yGroupMax = d3.max(layers, function(layer) {
return d3.max(layer, function(d) {
return d.y;
});
}), // algorithm for grouped passing through y data values
yStackMax = d3.max(layers, function(layer) {
return d3.max(layer, function(d) {
return d.y0 + d.y;
});
}); // algorithm for stacked passing through y values
var margin = {
top: 40,
right: 10,
bottom: 20,
left: 10
}, // "canvas" setup
width = 960 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom;
var x = d3.scale.ordinal() // setup for the rangeBands / rangeBand (fitting values to the canvas width that we have)
.domain(d3.range(m))
.rangeRoundBands([0, width], .08); // check reference on rangeRound behavior
var y = d3.scale.linear() // nb: do not need to change to time scale. unix has already been converted & t = 0 - 29
.domain([0, yStackMax])
.range([height, 0]); // question: what is the 0 value? does it resituate stacks on x = 0?
var color = d3.scale.linear()
.domain([0, n - 1])
.range(["#aad", "#556"]);
var xAxis = d3.svg.axis() // defines x-axis, situates it as the bottom (x) and not left (y)
.scale(x) // passing x values through ordinal scale
.tickSize(0)
.tickPadding(6)
.orient("bottom");
var svg = d3.select("body").append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
var layer = svg.selectAll(".layer") // !!!! layers = ?
.data(layers) // layers passed through database
.enter().append("g") // adding graphic
.attr("class", "layer") // selectAll is being applied here
.style("fill", function(d, i) {
return color(i);
}); // clarify: i = index of data
var rect = layer.selectAll("rect") // rect = actual bars
.data(function(d) {
return d;
})
.enter().append("rect")
.attr("x", function(d) {
return x(d.x);
})
.attr("y", height)
.attr("width", x.rangeBand())
.attr("height", 0);
// -------------------------------------------------------------------------------------- testing tooltip fx
// var tooltip = d3.select('body').append('div')
// .style('position','absolute')
// .style('padding', '0 10px')
// .style('background', 'white')
// .style('opacity', 0)
// ---------------------------------------------------------------------------------------------------------
rect.transition()
.delay(function(d, i) {
return i * 10;
})
.attr("y", function(d) {
return y(d.y0 + d.y);
})
.attr("height", function(d) {
return y(d.y0) - y(d.y0 + d.y);
});
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
d3.selectAll("input").on("change", change);
var timeout = setTimeout(function() {
d3.select("input[value=\"grouped\"]").property("checked", true).each(change);
}, 2000);
function change() {
clearTimeout(timeout);
if (this.value === "grouped") transitionGrouped();
else transitionStacked();
}
// ---------------------------------------------------------------------- transition fx : grouped + stacked
function transitionGrouped() {
y.domain([0, yGroupMax]);
rect.transition()
.duration(500)
.delay(function(d, i) {
return i * 10;
})
.attr("x", function(d, i, j) {
return x(d.x) + x.rangeBand() / n * j;
})
.attr("width", x.rangeBand() / n)
.transition()
.attr("y", function(d) {
return y(d.y);
})
.attr("height", function(d) {
return height - y(d.y);
});
}
function transitionStacked() {
y.domain([0, yStackMax]);
rect.transition()
.duration(500)
.delay(function(d, i) {
return i * 10;
})
.attr("y", function(d) {
return y(d.y0 + d.y);
})
.attr("height", function(d) {
return y(d.y0) - y(d.y0 + d.y);
})
.transition()
.attr("x", function(d) {
return x(d.x);
})
.attr("width", x.rangeBand());
}
// ---------------------------------------------------------------------------------------------------------
// ! testing : on mouseOver function for tooltip !
// tooltip.on('mouseover'), function(d){
// tooltip.transition()
// .style('opacity', .9)
//
// tooltip.html(d)
// .style('left', (d3.event.pageX) + 'px' )
// .style('top', (d3.event.pageY) + 'px')
// }
// ---------------------------------------------------------------------------------------------------------
function bumpLayer(n, o) {
console.log("print o");
var a = [],
i;
for (i = 0; i < n; ++i) a[i] = data[i].date; //o + o * Math.random();
// for (i = 0; i < 5; ++i){
// for (j = 0; j < n; ++j)
// a[j] = .25;
// }
// bump(a);
return a.map(function(d, i) {
return {
x: i,
y: Math.max(0, d)
};
});
}
}
body {
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
margin: auto;
position: relative;
width: 960px;
}
text {
font: 10px sans-serif;
}
.axis path,
.axis line {
fill: none;
stroke: #000;
shape-rendering: crispEdges;
}
form {
position: absolute;
right: 10px;
top: 10px;
}
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>hellotest</title>
<link rel="stylesheet" href="css/style.css">
<form>
<label>
<input type="radio" name="mode" value="grouped">Grouped</label>
<label>
<input type="radio" name="mode" value="stacked">Stacked</label>
</form>
</head>
<body>
<script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script>
<script src="js/testindex.js"></script>
</body>
</html>
d3.csv is asynchronous. I see that you made data global and associated it to myData, but sometimes the code below it runs before the CSV is loaded. Try to console.log(data) just outside the d3.csv function, to check if data is correctly populated. If not, put all the functions that depend on myData inside the d3.csv function.