Create a symbol generator with D3.js - d3.js

I'm using the function d3.svg.symbol() to plot symbols on my Line Chart.
I wrote this code but nothing happens.
The part to generate the symbols is:
svg.selectAll("path")
.data(donnees)
.enter().append("path")
.attr("transform", function(d) { return "translate(" + xScale(d.xValue) + "," + yScale(d.yValue) + ")"; })
.attr("d", d3.svg.symbol());

First, lets talk about your data. You have an object with a key and a value structure. You've given d3 something it can work with by iterating your object like:
for (var i in donnees) {
svg.append("path")
...
While this works, we can do better. Say we try:
var data = d3.entries(donnees);
which returns:
[Object ,Object ,Object]
key: "Cbio" key: "Cres"
value: Array[10] value: Array[10]
Now we are talking about some data d3 will really like. So with that lets rewrite your line drawing.
First, create a group for each line:
var lineGroup = svg.selectAll(".line")
.data(data)
.enter()
.append("g")
.attr("class", "line");
Now, all the line path:
lineGroup
.append("path")
.attr("d", function(d){
return line(d.value);
})
.attr("fill", "none")
.attr("stroke", function(d,i){
return colors(i);
})
.attr("stroke-width", 1);
And finally, lets do some symbols:
var types = ["circle","cross","diamond"];
lineGroup
.selectAll("symbol")
.data(function(d){
return d.value; //<-- this is a subselection, and allows you to build a symbol for each datapoint of your line
})
.enter()
.append("path")
.attr("transform", function(d) {
return "translate(" + xScale(d.xValue) + "," + yScale(d.yValue) + ")";
})
.attr("d", function(d,i,j){ //<-- the j here is the parent selection, each lineGroup
return d3.svg.symbol()
.type(types[j])(d); //<-- fancy up our symbols
})
.attr("fill", function(d,i,j){
return colors(j);
});
Full code:
<!DOCTYPE html>
<html>
<head>
<script data-require="d3#3.5.3" data-semver="3.5.3" src="//cdnjs.cloudflare.com/ajax/libs/d3/3.5.3/d3.js"></script>
<style>
.axis path,
.axis line {
fill: none;
stroke: #000;
shape-rendering: crispEdges;
}
.axis text {
font-family: sans-serif;
font-size: 11px;
}
</style>
</head>
<body>
<script>
var w = 500,
h = 400,
padding = 30;
var donnees = {
"Cbio": [{
"xValue": 1,
"yValue": 21
}, {
"xValue": 20,
"yValue": 150
}, {
"xValue": 40,
"yValue": 200
}, {
"xValue": 60,
"yValue": 150
}, {
"xValue": 80,
"yValue": 125
}, {
"xValue": 100,
"yValue": 100
}, {
"xValue": 120,
"yValue": 90
}, {
"xValue": 140,
"yValue": 80
}, {
"xValue": 160,
"yValue": 80
}, {
"xValue": 180,
"yValue": 40
}],
"Cres": [{
"xValue": 1,
"yValue": 350
}, {
"xValue": 20,
"yValue": 30
}, {
"xValue": 40,
"yValue": 20
}, {
"xValue": 60,
"yValue": 30
}, {
"xValue": 80,
"yValue": 30
}, {
"xValue": 100,
"yValue": 30
}, {
"xValue": 120,
"yValue": 20
}, {
"xValue": 140,
"yValue": 30
}, {
"xValue": 160,
"yValue": 30
}, {
"xValue": 180,
"yValue": 30
}],
"tsol84": [{
"xValue": 1,
"yValue": 10
}, {
"xValue": 20,
"yValue": 15
}, {
"xValue": 40,
"yValue": 20
}, {
"xValue": 60,
"yValue": 25
}, {
"xValue": 80,
"yValue": 30
}, {
"xValue": 100,
"yValue": 25
}, {
"xValue": 120,
"yValue": 25
}, {
"xValue": 140,
"yValue": 25
}, {
"xValue": 160,
"yValue": 30
}, {
"xValue": 180,
"yValue": 25
}]
};
var svg = d3.select("body")
.append("svg")
.attr("width", w)
.attr("height", h);
var data = d3.entries(donnees);
var xScale = d3.scale.linear()
.domain([0,
d3.max(d3.max(data, function(d) {
return d.value;
}), function(d){
return d.xValue;
})
])
.range([padding, w - padding]);
var yScale = d3.scale.linear()
.domain([0, d3.max(d3.max(data, function(d) {
return d.value;
}), function(d){
return d.yValue;
})
])
.range([h - padding, padding]);
var xAxis = d3.svg.axis()
.scale(xScale)
.orient('bottom');
var yAxis = d3.svg.axis()
.scale(yScale)
.orient('left');
svg.append("g")
.attr("class", "axis")
.attr("transform", "translate(0," + (h - padding) + ")")
.call(xAxis);
svg.append("g")
.attr("class", "axis")
.attr("transform", "translate(" + padding + ",0)")
.call(yAxis);
var line = d3.svg.line()
.x(function(d) {
return xScale(d.xValue)
})
.y(function(d) {
return yScale(d.yValue)
});
var colors = d3.scale.category20();
var lineGroup = svg.selectAll(".line")
.data(data)
.enter()
.append("g")
.attr("class", "line");
lineGroup
.append("path")
.attr("d", function(d){
return line(d.value);
})
.attr("fill", "none")
.attr("stroke", function(d,i){
return colors(i);
})
.attr("stroke-width", 1);
var types = ["circle","cross","diamond"];
lineGroup
.selectAll("symbol")
.data(function(d){
return d.value;
})
.enter()
.append("path")
.attr("transform", function(d) {
return "translate(" + xScale(d.xValue) + "," + yScale(d.yValue) + ")";
})
.attr("d", function(d,i,j){
return d3.svg.symbol()
.type(types[j])(d);
})
.attr("fill", function(d,i,j){
return colors(j);
});
</script>
</body>
</html>

Related

Last bin in histogram has smaller width than others

I have a D3.js histogram graph that has an issue where my last x-axis bin is significantly smaller than than the rest of the bins which are equal width. At first I thought this was a axis issue, but the axis is set with the typical width and height range and domains, making me believe it has to do with my bar code, but I'm not sure what would create just one wrong width for a bing, while the other bins are equal width. Provided below is my code. Any help would be appreciated!
Code:
<meta charset="utf-8">
<!-- Load d3.js -->
<script src="https://d3js.org/d3.v4.js"></script>
<!-- Create a div where the graph will take place -->
<div id="my_dataviz"></div>
<style>
#sleep-dist-histo {
stroke-width: 0.5;
stroke: goldenrod;
}
</style>
<script>
var data = [
{ "x": "7.41" },
{ "x": "7.01" },
{ "x": "8.39" },
{ "x": "8.22" },
{ "x": "8.31" },
{ "x": "8.33" },
{ "x": "8.16" },
{ "x": "8.00" },
{ "x": "6.04" },
{ "x": "8.18" },
{ "x": "7.47" },
{ "x": "7.57" },
{ "x": "7.11" },
{ "x": "6.59" },
{ "x": "7.51" },
{ "x": "6.31" },
{ "x": "8.01" },
{ "x": "8.14" },
{ "x": "8.26" },
{ "x": "7.44" },
{ "x": "7.54" },
{ "x": "6.23" },
{ "x": "6.25" },
{ "x": "7.50" },
{ "x": "7.45" },
{ "x": "9.34" },
{ "x": "7.53" },
{ "x": "7.11" },
{ "x": "8.17" },
{ "x": "8.02" },
{ "x": "8.12" },
{ "x": "8.14" },
{ "x": "7.49" },
{ "x": "6.35" },
{ "x": "7.07" },
{ "x": "5.46" },
{ "x": "6.56" },
{ "x": "7.41" },
{ "x": "8.06" },
{ "x": "7.31" },
{ "x": "8.53" },
{ "x": "7.42" },
{ "x": "7.41" },
{ "x": "7.57" },
{ "x": "7.38" },
{ "x": "8.04" },
{ "x": "6.29" },
{ "x": "7.52" },
{ "x": "7.42" },
{ "x": "8.06" },
{ "x": "8.09" },
{ "x": "8.03" },
{ "x": "7.06" },
{ "x": "7.33" },
{ "x": "8.09" },
{ "x": "7.47" },
{ "x": "7.54" },
{ "x": "7.31" },
{ "x": "7.30" },
{ "x": "7.50" },
{ "x": "4.07" },
{ "x": "8.22" },
{ "x": "7.44" }
]
// console.log(data)
var margin = { top: 15, right: 30, bottom: 50, left: 60 }
var width = 800 - margin.left - margin.right;
var height = 800 - margin.top - margin.bottom;
var svg = d3.select("#my_dataviz")
.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 + ")"); // translate(margin left, margin top)
// Append x-scale and x-scale tick labels
var xAxisGroup = svg.append("g")
.attr("class", "y-axis")
.attr("transform", "translate(" + 0 + "," + height + ")");
// Set x-scale range
var x = d3.scaleLinear()
.range([0, width]);
// Append x-scale title
svg.append("text")
.attr("transform",
"translate(" + (width/2) + " ," + (height + margin.bottom) + ")")
.style("text-anchor", "middle")
.text("Time Asleep in Hours (Bins)");
// Set y-scale range
var y = d3.scaleLinear()
.range([height, margin.top]);
// Append y-scale
var yAxisGroup = svg.append("g")
.attr("class", "y-axis");
// Append y-scale title
svg.append("text")
.attr("transform", "rotate(-90)")
.attr("y", 0 - margin.left)
.attr("x",0 - (height / 2))
.attr("dy", "1em")
.style("text-anchor", "middle")
.text("Count of Days Asleep");
d3.interval(function(){
update(data)
}, 1000);
update(data);
function update(data){
// X and Y axis domains
x.domain([0, d3.max(data, function(d) { return +d.x })])
var xAxisCall = d3.axisBottom(x);
var yAxisCall = d3.axisLeft(y);
xAxisGroup.call(xAxisCall);
yAxisGroup.call(yAxisCall);
var histogram = d3.histogram()
.value(function(d) { return d.x })
.domain(x.domain())
.thresholds(x.ticks());
var bins = histogram(data);
y.domain([0, d3.max(bins, function(d){ return d.length; })]);
// Append bars
svg.selectAll("bar")
.data(bins)
.enter()
.append("rect")
.attr("x", 1)
.attr("transform", function(d) { return "translate(" + x(d.x0) + "," + y(d.length) + ")"; })
.attr("width", function(d) { return x(d.x1) - x(d.x0) - 1 ; })
.attr("height", function(d) { return height - y(d.length); })
.style("fill", "steelblue")
.attr("id", "sleep-dist-histo");
svg.selectAll("label")
.data(bins)
.enter()
.append("text")
.text(function(d){ return d.length })
.attr("x", function(d){ return (x(d.x0) + x(d.x1)) / 2; })
.attr("y", function(d){ return y(d.length) - 15; })
.attr("class", "label")
.attr("dy", ".71em")
// .style("text-anchor", "end")
;
}
</script>
It is because the domain of x is [0, 9.34], so it ended up with 9.34 instead of 10 (to keep the same width)
Solution:
add .nice() to x to "Extends the domain so that it starts and ends on nice round values. " (See Here);
remove the last element of the new bin data otherwise there will be a zero from 10 to 11
<meta charset="utf-8">
<!-- Load d3.js -->
<script src="https://d3js.org/d3.v4.js"></script>
<!-- Create a div where the graph will take place -->
<div id="my_dataviz"></div>
<style>
#sleep-dist-histo {
stroke-width: 0.5;
stroke: goldenrod;
}
</style>
<script>
var data = [
{ "x": "7.41" },
{ "x": "7.01" },
{ "x": "8.39" },
{ "x": "8.22" },
{ "x": "8.31" },
{ "x": "8.33" },
{ "x": "8.16" },
{ "x": "8.00" },
{ "x": "6.04" },
{ "x": "8.18" },
{ "x": "7.47" },
{ "x": "7.57" },
{ "x": "7.11" },
{ "x": "6.59" },
{ "x": "7.51" },
{ "x": "6.31" },
{ "x": "8.01" },
{ "x": "8.14" },
{ "x": "8.26" },
{ "x": "7.44" },
{ "x": "7.54" },
{ "x": "6.23" },
{ "x": "6.25" },
{ "x": "7.50" },
{ "x": "7.45" },
{ "x": "9.34" },
{ "x": "7.53" },
{ "x": "7.11" },
{ "x": "8.17" },
{ "x": "8.02" },
{ "x": "8.12" },
{ "x": "8.14" },
{ "x": "7.49" },
{ "x": "6.35" },
{ "x": "7.07" },
{ "x": "5.46" },
{ "x": "6.56" },
{ "x": "7.41" },
{ "x": "8.06" },
{ "x": "7.31" },
{ "x": "8.53" },
{ "x": "7.42" },
{ "x": "7.41" },
{ "x": "7.57" },
{ "x": "7.38" },
{ "x": "8.04" },
{ "x": "6.29" },
{ "x": "7.52" },
{ "x": "7.42" },
{ "x": "8.06" },
{ "x": "8.09" },
{ "x": "8.03" },
{ "x": "7.06" },
{ "x": "7.33" },
{ "x": "8.09" },
{ "x": "7.47" },
{ "x": "7.54" },
{ "x": "7.31" },
{ "x": "7.30" },
{ "x": "7.50" },
{ "x": "4.07" },
{ "x": "8.22" },
{ "x": "7.44" }
]
// console.log(data)
var margin = { top: 15, right: 30, bottom: 50, left: 60 }
var width = 800 - margin.left - margin.right;
var height = 800 - margin.top - margin.bottom;
var svg = d3.select("#my_dataviz")
.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 + ")"); // translate(margin left, margin top)
// Append x-scale and x-scale tick labels
var xAxisGroup = svg.append("g")
.attr("class", "y-axis")
.attr("transform", "translate(" + 0 + "," + height + ")");
// Set x-scale range
var x = d3.scaleLinear()
.range([0, width]);
// Append x-scale title
svg.append("text")
.attr("transform",
"translate(" + (width/2) + " ," + (height + margin.bottom) + ")")
.style("text-anchor", "middle")
.text("Time Asleep in Hours (Bins)");
// Set y-scale range
var y = d3.scaleLinear()
.range([height, margin.top]);
// Append y-scale
var yAxisGroup = svg.append("g")
.attr("class", "y-axis");
// Append y-scale title
svg.append("text")
.attr("transform", "rotate(-90)")
.attr("y", 0 - margin.left)
.attr("x",0 - (height / 2))
.attr("dy", "1em")
.style("text-anchor", "middle")
.text("Count of Days Asleep");
/* d3.interval(function(){
update(data)
}, 1000);
*/
update(data);
function update(data){
// X and Y axis domains
x.domain([0, d3.max(data, function(d) { return (+d.x) })]).nice()
var xAxisCall = d3.axisBottom(x);
var yAxisCall = d3.axisLeft(y);
xAxisGroup.call(xAxisCall);
yAxisGroup.call(yAxisCall);
var histogram = d3.histogram()
.value(function(d) { return +d.x })
.domain(x.domain())
.thresholds(x.ticks());
var bins = histogram(data);
y.domain([0, d3.max(bins, function(d){ return d.length; })]);
bins = bins.slice(0, bins.length-1)
// Append bars
svg.selectAll("bar")
.data(bins)
.enter()
.append("rect")
.attr("x", 1)
.attr("transform", function(d) { return "translate(" + x(d.x0) + "," + y(d.length) + ")"; })
.attr("width", function(d) { return x(d.x1) - x(d.x0) - 1 ; })
.attr("height", function(d) { return height - y(d.length); })
.style("fill", "steelblue")
.attr("id", "sleep-dist-histo");
svg.selectAll("label")
.data(bins)
.enter()
.append("text")
.text(function(d){ return d.length })
.attr("x", function(d){ return (x(d.x0) + x(d.x1)) / 2; })
.attr("y", function(d){ return y(d.length) - 15; })
.attr("class", "label")
.attr("dy", ".71em")
// .style("text-anchor", "end")
;
}
</script>

d3, line chart, Error: <path> attribute d: Expected number

I have a stackbiltz here - https://stackblitz.com/edit/d3-start-above-zero-gtudz8?embed=1&file=index.js&hideNavigation=1
I'm getting an error in the console.
Error: <path> attribute d: Expected number
The console log in the code show the correct data but I dont think its getting passed to the line function.
Couple obvious issues:
Your X values are strings but you are using a scaleLinear. That's for numbers; try scaleBand.
With that fixed, you aren't setting your x domain properly.
Here's those two fixes:
var data = [
{
"date": "Jan",
"value": 1507
},
{
"date": "Feb",
"value": 1600
},
{
"date": "Mar",
"value": 1281
},
{
"date": "Apr",
"value": 1898
},
{
"date": "May",
"value": 1749
},
{
"date": "June",
"value": 1270
},
{
"date": "July",
"value": 1712
},
{
"date": "Aug",
"value": 1270
},
{
"date": "Sept",
"value": 1257
},
{
"date": "Oct",
"value": 1257
},
{
"date": "Nov",
"value": 1257
},
{
"date": "Dec",
"value": 1257
}
];
///////////////////////////// Create SVG
var w = 400;
var h = 250;
var margin = {
top: 20,
bottom: 20,
left: 40,
right: 20
}
var width = w - margin.left - margin.right
var height = h - margin.top - margin.bottom
var svg = d3.select("body").append("svg")
.attr("id", "svg")
.attr("width", w)
.attr("height", h)
var chart = svg.append('g')
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
///////////////////////////// Create Scale
var x = d3.scaleBand()
.range([0, width])
var y = d3.scaleLinear()
.rangeRound([height, 0])
///////////////////////////// Create Line
var line = d3.line()
.x(function(d) {
console.log(d.date)
console.log(x.domain())
return x(d.date)
})
.y(function(d) {
console.log(d.value)
console.log(y.domain())
return y(d.value)
})
x.domain(data.map(function(d) {
return d.date
}));
y.domain([0, d3.max(data, function(d) {
return d.value
})]);
chart.append("path")
.datum(data)
.attr("fill", "none")
.attr("stroke", "steelblue")
.attr("stroke-linejoin", "round")
.attr("stroke-linecap", "round")
.attr("stroke-width", 1.5)
.attr("d", line);
///////////////////////////// Create Axis
var xAxis = chart.append('g')
.classed('x-axis', true)
.attr("transform", "translate(0," + height + ")")
.call(d3.axisBottom(x))
var yAxis = chart.append('g')
.classed('y-axis', true)
.call(d3.axisLeft(y))
<script src="https://d3js.org/d3.v4.min.js"></script>

D3 V4 how to force Label of stacked bars to visible for small bars? please reply I'm really struggling for it

I'm new to D3JS and struggling with stacked bar below is my dummy code. I tried adding 10 to data to make it visible and then subtract 10 from label to make the label look correct but this cause problem with yAxis where value of bar is crossing the ticker with less then bar value, for example label was showing 95 but bar crossed 100 ticker coz bar size is 95 + 10 = 105. Help me with this.[In image you can find out small bars label are not visible.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>d3.js learning</title>
<script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script>
<style type="text/css">
svg {
font: 10px sans-serif;
shape-rendering: crispEdges;
}
.axis path,
.axis line {
fill: none;
stroke: #000;
}
path.domain {
stroke: none;
}
.y .tick line {
stroke: #ddd;
}
</style>
</head>
<body>
<div id="ashu" style="width: 700px; height:400px;"></div>
<script>
var data = [{
"health": "JAN",
"INSOLVENCIES": 1,
"SPV/ASSETBACKED": 67,
"OPERATINGCOMPANIES": 13,
"Bank": 15
}, {
"health": "FEB",
"INSOLVENCIES": 60,
"SPV/ASSETBACKED": 9,
"OPERATINGCOMPANIES": 20,
"Bank": 5
}, {
"health": "MAR",
"INSOLVENCIES": 40,
"SPV/ASSETBACKED": 22,
"OPERATINGCOMPANIES": 21,
"Bank": 99
}, {
"health": "APR",
"INSOLVENCIES": 60,
"SPV/ASSETBACKED": 1,
"OPERATINGCOMPANIES": 99,
"Bank": 90
}, {
"health": "MAY",
"INSOLVENCIES": 2,
"SPV/ASSETBACKED": 27,
"OPERATINGCOMPANIES": 43,
"Bank": 82
}, {
"health": "JUN",
"INSOLVENCIES": 17,
"SPV/ASSETBACKED": 52,
"OPERATINGCOMPANIES": 79,
"Bank": 9
}, {
"health": "JUL",
"INSOLVENCIES": 37,
"SPV/ASSETBACKED": 24,
"OPERATINGCOMPANIES": 35,
"Bank": 51
}, {
"health": "AUG",
"INSOLVENCIES": 16,
"SPV/ASSETBACKED": 17,
"OPERATINGCOMPANIES": 53,
"Bank": 38
}, {
"health": "SEP",
"INSOLVENCIES": 15,
"SPV/ASSETBACKED": 32,
"OPERATINGCOMPANIES": 5,
"Bank": 31
}];
let xData = d3.keys(data[0]);
const yData = xData.shift();
var div = d3.select("body").append("div")
.attr("class", "tooltip")
.style("opacity", 0);
var margin = {
top: 20,
right: 50,
bottom: 30,
left: 50
},
width = 400,
height = 300,
padding = 100;
var x = d3.scale.ordinal().rangeRoundBands([0, width], .05);
var y = d3.scale.linear().range([height, 0]);
var color = d3.scale.category10();
var xAxis = d3.svg.axis().scale(x).orient("bottom");
var y_axis = d3.svg.axis().scale(y).orient("left").ticks(6).innerTickSize(-width)
.tickPadding(10);
var svg = d3.select("#ashu").append("svg").attr("width",
"100%").attr("height",
"100%").append("g").attr(
"transform",
"translate(" + margin.left + "," + margin.top + ")");
var dataIntermediate = xData.map(function(c) {
return data.map(function(d, yData) {
return {
x: d[Object.keys(d)[0]],
y: d[c]
};
});
});
var dataStackLayout = d3.layout.stack()(dataIntermediate);
x.domain(dataStackLayout[0].map(function(d) {
return d.x;
}));
var total = 0;
var maximumY = d3.max(dataStackLayout[dataStackLayout.length - 1], function(d) {
return (d.y + d.y0);
});
y.domain([-(maximumY * .02), maximumY]).nice();
var layer = svg.selectAll(".stack").data(dataStackLayout).enter()
.append("g").attr("class", "stack").style("fill",
function(d, i) {
return color(i);
});
layer.selectAll("rect")
.data(function(d) {
return d;
})
.enter()
.append("rect")
.attr("x", function(d) {
return x(d.x);
})
.attr("y", function(d) {
return y(d.y + d.y0);
})
.attr("height", function(d) {
return y(d.y0) - y(d.y + d.y0);
})
.attr("width", x.rangeBand())
.on("mouseover", function(d) {
div.transition()
.duration(200)
.style("opacity", .9);
div.html("Total : " + (d.y + d.y0))
.style("left", (d3.event.pageX) + "px")
.style("top", (d3.event.pageY - 28) + "px");
})
.on("mouseout", function(d) {
div.transition()
.duration(500)
.style("opacity", 0);
});
layer.selectAll("text")
.data(function(d) {
return d;
})
.enter()
.append("text")
.text(function(d) {
let r = ((d.y < 10) ? (d.y - 10) : d.y);
return d.y;
})
.attr("x", function(d, i) {
return x(d.x) + 15;
})
.attr("y", function(d) {
return y(d.y0);
})
.attr("dy", "-0.15em")
.attr("text-anchor", "middle")
.style("fill", "black");
svg.append("g").attr("class", "axis").attr("transform",
"translate(0," + height + ")").call(xAxis);
svg.append("g").attr("class", "y axis").attr("transform", "translate(0,0)").call(y_axis);
var legend = svg.selectAll(".legend")
.data(color.domain().slice())
.enter().append("g")
.attr("class", "legend")
.attr("transform", function(d, i) {
return "translate(0," + Math.abs((i - 8) * 20) + ")";
});
legend.append("rect")
.attr("x", width + 10)
.attr("width", 18)
.attr("height", 18)
.style("fill", color);
legend.append("text")
.attr("x", width + 32)
.attr("y", 10)
.attr("dy", ".35em")
.style("text-anchor", "start")
.text(function(d, i) {
return xData[i];
});
</script>
</body>
</html>
the labels are being hidden due the order in which the g elements are creating in the DOM, in that elements created later will overlap elements created earlier. This means that the INSOLVENCIES group labels will be hidden by the orange rects for the SPV/ASSETBACKED.
A solution would be to create new g element for your labels, so they always appear on top of your rects. See the snippet below.
Now, where you have small values, there will always be a challenge about where to position the labels. The snippet places them in the middle of the bar, but you may need to play around with that
var data = [{
"health": "JAN",
"INSOLVENCIES": 1,
"SPV/ASSETBACKED": 67,
"OPERATINGCOMPANIES": 13,
"Bank": 15
}, {
"health": "FEB",
"INSOLVENCIES": 60,
"SPV/ASSETBACKED": 9,
"OPERATINGCOMPANIES": 20,
"Bank": 5
}, {
"health": "MAR",
"INSOLVENCIES": 40,
"SPV/ASSETBACKED": 22,
"OPERATINGCOMPANIES": 21,
"Bank": 99
}, {
"health": "APR",
"INSOLVENCIES": 60,
"SPV/ASSETBACKED": 1,
"OPERATINGCOMPANIES": 99,
"Bank": 90
}, {
"health": "MAY",
"INSOLVENCIES": 2,
"SPV/ASSETBACKED": 27,
"OPERATINGCOMPANIES": 43,
"Bank": 82
}, {
"health": "JUN",
"INSOLVENCIES": 17,
"SPV/ASSETBACKED": 52,
"OPERATINGCOMPANIES": 79,
"Bank": 9
}, {
"health": "JUL",
"INSOLVENCIES": 37,
"SPV/ASSETBACKED": 24,
"OPERATINGCOMPANIES": 35,
"Bank": 51
}, {
"health": "AUG",
"INSOLVENCIES": 16,
"SPV/ASSETBACKED": 17,
"OPERATINGCOMPANIES": 53,
"Bank": 38
}, {
"health": "SEP",
"INSOLVENCIES": 15,
"SPV/ASSETBACKED": 32,
"OPERATINGCOMPANIES": 5,
"Bank": 31
}];
let xData = d3.keys(data[0]);
const yData = xData.shift();
var div = d3.select("body").append("div")
.attr("class", "tooltip")
.style("opacity", 0);
var margin = {
top: 20,
right: 50,
bottom: 30,
left: 50
},
width = 400,
height = 300,
padding = 100;
var x = d3.scale.ordinal()
.rangeRoundBands([0, width], .05);
var y = d3.scale.linear().range([height, 0]);
var color = d3.scale.category10();
var xAxis = d3.svg.axis().scale(x).orient("bottom");
var y_axis = d3.svg.axis().scale(y).orient("left").ticks(6).innerTickSize(-width)
.tickPadding(10);
var svg = d3.select("#ashu").append("svg").attr("width",
"100%").attr("height",
"100%").append("g").attr(
"transform",
"translate(" + margin.left + "," + margin.top + ")");
var dataIntermediate = xData.map(function(c) {
return data.map(function(d, yData) {
return {
x: d[Object.keys(d)[0]],
y: d[c]
};
});
});
var dataStackLayout = d3.layout.stack()(dataIntermediate);
x.domain(dataStackLayout[0].map(function(d) {
return d.x;
}));
var total = 0;
var maximumY = d3.max(dataStackLayout[dataStackLayout.length - 1], function(d) {
return (d.y + d.y0);
});
y.domain([0, maximumY]).nice();
var layer1 = svg.selectAll(".stack1").data(dataStackLayout).enter()
.append("g").attr("class", "stack").style("fill",
function(d, i) {
return color(i);
});
var layer2 = svg.selectAll(".stack2").data(dataStackLayout).enter()
.append("g")
.attr("class", "stack")
.style("fill", "black");
layer1.selectAll("rect")
.data(function(d) {
return d;
})
.enter()
.append("rect")
.attr("x", function(d) {
return x(d.x);
})
.attr("y", function(d) {
return y(d.y + d.y0);
})
.attr("height", function(d) {
return y(d.y0) - y(d.y + d.y0);
})
.attr("width", x.rangeBand())
.on("mouseover", function(d) {
div.transition()
.duration(200)
.style("opacity", .9);
div.html("Total : " + (d.y + d.y0))
.style("left", (d3.event.pageX) + "px")
.style("top", (d3.event.pageY - 28) + "px");
})
.on("mouseout", function(d) {
div.transition()
.duration(500)
.style("opacity", 0);
});
layer2.selectAll("text")
.data(function(d) {
return d;
})
.enter()
.append("text")
.text(function(d) {
return d.y;
})
.attr("x", function(d, i) {
return x(d.x) + (x.rangeBand())/2;
})
.attr("y", function(d) {
return y(d.y0 + (d.y/2));
})
.attr("dy", "0.35em")
.attr("text-anchor", "middle")
.style("fill", "black");
svg.append("g").attr("class", "axis").attr("transform",
"translate(0," + height + ")").call(xAxis);
svg.append("g").attr("class", "y axis").attr("transform", "translate(0,0)").call(y_axis);
var legend = svg.selectAll(".legend")
.data(color.domain().slice())
.enter().append("g")
.attr("class", "legend")
.attr("transform", function(d, i) {
return "translate(0," + Math.abs((i - 8) * 20) + ")";
});
legend.append("rect")
.attr("x", width + 10)
.attr("width", 18)
.attr("height", 18)
.style("fill", color);
legend.append("text")
.attr("x", width + 32)
.attr("y", 10)
.attr("dy", ".35em")
.style("text-anchor", "start")
.text(function(d, i) {
return xData[i];
});
svg {
font: 10px sans-serif;
shape-rendering: crispEdges;
}
.axis path,
.axis line {
fill: none;
stroke: #000;
}
path.domain {
stroke: none;
}
.y .tick line {
stroke: #ddd;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
<div id="ashu" style="width: 700px; height:400px;"></div>

Making an existing vertical bar chart horizontal

I have an existing bar chart which works fine.
But I want to make it horizontal by flipping the axis.
Full code:
$(document).ready(function() {
render_chart();
});
function render_chart() {
var stack = d3.stack;
var dataset = {
"categories": ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'],
"series": ["Group1", "Group2", "Group3"],
"colors": ["#3498db", "#e74c3c", "#2ecc71"],
"layers": [
[{
"y": 1,
"y0": 20,
"month": "Monday"
},
{
"y": 2,
"y0": 18,
"month": "Tuesday"
},
{
"y": 5,
"y0": 18,
"month": "Wednesday"
},
{
"y": 10,
"y0": 20,
"month": "Thursday"
},
{
"y": 14,
"y0": 23,
"month": "Friday"
},
{
"y": 18,
"y0": 24,
"month": "Saturday"
},
{
"y": 20,
"y0": 24,
"month": "Sunday"
}
],
[{
"y": 12,
"y0": 24,
"month": "Monday"
},
{
"y": 14,
"y0": 24,
"month": "Tuesday"
},
{
"y": 13,
"y0": 23,
"month": "Wednesday"
},
{
"y": 16,
"y0": 21,
"month": "Thursday"
},
{
"y": 18,
"y0": 23,
"month": "Friday"
},
{
"y": 19,
"y0": 22,
"month": "Saturday"
},
{
"y": 20,
"y0": 22,
"month": "Sunday"
}
],
[{
"y": 8,
"y0": 24,
"month": "Monday"
},
{
"y": 14,
"y0": 21,
"month": "Tuesday"
},
{
"y": 12,
"y0": 19,
"month": "Wednesday"
},
{
"y": 15,
"y0": 23,
"month": "Thursday"
},
{
"y": 18,
"y0": 21,
"month": "Friday"
},
{
"y": 16,
"y0": 23,
"month": "Saturday"
},
{
"y": 17,
"y0": 24,
"month": "Sunday"
}
]
]
};
n = dataset["series"].length;
m = dataset["layers"].length;
yGroupMax = d3.max(dataset["layers"], function(layer) {
return d3.max(layer, function(d) {
return d.y0;
});
});
yGroupMin = d3.min(dataset["layers"], function(layer) {
return d3.min(layer, function(d) {
return d.y;
});
});
var margin = {
top: 50,
right: 50,
bottom: 50,
left: 100
},
width = 900 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom;
var xScale = d3.scaleBand()
.domain(dataset["categories"])
.rangeRound([0, width])
.padding(.08);
var yScale = d3.scaleLinear()
.domain([yGroupMin, yGroupMax])
.range([height, 0]);
var xAxis = d3.axisBottom(xScale)
.tickSize(7)
.tickPadding(6);
var yAxis = d3.axisLeft(yScale).ticks(24);
var svg = d3.select("#groupchart").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")
.data(dataset["layers"])
.enter().append("g")
.attr("class", "layer");
var rect = layer.selectAll("rect")
.data(function(d, i) {
d.map(function(b) {
b.colorIndex = i;
return b;
});
return d;
})
.enter()
.append("rect")
.transition()
.duration(500)
.delay(function(d, i) {
return i * 10;
})
.attr("x", function(d, i, j) {
var k = Array.prototype.indexOf.call(j[i].parentNode.parentNode.childNodes, j[i].parentNode);
return xScale(d.month) + xScale.bandwidth() / n * k;
})
.attr("width", xScale.bandwidth() / n)
.transition()
.attr("y", function(d) {
return yScale(d.y0);
})
.attr("height", function(d) {
return height - yScale(d.y0 - d.y)
})
.attr("class", "bar")
.style("fill", function(d) {
return dataset["colors"][d.colorIndex];
});
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
svg.select("g")
.attr("class", "y axis")
.call(yAxis);
svg.append("text")
.attr("x", width / 3)
.attr("y", 0)
.attr("dx", ".71em")
.attr("dy", "-.71em")
.text("Grouped Bar Chart Test");
var legend = svg.append("g")
.attr("class", "legend")
legend.selectAll('text')
.data(dataset["colors"])
.enter()
.append("rect")
.attr("x", function(d, i) {
return (i * 120) + (width / 3);
})
.attr("y", (width - margin.right) / 1.6)
.attr("width", 10)
.attr("height", 10)
.style("fill", function(d) {
return d;
})
legend.selectAll('text')
.data(dataset["series"])
.enter()
.append("text")
.attr("x", function(d, i) {
return (i * 120) + (width / 3) + 12;
})
.attr("y", ((width - margin.right) / 1.6) + 9)
.text(function(d) {
return d;
});
var tooltip = d3.select("body")
.append('div')
.attr('class', 'tooltip');
tooltip.append('div')
.attr('class', 'month');
tooltip.append('div')
.attr('class', 'tempRange');
svg.selectAll("rect")
.on('mouseover', function(d) {
if (!d.month) return null;
tooltip.select('.month').html("<b>" + d.month + "</b>");
tooltip.select('.tempRange').html(d.y + ":00 Hours to " + d.y0 + ":00 Hours");
tooltip.style('display', 'block');
tooltip.style('opacity', 2);
})
.on('mousemove', function(d) {
if (!d.month) return null;
tooltip.style('top', (d3.event.layerY + 10) + 'px')
.style('left', (d3.event.layerX - 25) + 'px');
})
.on('mouseout', function() {
tooltip.style('display', 'none');
tooltip.style('opacity', 0);
});
}
.axis path,
.axis line {
fill: none;
font: 10px sans-serif;
stroke: #000;
shape-rendering: crispEdges;
}
.legend {
padding: 5px;
font-size: 15px;
font-family: 'Roboto', sans-serif;
background: yellow;
box-shadow: 2px 2px 1px #888;
}
.tooltip {
background: #eee;
box-shadow: 0 0 5px #999999;
color: #333;
font-size: 12px;
left: 130px;
padding: 10px;
position: absolute;
text-align: center;
top: 95px;
z-index: 10;
display: block;
opacity: 0;
}
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Grouped Bar Graph</title>
<script
src="https://code.jquery.com/jquery-3.3.1.min.js"
integrity="sha256-FgpCb/KJQlLNfOu91ta32o/NMZxltwRo8QtmkMRdAu8="
crossorigin="anonymous"></script>
<script src="https://d3js.org/d3.v4.min.js"></script>
</head>
<body>
<div id="groupchart" class="chart"></div>
</body>
</html>
I tried to do it but I mess it up everytime. When I try to flip the axis by changing the portion below which is just reversing the x and y, it does not appear correctly:
var xAxis = d3.axisBottom(xScale)
.tickSize(7)
.tickPadding(6);
var yAxis = d3.axisLeft(yScale).ticks(24);
I can't figure this out.
Why:
So that I can fit more stuff per group of bars when they are horizontal as they are going to be long and have more space inside.
Here is a reversed (horizontal) version of your chart:
$(document).ready(function() {
render_chart();
});
function render_chart() {
var stack = d3.stack;
var dataset = {
"categories": ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'],
"series": ["Group1", "Group2", "Group3"],
"colors": ["#3498db", "#e74c3c", "#2ecc71"],
"layers": [
[{
"y": 1,
"y0": 20,
"month": "Monday"
},
{
"y": 2,
"y0": 18,
"month": "Tuesday"
},
{
"y": 5,
"y0": 18,
"month": "Wednesday"
},
{
"y": 10,
"y0": 20,
"month": "Thursday"
},
{
"y": 14,
"y0": 23,
"month": "Friday"
},
{
"y": 18,
"y0": 24,
"month": "Saturday"
},
{
"y": 20,
"y0": 24,
"month": "Sunday"
}
],
[{
"y": 12,
"y0": 24,
"month": "Monday"
},
{
"y": 14,
"y0": 24,
"month": "Tuesday"
},
{
"y": 13,
"y0": 23,
"month": "Wednesday"
},
{
"y": 16,
"y0": 21,
"month": "Thursday"
},
{
"y": 18,
"y0": 23,
"month": "Friday"
},
{
"y": 19,
"y0": 22,
"month": "Saturday"
},
{
"y": 20,
"y0": 22,
"month": "Sunday"
}
],
[{
"y": 8,
"y0": 24,
"month": "Monday"
},
{
"y": 14,
"y0": 21,
"month": "Tuesday"
},
{
"y": 12,
"y0": 19,
"month": "Wednesday"
},
{
"y": 15,
"y0": 23,
"month": "Thursday"
},
{
"y": 18,
"y0": 21,
"month": "Friday"
},
{
"y": 16,
"y0": 23,
"month": "Saturday"
},
{
"y": 17,
"y0": 24,
"month": "Sunday"
}
]
]
};
n = dataset["series"].length;
m = dataset["layers"].length;
xGroupMax = d3.max(dataset["layers"], function(layer) {
return d3.max(layer, function(d) {
return d.y0;
});
});
xGroupMin = d3.min(dataset["layers"], function(layer) {
return d3.min(layer, function(d) {
return d.y;
});
});
var margin = {
top: 50,
right: 50,
bottom: 50,
left: 100
},
width = 900 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom;
var xScale = d3.scaleLinear() //
.domain([xGroupMin, xGroupMax]) //
.range([0, width - margin.left]); //
var yScale = d3.scaleBand() //
.domain(dataset["categories"])
.rangeRound([0, height]) //
.padding(.08);
var xAxis = d3.axisBottom(xScale).ticks(24); //
var yAxis = d3.axisLeft(yScale).tickSize(7).tickPadding(6); //
var svg = d3.select("#groupchart").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")
.data(dataset["layers"])
.enter().append("g")
.attr("class", "layer");
var rect = layer.selectAll("rect")
.data(function(d, i) {
d.map(function(b) {
b.colorIndex = i;
return b;
});
return d;
})
.enter()
.append("rect")
.transition()
.duration(500)
.delay(function(d, i) {
return i * 10;
})
.attr("y", function(d, i, j) { //
var k = Array.prototype.indexOf.call(j[i].parentNode.parentNode.childNodes, j[i].parentNode);
return yScale(d.month) + yScale.bandwidth() / n * k; //
})
.attr("height", yScale.bandwidth() / n) //
.transition()
.attr("x", function(d) { //
return xScale(d.y) //
})
.attr("width", function(d) { //
return xScale(d.y0 - d.y); //
})
.attr("class", "bar")
.style("fill", function(d) {
return dataset["colors"][d.colorIndex];
});
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
svg.select("g")
.attr("class", "y axis")
.call(yAxis);
svg.append("text")
.attr("x", width / 3)
.attr("y", 0)
.attr("dx", ".71em")
.attr("dy", "-.71em")
.text("Grouped Bar Chart Test");
var legend = svg.append("g")
.attr("class", "legend")
legend.selectAll('text')
.data(dataset["colors"])
.enter()
.append("rect")
.attr("x", function(d, i) {
return (i * 120) + (width / 3);
})
.attr("y", (width - margin.right) / 1.6)
.attr("width", 10)
.attr("height", 10)
.style("fill", function(d) {
return d;
})
legend.selectAll('text')
.data(dataset["series"])
.enter()
.append("text")
.attr("x", function(d, i) {
return (i * 120) + (width / 3) + 12;
})
.attr("y", ((width - margin.right) / 1.6) + 9)
.text(function(d) {
return d;
});
var tooltip = d3.select("body")
.append('div')
.attr('class', 'tooltip');
tooltip.append('div')
.attr('class', 'month');
tooltip.append('div')
.attr('class', 'tempRange');
svg.selectAll("rect")
.on('mouseover', function(d) {
if (!d.month) return null;
tooltip.select('.month').html("<b>" + d.month + "</b>");
tooltip.select('.tempRange').html(d.y + ":00 Hours to " + d.y0 + ":00 Hours");
tooltip.style('display', 'block');
tooltip.style('opacity', 2);
})
.on('mousemove', function(d) {
if (!d.month) return null;
tooltip.style('top', (d3.event.layerY + 10) + 'px')
.style('left', (d3.event.layerX - 25) + 'px');
})
.on('mouseout', function() {
tooltip.style('display', 'none');
tooltip.style('opacity', 0);
});
}
.axis path,
.axis line {
fill: none;
font: 10px sans-serif;
stroke: #000;
shape-rendering: crispEdges;
}
.legend {
padding: 5px;
font-size: 15px;
font-family: 'Roboto', sans-serif;
background: yellow;
box-shadow: 2px 2px 1px #888;
}
.tooltip {
background: #eee;
box-shadow: 0 0 5px #999999;
color: #333;
font-size: 12px;
left: 130px;
padding: 10px;
position: absolute;
text-align: center;
top: 95px;
z-index: 10;
display: block;
opacity: 0;
}
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Grouped Bar Graph</title>
<script
src="https://code.jquery.com/jquery-3.3.1.min.js"
integrity="sha256-FgpCb/KJQlLNfOu91ta32o/NMZxltwRo8QtmkMRdAu8="
crossorigin="anonymous"></script>
<script src="https://d3js.org/d3.v5.min.js"></script>
</head>
<body>
<div id="groupchart" class="chart"></div>
</body>
</html>
This requires a bit more than just switching x and y axes. You'll also have to modify the w/y/width/height attributes of rectangles, as well as the the position of axes.
I've marked the modified lines with //.
Just for the fun (and if like me, starting from a vertical graph, you're lost doing all these inversions of axes/scales), here is another way of doing using a rotation by 90° of the whole graph!:
$(document).ready(function() {
render_chart();
});
function render_chart() {
var stack = d3.stack;
var dataset = {
"categories": ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'],
"series": ["Group1", "Group2", "Group3"],
"colors": ["#3498db", "#e74c3c", "#2ecc71"],
"layers": [
[{
"y": 1,
"y0": 20,
"month": "Monday"
},
{
"y": 2,
"y0": 18,
"month": "Tuesday"
},
{
"y": 5,
"y0": 18,
"month": "Wednesday"
},
{
"y": 10,
"y0": 20,
"month": "Thursday"
},
{
"y": 14,
"y0": 23,
"month": "Friday"
},
{
"y": 18,
"y0": 24,
"month": "Saturday"
},
{
"y": 20,
"y0": 24,
"month": "Sunday"
}
],
[{
"y": 12,
"y0": 24,
"month": "Monday"
},
{
"y": 14,
"y0": 24,
"month": "Tuesday"
},
{
"y": 13,
"y0": 23,
"month": "Wednesday"
},
{
"y": 16,
"y0": 21,
"month": "Thursday"
},
{
"y": 18,
"y0": 23,
"month": "Friday"
},
{
"y": 19,
"y0": 22,
"month": "Saturday"
},
{
"y": 20,
"y0": 22,
"month": "Sunday"
}
],
[{
"y": 8,
"y0": 24,
"month": "Monday"
},
{
"y": 14,
"y0": 21,
"month": "Tuesday"
},
{
"y": 12,
"y0": 19,
"month": "Wednesday"
},
{
"y": 15,
"y0": 23,
"month": "Thursday"
},
{
"y": 18,
"y0": 21,
"month": "Friday"
},
{
"y": 16,
"y0": 23,
"month": "Saturday"
},
{
"y": 17,
"y0": 24,
"month": "Sunday"
}
]
]
};
n = dataset["series"].length;
m = dataset["layers"].length;
yGroupMax = d3.max(dataset["layers"], function(layer) {
return d3.max(layer, function(d) {
return d.y0;
});
});
yGroupMin = d3.min(dataset["layers"], function(layer) {
return d3.min(layer, function(d) {
return d.y;
});
});
var margin = {
top: 50,
right: 50,
bottom: 50,
left: 100
},
width = 900 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom;
var xScale = d3.scaleBand()
.domain(dataset["categories"])
.rangeRound([0, width])
.padding(.08);
var yScale = d3.scaleLinear()
.domain([yGroupMin, yGroupMax])
.range([height, 0]);
var xAxis = d3.axisBottom(xScale)
.tickSize(7)
.tickPadding(6);
var yAxis = d3.axisLeft(yScale).ticks(24);
var svg = d3.select("#groupchart").append("svg")
.attr("height", width + margin.left + margin.right) //
.attr("width", height + margin.left + margin.bottom) //
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.left + ") rotate(90) translate(0,-400)"); //
var layer = svg.selectAll(".layer")
.data(dataset["layers"])
.enter().append("g")
.attr("class", "layer");
var rect = layer.selectAll("rect")
.data(function(d, i) {
d.map(function(b) {
b.colorIndex = i;
return b;
});
return d;
})
.enter()
.append("rect")
.transition()
.duration(500)
.delay(function(d, i) {
return i * 10;
})
.attr("x", function(d, i, j) {
var k = Array.prototype.indexOf.call(j[i].parentNode.parentNode.childNodes, j[i].parentNode);
return xScale(d.month) + xScale.bandwidth() / n * k;
})
.attr("width", xScale.bandwidth() / n)
.transition()
.attr("y", function(d) {
return yScale(d.y0);
})
.attr("height", function(d) {
return height - yScale(d.y0 - d.y)
})
.attr("class", "bar")
.style("fill", function(d) {
return dataset["colors"][d.colorIndex];
});
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis)
.selectAll("text") //
.attr("transform", "rotate(-90) translate(-10,-18)") //
.style("text-anchor", "end"); //
svg.select("g")
.attr("class", "y axis")
.call(yAxis)
.selectAll("text") //
.attr("transform", "rotate(-90) translate(13,-18)") //
.style("text-anchor", "end"); //
svg.append("text")
.attr("dx", ".71em")
.attr("dy", "-.71em")
.text("Grouped Bar Chart Test (Rien ne va plus)")
.attr("transform", "rotate(-90) translate(-350,-35)"); //
var legend = svg.append("g")
.attr("class", "legend")
legend.selectAll('text')
.data(dataset["colors"])
.enter()
.append("rect")
.attr("x", function(d, i) {
return (i * 120) + (width / 3);
})
.attr("y", (width - margin.right) / 1.6)
.attr("width", 10)
.attr("height", 10)
.style("fill", function(d) {
return d;
})
.attr("transform", "rotate(-90) translate(-600," + (width/2 - 30) + ")"); //
legend.selectAll('text')
.data(dataset["series"])
.enter()
.append("text")
.attr("x", function(d, i) {
return (i * 120) + (width / 3) + 12;
})
.attr("y", ((width - margin.right) / 1.6) + 9)
.text(function(d) {
return d;
})
.attr("transform", "rotate(-90) translate(-600," + (width/2 - 30) + ")"); //
var tooltip = d3.select("body")
.append('div')
.attr('class', 'tooltip');
tooltip.append('div')
.attr('class', 'month');
tooltip.append('div')
.attr('class', 'tempRange');
svg.selectAll("rect")
.on('mouseover', function(d) {
if (!d.month) return null;
tooltip.select('.month').html("<b>" + d.month + "</b>");
tooltip.select('.tempRange').html(d.y + ":00 Hours to " + d.y0 + ":00 Hours");
tooltip.style('display', 'block');
tooltip.style('opacity', 2);
})
.on('mousemove', function(d) {
if (!d.month) return null;
tooltip.style('top', (d3.event.layerY + 10) + 'px')
.style('left', (d3.event.layerX - 25) + 'px');
})
.on('mouseout', function() {
tooltip.style('display', 'none');
tooltip.style('opacity', 0);
});
}
.axis path,
.axis line {
fill: none;
font: 10px sans-serif;
stroke: #000;
shape-rendering: crispEdges;
}
.legend {
padding: 5px;
font-size: 15px;
font-family: 'Roboto', sans-serif;
background: yellow;
box-shadow: 2px 2px 1px #888;
}
.tooltip {
background: #eee;
box-shadow: 0 0 5px #999999;
color: #333;
font-size: 12px;
left: 130px;
padding: 10px;
position: absolute;
text-align: center;
top: 95px;
z-index: 10;
display: block;
opacity: 0;
}
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Grouped Bar Graph</title>
<script
src="https://code.jquery.com/jquery-3.3.1.min.js"
integrity="sha256-FgpCb/KJQlLNfOu91ta32o/NMZxltwRo8QtmkMRdAu8="
crossorigin="anonymous"></script>
<script src="https://d3js.org/d3.v5.min.js"></script>
</head>
<body>
<div id="groupchart" class="chart"></div>
</body>
</html>
Note: this is of course not recommended.

d3.js static force layout

I am using d3.js and would like the force layout to be NOT random every time I load up the page.
I have already read over a few questions and I set the node position but the layout still is random.
Just set static x and y positions in your node objects.
var graph = {
"nodes": [{
"name": "1",
"rating": 90,
"id": 2951,
x: 5, //Any random value
y: 10 //Any random value
}, {
"name": "2",
"rating": 80,
"id": 654654,
x: 15,
y: 20
------------------
-------------------
}],
"links": [{
"source": 5,
"target": 2,
"value": 6,
"label": "publishedOn"
}, {
"source": 1,
"target": 5,
"value": 6,
"label": "publishedOn"
},
------------------
-------------------
}
Here is the working code snippet.
var graph = {
"nodes": [{
"name": "1",
"rating": 90,
"id": 2951,
x: 5,
y: 10
}, {
"name": "2",
"rating": 80,
"id": 654654,
x: 15,
y: 20
}, {
"name": "3",
"rating": 80,
"id": 6546544,
x: 5,
y: 60
}, {
"name": "4",
"rating": 1,
"id": 68987978,
x: 55,
y: 17
}, {
"name": "5",
"rating": 1,
"id": 9878933,
x: 24,
y: 70
}, {
"name": "6",
"rating": 1,
"id": 6161,
x: 35,
y: 10
}],
"links": [{
"source": 5,
"target": 2,
"value": 6,
"label": "publishedOn"
}, {
"source": 1,
"target": 5,
"value": 6,
"label": "publishedOn"
}, {
"source": 4,
"target": 5,
"value": 4,
"label": "containsKeyword"
}, {
"source": 2,
"target": 3,
"value": 3,
"label": "containsKeyword"
}, {
"source": 3,
"target": 2,
"value": 4,
"label": "publishedBy"
}]
}
var margin = {
top: -5,
right: -5,
bottom: -5,
left: -5
};
var width = 500 - margin.left - margin.right,
height = 400 - margin.top - margin.bottom;
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 zoom = d3.behavior.zoom()
.scaleExtent([1, 10])
.on("zoom", zoomed);
var drag = d3.behavior.drag()
.origin(function(d) {
return d;
})
.on("dragstart", dragstarted)
.on("drag", dragged)
.on("dragend", dragended);
var svg = d3.select("#map").append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.right + ")")
.call(zoom);
var rect = svg.append("rect")
.attr("width", width)
.attr("height", height)
.style("fill", "none")
.style("pointer-events", "all");
var container = svg.append("g");
//d3.json('http://blt909.free.fr/wd/map2.json', function(error, graph) {
force
.nodes(graph.nodes)
.links(graph.links)
.start();
var link = container.append("g")
.attr("class", "links")
.selectAll(".link")
.data(graph.links)
.enter().append("line")
.attr("class", "link")
.style("stroke-width", function(d) {
return Math.sqrt(d.value);
});
var node = container.append("g")
.attr("class", "nodes")
.selectAll(".node")
.data(graph.nodes)
.enter().append("g")
.attr("class", "node")
.attr("cx", function(d) {
return d.x;
})
.attr("cy", function(d) {
return d.y;
})
.call(drag);
node.append("circle")
.attr("r", function(d) {
return d.weight * 2 + 12;
})
.style("fill", function(d) {
return color(1 / d.rating);
});
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 dottype(d) {
d.x = +d.x;
d.y = +d.y;
return d;
}
function zoomed() {
container.attr("transform", "translate(" + d3.event.translate + ")scale(" + d3.event.scale + ")");
}
function dragstarted(d) {
d3.event.sourceEvent.stopPropagation();
d3.select(this).classed("dragging", true);
force.start();
}
function dragged(d) {
d3.select(this).attr("cx", d.x = d3.event.x).attr("cy", d.y = d3.event.y);
}
function dragended(d) {
d3.select(this).classed("dragging", false);
}
.node {
stroke: #fff;
stroke-width: 1.5px;
}
.node-active{
stroke: #555;
stroke-width: 1.5px;
}
.link {
stroke: #555;
stroke-opacity: .3;
}
.link-active {
stroke-opacity: 1;
}
.overlay {
fill: none;
pointer-events: all;
}
#map{
border: 2px #555 dashed;
width:500px;
height:400px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
<body>
<div id="map"></div>
</body>

Resources