I've tried to build d3 graph where line and columns are combined, but all of my attempts were unsuccessful.
Styles:
svg {
margin-left: auto;
margin-right: auto;
display: block;
}
.axis path,
.axis line {
fill: none;
stroke: #000;
shape-rendering: crispEdges;
}
.axis text{
font: Times;
font-size: 12px;
font-weight: bold;
}
JavaScript:
var margin = {top: 20, right: 10, bottom: 100, left:50},
width = 700 - margin.right - margin.left,
height = 500 - margin.top - margin.bottom;
var svg = d3.select("body")
.append("svg")
.attr ({
"width": width + margin.right + margin.left,
"height": height + margin.top + margin.bottom
})
.append("g")
.attr("transform","translate(" + margin.left + "," + margin.right + ")");
// define x and y scales
var xScale = d3.scale.ordinal()
.rangeRoundBands([0,width], 0.93, 0.93);
var yScale = d3.scale.linear()
.range([height, 0]);
var formater = d3.format("");
// define x axis and y axis
var xAxis = d3.svg.axis()
.scale(xScale)
.orient("bottom");
var yAxis = d3.svg.axis()
.scale(yScale)
.orient("left")
.tickFormat(formater);
d3.csv("result.csv", function(error,data) {
if(error) console.log("Error: data not loaded!");
data.forEach(function(d) {
d.day = d.day;
d.dayStr = d.dayStr;
d.Ratio = +d.Ratio;
console.log(d.dayStr);
});
// Specify the domains of the x and y scales
xScale.domain(data.map(function(d) { return d.dayStr; }) );
yScale.domain([0, 6]);
// Draw xAxis and position the label
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis)
.selectAll("text")
.attr("dx", "-.8em")
.attr("dy", ".25em")
.attr("transform", "rotate(-60)" )
.style("text-anchor", "end")
.attr("font-size", "10px");
// Draw yAxis and postion the label
svg.append("g")
.attr("class", "y axis")
.call(yAxis)
.append("text")
.attr("transform", "rotate(-90)")
.attr("x", -height/8)
.attr("dy", "-3em")
.style("text-anchor", "middle")
.text("Risk Value (in %)");
});
Data:
Day,DayStr,Ratio,Note
2016-06-29T00:00:00+03:00,06-29-2016,1.3,
2016-06-30T00:00:00+03:00,06-30-2016,1.4,
2016-07-01T00:00:00+03:00,07-01-2016,1.2,
2016-07-02T00:00:00+03:00,07-02-2016,1.7,
2016-07-03T00:00:00+03:00,07-03-2016,1.9,
2016-07-04T00:00:00+03:00,07-04-2016,2.2,
2016-07-05T00:00:00+03:00,07-05-2016,2.5,
2016-07-06T00:00:00+03:00,07-06-2016,2.5,
2016-07-07T00:00:00+03:00,07-07-2016,2.4,
2016-07-08T00:00:00+03:00,07-08-2016,2.7,
2016-07-09T00:00:00+03:00,07-09-2016,3.1,
2016-07-10T00:00:00+03:00,07-10-2016,3.5,
2016-07-11T00:00:00+03:00,07-11-2016,3.7,
2016-07-12T00:00:00+03:00,07-12-2016,4.5,
2016-07-13T00:00:00+03:00,07-13-2016,4.4,
2016-07-14T00:00:00+03:00,07-14-2016,5,Alert!
Link to full code.
The final result should be something like this:
Your code is a good starting point, but you haven't drawn any of the columns, points or text. Here's one way to do it:
var colAndPointAndText =
svg.selectAll(".cPT")
.data(data)
.enter().append("g")
.attr("class", "cPT");
colAndPointAndText.append("rect")
.attr("x", function(d) {
return xScale(d.dayStr);
})
.attr("width", xScale.rangeBand())
.attr("y", function(d) {
return yScale(d.Ratio);
})
.attr("height", function(d) {
return height - yScale(d.Ratio);
})
.style("fill", "black");
colAndPointAndText.append("circle")
.attr("cx", function(d) {
return xScale(d.dayStr);
})
.attr("cy", function(d) {
return yScale(d.Ratio);
})
.attr("r", 5)
.style("fill", "none")
.style("stroke", "orange")
.style("stroke-width", "2px")
colAndPointAndText.append("text")
.attr("x", function(d) {
return xScale(d.dayStr);
})
.attr("y", function(d) {
return yScale(d.Ratio);
})
.text(function(d) {
return d.Note;
})
.style("fill", "#d62728")
var line = d3.svg.line()
.x(function(d) {
return xScale(d.dayStr);
})
.y(function(d) {
return yScale(d.Ratio);
});
svg.append("path")
.datum(data)
.attr("class", "line")
.attr("d", line)
.style("fill", "none")
.style("stroke", "steelblue")
.style("stroke-width", "2px");
Full code running here.
Related
I am trying to add text on each bar in grouped bar chart. but it is not showing & no error is there on console.
I am using the sample code from https://bl.ocks.org/bricedev/0d95074b6d83a77dc3ad
I tried below code:
<!DOCTYPE html>
<meta charset="utf-8">
<head>
<style>
body {
font: 10px sans-serif;
}
.axis path,
.axis line {
fill: none;
stroke: #000;
shape-rendering: crispEdges;
}
.x.axis path {
//display: none; //to show x axis
}
</style>
</head>
<body>
<script src="https://d3js.org/d3.v3.min.js"></script>
<script>
var margin = {top: 40, right: 60, bottom: 40, left: 40},
width = 560 - margin.left - margin.right,
height = 300 - margin.top - margin.bottom;
var x0 = d3.scale.ordinal()
.rangeRoundBands([0, width], .1);
var x1 = d3.scale.ordinal();
var y = d3.scale.linear()
.range([height, 0]);
var xAxis = d3.svg.axis()
.scale(x0)
.tickSize(0)
.orient("bottom");
var yAxis = d3.svg.axis()
.scale(y)
.orient("left");
var color = d3.scale.ordinal()
.range(["#ca0020","#f4a582","#d5d5d5","#92c5de","#0571b0"]);
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 + ")");
d3.json("data.json", function(error, data) {
var categoriesNames = data.map(function(d) { return d.categorie; });
var rateNames = data[0].values.map(function(d) { return d.rate; });
x0.domain(categoriesNames);
x1.domain(rateNames).rangeRoundBands([0, x0.rangeBand()]);
y.domain([0, d3.max(data, function(categorie) { return d3.max(categorie.values, function(d) { return d.value; }); })]);
//Graph Title
svg.append("text")
.attr("transform", "translate(100,0)")
.attr("x", 100)
.attr("y", -20)
.attr("font-size", "24px")
.text("Grouped Bar Chart");
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis)
.append("text")
.attr("y", 6)
.attr("dy", ".71em")
.style("text-anchor", "end")
.style('font-weight','bold')
.attr("transform", "translate(" + width + ",10)")
.text("Months");
svg.append("g")
.attr("class", "y axis")
.style('opacity','0')
.call(yAxis)
.append("text")
.attr("transform", "rotate(-90)")
.attr("y", 6)
.attr("dy", ".71em")
.style("text-anchor", "end")
.style('font-weight','bold')
.text("Incidents");
svg.select('.y').transition().duration(500).delay(1300).style('opacity','1');
var slice = svg.selectAll(".slice")
.data(data)
.enter().append("g")
.attr("class", "g")
.attr("transform",function(d) { return "translate(" + x0(d.categorie) + ",0)"; });
//draw bars
slice.selectAll("rect")
.data(function(d) { return d.values; })
.enter().append("rect")
.attr("width", x1.rangeBand())
.attr("x", function(d) { return x1(d.rate); })
.style("fill", function(d) { return color(d.rate) })
.attr("y", function(d) { return y(0); })
.attr("height", function(d) { return height - y(0); })
.on("mouseover", function(d) {
d3.select(this).style("fill", d3.rgb(color(d.rate)).darker(2));
})
.on("mouseout", function(d) {
d3.select(this).style("fill", color(d.rate));
});
slice.selectAll("text")
.data(function(d) {return d.values ;})
.enter()
.append("text")
.attr("x", function(d) { return x1(d.rate); })
.attr("y", function(d) { return ( y(0) ) ; })
.text(function(d) {
return (d.value); // Value of the text
});
slice.selectAll("rect")
.transition()
.delay(function (d) {return Math.random()*1000;})
.duration(1000)
.attr("y", function(d) { return y(d.value); })
.attr("height", function(d) { return height - y(d.value); });
//Legend
var legend = svg.selectAll(".legend")
.data(data[0].values.map(function(d) { return d.rate; }).reverse())
.enter().append("g")
.attr("class", "legend")
.attr("transform", function(d,i) { return "translate(60," + i * 20 + ")"; })
.style("opacity","0");
legend.append("rect")
.attr("x", width - 18)
.attr("width", 18)
.attr("height", 18)
.style("fill", function(d) { return color(d); });
legend.append("text")
.attr("x", width - 24)
.attr("y", 9)
.attr("dy", ".35em")
.style("text-anchor", "end")
.text(function(d) {return d; });
legend.transition().duration(500).delay(function(d,i){ return 1300 + 100 * i; }).style("opacity","1");
});
</script>
</body>
</html>
But the output is output after adding block
It is showing object object in output.
Please help.
output of code is here
You're appending to slice, which is a selection of all the bar groups, not the bars themselves. Try something like this to get started:
slice.selectAll("text")
.data(function(d) { return d.values; })
.enter().append("text")
.attr("x", function(d) { return x1(d.rate); })
.attr("y", function(d) { return y(d.value); })
.text(function(d) { return d.value })
I'm having issues trying to make mouseover works on my D3 graph (I'm not an D3 expert). I managed to make line and points sincronized with zoom but unable to show toolptip on point over, not sure if I'm missing something, as you can see in the image below everything is working fine.
You can my code using the button below. Thanks for the help.
var data = JSON.parse('{"success":true,"response":[{"product_date":"2019-09-01","value":{"temperature":"30.6029968261719"}},{"product_date":"2019-09-02","value":{"temperature":"30.1170043945312"}},{"product_date":"2019-09-03","value":{"temperature":"30.0830078125"}},{"product_date":"2019-09-04","value":{"temperature":"30.2479858398438"}},{"product_date":"2019-09-05","value":{"temperature":"30.9110107421875"}},{"product_date":"2019-09-06","value":{"temperature":"31.3150024414062"}},{"product_date":"2019-09-07","value":{"temperature":"31.2909851074219"}},{"product_date":"2019-09-08","value":{"temperature":"30.7149963378906"}},{"product_date":"2019-09-09","value":{"temperature":"30.010009765625"}},{"product_date":"2019-09-10","value":{"temperature":"29.7990112304688"}},{"product_date":"2019-09-11","value":{"temperature":"29.6549987792969"}},{"product_date":"2019-09-12","value":{"temperature":"30.0769958496094"}},{"product_date":"2019-09-13","value":{"temperature":"30.0830078125"}},{"product_date":"2019-09-14","value":{"temperature":"29.8619995117188"}},{"product_date":"2019-09-15","value":{"temperature":"30.0029907226562"}},{"product_date":"2019-09-16","value":{"temperature":"30.1080017089844"}},{"product_date":"2019-09-17","value":{"temperature":"30.6979980469"}},{"product_date":"2019-09-18","value":{"temperature":"30.3139953613"}},{"product_date":"2019-09-19","value":{"temperature":"30.5180053710938"}},{"product_date":"2019-09-20","value":{"temperature":"30.3720092773"}},{"product_date":"2019-09-21","value":{"temperature":"29.8710021973"}},{"product_date":"2019-09-22","value":{"temperature":"29.7460021972656"}},{"product_date":"2019-09-23","value":{"temperature":"29.5769958496"}},{"product_date":"2019-09-24","value":{"temperature":"29.1159973145"}},{"product_date":"2019-09-25","value":{"temperature":"28.908996582"}}]}');
var svg = d3.select("svg"),
margin = {top: 20, right: 20, bottom: 110, left: 40},
margin2 = {top: 430, right: 20, bottom: 30, left: 40},
width = +svg.attr("width") - margin.left - margin.right,
height = +svg.attr("height") - margin.top - margin.bottom,
height2 = +svg.attr("height") - margin2.top - margin2.bottom;
var parseDate = d3.timeParse("%b %Y");
var x = d3.scaleTime().range([0, width]),
x2 = d3.scaleTime().range([0, width]),
y = d3.scaleLinear().range([height, 0]),
y2 = d3.scaleLinear().range([height2, 0]);
var xAxis = d3.axisBottom(x),
xAxis2 = d3.axisBottom(x2),
yAxis = d3.axisLeft(y);
var brush = d3.brushX()
.extent([[0, 0], [width, height2]])
.on("brush end", brushed);
var zoom = d3.zoom()
.scaleExtent([1, Infinity])
.translateExtent([[0, 0], [width, height]])
.extent([[0, 0], [width, height]])
.on("zoom", zoomed);
var line1 = d3.line()
.curve(d3.curveMonotoneX)
.x(function(d) { return x(d.date) })
.y(function(d) { return y(d.value) });
var line2 = d3.line()
.curve(d3.curveMonotoneX)
.x(function(d) { return x2(d.date) })
.y(function(d) { return y2(d.value) });
svg.append("defs").append("clipPath")
.attr("id", "clip")
.append("rect")
.attr("width", width)
.attr("height", height);
var focus = svg.append("g")
.attr("class", "focus")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
var points = svg.append('g')
.attr("clip-path", "url(#clip)")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")")
var context = svg.append("g")
.attr("class", "context")
.attr("transform", "translate(" + margin2.left + "," + margin2.top + ")");
var div = d3.select("body").append("div")
.attr("class", "tooltip")
.style("opacity", 0);
let vdata = data.response;
// format the data
vdata.forEach((d) => {
d.date = d3.timeParse("%Y-%m-%d")(d.product_date);
d.value = +d.value.temperature;
});
x.domain(d3.extent(vdata, function(d) { return d.date; }));
y.domain([0, d3.max(vdata, function(d) { return d.value; })]);
x2.domain(x.domain());
y2.domain(y.domain());
focus.append("path")
.datum(vdata)
.attr("clip-path", "url(#clip)")
.attr("class", "line")
.attr("fill", "none")
.attr("stroke", "steelblue")
.attr("stroke-width", 1.5)
.attr("d", line1);
focus.append("g")
.attr("class", "axis axis--x")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
focus.append("g")
.attr("class", "axis axis--y")
.call(yAxis);
points.selectAll(".dot")
.data(vdata)
.enter().append("circle")
.attr("class", "dot")
.attr("cx", function(d, i) { return x(d.date) })
.attr("cy", function(d) { return y(d.value) })
.attr("r", 3)
.attr("pointer-events", "all")
.on("mouseover", function(d) {
div.transition()
.duration(200)
.style("opacity", .9);
div .html(parseDate(d.date) + "<br/>" + f(d.value))
.style("left", (d3.event.pageX) + "px")
.style("top", (d3.event.pageY - 28) + "px");
})
.on("mouseout", function(d) {
div.transition()
.duration(500)
.style("opacity", 0);
});
points.append("g")
.attr("class", "axis axis--y")
.call(yAxis);
context.append("path")
.datum(vdata)
.attr("class", "line")
.attr("fill", "none")
.attr("stroke", "steelblue")
.attr("stroke-width", 1.5)
.attr("d", line2);
context.append("g")
.attr("class", "axis axis--x")
.attr("transform", "translate(0," + height2 + ")")
.call(xAxis2);
context.append("g")
.attr("class", "brush")
.call(brush)
.call(brush.move, x.range());
svg.append("rect")
.attr("class", "zoom")
.attr("width", width)
.attr("height", height)
.attr("transform", "translate(" + margin.left + "," + margin.top + ")")
.call(zoom);
function brushed() {
if (d3.event.sourceEvent && d3.event.sourceEvent.type === "zoom") return; // ignore brush-by-zoom
var s = d3.event.selection || x2.range();
x.domain(s.map(x2.invert, x2));
focus.select(".line").attr("d", d3.line()
.x(function(d) { return x(d.date) })
.y(function(d) { return y(d.value) })
.curve(d3.curveMonotoneX)
);
focus.select(".axis--x").call(xAxis);
points.selectAll('circle')
.attr("cx", function(d, i) { return x(d.date) })
.attr("cy", function(d) { return y(d.value) });
points.select(".axis--x").call(xAxis);
svg.select(".zoom").call(zoom.transform, d3.zoomIdentity
.scale(width / (s[1] - s[0]))
.translate(-s[0], 0));
}
function zoomed() {
if (d3.event.sourceEvent && d3.event.sourceEvent.type === "brush") return; // ignore zoom-by-brush
var t = d3.event.transform;
x.domain(t.rescaleX(x2).domain());
focus.select(".line").attr("d", d3.line()
.x(function(d) { return x(d.date) })
.y(function(d) { return y(d.value) })
.curve(d3.curveMonotoneX)
);
points.selectAll('circle')
.attr("cx", function(d, i) { return x(d.date) })
.attr("cy", function(d) { return y(d.value) });
points.select(".axis--x").call(xAxis);
focus.select(".axis--x").call(xAxis);
context.select(".brush").call(brush.move, x.range().map(t.invertX, t));
}
function type(d) {
d.date = parseDate(d.date);
d.value = +d.value;
return d;
}
.area {
fill: steelblue;
clip-path: url(#clip);
}
.zoom {
cursor: move;
fill: none;
pointer-events: all;
}
.dot {
fill: steelblue;
stroke: #fff;
}
div.tooltip {
position: absolute;
text-align: left;
width: 70px;
height: 28px;
padding: 3px;
font: 11px sans-serif;
background: lightsteelblue;
border: 0px;
border-radius: 3px;
pointer-events: none;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.13.0/d3.min.js"></script>
<svg width="960" height="500"></svg>
In order to do zoom interaction you have placed an invisible rectangle over your plot area:
svg.append("rect")
.attr("class", "zoom")
.attr("width", width)
.attr("height", height)
.attr("transform", "translate(" + margin.left + "," + margin.top + ")")
.call(zoom);
You do this after you append the g that holds the plot, so the rectangle is over the points.
The pointer events are intercepted by this rectangle before they can interact with the points.
What you can do instead is append the rectangle to the g that is selected as focus and lower it with selection.lower() (this just moves it so it is the first child of the g, which has the effect of drawing it first or under the plot):
focus.append("rect")
.attr("class", "zoom")
.attr("width", width)
.attr("height", height)
.lower();
.call(zoom);
However now we have the opposite problem (though it is slight): the plot intercepts mouse events meaning that one cannot zoom if the mouse is over the plot, so we could modify this slightly:
focus.append("rect")
.attr("class", "zoom")
.attr("width", width)
.attr("height", height)
.lower();
focus.call(zoom);
However, as focus is not a selection of the g that holds the points, when the mouse is over a point, the graph won't zoom (when the mouse is over the line, it will though). Likewise, as the axes are part of the g selected in focus, one can zoom when the mouse is over the axes.
This may be a problem, perhaps, not, but to address it, we can rejig the DOM structure a bit to ensure everything in the plot area (above the bottom axis and to the right of the vertical axis) interacts with the zoom, but nothing else.
To do so we add the points as children of the focus g, and call the axes on a different g (I've added a new one for you):
var axes = svg.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")")
var points = focus.append('g') // no need to add a transform, focus already has one.
.attr("clip-path", "url(#clip)")
Of course we'll need to update all the places where we call an axis to call it on the new g. Altogether we get:
var data = JSON.parse('{"success":true,"response":[{"product_date":"2019-09-01","value":{"temperature":"30.6029968261719"}},{"product_date":"2019-09-02","value":{"temperature":"30.1170043945312"}},{"product_date":"2019-09-03","value":{"temperature":"30.0830078125"}},{"product_date":"2019-09-04","value":{"temperature":"30.2479858398438"}},{"product_date":"2019-09-05","value":{"temperature":"30.9110107421875"}},{"product_date":"2019-09-06","value":{"temperature":"31.3150024414062"}},{"product_date":"2019-09-07","value":{"temperature":"31.2909851074219"}},{"product_date":"2019-09-08","value":{"temperature":"30.7149963378906"}},{"product_date":"2019-09-09","value":{"temperature":"30.010009765625"}},{"product_date":"2019-09-10","value":{"temperature":"29.7990112304688"}},{"product_date":"2019-09-11","value":{"temperature":"29.6549987792969"}},{"product_date":"2019-09-12","value":{"temperature":"30.0769958496094"}},{"product_date":"2019-09-13","value":{"temperature":"30.0830078125"}},{"product_date":"2019-09-14","value":{"temperature":"29.8619995117188"}},{"product_date":"2019-09-15","value":{"temperature":"30.0029907226562"}},{"product_date":"2019-09-16","value":{"temperature":"30.1080017089844"}},{"product_date":"2019-09-17","value":{"temperature":"30.6979980469"}},{"product_date":"2019-09-18","value":{"temperature":"30.3139953613"}},{"product_date":"2019-09-19","value":{"temperature":"30.5180053710938"}},{"product_date":"2019-09-20","value":{"temperature":"30.3720092773"}},{"product_date":"2019-09-21","value":{"temperature":"29.8710021973"}},{"product_date":"2019-09-22","value":{"temperature":"29.7460021972656"}},{"product_date":"2019-09-23","value":{"temperature":"29.5769958496"}},{"product_date":"2019-09-24","value":{"temperature":"29.1159973145"}},{"product_date":"2019-09-25","value":{"temperature":"28.908996582"}}]}');
var svg = d3.select("svg"),
margin = {top: 20, right: 20, bottom: 110, left: 40},
margin2 = {top: 430, right: 20, bottom: 30, left: 40},
width = +svg.attr("width") - margin.left - margin.right,
height = +svg.attr("height") - margin.top - margin.bottom,
height2 = +svg.attr("height") - margin2.top - margin2.bottom;
var parseDate = d3.timeParse("%b %Y");
var x = d3.scaleTime().range([0, width]),
x2 = d3.scaleTime().range([0, width]),
y = d3.scaleLinear().range([height, 0]),
y2 = d3.scaleLinear().range([height2, 0]);
var xAxis = d3.axisBottom(x),
xAxis2 = d3.axisBottom(x2),
yAxis = d3.axisLeft(y);
var brush = d3.brushX()
.extent([[0, 0], [width, height2]])
.on("brush end", brushed);
var zoom = d3.zoom()
.scaleExtent([1, Infinity])
.translateExtent([[0, 0], [width, height]])
.extent([[0, 0], [width, height]])
.on("zoom", zoomed);
var line1 = d3.line()
.curve(d3.curveMonotoneX)
.x(function(d) { return x(d.date) })
.y(function(d) { return y(d.value) });
var line2 = d3.line()
.curve(d3.curveMonotoneX)
.x(function(d) { return x2(d.date) })
.y(function(d) { return y2(d.value) });
svg.append("defs").append("clipPath")
.attr("id", "clip")
.append("rect")
.attr("width", width)
.attr("height", height);
var focus = svg.append("g")
.attr("class", "focus")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
var axes = svg.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")")
var points = focus.append('g')
.attr("clip-path", "url(#clip)")
var context = svg.append("g")
.attr("class", "context")
.attr("transform", "translate(" + margin2.left + "," + margin2.top + ")");
var div = d3.select("body").append("div")
.attr("class", "tooltip")
.style("opacity", 0);
let vdata = data.response;
// format the data
vdata.forEach((d) => {
d.date = d3.timeParse("%Y-%m-%d")(d.product_date);
d.value = +d.value.temperature;
});
x.domain(d3.extent(vdata, function(d) { return d.date; }));
y.domain([0, d3.max(vdata, function(d) { return d.value; })]);
x2.domain(x.domain());
y2.domain(y.domain());
focus.append("path")
.datum(vdata)
.attr("clip-path", "url(#clip)")
.attr("class", "line")
.attr("fill", "none")
.attr("stroke", "steelblue")
.attr("stroke-width", 1.5)
.attr("d", line1);
axes.append("g")
.attr("class", "axis axis--x")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
axes.append("g")
.attr("class", "axis axis--y")
.call(yAxis);
points.selectAll(".dot")
.data(vdata)
.enter().append("circle")
.attr("class", "dot")
.attr("cx", function(d, i) { return x(d.date) })
.attr("cy", function(d) { return y(d.value) })
.attr("r", 3)
.attr("pointer-events", "all")
.on("mouseover", function(d) {
div.transition()
.duration(200)
.style("opacity", .9);
div .html(parseDate(d.date) + "<br/>" + (d.value))
.style("left", (d3.event.pageX) + "px")
.style("top", (d3.event.pageY - 28) + "px");
})
.on("mouseout", function(d) {
div.transition()
.duration(500)
.style("opacity", 0);
});
points.append("g")
.attr("class", "axis axis--y")
.call(yAxis);
context.append("path")
.datum(vdata)
.attr("class", "line")
.attr("fill", "none")
.attr("stroke", "steelblue")
.attr("stroke-width", 1.5)
.attr("d", line2);
context.append("g")
.attr("class", "axis axis--x")
.attr("transform", "translate(0," + height2 + ")")
.call(xAxis2);
context.append("g")
.attr("class", "brush")
.call(brush)
.call(brush.move, x.range());
focus.append("rect")
.attr("class", "zoom")
.attr("width", width)
.attr("height", height)
.lower();
focus.call(zoom);
function brushed() {
if (d3.event.sourceEvent && d3.event.sourceEvent.type === "zoom") return; // ignore brush-by-zoom
var s = d3.event.selection || x2.range();
x.domain(s.map(x2.invert, x2));
focus.select(".line").attr("d", d3.line()
.x(function(d) { return x(d.date) })
.y(function(d) { return y(d.value) })
.curve(d3.curveMonotoneX)
);
axes.select(".axis--x").call(xAxis);
points.selectAll('circle')
.attr("cx", function(d, i) { return x(d.date) })
.attr("cy", function(d) { return y(d.value) });
points.select(".axis--x").call(xAxis);
svg.select(".zoom").call(zoom.transform, d3.zoomIdentity
.scale(width / (s[1] - s[0]))
.translate(-s[0], 0));
}
function zoomed() {
if (d3.event.sourceEvent && d3.event.sourceEvent.type === "brush") return; // ignore zoom-by-brush
var t = d3.event.transform;
x.domain(t.rescaleX(x2).domain());
focus.select(".line").attr("d", d3.line()
.x(function(d) { return x(d.date) })
.y(function(d) { return y(d.value) })
.curve(d3.curveMonotoneX)
);
points.selectAll('circle')
.attr("cx", function(d, i) { return x(d.date) })
.attr("cy", function(d) { return y(d.value) });
points.select(".axis--x").call(xAxis);
axes.select(".axis--x").call(xAxis);
context.select(".brush").call(brush.move, x.range().map(t.invertX, t));
}
function type(d) {
d.date = parseDate(d.date);
d.value = +d.value;
return d;
}
.area {
fill: steelblue;
clip-path: url(#clip);
}
.zoom {
cursor: move;
fill: none;
pointer-events: all;
}
.dot {
fill: steelblue;
stroke: #fff;
}
div.tooltip {
position: absolute;
text-align: left;
width: 70px;
height: 28px;
padding: 3px;
font: 11px sans-serif;
background: lightsteelblue;
border: 0px;
border-radius: 3px;
pointer-events: none;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.13.0/d3.min.js"></script>
<svg width="960" height="500"></svg>
I am creating a D3 bar chart using below code .
<head>
<style>
.axis {
font: 10px sans-serif;
}
.axis path,
.axis line {
fill: none;
stroke: #000;
shape-rendering: crispEdges;
}
</style>
</head>
<script src="http://d3js.org/d3.v3.min.js"></script>
<script>
var margin = {top: 20, right: 20, bottom: 70, left: 40},
width = 600 - margin.left - margin.right,
height = 300 - margin.top - margin.bottom;
var x = d3.scale.ordinal().rangeRoundBands([0, width], .05);
var y = d3.scale.linear().range([height, 0]);
var xAxis = d3.svg.axis()
.scale(x)
.orient("bottom");
var yAxis = d3.svg.axis()
.scale(y)
.orient("left")
.ticks(10);
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 data = [{"text":"A","value":50,"linkurl":"http://google.com"}, {"text":"B","value":100,"linkurl":"http://php.net"},{"text":"C","value":150,"linkurl":"http://drupal.org"}]
data.forEach(function(d) {
d.text = d.text;
d.value = +d.value;
d.linkurl = d.linkurl;
});
x.domain(data.map(function(d) { return d.text; }));
y.domain([0, d3.max(data, function(d) { return d.value; })]);
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis)
.selectAll("text")
.style("text-anchor", "end")
.attr("dx", "-.8em")
.attr("dy", "-.55em")
.attr("transform", "rotate(-45)" );
svg.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("");
svg.selectAll("bar")
.data(data)
.enter().append("rect")
.style("fill", "steelblue")
.attr("x", function(d) { return x(d.text); })
.attr("width", x.rangeBand())
.attr("y", function(d) { return y(d.value); })
.attr("height", function(d) { return height - y(d.value); });
svg.on("click", function (d) { //<-D
//var position = d3.mouse(svg.node());
window.location.href='http://google.com';
//window.location.href=d.linkurl;
});
</script>
</body>
And want to create a link on each bar.. for that I am using the code . It is working fine when I am using same URL for each bar but doesn't
for different URl for each bar...
var data = [{"text":"A","value":50,"linkurl":"http://google.com"},{"text":"B","value":100,"linkurl":"http://php.net"},{"text":"C","value":150,"linkurl":"http://drupal.org"}]
data.forEach(function(d) {
d.text = d.text;
d.value = +d.value;
d.linkurl = d.linkurl;
});
svg.on("click", function (d) { //<-D
//var position = d3.mouse(svg.node());
window.location.href='http://google.com';
//window.location.href=d.linkurl;
});
You have to bind the click listener to the bars (rectangles) instead of svg.
var bars = svg.selectAll("bar")
.data(data)
.enter()
.append("rect")
.style("fill", "steelblue")
.attr("x", function(d) {
return x(d.text);
}).attr("width", x.rangeBand())
.attr("y", function(d) {
return y(d.value);
}).attr("height", function(d) {
return height - y(d.value);
});
bars.on("click", function(d) {
window.location.href = d.linkurl;
});
var margin = {
top: 20,
right: 20,
bottom: 70,
left: 40
}, width = 600 - margin.left - margin.right, height = 300 - margin.top - margin.bottom;
var x = d3.scale.ordinal().rangeRoundBands([ 0, width ], .05);
var y = d3.scale.linear().range([ height, 0 ]);
var xAxis = d3.svg.axis().scale(x).orient("bottom");
var yAxis = d3.svg.axis().scale(y).orient("left").ticks(10);
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 data = [ {
text: "A",
value: 50,
linkurl: "http://google.com"
}, {
text: "B",
value: 100,
linkurl: "http://php.net"
}, {
text: "C",
value: 150,
linkurl: "http://drupal.org"
} ];
data.forEach(function(a) {
a.text = a.text;
a.value = +a.value;
a.linkurl = a.linkurl;
});
x.domain(data.map(function(a) {
return a.text;
}));
y.domain([ 0, d3.max(data, function(a) {
return a.value;
}) ]);
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis)
.selectAll("text")
.style("text-anchor", "end")
.attr("dx", "-.8em")
.attr("dy", "-.55em")
.attr("transform", "rotate(-45)");
svg.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("");
var bars = svg.selectAll("bar")
.data(data)
.enter()
.append("rect")
.style("fill", "steelblue")
.attr("x", function(a) {
return x(a.text);
}).attr("width", x.rangeBand())
.attr("y", function(a) {
return y(a.value);
}).attr("height", function(a) {
return height - y(a.value);
});
bars.on("click", function(a) {
window.location.href = a.linkurl;
});
.axis {
font: 10px sans-serif;
}
.axis path,
.axis line {
fill: none;
stroke: #000;
shape-rendering: crispEdges;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
I'm trying to create a grouped bar chart that can include transitions. I referenced Mike Bostock's grouped bar chart example and have the bar chart transition working but can't get the axis to transition as well. What I'm referring to in this example is the state labels.
I tried following another example posted but I'm baffled as to why I can get it to work. For my example code the transition occurs on click of the SVG
Grouped Bar Chart Reference Example
Axis Reference Example
<!DOCTYPE html>
<meta charset="utf-8">
<style>
body {
font: 10px sans-serif;
}
.axis path,
.axis line {
fill: none;
stroke: #000;
shape-rendering: crispEdges;
}
.bar {
fill: steelblue;
}
.x_axis path {
display: none;
}
</style>
<body>
<script src="http://d3js.org/d3.v3.min.js"></script>
<script>
//Update the flips bars but not the axis
function update() {
var data_update = data.reverse()
x0.domain[data_update]
svg.selectAll(".state")
.data(data_update)
.transition()
.attr("transform", function(d) { return "translate(" + x0(d.State) + ",0)"; });
svg.select(".x_axis")
.transition()
.call(xAxis);
}
d3.select("svg")
.on("click", update)
//The rest of the code
var data
var margin = {top: 20, right: 20, bottom: 30, left: 40},
width = 960 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom;
var x0 = d3.scale.ordinal()
.rangeRoundBands([0, width], .1);
var x1 = d3.scale.ordinal();
var y = d3.scale.linear()
.range([height, 0]);
var color = d3.scale.ordinal()
.range(["#98abc5", "#8a89a6", "#7b6888", "#6b486b", "#a05d56", "#d0743c", "#ff8c00"]);
var xAxis = d3.svg.axis()
.scale(x0)
.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 + ")");
d3.csv("data.csv", function(error, csv) {
data = csv
var ageNames = d3.keys(data[0]).filter(function(key) { return key !== "State"; });
data.forEach(function(d) {
d.ages = ageNames.map(function(name) { return {name: name, value: +d[name]}; });
});
x0.domain(data.map(function(d) { return d.State; }));
x1.domain(ageNames).rangeRoundBands([0, x0.rangeBand()]);
y.domain([0, d3.max(data, function(d) { return d3.max(d.ages, function(d) { return d.value; }); })]);
svg.append("g")
.attr("class", "x_axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
var state = svg.selectAll(".state")
.data(data)
.enter().append("g")
.attr("class", "state")
.attr("transform", function(d) { return "translate(" + x0(d.State) + ",0)"; });
state.selectAll("rect")
.data(function(d) { return d.ages; })
.enter().append("rect")
.attr("width", x1.rangeBand())
.attr("x", function(d) { return x1(d.name); })
.attr("y", function(d) { return y(d.value); })
.attr("height", function(d) { return height - y(d.value); })
.style("fill", function(d) { return color(d.name); });
});
</script>
I'm a dummy and figured it out.
Calling the .domain method on an array of objects is useless. I forgot to map the object array to get the value of the states
x0.domain(data_update.map(function(d) { return d.State; }))
Full Code below for those curious
<!DOCTYPE html>
<meta charset="utf-8">
<style>
body {
font: 10px sans-serif;
}
.axis path,
.axis line {
fill: none;
stroke: #000;
shape-rendering: crispEdges;
}
.bar {
fill: steelblue;
}
.x_axis path {
display: none;
}
</style>
<body>
<script src="http://d3js.org/d3.v3.min.js"></script>
<script>
var data
var margin = {top: 20, right: 20, bottom: 30, left: 40},
width = 960 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom;
var x0 = d3.scale.ordinal()
.rangeRoundBands([0, width], .1);
var x1 = d3.scale.ordinal();
var y = d3.scale.linear()
.range([height, 0]);
var color = d3.scale.ordinal()
.range(["#98abc5", "#8a89a6", "#7b6888", "#6b486b", "#a05d56", "#d0743c", "#ff8c00"]);
var xAxis = d3.svg.axis()
.scale(x0)
.orient("bottom");
var yAxis = d3.svg.axis()
.scale(y)
.orient("left")
.tickFormat(d3.format(".2s"));
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 + ")");
d3.csv("data.csv", function(error, csv) {
data = csv
var ageNames = d3.keys(data[0]).filter(function(key) { return key !== "State"; });
data.forEach(function(d) {
d.ages = ageNames.map(function(name) { return {name: name, value: +d[name]}; });
});
x0.domain(data.map(function(d) { return d.State; }));
x1.domain(ageNames).rangeRoundBands([0, x0.rangeBand()]);
y.domain([0, d3.max(data, function(d) { return d3.max(d.ages, function(d) { return d.value; }); })]);
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("transform", "rotate(-90)")
.attr("y", 6)
.attr("dy", ".71em")
.style("text-anchor", "end")
.text("Population");
var state = svg.selectAll(".state")
.data(data, function(d) {return d.State})
.enter().append("g")
.attr("class", "state")
.attr("transform", function(d) { return "translate(" + x0(d.State) + ",0)"; });
state.selectAll("rect")
.data(function(d) { return d.ages; })
.enter().append("rect")
.attr("width", x1.rangeBand())
.attr("x", function(d) { return x1(d.name); })
.attr("y", function(d) { return y(d.value); })
.attr("height", function(d) { return height - y(d.value); })
.style("fill", function(d) { return color(d.name); });
var legend = svg.selectAll(".legend")
.data(ageNames.slice().reverse())
.enter().append("g")
.attr("class", "legend")
.attr("transform", function(d, i) { return "translate(0," + i * 20 + ")"; });
legend.append("rect")
.attr("x", width - 18)
.attr("width", 18)
.attr("height", 18)
.style("fill", color);
legend.append("text")
.attr("x", width - 24)
.attr("y", 9)
.attr("dy", ".35em")
.style("text-anchor", "end")
.text(function(d) { return d; });
});
//Update the flips bars
function update() {
data.reverse()
x0.domain(data.map(function(d) { return d.State; }))
svg.selectAll(".state")
.data(data, function(d) {return d.State})
.transition()
.attr("transform", function(d) { return "translate(" + x0(d.State) + ",0)"; });
svg.select(".x_axis")
.transition()
.call(xAxis);
}
d3.select("svg")
.on("click", update)
</script>
Difference chart in D3 js does not show the graph properly.
I have the below data in the tsv file.
for column C there is a value 50 but however the graph stops at approx 30+ on Y axis.
May I know how can I get the graph to be plotted properly.
date A C
20140108 1
20140110 2
20140116 1 3
20140117 1 1
20140120 20 38
20140127 0 1
20140128 0 50
20140130 1 2
20140203 25 2
20140210 3 5
20140211 40 0
20140212 1
20140218 4
Code:
body {
font: 10px sans-serif;
}
.axis path,
.axis line {
fill: none;
stroke: #000;
shape-rendering: crispEdges;
}
.x.axis path {
display: none;
}
.area.above {
fill: rgb(252,141,89); //for red
}
.area.below {
fill: rgb(145,207,96); //for green
}
.line {
fill: none;
stroke: #000;
stroke-width: 1.5px;
}
</style>
<body>
<!script type="text/javascript" src="d3/d3.v3.min.js"><!/script>
<script src="http://d3js.org/d3.v3.min.js"></script>
<script>
var margin = {top: 30, right: 30, bottom: 50, left: 50},
width = 960 - margin.left - margin.right,
height = 800 - margin.top - margin.bottom;
var parseDate = d3.time.format("%Y%m%d").parse;
var x = d3.time.scale()
.range([0, width]);
var y = d3.scale.linear()
.range([height, 0]);
var xAxis = d3.svg.axis()
.scale(x)
.orient("bottom");
var yAxis = d3.svg.axis()
.scale(y)
.orient("left");
var line = d3.svg.area()
.interpolate("basis")
.x(function(d) { return x(d.date); })
.y(function(d) { return y(d["A"]); });
var area = d3.svg.area()
.interpolate("basis")
.x(function(d) { return x(d.date); })
.y1(function(d) { return y(d["A"]); });
var svg = d3.select("body").append("svg") //main svg object which does everything
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
d3.tsv("data.tsv", function(error, data) {
data.forEach(function(d) {
d.date = parseDate(d.date);
d["A"]= +d["A"]; //data here should be in sync with columns in the input file
d["C"] = +d["C"];
});
x.domain(d3.extent(data, function(d) { return d.date; }));
y.domain([
d3.min(data, function(d) { return Math.min(d["A"], d["C"]); }),
d3.max(data, function(d) { return Math.max(d["A"], d["C"]); })
]);
//svg block starts from here
svg.datum(data); //get or set data for individual elements, without computing a join
svg.append("clipPath")
.attr("id", "clip-below")
.append("path")
.attr("d", area.y0(height));
svg.append("clipPath")
.attr("id", "clip-above")
.append("path")
.attr("d", area.y0(0));
svg.append("path")
.attr("class", "area above")
.attr("clip-path", "url(#clip-above)")
.attr("d", area.y0(function(d) { return y(d["C"]); }));
svg.append("path")
.attr("class", "area below")
.attr("clip-path", "url(#clip-below)")
.attr("d", area);
svg.append("path")
.attr("class", "line")
.attr("d", line);
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
// .append ("text")
// .text("New York");
svg.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("count");
});
</script>