First Question:
For single bar chart, when we "mouseover" a bar, we will get the value of the bar we selected as i. For example, the following code detects which element of the x-axis we chose and assign that to a variable called selectedYear:
.on("mouseover", function (d, i) {
selectedYear = i;
update();
barChart.selectAll("text")
.attr("fill", "black");
d3.select(this).attr("fill", "orange");
})
However, when it is the stacked bar below, how can I give "2006" to selectedYear and "SmartPhone" to seletedCategory within mouseover function?
Second Question:
How can I highlight corresponding text on the x-axis when I mouseover a bar?
In the picture above, how can I make the text "2006" highlighted when any blocks of the 2006 bar are being mouseovered?
And below is my entire code:
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title></title>
</head>
<body>
<script src="d3.min.js" charset="UTF-8"></script>
<script>
var width = 700;
var height = 500;
var dataSet;
var svg = d3.select("body")
.append("svg")
.attr("width", width)
.attr("height", height);
var dataSet1 = [
{ name: "PC" ,
sales: [ { year:2005, profit: 3000 },
{ year:2006, profit: 1300 },
{ year:2007, profit: 3700 },
{ year:2008, profit: 4900 },
{ year:2009, profit: 700 }] },
{ name: "SmartPhone" ,
sales: [ { year:2005, profit: 2000 },
{ year:2006, profit: 4000 },
{ year:2007, profit: 1810 },
{ year:2008, profit: 6540 },
{ year:2009, profit: 2820 }] },
{ name: "Software" ,
sales: [ { year:2005, profit: 1100 },
{ year:2006, profit: 1700 },
{ year:2007, profit: 1680 },
{ year:2008, profit: 4000 },
{ year:2009, profit: 4900 }] }
];
var stack = d3.layout.stack()
.values(function(d){ return d.sales; })
.x(function(d){ return d.year; })
.y(function(d){ return d.profit; });
var data = stack(dataSet1);
var padding = { left:50, right:100, top:30, bottom:30 };
var xRangeWidth = width - padding.left - padding.right;
var xScale = d3.scale.ordinal()
.domain(data[0].sales.map(function(d){ return d.year; }))
.rangeBands([0, xRangeWidth],0.3);
var maxProfit = d3.max(data[data.length-1].sales, function(d){
return d.y0 + d.y;
});
var yRangeWidth = height - padding.top - padding.bottom;
var yScale = d3.scale.linear()
.domain([0, maxProfit])
.range([0, yRangeWidth]);
var color = d3.scale.category10();
var groups = svg.selectAll("g")
.data(data)
.enter()
.append("g")
.style("fill",function(d,i){ return color(i); });
var rects = groups.selectAll("rect")
.data(function(d){ return d.sales; })
.enter()
.append("rect")
.attr("x",function(d){ return xScale(d.year); })
.attr("y",function(d){ return yRangeWidth - yScale( d.y0 + d.y ); })
.attr("width",60)
.attr("height",function(d){ return yScale(d.y); })
.attr("transform","translate(" + padding.left + "," + padding.top + ")")
.attr("stroke","white")
.on("mouseover", function (d, i) {
groups.selectAll("rect")
.attr("stroke","white")
d3.select(this)
.attr("stroke", "black")
.attr("stroke-width", 3);
selectedYear = i;
})
.on("mouseout", function (d) {
// d3.select(this).attr("stroke", "white").attr("stroke-width", 0);
});
var xAxis = d3.svg.axis()
.scale(xScale)
.orient("bottom");
yScale.range([yRangeWidth, 0]);
var yAxis = d3.svg.axis()
.scale(yScale)
.orient("left");
svg.append("g")
.attr("class","axis")
.attr("transform","translate(" + padding.left + "," + (height - padding.bottom) + ")")
.call(xAxis);
svg.append("g")
.attr("class","axis")
.attr("transform","translate(" + padding.left + "," + (height - padding.bottom - yRangeWidth) + ")")
.call(yAxis);
var labHeight = 50;
var labRadius = 10;
var labelCircle = groups.append("circle")
.attr("cx",width - padding.right*0.98)
.attr("cy",function(d,i){ return padding.top * 2 + labHeight * i; })
.attr("r",labRadius);
var labelText = groups.append("text")
.attr("x",width - padding.right*0.8)
.attr("y",function(d,i){ return padding.top * 2 + labHeight * i; })
.attr("dy",labRadius/2)
.text(function(d){ return d.name; });
</script>
</body>
</html>
Some ideas...
select year on axis (why, I don't know...)
selected category from node datum
show selected profit next to category label
improved highlighting of selected rectangle
protect x axis from being overwritten by white stroke
Working code
var width = 600,
height = 200,
padding = { left:50, right:200, top:20, bottom:30},
xRangeWidth = width - padding.left - padding.right,
yRangeWidth = height - padding.top - padding.bottom;
var dataSet;
var svg = d3.select("body")
.append("svg")
.attr("width", width)
.attr("height", height)
.append("g")
.attr("transform", "translate(" + [padding.left, padding.top] + ")");
var dataSet1 = [
{ name: "PC" ,
sales: [ { year:2005, profit: 3000 },
{ year:2006, profit: 1300 },
{ year:2007, profit: 3700 },
{ year:2008, profit: 4900 },
{ year:2009, profit: 700 }] },
{ name: "SmartPhone" ,
sales: [ { year:2005, profit: 2000 },
{ year:2006, profit: 4000 },
{ year:2007, profit: 1810 },
{ year:2008, profit: 6540 },
{ year:2009, profit: 2820 }] },
{ name: "Software" ,
sales: [ { year:2005, profit: 1100 },
{ year:2006, profit: 1700 },
{ year:2007, profit: 1680 },
{ year:2008, profit: 4000 },
{ year:2009, profit: 4900 }] }
],
// experiment to demonstrate unsupported data structure //////////////////////////////
dataset2 = dataSet1.map(function(d){
return {
name: d.name,
sales: d.sales.reduce(function(s, o) {
return (s[o.year] = o.profit, s)
},{})
}
}),
_stack = d3.layout.stack()
.values(layer)
.x(function(d){ return d.year; })
.y(function(d){ return d.profit; }),
dataRaw = _stack(dataset2).map(function(d){
return {
name: d.name,
sales: layer(d)
}
});
function layer(d){
return Object.keys(d.sales).map(function(y){
return {profit: d.sales[y],year:y}
});
}
// end experiment /////////////////////////////////////////////////////////////////////
var offsetSelect = d3.ui.select({
before: "svg",
style: {position: "absolute", left: width - padding.right + 15 + "px", top: yRangeWidth + "px"},
onUpdate: function() {
update(dataSet1)
},
data : ["wiggle", "zero", "expand", "silhouette"]
}),
orderSelect = d3.ui.select({
before: "svg",
style: {position: "absolute", left: width - padding.right + 15 + "px", top: yRangeWidth - 20 + "px"},
onUpdate: function() {
update(dataSet1)
},
data : ["inside-out", "default", "reverse"]
}),
stack = d3.layout.stack()
.values(function(d){ return d.sales; })
.x(function(d){ return d.year; })
.y(function(d){ return d.profit; })
.out(function out(d, y0, y) {
d.p0 = y0;
d.y = y;
}
);
// apply a transform to map screen space to cartesian space
// this removes all confusion and mess when plotting data!
var plotArea = svg.append("g")
.attr(transplot(yRangeWidth))
.attr("class", "plotArea");
// x Axis
var xPadding = {inner: 0.1, outer: 0.3},
xScale = d3.scale.ordinal()
.rangeBands([0, xRangeWidth], xPadding.inner, xPadding.outer),
xAxis = d3Axis()
.scale(xScale)
.orient("bottom"),
gX = svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + yRangeWidth + ")");
// y Axis
var yAxisScale = d3.scale.linear()
.range([yRangeWidth, 0]),
yAxis = d3Axis()
.scale(yAxisScale)
.orient("left"),
gY = svg.append("g")
.attr("class", "y axis")
.style("pointer-events", "none");
var yScale = d3.scale.linear()
.range([0, yRangeWidth]);
var color = d3.scale.category10();
function update(dataSet) {
var data = stack.offset(offsetSelect.value())
.order(orderSelect.value())(dataSet),
maxProfit = d3.max(data,function(d) {
return d3.max(d.sales, function(s) {
return s.profit + s.p0
})
});
function yDomain(){return [0, offsetSelect.value() == "expand" ? 1 : maxProfit]}
xScale.domain(data[0].sales.map(stack.x()));
yAxisScale.domain(yDomain());
yScale.domain(yAxisScale.domain());
var series = plotArea.selectAll(".series")
.data(data);
series.enter()
.append("g")
.attr("class", "series");
series.style("fill", function(d, i) {
return color(i);
});
series.exit().remove();
var s = xScale.rangeBand(),
w = s - xPadding.inner,
points = series.selectAll("rect")
.data(function(d) {
return d.sales;
}),
newPoints = points.enter()
.append("rect")
.attr("width", w)
.on("mouseover", function(d) {
var rect = d3.select(this), selectedYear = d.year;
// if the plot is not normalised, offset the axis to align with the selected group
if(offsetSelect.value() != "expand") {
var pMin = d3.min(data,function(d) {
return d3.min(d.sales.filter(function(p) {
return p.year == selectedYear
}), function(s) {
return s.p0
})
});
yAxisScale.domain([-pMin, yDomain()[1] - pMin]);
gY.transition().call(yAxis).attr("transform", "translate(" + rect.attr("x") + ",0)");
}
// manage the highlighting
series.selectAll("rect")
.transition()
.attr({opacity: 0.5});
rect
.transition()
.attr({opacity: 1});
d3.selectAll(".x.axis .tick")
.filter(function(d) {
return d == selectedYear
})
.classed("highlight", true);
// move the selected element to the front
d3.select(this.parentNode)
.moveToFront();
gX.moveToFront();
// add the value for the moused over item to the legend text and highlight it
var g = d3.select(this.parentNode).selectAll(".label").select("text");
g.classed("highlight", true);
g.text(g.text() + ": " + d3.format(">8.0f")(d.profit));
series
.append("g")
.attr("class", "tooltip")
.attr("transform", "translate(" + [rect.attr("x"), rect.attr("y")] + ")")
.append("text")
.attr(transflip())
.text(d3.format(">8.0f")(d.profit))
.attr({x: "1em", y: -rect.attr("height")/2, dy: ".35em", opacity: 0})
.transition().attr("opacity", 1)
.style({fill: "black", "pointer-events": "none"})
})
.on("mouseout", function(d) {
var year = d.year;
d3.selectAll(".x.axis .tick")
.filter(function(d) {
return d == year
})
.classed("highlight", false);
series.selectAll("rect")
.transition()
.attr({opacity: 1});
var g = d3.select(this.parentNode).select("text");
g.classed("highlight", false);
g.text(g.text().split(":")[0])
yAxisScale.domain(yDomain());
yAxis.tickSize(6);
gY.transition().call(yAxis).attr("transform", "translate(0,0)");
series.selectAll(".tooltip")
.transition()
.attr({opacity: 0})
.remove();
});
points.transition()
.attr("x", function(d) {
return xScale(d.year);
})
.attr("y", function(d) {
return yScale(d.p0);
})
.attr("height", function(d) {
return yScale(d.y);
})
.attr("stroke", "white");
points.exit().remove;
gX.transition().call(xAxis);
gY.transition().call(yAxis);
// Add the legend inside the series containers
// The series legend is wrapped in another g so that the
// plot transform can be reversed. Otherwise the text would be mirrored
var labHeight = 40,
labRadius = 10,
label = series.selectAll(".label").data(function(d){return [d.name]}),
newLabel = label.enter().append("g")
.attr("class", "label")
// reverse the transform (it is it's own inverse)
.attr(transplot(yRangeWidth));
label.exit().remove();
// add the marker and the legend text to the normalised container
// push the data (name) down to them
var labelCircle = label.selectAll("circle").data(aID),
// take a moment to get the series order delivered by stack
orders = data.map(function(d) { // simplify the form
return {name: d.name, base: d.sales[0].p0}
}).map(function(d) { // get a copy, sorted by p0
return d
}).sort(function(a, b){
return a.base - b.base
}).map(function(d) { // convert to index permutations
return data.map(function(p) {
return p.name
}).indexOf(d.name)
}).reverse(); // convert to screen y ordinate
labelCircle.enter().append("circle");
labelCircle.attr("cx", xRangeWidth + 20)
.attr("cy", function(d, i, j) {
return labHeight * orders[j];
})
.attr("r", labRadius);
var labelText = label.selectAll("text").data(aID);
labelText.enter().append("text");
labelText.attr("x", xRangeWidth + 40)
.attr("y", function(d, i, j) {
return labHeight * orders[j];
})
.attr("dy", labRadius / 2)
.text(function(d) {
return d;
});
function aID(d){
return [d];
}
}
update(dataSet1);
d3.selection.prototype.moveToFront = function() {
return this.each(function() {
this.parentNode.appendChild(this);
});
};
body {
position: relative;
}
.axis path,
.axis line {
fill: none;
stroke: #000;
shape-rendering: crispEdges;
}
.axis .tick line {
stroke: #ccc;
/*opacity: 0.5;*/
pointer-events: none;
}
.highlight {
font-weight: bold ;
}
svg {
overflow: visible;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
<script src="https://gitcdn.xyz/repo/cool-Blue/d3-lib/master/inputs/select/select.js"></script>
<script src="https://gitcdn.xyz/repo/cool-Blue/d3-lib/master/plot/plot-transform.js"></script>
Related
I'm trying to implement click function for a bar graph with x-axis scroll.
When I click the scrollbar the graph x-axis is moving right and the scrollbar is disappearing.
Here is my complete code on codepen: https://codepen.io/sampath-PerOxide/pen/QYdqyZ
var data = [
{ label: "Company Average", value: "20" },
{ label: "Banking & Finance", value: "10" },
{ label: "Research & Development", value: "40" },
{ label: "Design & Innovaon", value: "20" },
{ label: "Sales & Marketing", value: "10" },
{ label: "Company Average1", value: "20" },
{ label: "Banking & Finance1", value: "10" },
{ label: "Research & Development1", value: "40" },
{ label: "Design & Innovaon1", value: "20" },
{ label: "Sales & Marketing1", value: "10" },
{ label: "Company Average2", value: "20" },
{ label: "Banking & Finance2", value: "10" },
{ label: "Research & Development2", value: "40" },
{ label: "Design & Innovaon2", value: "20" },
{ label: "Sales & Marketing2", value: "10" },
{ label: "Company Average3", value: "20" },
{ label: "Banking & Finance3", value: "10" },
{ label: "Research & Development3", value: "40" },
{ label: "Design & Innovaon3", value: "20" },
{ label: "Sales & Marketing3", value: "10" },
{ label: "Company Average4", value: "20" },
{ label: "Banking & Finance4", value: "10" },
{ label: "Research & Development4", value: "40" },
{ label: "Design & Innovaon4", value: "20" },
{ label: "Sales & Marketing4", value: "10" },
{ label: "Company Average5", value: "20" },
{ label: "Banking & Finance5", value: "10" },
{ label: "Research & Development5", value: "40" },
{ label: "Design & Innovaon5", value: "20" },
{ label: "Sales & Marketing5", value: "10" }
];
var margin = { top: 20, right: 10, bottom: 20, left: 40 };
var marginOverview = { top: 30, right: 10, bottom: 20, left: 40 };
var selectorHeight = 40;
var width = 1100 - margin.left - margin.right;
var height = 400 - margin.top - margin.bottom - selectorHeight;
var heightOverview = 80 - marginOverview.top - marginOverview.bottom;
var MIN_BAR_WIDTH = 20;
var MIN_BAR_PADDING = 5;
var svg = d3
.select("#atthbd")
.append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom + selectorHeight);
var diagram = svg
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
var maxLength = d3.max(
data.map(function(d) {
return d.label.length;
})
);
var barWidth = maxLength * 7;
var numBars = Math.round(width / barWidth);
var isScrollDisplayed = barWidth * data.length > width;
var xscale = d3.scale
.ordinal()
.domain(
data.slice(0, numBars).map(function(d) {
return d.label;
})
)
.rangeBands([0, width], 0.7);
var yscale = d3.scale
.linear()
.domain([0, 40])
.range([height, 0]);
var xAxis = d3.svg
.axis()
.scale(xscale)
.orient("bottom");
var yAxis = d3.svg
.axis()
.scale(yscale)
.orient("left");
var tip2 = d3
.tip()
.attr("class", "d3-tip")
.offset([-10, 0])
.html(function(d2) {
return "<p class='sec-sub-head'>Avg No.of days:" + d2.value + "</p>";
});
svg.call(tip2);
diagram
.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0, " + height + ")")
.call(xAxis);
diagram
.append("g")
.attr("class", "y axis")
.call(yAxis)
.append("text")
.attr("transform", "rotate(-90)")
.attr("y", 6)
.attr("dy", ".71em")
.style("text-anchor", "end")
.text("Average No. of days");
var bartext = diagram
.append("g")
.attr("class", "bar-texts")
.selectAll(".bar-text")
.data(data.slice(0, numBars));
var barTextEnter = bartext
.enter()
.append("text")
.attr("class", "bar-text")
.attr("x", function(d) {
return xscale(d.label)+20;
})
.attr("y", function(d) {
return yscale(d.value) - 5;
})
.text(function(d) {
return d.value;
})
.attr("text-anchor", "middle");
var bars = diagram.append("g").attr("class", "bars");
bars
.selectAll("rect")
.data(data.slice(0, numBars), function(d) {
return d.label;
})
.enter()
.append("rect")
.attr("class", "bar")
.attr("x", function(d) {
return xscale(d.label);
})
.attr("y", function(d) {
return yscale(d.value);
})
.attr("width", xscale.rangeBand())
.attr("height", function(d) {
return height - yscale(d.value);
})
.on("mouseover", tip2.show)
.on("mouseout", tip2.hide);
if (isScrollDisplayed) {
var xOverview = d3.scale
.ordinal()
.domain(
data.map(function(d) {
return d.label;
})
)
.rangeBands([0, width], 0.2);
yOverview = d3.scale.linear().range([heightOverview, 0]);
yOverview.domain(yscale.domain());
var overviewGroup = diagram.append('g')
.attr('width', width)
.attr('height', heightOverview);
var subBars = overviewGroup
.append("g")
.attr("class", "sub-bars")
.selectAll(".subBar")
.data(data);
subBars
.enter()
.append("rect")
.classed("subBar", true)
.attr({
height: function(d) {
return heightOverview - yOverview(d.value);
},
width: function(d) {
return xOverview.rangeBand();
},
x: function(d) {
return xOverview(d.label);
},
y: function(d) {
return height + heightOverview + yOverview(d.value);
}
});
var overviewRect = overviewGroup.append('rect')
.attr('y', height + marginOverview.top)
.attr('width', width)
.attr('height', heightOverview)
.style("opacity", "0")
.style("cursor", "pointer").on("click", click);
var selectorWidth = (width / (MIN_BAR_WIDTH) * (xOverview.rangeBand()));
var displayed = d3.scale
.quantize()
.domain([0, width])
.range(d3.range(data.length));
var selector=diagram
.append("rect")
.attr("transform", "translate(0, " + (height + margin.bottom) + ")")
.attr("class", "mover")
.attr("x", 0)
.attr("y", 0)
.attr("height", selectorHeight)
.attr("width", Math.round(parseFloat(numBars * width) / data.length))
.attr("pointer-events", "all")
.attr("cursor", "ew-resize")
.call(d3.behavior.drag().on("drag", display));
}
var zoom = d3.behavior.zoom().scaleExtent([1, 1]);
function click() {
var newX = null;
var selectorX = null;
var customScale = d3.scale.linear().domain([0, width]).range([0, ((MIN_BAR_WIDTH + MIN_BAR_PADDING) * data.length)])
selectorX = (d3.event.x - marginOverview.left) - selectorWidth / 2;
newX = customScale(selectorX);
if (selectorX > width - selectorWidth) {
newX = customScale(width - selectorWidth);
selectorX = width - selectorWidth;
} else if (selectorX - (selectorWidth / 2) < 0) {
newX = 0;
selectorX = 0
}
selector.transition().attr("x", selectorX)
bars.transition().duration(300).attr("transform", "translate(" + (-newX) + ",0)");
diagram.transition().duration(300).select(".x.axis").attr("transform", "translate(" + -(newX - (MIN_BAR_WIDTH + MIN_BAR_PADDING) / 2) + "," + (height) + ")");
diagram.select(".y.axis").call(yAxis);
var transformX = (-(d3.event.x - selectorWidth) * ((MIN_BAR_WIDTH + MIN_BAR_PADDING) * data.length) / width);
zoom.translate([-newX, 0])
}
function display() {
var x = parseInt(d3.select(this).attr("x")),
nx = x + d3.event.dx,
w = parseInt(d3.select(this).attr("width")),
f,
nf,
new_data,
rects;
if (nx < 0 || nx + w > width) return;
d3.select(this).attr("x", nx);
f = displayed(x);
nf = displayed(nx);
if (f === nf) return;
new_data = data.slice(nf, nf + numBars);
xscale.domain(
new_data.map(function(d) {
return d.label;
})
);
diagram.select(".x.axis").call(xAxis);
rects = bars.selectAll("rect").data(new_data, function(d) {
return d.label;
});
rects.attr("x", function(d) {
return xscale(d.label);
});
rects
.enter()
.append("rect")
.attr("class", "bar")
.attr("x", function(d) {
return xscale(d.label);
})
.attr("y", function(d) {
return yscale(d.value);
})
.attr("width", xscale.rangeBand())
.attr("height", function(d) {
return height - yscale(d.value);
})
.on("mouseover", tip2.show)
.on("mouseout", tip2.hide);
bartext
.data(new_data)
.attr("x", function(d) {
return xscale(d.label)+20;
})
.attr("y", function(d) {
return yscale(d.value) - 5;
})
.text(function(d) {
return d.value;
});
bartext.exit().remove();
rects.exit().remove();
}
How can I move the bars when I click on the X-axis scrollbar?
The X-axis scrollbar is a subgraph of actual graph.
I've the following d3 chart which is both grouped and each grouped contains a stacked bar. But somehow, I feel this is not a proper way to implement and little complicated. If there was only stacked bar chart, I would have used d3.stack(). Can someone let me know is there any better way to do this?
Snippet as follows:
var data = [
{
Category: "cat1",
type1: 300,
type2: 450,
type3: 120
},
{
Category: "cat2",
type1: 400,
type2: 100,
type3: 200
},
{
Category: "cat3",
type1: 400,
type2: 100,
type3: 200
},
{
Category: "cat4",
type1: 400,
type2: 100,
type3: 200
}
];
var margin = { top: 20, right: 20, bottom: 30, left: 40 },
width = 500 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom;
var barWidth = 40;
var x0 = d3.scaleBand().range([0, width]);
var x1 = d3.scaleBand();
var y = d3.scaleLinear().range([height, 0]);
var xAxis = d3.axisBottom(x0);
var yAxis = d3.axisLeft(y).tickFormat(d3.format(".2s"));
var color = d3.scaleOrdinal().range(["#98abc5", "#8a89a6", "#7b6888"]);
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 yBegin;
var innerColumns = {
column1: ["type1", "type2"],
column2: ["type3"]
};
var columnHeaders = d3.keys(data[0]).filter(function(key) {
return key !== "Category";
});
color.domain(
d3.keys(data[0]).filter(function(key) {
return key !== "Category";
})
);
var groupData = data.forEach(function(d) {
var yColumn = new Array();
d.columnDetails = columnHeaders.map(function(name) {
for (ic in innerColumns) {
if (innerColumns[ic].indexOf(name) >= 0) {
if (!yColumn[ic]) {
yColumn[ic] = 0;
}
yBegin = yColumn[ic];
yColumn[ic] += +d[name];
return {
name: name,
column: ic,
yBegin: yBegin,
yEnd: +d[name] + yBegin
};
}
}
});
d.total = d3.max(d.columnDetails, function(d) {
return d.yEnd;
});
});
//console.log(data);
x0.domain(
data.map(function(d) {
return d.Category;
})
);
x1.domain(d3.keys(innerColumns)).range([0, x0.bandwidth()]);
y.domain([
0,
1.15 *
d3.max(data, function(d) {
return d.total;
})
]);
svg
.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
svg
.append("g")
.attr("class", "y axis")
.call(yAxis);
var stackedbar = svg
.selectAll(".stackedbar")
.data(data)
.enter()
.append("g")
.attr("class", "g")
.attr("transform", function(d) {
return "translate(" + x0(d.Category) + ",0)";
});
stackedbar
.selectAll("rect")
.data(function(d) {
return d.columnDetails;
})
.enter()
.append("rect")
.attr("width", barWidth)
.attr("x", function(d) {
return x1(d.column) + (x1.bandwidth() - barWidth) / 2;
})
.attr("y", function(d) {
return y(d.yEnd);
})
.attr("height", function(d) {
return y(d.yBegin) - y(d.yEnd);
})
.style("fill", function(d) {
return color(d.name);
});
body {
font: 10px sans-serif;
}
.axis path,
.axis line {
fill: none;
stroke: #000;
shape-rendering: crispEdges;
}
.bar {
fill: steelblue;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.6.0/d3.min.js"></script>
I have tried to achieve grouped stacked bar chart using d3.stack(). Here are 2 important parts of my solution:
var datasets=[d3.stack().keys(['type1','type3'])(data),
d3.stack().keys(['type2'])(data)];
var num_groups=datasets.length;
Here I am using .keys() method of d3.stack to create datasets for each group. After this we can use the code for creating stacked bar chart like this:
d3.range(num_groups).forEach(function(gnum) {
svg.selectAll('g.group'+gnum)
.data(datasets[gnum])
.enter()
.append('g')
.attr('fill',accent)
.attr('class', 'group'+gnum)
.selectAll('rect')
.data(d=>d)
.enter()
.append('rect')
.attr('x',(d,i)=>xscale(xlabels[i])+(xscale.bandwidth()/num_groups)*gnum)
.attr('y',d=>yscale(d[1]))
.attr('width',xscale.bandwidth()/num_groups)
.attr('height',d=>yscale(d[0])-yscale(d[1]));
});
You can see the complete solution here: https://jsfiddle.net/Abhi9kt/28wzdrfk/4/
You might need to have for ... in loops to build that object in your innerColumns like this:
itemLookup= data[0],
category = d3.keys(itemLookup.category),
items = d3.keys(itemLookup.category[type1[0]]),
columnHeaders = [],
innerColumns = (function(){
var result = {};
for(var i = 0, ii = category.length; i<ii; i++){
var holder = [];
for(var j = 0, jj = items.length; j<jj; j++){
columnHeaders.push(items[j]+'-'+category[i]);
holder.push(items[j]+'-'+category[i]);
result[category[i]] = holder;
}
}
return result;
})()...
You can refer to this for reference: https://jsfiddle.net/kyroskoh/tmec32z0/
I trying to display a d3 linechart. I've a problem - I cannot stop the date from repeating. How can I stop the date keep repeating? I only want to show two columns(17/12/2013 and 18/12/2013) based on the JSON data reflected below. Or what do I need to do so the first tickmark would show 17/12/2013 and the last one would show 18/12/2013?
[
{
"key": "Excited",
"values": [ [1387212490000, 0], [1387298890000 , 10] ]
},
{
"key": "Sad",
"values": [ [1387212490000, 20], [1387298890000 , 50] ]
},
{
"key": "Angry",
"values": [ [1387212490000, 30], [1387298890000 , 30] ]
},
{
"key": "Happy",
"values": [ [1387212490000, 40], [1387298890000 , 70] ]
}
]
Below is the JS script
$(document).ready(function() {
d3.json('sales.json', function(data) {
nv.addGraph(function() {
var chart = nv.models.lineChart().x(function(d) {
return d[0]
}).y(function(d) {
return d[1]
}).color(d3.scale.category10().range())
.useInteractiveGuideline(true);
chart.xAxis.tickFormat(function(d) {
return d3.time.format('%d/%m/%Y')(new Date(d))
});
//chart.xScale(d3.time.scale());
d3.select('#nvd3 svg').datum(data).transition().duration(500).call(chart);
nv.utils.windowResize(chart.update);
return chart;
});
});
});
You didn't show enough code so it may be difficult to debug...
Anyway, try this and I'm working on an example to prove it...
chart.xAxis
.tickFormat(function(d) {
return d3.time.format('%d/%m/%Y')(new Date(d))
})
.ticks(d3.time.days, 1)
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
var margin = {top: 20, right: 40, bottom: 30, left: 20},
width = 960 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom,
barWidth = Math.floor(width / 19) - 1;
var x = d3.scale.linear()
.range([barWidth / 2, width - barWidth / 2]);
var y = d3.scale.linear()
.range([height, 0]);
var yAxis = d3.svg.axis()
.scale(y)
.orient("right")
.tickSize(-width)
.tickFormat(function(d) { return Math.round(d / 1e6) + "M"; });
// An SVG element with a bottom-right origin.
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 + ")");
// A sliding container to hold the bars by birthyear.
var birthyears = svg.append("g")
.attr("class", "birthyears");
// A label for the current year.
var title = svg.append("text")
.attr("class", "title")
.attr("dy", ".71em")
.text(2000);
d3.csv("population.csv", function(error, data) {
// Convert strings to numbers.
data.forEach(function(d) {
d.people = +d.people;
d.year = +d.year;
d.age = +d.age;
});
// Compute the extent of the data set in age and years.
var age1 = d3.max(data, function(d) { return d.age; }),
year0 = d3.min(data, function(d) { return d.year; }),
year1 = d3.max(data, function(d) { return d.year; }),
year = year1;
// Update the scale domains.
x.domain([year1 - age1, year1]);
y.domain([0, d3.max(data, function(d) { return d.people; })]);
// Produce a map from year and birthyear to [male, female].
data = d3.nest()
.key(function(d) { return d.year; })
.key(function(d) { return d.year - d.age; })
.rollup(function(v) { return v.map(function(d) { return d.people; }); })
.map(data);
// Add an axis to show the population values.
svg.append("g")
.attr("class", "y axis")
.attr("transform", "translate(" + width + ",0)")
.call(yAxis)
.selectAll("g")
.filter(function(value) { return !value; })
.classed("zero", true);
// Add labeled rects for each birthyear (so that no enter or exit is required).
var birthyear = birthyears.selectAll(".birthyear")
.data(d3.range(year0 - age1, year1 + 1, 5))
.enter().append("g")
.attr("class", "birthyear")
.attr("transform", function(birthyear) { return "translate(" + x(birthyear) + ",0)"; });
birthyear.selectAll("rect")
.data(function(birthyear) { return data[year][birthyear] || [0, 0]; })
.enter().append("rect")
.attr("x", -barWidth / 2)
.attr("width", barWidth)
.attr("y", y)
.attr("height", function(value) { return height - y(value); });
// Add labels to show birthyear.
birthyear.append("text")
.attr("y", height - 4)
.text(function(birthyear) { return birthyear; });
// Add labels to show age (separate; not animated).
svg.selectAll(".age")
.data(d3.range(0, age1 + 1, 5))
.enter().append("text")
.attr("class", "age")
.attr("x", function(age) { return x(year - age); })
.attr("y", height + 4)
.attr("dy", ".71em")
.text(function(age) { return age; });
// Allow the arrow keys to change the displayed year.
window.focus();
d3.select(window).on("keydown", function() {
switch (d3.event.keyCode) {
case 37: year = Math.max(year0, year - 10); break;
case 39: year = Math.min(year1, year + 10); break;
}
update();
});
function update() {
if (!(year in data)) return;
title.text(year);
birthyears.transition()
.duration(750)
.attr("transform", "translate(" + (x(year1) - x(year)) + ",0)");
birthyear.selectAll("rect")
.data(function(birthyear) { return data[year][birthyear] || [0, 0]; })
.transition()
.duration(750)
.attr("y", y)
.attr("height", function(value) { return height - y(value); });
}
});
svg {
font: 10px sans-serif;
}
.y.axis path {
display: none;
}
.y.axis line {
stroke: #fff;
stroke-opacity: .2;
shape-rendering: crispEdges;
}
.y.axis .zero line {
stroke: #000;
stroke-opacity: 1;
}
.title {
font: 300 78px Helvetica Neue;
fill: #666;
}
.birthyear,
.age {
text-anchor: middle;
}
.birthyear {
fill: #fff;
}
rect {
fill-opacity: .6;
fill: #e377c2;
}
rect:first-child {
fill: #1f77b4;
}
I'm working with the D3 library and I have a Y-axis only that I want to update when my new data is updated. The new data is updated when the slider changes numbers and that works fine. The problem is that the new axis prints over the old one. I need the old ones to be removed obviously and the new ones replacing it when the data is changed. Would appreciate any help on this, thanks.
<script type="text/javascript">
var myYear = 2006;
//Width and height
var w = 1000;
var h = 500;
var barPadding = 20;
var myNames = ["Pedestrian", "Bicycle", "Motorbike", "Car", "Other"];
//Original data
var dataset = [
[
{ y: 20 }, //male
{ y: 4 },
{ y: 16},
{ y: 53},
{ y: 15 }
],
[
{ y: 12 }, //female
{ y: 4 },
{ y: 3 },
{ y: 36 },
{ y: 2 }
],
];
console.log(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([30, w], 0.05);
var yScale = d3.scale.linear()
.domain([0,
d3.max(dataset, function(d) {
return d3.max(d, function(d) {
return d.y0 + d.y;
});
})
])
.range([0, h]);
yScale2 = d3.scale.linear() //for Y axis
.domain([0,
d3.max(dataset, function(d) {
return d3.max(d, function(d) {
return d.y0 + d.y;
});
})
])
.range([h-10, 0]);
//Easy colors accessible via a 10-step ordinal scale
// var colors = d3.scale.category20c();
var color = d3.scale.ordinal()
.domain(["Male", "Female"])
.range(["#00B2EE", "#FF69B4"]);
//Create SVG element
var svg = d3.select("body")
.append("svg")
.attr("width", w)
.attr("height", h);
// Add a group for each row of data
var groups = svg.selectAll("g")
.data(dataset)
.enter()
.append("g")
.style("fill", function(d, i) {
return color(i);
});
//Define X axis
var xAxis = d3.svg.axis()
.scale(xScale)
.orient("bottom")
.ticks(5);
//Define Y axis
var yAxis = d3.svg.axis()
.scale(yScale2)
.orient("left")
.ticks(5);
// Add a rect for each data value
groups.selectAll("rect")
.data(function(d) { return d; })
.enter()
.append("rect")
.attr("x", function(d, i) {
return xScale(i)
})
.attr("width", xScale.rangeBand())
.attr("y", function(d) {
return h - yScale(d.y0) - yScale(d.y) -20
})
.attr("height", function(d) {
return yScale(d.y)
})
.on("mouseover", function(d) {
//Get this bar's x/y values, then augment for the tooltip
d3.select(this)
.attr("stroke", "white")
.attr("stroke-width", "3px")
var xPosition = parseFloat(d3.select(this).attr("x")) + xScale.rangeBand() / 2; var yPosition = parseFloat(d3.select(this).attr("y")) / 2 + h / 2;
//Update the tooltip position and value
d3.select("#tooltip")
.style("left", xPosition + "px")
.style("top", yPosition + "px")
.select(".deathCount")
.text(d.y);
//Show the tooltip
d3.select("#tooltip").classed("hidden", false);
})
.on("mouseout", function(d) {
//Hide the tooltip
d3.select("#tooltip").classed("hidden", true);
d3.select(this)
.transition()
.duration(2000)
.attr("stroke", "none")
// .attr("fill", "rgb(0, 0, " + (d * 1) + ")");
});
///////// MOUSE CLICK TO CHANGE DATA //////////////////////////////
function data2012() {
dataset = [
[
{ y: 20 }, //male
{ y: 4 },
{ y: 16},
{ y: 53},
{ y: 15 }
],
[
{ y: 12 }, //female
{ y: 4 },
{ y: 3 },
{ y: 36 },
{ y: 2 }
],
];
}
function data2011() {
dataset = [
[
{ y: 33 }, //male
{ y: 9 },
{ y: 17},
{ y: 57},
{ y: 14 }
],
[
{ y: 14 }, //female
{ y: 0 },
{ y: 1 },
{ y: 38 },
{ y: 3 }
],
];
}
function data2010() {
dataset = [
[
{ y: 26 }, //male
{ y: 7 },
{ y: 25},
{ y: 106},
{ y: 18 }
],
[
{ y: 14 }, //female
{ y: 0 },
{ y: 0 },
{ y: 40 },
{ y: 2 }
],
];
}
function data2009() {
dataset = [
[
{ y: 31 }, //male
{ y: 11 },
{ y: 28},
{ y: 102},
{ y: 27 }
],
[
{ y: 17 }, //female
{ y: 2 },
{ y: 1 },
{ y: 55 },
{ y: 0 }
],
];
}
function updateData() {
// RE-SET SCALES AND LAYOUT
d3.select("g").selectAll("svg").remove();
//Data, stacked
stack(dataset);
//Set up scales
xScale = d3.scale.ordinal()
.domain(d3.range(dataset[0].length))
.rangeRoundBands([30, w], 0.05);
yScale = d3.scale.linear()
.domain([0,
d3.max(dataset, function(d) {
return d3.max(d, function(d) {
return d.y0 + d.y;
});
})
])
.range([0, h]);
// d3.selectAll(yAxis).remove(); //new stuff
groups = svg.selectAll("g")
.data(dataset)
//Update all rects
var gas = groups.selectAll("rect")
.data(function(d) {return d;});
gas
.exit
.remove;
gas
.transition()
.duration(750)
.ease("linear")
.attr("width", xScale.rangeBand())
.attr("y", function(d) {
return h - yScale(d.y0) - yScale(d.y) - 20
})
.attr("height", function(d) {
return yScale(d.y)
})
.attr("x", function(d, i) {
return xScale(i);
});
// d3.select(yAxis).remove();
//REDRAW Y AXIS
yScale2 = d3.scale.linear()
.domain([0,
d3.max(dataset, function(d) {
return d3.max(d, function(d) {
return d.y0 + d.y;
});
})
])
.range([h-10, 0]);
yAxis = d3.svg.axis()
.scale(yScale2)
.orient("left")
.ticks(5);
svg.append("g")
.attr("class", "axis")
.attr("transform", "translate(" + 30 + ",-10)")
.transition()
.duration(500)
.call(yAxis)
}
//SLIDER STUFF
xAxis = d3.svg.axis()
.scale(xScale)
.orient("bottom")
.ticks(5)
.tickFormat(function(d) {
return myNames[d];
});
//Create Y axis
svg.append("g")
.attr("class", "axis")
.attr("transform", "translate(" + 30 + ",-10)")
// .call(yAxis);
svg.append("g")
.attr("class", "axis")
.attr("transform", "translate(0," + (h - barPadding ) + ")")
.transition()
.duration(500)
.call(xAxis)
</script>
<script> //Jquery slider
$(function() {
$( "#slider" ).slider({
value:2012,
min: 2009,
max: 2012,
step: 1,
slide: function( event, ui ) {
$( "#amount" ).val( ui.value );
myYear = ui.value;
console.log(myYear);
if (myYear == 2012){
data2012();
}
if (myYear == 2011){
data2011();
}
if (myYear == 2010){
data2010();
}
if (myYear == 2009){
data2009();
}
updateData();
// console.log(myYear);
}
});
In your updateData() function don't re-append the axis. Do it once on initial and then update it. This is consistent with d3's enter, update, and exit pattern.
function updateData(){
...
yScale2 = d3.scale.linear()
.domain([0,
d3.max(dataset, function(d) {
return d3.max(d, function(d) {
return d.y0 + d.y;
});
})
])
.range([h - 10, 0]);
// set scale
yAxis.scale(yScale2);
// redraw it
d3.select('.yaxis').call(yAxis);
}
Example here.
I have a D3 grouped bar chart with x-axis formed using my x0 scale which has the domain as the data values. As the domain has data values my tick text is also the same data values. I want to change the tick values to data names keeping my scale unchanged as names can be same but data values are unique.
Please help me to change the tick values.
e.g. name: 'New Jersey',
value:'[Calendar]&NewJersey'
I want my axis to be made using the value but the tick text should be name.
http://jsfiddle.net/pragyan88/681q7umb/6
var data = {
chartTitle: "PopulationByState",
xAxisLabel: "State",
yAxisLabel: "Population",
series: [{
name: "< 5 Years",
longName: "Age less than 5 Years",
value: "i",
data: [2704659, 2027307, 1208495, 894368, 3157759]
}, {
name: "5-13 Years",
longName: "Age between 5 to 13 years",
value: "i",
data: [4704659, 6027307, 808495, 1094368, 2157759]
}, {
name: "14-20 Years",
longName: "Age between 14 to 20 years",
value: "i",
data: [1104659, 8027307, 1008495, 394368, 1157759]
}, {
name: "21-40 Years",
longName: "Age between 21 to 40 years",
value: "i",
data: [1404659, 2027307, 4208495, 6027307, 5157759]
}, {
name: "41-65 Years",
longName: "Age between 41 to 65 years",
value: "i",
data: [2404659, 3027307, 7208495, 8027307, 6157759]
}, {
name: ">65 Years",
longName: "Age greater than 65 years",
value: "i",
data: [1404659, 9027307, 4208495, 10027307, 5157759]
}],
categories: [{
name: 'CA',
longName: 'California',
value: '[Calendar]&California'
}, {
name: "TX",
longName: 'Texas',
value: '[Calendar]&Texas'
}, {
name: 'NY',
longName: 'New York',
value: '[Calendar]&NewYork'
}, {
name: "FL",
longName: 'Florida',
value: '[Calendar]&Florida'
}, {
name: "NJ",
longName: 'New Jersey',
value: '[Calendar]&NewJersey'
}]
}
var format = d3.format('.2s');
var returnArray = [];
var canvasWidth = document.getElementById("chart").offsetWidth,
canvasHeight = document.getElementById("chart").offsetHeight;
var margin = {
top: 80,
right: 10,
bottom: 60,
left: 30
},
width = canvasWidth - margin.left - margin.right,
height = canvasHeight - margin.top - margin.bottom;
var x0 = d3.scale.ordinal()
.rangeRoundBands([0, width], 0.1, 0.2);
var x1 = d3.scale.ordinal();
var y = d3.scale.linear()
.range([height, 0]);
var color = ['rgb(218,165,32)', 'rgb(41,95,72)', 'rgb(82,82,20)', 'rgb(43,33,6)', 'rgb(96,35,32)', 'rgb(54,69,79)'];
var xAxis = d3.svg.axis()
.scale(x0)
.orient("bottom")
.tickSize(-height, 0, 0);
var yAxis = d3.svg.axis()
.scale(y)
.orient("left")
.tickFormat(d3.format(".2s"))
.tickSize(-width, 0, 0);
var tip = d3.tip()
.attr('class', 'd3-tip')
.offset([-10, 0])
.html(function(d) {
return "data: <span style='color:green;'>" + d.data[d.index] + "</span><br/>" + "series: <span style='color:yellow;'>" + d.seriesLongName + "</span><br/>" + "category: <span style='color:red;'>" + data.categories[d.index].longName + "</span>";
});
var legendTip = d3.tip()
.attr('class', 'd3-tip')
.offset([-10, 0])
.html(function(d) {
return "<span style='color:green;'>" + d.longName + "</span>";
});
var svg = d3.select("#chart").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 + ")");
for (var i = 0; i < data.series.length; i++) {
var rgbColor = d3.rgb(color[i]);
var rgbLighterColor = d3.rgb(color[i]).brighter(4);
var id = 'gradient' + i;
var gradient = svg.append("svg:defs")
.append("svg:linearGradient")
.attr('id', id)
.attr("x1", "0%")
.attr("y1", "0%")
.attr("x2", "100%")
.attr("y2", "100%");
gradient
.append("stop")
.attr("offset", "0%")
.attr("stop-color", rgbLighterColor)
gradient
.append("stop")
.attr("offset", "100%")
.attr("stop-color", rgbColor)
}
svg.call(tip);
svg.call(legendTip);
x0.domain(data.categories.map(function(d) {
return d.name;
}));
x1.domain(data.series.map(function(d) {
return d.name
})).rangeRoundBands([0, x0.rangeBand()]);
y.domain([0, d3.max(data.series, function(d) {
return d3.max(d.data);
})]);
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis)
svg.append("g")
.attr("class", "y axis")
.call(yAxis)
.append("text")
.attr("y", 15)
.attr("x", -15)
.style("text-anchor", "end")
.attr("transform", "rotate(-90)")
.attr('class', 'chartLabel')
.text(data.yAxisLabel)
var state = svg.selectAll(".state")
.data(data.categories)
.enter().append("g")
.attr("class", "state")
.attr("transform", function(d) {
return "translate(" + x0(d.name) + ",0)";
});
var bars = state.selectAll("rect")
.data(function(d, i) {
var rArray = [];
for (var x = 0; x < data.series.length; x++) {
rArray.push({
name: data.series[x].name,
data: data.series[x].data,
index: i,
seriesLongName: data.series[x].longName
});
}
return rArray;
})
.enter().append("rect")
.on('click', function(d) {
if (d3.event.ctrlKey) {
if (d3.select(this).style('opacity') == 1) {
returnArray.push({
categoryName: data.categories[d.index].name,
seriesName: d.name,
data: d.data[d.index]
});
d3.select(this).style('opacity', 0.5);
} else {
returnArray.forEach(function(obj, i) {
if (obj.categoryName == data.categories[d.index].name && obj.seriesName == d.name && obj.data == d.data[d.index])
returnArray.splice(i, 1);
});
d3.select(this).style('opacity', 1);
}
} else {
var rect = svg.selectAll('rect');
rect.forEach(function(rec) {
rec.forEach(function(r) {
returnArray = [];
r.style.opacity = 1;
})
});
if (d3.select(this).style('opacity') == 1) {
d3.select(this).style('opacity', 0.5);
returnArray.push({
categoryName: data.categories[d.index].name,
seriesName: d.name,
data: d.data[d.index]
});
}
}
})
.on('contextmenu', function(d) {
d3.event.preventDefault();
alert(d.name);
})
.on('mouseover', tip.show)
.on('mouseout', tip.hide)
.attr('class', 'bar')
.attr("width", x1.rangeBand())
.attr("x", function(d) {
return x1(d.name);
})
.attr("y", height)
.attr("height", 0)
.style("fill", function(d, i) {
return "url(#gradient" + i + ")"
});
bars.transition()
.attr('y', function(d) {
return y(d.data[d.index]);
})
.attr('height', function(d) {
return height - y(d.data[d.index]);
})
.delay(function(d, i) {
return i * 250;
}).ease('elastic');
svg.append("text")
.attr("transform", "translate(" + (width / 2) + " ," + (height + margin.bottom / 2) + ")")
.style("text-anchor", "middle")
.attr('class', 'chartLabel')
.text(data.xAxisLabel);
svg.append("text")
.attr("transform", "translate(" + (width / 2) + " ," + "0)")
.style("text-anchor", "middle")
.attr('class', 'chartTitle')
.text(data.chartTitle);
d3.select("svg").on('contextmenu', function() {
var d3_target = d3.select(d3.event.target);
if (!d3_target.classed("bar")) {
d3.event.preventDefault();
alert('I m the body!!')
}
});
d3.select("svg").on('click', function() {
var d3_target = d3.select(d3.event.target);
if (!(d3_target.classed("bar") || d3_target.classed("legend"))) {
returnArray = [];
var rect = svg.selectAll('rect');
rect.forEach(function(rec) {
rec.forEach(function(r) {
r.style.opacity = 1;
})
});
}
});
body {
font: 10px sans-serif;
}
.axis path,
.axis line {
fill: none;
stroke: #000;
shape-rendering: crispEdges;
}
.bar {
fill: steelblue;
}
.x.axis path {
display: none;
}
<section class="container">
<div class='watermark'>
<div id="chart" style="width:300px;height:400px;"></div>
</div>
</section>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
/
Thanks in advance.
According to the json structure of the the input data in question, using the following line for x-axis helped:
svg.append("g")
.attr("class", "x axis")
.attr("id", "xaxis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis)
.selectAll('text')
.text(function (d,i) {
return data.categories[i].name;
})