D3.js line chart with dates on x axes - javascript

I'm working on this line chart with d3.js .
I have a problem formatting the dates and as much I change the parseDate field, there is no way I can find to get for example "15 June".
If I change .tickformat in the x axis on %d I will just have "01 Oct" and not the exact date.
Here is the JS fiddle
http://jsfiddle.net/w0d4t1n5/
<script async src="//jsfiddle.net/w0d4t1n5/embed/"></script>
Thanks for your help!

If I understand, you want every datapoint's date displayed on the x axis, instead of just a time division.
For that, you need to create an ordinal scale and call that in the X axis:
fiddle is here:
http://jsfiddle.net/z94uzc0L/1/
var margin = {
top: 30,
right: 100,
bottom: 30,
left: 50
},
width = 365 - margin.left - margin.right,
height = 280 - margin.top - margin.bottom,
padding = 1;
var parseDate = d3.time.format("%d-%b-%y").parse;
// Set the ranges
var x = d3.time.scale()
.range([10, width - 15]);
//ordinal scale
var x2 = d3.scale.ordinal().rangePoints([0, width ], .25)
var y = d3.scale.linear()
.range([height, 0]);
var xAxis = d3.svg.axis().scale(x2)
.orient("bottom")
.tickFormat(d3.time.format("%b %d"))
.ticks(4)
.tickPadding(2);
var yAxis = d3.svg.axis().scale(y)
.orient("left");
var valueline = d3.svg.line()
.interpolate("basis")
.x(function(d) {
return x(d.date);
})
.y(function(d) {
return y(d.trump);
});
var valueline2 = d3.svg.line()
.interpolate("basis")
.x(function(d) {
return x(d.date);
})
.y(function(d) {
return y(d.clinton);
});
//florida
var chart1 = d3.select("#florida")
.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 + ")");
//needed for the grid
function make_y_axis() {
return d3.svg.axis()
.scale(y)
.orient("left")
}
data1 = [{
"date": "15-Jun-16",
"trump": 43.4,
"clinton": 44
}, {
"date": "15-Jul-16",
"trump": 43.4,
"clinton": 44
}, {
"date": "15-Aug-16",
"trump": 42,
"clinton": 45.6
}, {
"date": "15-Sep-16",
"trump": 45.1,
"clinton": 44.4
}, {
"date": "06-Oct-16",
"trump": 43.3,
"clinton": 46.2
}, {
"date": "10-Oct-16",
"trump": 49.3,
"clinton": 49.2
}];
var color = d3.scale.ordinal().range(["#004ecc", "#cc0000"]);
//d3.csv("data.csv", function(error, data) {
data1.forEach(function(d) {
d.date = parseDate(d.date);
d.trump = +d.trump;
d.clinton = +d.clinton;
});
// Scale the range of the data
x.domain(d3.extent(data1, function(d) {
return d.date;
}));
y.domain([36, 50]);
//update ordinal scale domain
x2.domain(data1.map(function(d) { return d.date; }));
//add the grid
chart1.append("g")
.attr("class", "grid")
.call(make_y_axis()
.tickSize(-width, 0, 0)
.tickFormat("")
)
chart1.append("path")
.attr("class", "line")
.attr("stroke", "red")
.attr("d", valueline(data1));
chart1.append("path")
.attr("class", "line2")
.attr("d", valueline2(data1));
// Add the X Axis
chart1.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
// Add the Y Axis
chart1.append("g")
.attr("class", "y axis")
.call(yAxis);
chart1.append("text")
.attr("transform", "translate(" + (width + 3) + "," + y(data1[0].clinton) + ")")
.attr("x", ".1em")
.attr("y", "-40")
.attr("text-anchor", "start")
.style("fill", "red")
.style("font-size", "15")
.style("font-weight", "bold")
.text("Clinton 46.2%");
chart1.append("text")
.attr("transform", "translate(" + (width + 3) + "," + y(data1[0].trump) + ")")
.attr("x", ".1em")
.attr("y", "10")
.attr("text-anchor", "start")
.style("fill", "steelblue")
.style("font-size", "15")
.style("font-weight", "bold")
.text("Trump 43.3%");
//plus 1: animation
var curtain = chart1.append('rect')
.attr('x', -1 * width)
.attr('y', -1 * height)
.attr('height', height)
.attr('width', width)
.attr('class', 'curtain')
.attr('transform', 'rotate(180)')
.style('fill', '#ffffff')
/* Optionally add a guideline */
var guideline = chart1.append('line')
.attr('stroke', '#333')
.attr('stroke-width', 0.4)
.attr('class', 'guide')
.attr('x1', 1)
.attr('y1', 1)
.attr('x2', 1)
.attr('y2', height)
var t = chart1.transition()
.delay(120)
.duration(500)
.ease('linear')
.each('end', function() {
d3.select('line.guide')
.transition()
.style('opacity', 0)
.remove()
});
t.select('rect.curtain')
.attr('width', 0);
t.select('line.guide')
.attr('transform', 'translate(' + width + ', 0)')
d3.select("#show_guideline").on("change", function(e) {
guideline.attr('stroke-width', this.checked ? 1 : 0);
curtain.attr("opacity", this.checked ? 0.75 : 1);
});

Related

I had some simple problems in D3.JS

https://i.stack.imgur.com/90isf.png
When visualizing the data, I got some troubles of X axis of line chart.
As picture shows, line of X axis disappeared, in fact, it only shows the scale of X axis. I wonder why this condition happens. Was it due to the illegal coding or because of the size of SVG was not big enough to contain the whole picture?
var margin = { top: 30, right: 120, bottom: 30, left: 50 },
width = 960 - margin.left - margin.right,
height = 600 - margin.top - margin.bottom,
tooltip = { width: 100, height: 100, x: 10, y: -30 };
var parseDate = d3.timeParse("%m-%d-%Y"),
bisectDate = d3.bisector(function(d) { return d.date; }).left,
formatValue = d3.format(","),
dateFormatter = d3.timeParse("%m-%d-%Y");
var x = d3.scaleTime()
.range([0, width]);
var y = d3.scaleLinear()
.range([height, 0]);
var xAxis = d3.axisBottom()
var yAxis = d3.axisLeft()
.scale(y);
var line = d3.line()
.x(function(d) { return x(d.date); })
.y(function(d) { return y(d.likes); });
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("output4.csv",
function(d){
return { date : d.framenum, likes : d.nSNR }
},
function(data) {
x.domain([0, d3.max(data, function(d) { return +d.date; })]);
y.domain([-d3.max(data, function(d) { return +d.likes; }), d3.max(data, function(d) { return +d.likes; })]);
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(d3.axisBottom(x));
svg.append("g")
.attr("class", "y axis")
.call(yAxis)
.style("font-size","17px")
.append("text")
.attr("transform", "rotate(-90)")
.attr("y", 6)
.attr("dy", ".71em")
.style("text-anchor", "end")
.text("Number of Likes");
svg.append("path")
.datum(data)
.attr("class", "line")
.attr("d", line);
var focus = svg.append("g")
.attr("class", "focus")
.style("display", "none");
focus.append("circle")
.attr("r", 5);
focus.append("rect")
.attr("class", "tooltip")
.attr("width", 100)
.attr("height", 50)
.attr("x", 10)
.attr("y", -22)
.attr("rx", 4)
.attr("ry", 4);
focus.append("text")
.attr("class", "tooltip-date")
.attr("x", 18)
.attr("y", -2);
focus.append("text")
.attr("x", 18)
.attr("y", 18)
.text("Likes:");
focus.append("text")
.attr("class", "tooltip-likes")
.attr("x", 60)
.attr("y", 18);
svg.append("rect")
.attr("class", "overlay")
.attr("width", width)
.attr("height", height)
.on("mouseover", function() { focus.style("display", null); })
.on("mouseout", function() { focus.style("display", "none"); })
.on("mousemove", mousemove);
function mousemove() {
var x0 = x.invert(d3.mouse(this)[0]),
i = bisectDate(data, x0, 1),
d0 = data[i - 1],
d1 = data[i],
d = x0 - d0.date > d1.date - x0 ? d1 : d0;
focus.attr("transform", "translate(" + x(d.date) + "," + y(d.likes) + ")");
focus.select(".tooltip-date").text(dateFormatter(d.date));
focus.select(".tooltip-likes").text(formatValue(d.likes));
}
});

Show values on top of line graph

I'm trying to display values on the top of line graph using d3 js. How can I append values to the path of the line graph?
And How can I display month-year as X-axis ticks like May'18, June'19?
I tried using the below code, but the values are not displaying.
lineSvg.selectAll("path")
.data(data)
.enter().append("text")
.attr("class", "line")
.attr("text-anchor", "middle")
.attr("x", function(d) { return 10; })
.attr("y", function(d) { return yscale(d.value) - 5; })
.text(function(d) { return d.value; });
Here is my complete code:
var data = [{
"date": "2018-1",
"value": 40.13,
"status": 1
}, {
"date": "2018-2",
"value": 45.88,
"status": 1
}, {
"date": "2018-3",
"value": 50.89,
"status": 1
}, {
"date": "2018-4",
"value": 55.87,
"status": 1
}, {
"date": "2018-5",
"value": 88.54,
"status": 1
}, {
"date": "2018-6",
"value": 74.41,
"status": 1
}, {
"date": "2018-7",
"value": 98.56,
"status": 1
}, {
"date": "2018-8",
"value": 81.05,
"status": 1
}, {
"date": "2018-9",
"value": 58.13,
"status": 1
}, {
"date": "2018-10",
"value": 95.86,
"status": 1
}, {
"date": "2018-11",
"value": 78.13,
"status": 1
}, {
"date": "2018-12",
"value": 98.86,
"status": 1
}, {
"date": "2019-1",
"value": 105.86,
"status": 0
}, {
"date": "2019-2",
"value": 110.86,
"status": 0
}];
/* Monday 2012 */
var data1 = data
var dateformat = "%Y-%m"
drawTimeSeriesGraph(data1, dateformat);
/*
Tooltip from: http://bl.ocks.org/d3noob/6eb506b129f585ce5c8a
line graph from here: http://www.d3noob.org/2012/12/starting-with-basic-d3-line-graph.html
*/
function drawTimeSeriesGraph(data, dateformat) {
//Set bounds for red dots
var lbound = 0.045,
ubound = 0.075;
// Set the dimensions of the canvas / graph
var margin = {
top: 50,
right: 150,
bottom: 50,
left: 50
},
width = 900 - margin.left - margin.right,
height = 270 - margin.top - margin.bottom;
// Parse the date / time
var parseDate = d3.time.format(dateformat).parse,
formatDate = d3.time.format(dateformat),
bisectDate = d3.bisector(function(d) {
return d.date;
}).left;
// Set the ranges
var x = d3.time.scale().range([0, width]);
var y = d3.scale.linear().range([height, 0]);
// Define the axes
var xAxis = d3.svg.axis().scale(x)
.orient("bottom").ticks(10);
var yAxis = d3.svg.axis().scale(y)
.orient("left").ticks(10);
// Define the line
var valueline = d3.svg.line()
.x(function(d) {
return x(d.date);
})
.y(function(d) {
return y(d.value);
}).interpolate("linear");
var full_date = new Date();
var day = full_date.getDay(); //returns 0 - 6
var month = full_date.getMonth() + 1; //returns 0 - 11
var year = full_date.getFullYear(); //returns 4 digit year ex: 2000
var my = year + "-" + month;
//alert(my);
// Adds the svg canvas
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 lineSvg = svg.append("g");
var focus = svg.append("g")
.style("display", "none");
// Get the data
data.forEach(function(d) {
d.date = parseDate(d.date);
d.value = +d.value;
});
// Scale the range of the data
x.domain(d3.extent(data, function(d) {
return d.date;
}));
y.domain([0, d3.max(data, function(d) {
return d.value;
})]);
//Use below if instead you want to define the y limits:
//y.domain([0, 0.11]);
// Add the valueline path.
var lineGraph2 = lineSvg.append("path")
.attr("class", "line")
.attr("d", valueline(data.filter(function(d) {
return d.status > 0;
})))
.attr("stroke", "blue")
.attr("stroke-width", 2)
.attr("fill", "none");
var lineGraph1 = lineSvg.append("path")
.attr("class", "line")
.attr("d", valueline(data.slice(-3)))
.attr("stroke", "red")
.attr("stroke-width", 2)
.attr("fill", "none");
// Add the X Axis
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
// Add the Y Axis
svg.append("g")
.attr("class", "y axis")
.call(yAxis);
// append the x line
focus.append("line")
.attr("class", "x")
.style("stroke", "blue")
.style("stroke-dasharray", "3,3")
.style("opacity", 0.5)
.attr("y1", 0)
.attr("y2", height);
// append the y line
focus.append("line")
.attr("class", "y")
.style("stroke", "blue")
.style("stroke-dasharray", "3,3")
.style("opacity", 0.5)
.attr("x1", width)
.attr("x2", width);
// append the circle at the intersection
focus.append("circle")
.attr("class", "y")
.style("fill", "none")
.style("stroke", "blue")
.attr("r", 4);
// place the value at the intersection
focus.append("text")
.attr("class", "y1")
.style("stroke", "white")
.style("stroke-width", "3.5px")
.style("opacity", 0.8)
.attr("dx", 8)
.attr("dy", "-.3em");
focus.append("text")
.attr("class", "y2")
.attr("dx", 8)
.attr("dy", "-.3em");
// place the date at the intersection
focus.append("text")
.attr("class", "y3")
.style("stroke", "white")
.style("stroke-width", "3.5px")
.style("opacity", 0.8)
.attr("dx", 8)
.attr("dy", "1em");
focus.append("text")
.attr("class", "y4")
.attr("dx", 8)
.attr("dy", "1em");
// append the rectangle to capture mouse
svg.append("rect")
.attr("width", width)
.attr("height", height)
.style("fill", "none")
.style("pointer-events", "all")
.on("mouseover", function() {
focus.style("display", null);
})
.on("mouseout", function() {
focus.style("display", "none");
})
.on("mousemove", mousemove);
function mousemove() {
var x0 = x.invert(d3.mouse(this)[0]),
i = bisectDate(data, x0, 1),
d0 = data[i - 1],
d1 = data[i],
d = x0 - d0.date > d1.date - x0 ? d1 : d0;
focus.select("circle.y")
.attr("transform", "translate(" + x(d.date) + "," + y(d.value) + ")");
focus.select("text.y1")
.attr("transform", "translate(" + x(d.date) + "," + y(d.value) + ")")
.text(d.value.toFixed(2));
focus.select("text.y2")
.attr("transform", "translate(" + x(d.date) + "," + y(d.value) + ")")
.text(d.value.toFixed(2));
focus.select("text.y3")
.attr("transform", "translate(" + x(d.date) + "," + y(d.value) + ")")
.text(formatDate(d.date));
focus.select("text.y4")
.attr("transform", "translate(" + x(d.date) + "," + y(d.value) + ")")
.text(formatDate(d.date));
focus.select(".x")
.attr("transform", "translate(" + x(d.date) + "," + y(d.value) + ")")
.attr("y2", height - y(d.value));
focus.select(".y")
.attr("transform", "translate(" + width * -1 + "," + y(d.value) + ")")
.attr("x2", width + width);
};
svg.append("text")
.attr("x", (width / 2))
.attr("y", 0 - (margin.top / 2))
.attr("text-anchor", "middle")
.style("font-size", "16px")
.style("text-decoration", "underline")
};
I'm trying to get line graph like this:
For the axis you have to set the tickFormat.
xAxis.tickFormat(d3.time.format("%b'%y"));
or if you want full month name
xAxis.tickFormat(d3.time.format("%B'%y"));
For the text just add them like you do with circles or rects
svg.selectAll(".val").data(data)
.enter()
.append('text')
.attr("x", d => x(d.date))
.attr("y", d => y(d.value))
.attr("dy", "-0.5em")
.attr("text-anchor", "middle")
.text(d => d.value);

Grouping bar and line charts

I am trying to group bar chart and line chart in d3 js and I followed one Link for that purpose,
Here is what my Ajax is returning in response:
[
{
"date_created": "2017-12-27",
"jobs_fail": 19,
"jobs_resub": 31,
"jobs_success": 50
},
{
"date_created": "2017-12-29",
"jobs_fail": 18,
"jobs_resub": 25,
"jobs_success": 44
},
{
"date_created": "2017-12-28",
"jobs_fail": 8,
"jobs_resub": 24,
"jobs_success": 44
},
{
"date_created": "2018-01-02",
"jobs_fail": 2,
"jobs_resub": 0,
"jobs_success": 0
}
]
And what I am trying to show is displaying the jobs_fail and jobs_resub as a bar and jobs_sucess as line chart in same graphs with respect to date_created,
Here is my code for that purpose.
<script>
function get_data() {
console.log("create post is working!") // sanity check
return $.ajax({
url : "/group/guest/query/", // the endpoint
type : "GET", // http method
});
};
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 colorRange = d3.scale.category20();
var color = d3.scale.ordinal()
.range(colorRange.range());
var divTooltip = d3.select("body").append("div").attr("class", "toolTip");
var xAxis = d3.svg.axis()
.scale(x0)
.orient("bottom");
var yAxis = d3.svg.axis()
.scale(y)
.orient("left")
.ticks(10, "");
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 + ")");
var ajdata = get_data();
var k = [];
ajdata.success(function (data) {
var obj = jQuery.parseJSON(data);
alert(data);
var options = d3.keys(obj[0]).filter(function(key) { if (key != "date_created" & key != "jobs_success" ) { return key }}); // & key != "date_created"){return key} });
var line_option = d3.keys(obj[0]).filter(function(key) { if (key == "jobs_success" & key == "date_created"){return key} });
alert(options);
obj.forEach(function(d) {
d.valores = options.map(function(name) {return { name: name, value: +d[name]}; });});
x0.domain(obj.map(function(d) { return d.date_created; }));
x1.domain(options).rangeRoundBands([0, x0.rangeBand()]);
y.domain([0, d3.max(obj, function(d) { return d3.max(d.valores, function(d) { return d.value; }); })]);
var line = d3.svg.line()
.x(function(d) { return x1(d.date_created); })
.y(function(d) { return y(d.jobs_success); });
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("Number of jobs");
var bar = svg.selectAll(".bar")
.data(obj)
.enter().append("g")
.attr("class", "rect")
.attr("transform", function(d) { return "translate(" + x0(d.date_created) + ",0)"; });
bar.selectAll("rect")
.data(function(d) { return d.valores; })
.enter().append("rect")
.attr("width", x1.rangeBand())
.attr("x", function(d) { return x1(d.name); })
.attr("y", function(d) { return y(d.value); })
.attr("value", function(d){return d.name;})
.attr("height", function(d) { return height - y(d.value); })
.style("fill", function(d) { return color(d.name); });
bar
.on("mousemove", function(d){
divTooltip.style("left", d3.event.pageX+10+"px");
divTooltip.style("top", d3.event.pageY-25+"px");
divTooltip.style("display", "inline-block");
var x = d3.event.pageX, y = d3.event.pageY
var elements = document.querySelectorAll(':hover');
l = elements.length
l = l-1
elementData = elements[l].__data__
divTooltip.html((d.date_created)+"<br>"+elementData.name+"<br>"+elementData.value);
});
bar
.on("mouseout", function(d){
divTooltip.style("display", "none");
});
var legend = svg.selectAll(".legend")
.data(options.slice())
.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; });
svg.append("path")
//.data(obj)
.attr("class", "line")
.attr("d", line(obj));
UPDATE
What problem I am facing is I am able to render bar but not the line chart on bars.
I am trying to debug but not able to do so.
Please let me know what might I am doing wrong here.
You have some minor problems and a big problem.
The minor problems are:
Your y scale should take into account the maximum value in your dataset:
y.domain([0, d3.max(obj, function(d) {
return d.jobs_success
})]);
Your line generator should use x0. Besides that, you'll have to move the line by half rangeBand:
.x(function(d) {
return x0(d.date_created) + x0.rangeBand() / 2;
})
By default, a <path> has a black fill. Change it:
.style("fill", "none")
Those, however, are minor problems. The biggest problem lies here, in the data() method:
svg.append("path")
.data(obj)
.attr("class", "line")
.attr("d", line);
Let's see in detail what's happening here. You're passing the obj array to the data(). However, if you do this, each element of that array will be passed, individually, to the line generator.
So, supposing that this is your array...
["foo", "bar", "baz"]
...what you're passing to the line generator is just:
"foo".
You have some different solutions here. First, you can pass the array to the line generator directly, as you did in your edit. Second, you can wrap the array in an outer array:
svg.append("path")
.data([obj])
.attr("class", "line")
.attr("d", line);
That way, the whole obj array will be passed to the line generator.
Or, third, you can use datum:
svg.append("path")
.datum(obj)
.attr("class", "line")
.attr("d", line);
Here is your code with those changes and using datum to draw the path:
var obj = [{
"date_created": "2017-12-27",
"jobs_fail": 19,
"jobs_resub": 31,
"jobs_success": 50
}, {
"date_created": "2017-12-29",
"jobs_fail": 18,
"jobs_resub": 25,
"jobs_success": 44
}, {
"date_created": "2017-12-28",
"jobs_fail": 8,
"jobs_resub": 24,
"jobs_success": 44
}, {
"date_created": "2018-01-02",
"jobs_fail": 2,
"jobs_resub": 0,
"jobs_success": 0
}];
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 colorRange = d3.scale.category20();
var color = d3.scale.ordinal()
.range(colorRange.range());
var divTooltip = d3.select("body").append("div").attr("class", "toolTip");
var xAxis = d3.svg.axis()
.scale(x0)
.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 options = d3.keys(obj[0]).filter(function(key) {
if (key != "date_created" & key != "jobs_success") {
return key
}
}); // & key != "date_created"){return key} });
var line_option = d3.keys(obj[0]).filter(function(key) {
if (key == "jobs_success" & key == "date_created") {
return key
}
});
obj.forEach(function(d) {
d.valores = options.map(function(name) {
return {
name: name,
value: +d[name]
};
});
});
x0.domain(obj.map(function(d) {
return d.date_created;
}));
x1.domain(options).rangeRoundBands([0, x0.rangeBand()]);
y.domain([0, d3.max(obj, function(d) {
return d.jobs_success
})]);
var line = d3.svg.line()
.x(function(d) {
return x0(d.date_created) + x0.rangeBand() / 2;
})
.y(function(d) {
return y(d.jobs_success);
});
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("Number of jobs");
var bar = svg.selectAll(".bar")
.data(obj)
.enter().append("g")
.attr("class", "rect")
.attr("transform", function(d) {
return "translate(" + x0(d.date_created) + ",0)";
});
bar.selectAll("rect")
.data(function(d) {
return d.valores;
})
.enter().append("rect")
.attr("width", x1.rangeBand())
.attr("x", function(d) {
return x1(d.name);
})
.attr("y", function(d) {
return y(d.value);
})
.attr("value", function(d) {
return d.name;
})
.attr("height", function(d) {
return height - y(d.value);
})
.style("fill", function(d) {
return color(d.name);
});
bar
.on("mousemove", function(d) {
divTooltip.style("left", d3.event.pageX + 10 + "px");
divTooltip.style("top", d3.event.pageY - 25 + "px");
divTooltip.style("display", "inline-block");
var x = d3.event.pageX,
y = d3.event.pageY
var elements = document.querySelectorAll(':hover');
l = elements.length
l = l - 1
elementData = elements[l].__data__
divTooltip.html((d.date_created) + "<br>" + elementData.name + "<br>" + elementData.value);
});
bar
.on("mouseout", function(d) {
divTooltip.style("display", "none");
});
var legend = svg.selectAll(".legend")
.data(options.slice())
.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;
});
svg.append("path")
.datum(obj)
.attr("class", "line")
.attr("d", line)
.style("fill", "none")
.style("stroke", "red")
.style("stroke-width", 2);
.axis line,
.axis path {
fill: none;
stroke: black;
shape-rendering: crispEdges;
}
<script src="https://d3js.org/d3.v3.min.js"></script>
Ok a couple of things. Your line's x function should be relying on x0 not x1:
var line = d3.svg.line()
.x(function(d) { return x0(d.date_created); })
.y(function(d) { return y(d.jobs_success); });
And your path needs to be called like this:
svg.append("path")
.attr("class", "line")
.attr("d", line(obj));
That should get you most of the way there - you might want to tweak the maximum y-value, and shift the x co-ordinate of the line by x0.rangeBand()/2 as well to make it line up properly with the centre of the bars.

how to left align ticks in d3 bar chart

i created a stacked bar graph.
on the y axis side i have ticks with varying lengths.
what i am trying to accomplish is to align the text in the tick to the left.
this is my example:http://jsfiddle.net/2khbceut/2/
html
<title>Diverging Stacked Bar Chart with D3.js</title>
<body>
<div id="figure" align="center" style="margin-bottom: 50px;"></div>
</body>
javascript
$(document).ready(getTopolegy());
function getTopolegy(){
var data = null;
var links = parseTopology(data);
createChart(links);
}
function parseTopology(data){
var links=[{1:5,2:5,3:10,N:20,link_name: "Link CHGIL21CRS-SFXCA21CRS"},
{1:5,2:5,3:10,N:20,link_name: "Link NYCNY21CRS-NYCNY22CRS"}];
return links;
}
function jsonNameToId(name){
switch (allocated_priority) {
case "allocated_priority":
return 1;
case "allocated_default":
return 2;
case "spare_capacity":
return 3;
case "total":
return "N";
default:
return 999;
}
}
function createChart(data){
var margin = {top: 50, right: 20, bottom: 10, left: 210},
width = 1000 - margin.left - margin.right,
height = 100 - margin.top - margin.bottom;
var y = d3.scale.ordinal()
.rangeRoundBands([0, height], .3);
var x = d3.scale.linear()
.rangeRound([0, width]);
var color = d3.scale.ordinal()
.range(["#cccccc", "#92c6db", "#086fad"]);
var xAxis = d3.svg.axis()
.scale(x)
.orient("top");
var yAxis = d3.svg.axis()
.scale(y)
.orient("left")
var svg = d3.select("#figure").append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.attr("id", "d3-plot")
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
color.domain(["Allocated Priority %", "Allocated Default %", "Spare Capacity %"]);
// d3.csv("js/raw_data.csv", function(error, data) {
data.forEach(function(d) {
d["Allocated Priority %"] = +d[1]*100/d.N;
d["Allocated Default %"] = +d[2]*100/d.N;
d["Spare Capacity %"] = +d[3]*100/d.N;
var x0 = 0;
var idx = 0;
d.boxes = color.domain().map(function(name) { return {name: name, x0: x0, x1: x0 += +d[name], N: +d.N, n: +d[idx += 1]}; });
});
var min_val = d3.min(data, function(d) {
return d.boxes["0"].x0;
});
var max_val = d3.max(data, function(d) {
return d.boxes["2"].x1;
});
x.domain([min_val, max_val]).nice();
y.domain(data.map(function(d) { return d.link_name; }));
svg.append("g")
.attr("class", "x axis")
.call(xAxis);
svg.append("g")
.attr("class", "y axis")
.call(yAxis)
var vakken = svg.selectAll(".Link")
.data(data)
.enter().append("g")
.attr("class", "bar")
.attr("transform", function(d) { return "translate(0," + y(d.link_name) + ")"; });
var bars = vakken.selectAll("rect")
.data(function(d) { return d.boxes; })
.enter().append("g").attr("class", "subbar");
bars.append("rect")
.attr("height", y.rangeBand())
.attr("x", function(d) { return x(d.x0); })
.attr("width", function(d) { return x(d.x1) - x(d.x0); })
.style("fill", function(d) { return color(d.name); });
bars.append("text")
.attr("x", function(d) { return x(d.x0); })
.attr("y", y.rangeBand()/2)
.attr("dy", "0.5em")
.attr("dx", "0.5em")
.style("font" ,"10px sans-serif")
.style("text-anchor", "begin")
.text(function(d) { return d.n !== 0 && (d.x1-d.x0)>3 ? d.n : "" });
vakken.insert("rect",":first-child")
.attr("height", y.rangeBand())
.attr("x", "1")
.attr("width", width)
.attr("fill-opacity", "0.5")
.style("fill", "#F5F5F5")
.attr("class", function(d,index) { return index%2==0 ? "even" : "uneven"; });
svg.append("g")
.attr("class", "y axis")
.append("line")
.attr("x1", x(0))
.attr("x2", x(0))
.attr("y2", height);
var startp = svg.append("g").attr("class", "legendbox").attr("id", "mylegendbox");
// this is not nice, we should calculate the bounding box and use that
var legend_tabs = [0, 150, 300];
var legend = startp.selectAll(".legend")
.data(color.domain().slice())
.enter().append("g")
.attr("class", "legend")
.attr("transform", function(d, i) { return "translate(" + legend_tabs[i] + ",-45)"; });
legend.append("rect")
.attr("x", 0)
.attr("width", 18)
.attr("height", 18)
.style("fill", color);
legend.append("text")
.attr("x", 22)
.attr("y", 9)
.attr("dy", ".35em")
.style("text-anchor", "begin")
.style("font" ,"10px sans-serif")
.text(function(d) { return d; });
d3.selectAll(".axis path")
.style("fill", "none")
.style("stroke", "#000")
.style("shape-rendering", "crispEdges")
d3.selectAll(".axis line")
.style("fill", "none")
.style("stroke", "#000")
.style("shape-rendering", "crispEdges")
var movesize = width/2 - startp.node().getBBox().width/2;
d3.selectAll(".legendbox").attr("transform", "translate(" + movesize + ",0)");
// });
}
as can be seen the current positioning of the tick text is to the right.
i tried the following idea:
svg.append("g")
.attr("class", "y axis")
.call(yAxis)
.selectAll("text")
.style("text-anchor", "start");
but it did not position the ticks in the desired alignment.
any ideas?
You can make the Y axis right-oriented, which will have the effect of positioning all the labels to the right of the axis, left-aligning them:
var yAxis = d3.svg.axis()
.scale(y)
.orient("right")// <- 1st step
At that point the labels would disappear, because they'll get covered up by the bars of the graph.
But then you can shift all those left-aligned labels some constant distance in the negative X direction, such that they're back on the left side of the Y axis, but still left-aligned the way you wanted. tickPadding() is a way to shift them:
var yAxis = d3.svg.axis()
.scale(y)
.orient("right")
.tickPadding(-180)
Here's your example, modified with the above: http://jsfiddle.net/2khbceut/3/
Maybe hardcoding the -180 is ok for you. If you need that amount to be dynamic, you can compute it using getBBox() on each text element of the axis and taking the maximum width to be the negative offset.
You can set the text-anchor to "start" and adjust the x position with translate, I added the code below in the chart model "boxPlotChart.js"
g.select('.nv-y.nv-axis').selectAll('.tick').selectAll('text')
.style('text-anchor','start')
.attr('transform', function(d,i,j) { return 'translate(-14,0)' });
g.select('.nv-y.nv-axis').selectAll('.nv-axisMaxMin').selectAll('text')
.style('text-anchor','start')
.attr('transform', function(d,i,j) { return 'translate(-16,0)' });

how to plot data from JSON object on .svg file using D3.js

Image is appending as a background which is not clear.
Able to plot data on svg element which is created in this code.
But want to plot json data on image/.svg file with the following..
Will appreciate if any references...
$(function(){
makePlot();
// $('#zoomReset').on('click',function(e){
// e.preventDefault();
// //$('#chart').empty();
// console.log("sadf");
// makePlot();
// });
});
var makePlot = function() {
d3.json("scatter-data-2010.json", function(dataset) {
//Width and height
var margin = {top: 80, right: 10, bottom: 60, left: 80},
width = 600 - margin.left - margin.right,
height = 600 - margin.top - margin.bottom;
var centered = undefined;
//Create SVG element
tooltip = d3.select("body").append("div")
.attr("class", "plan_tooltip")
.style("position", "absolute")
.style("z-index", "10")
.style("visibility", "hidden")
.text("");
var svg = d3.select("#vis")
.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 + ")");
svg.append("defs").append("clipPath")
.attr("id", "clip")
.append("rect")
.attr("width", width)
.attr("height", height);
/// Set Scales and Distortions
var xScale = d3.scale.linear()
.domain([d3.min(dataset, function(d) { return d['n_workers_change']; }), d3.max(dataset, function(d) { return d['n_workers_change']; })])
.range([0, width]);
var yScale = d3.scale.linear()
.domain([d3.min(dataset, function(d) { return d['earnings_change']; }), d3.max(dataset, function(d) { return d['earnings_change']; })])
.range([height,0]);
var color_scale = d3.scale.category20();
//Add 2 more colors to category 20 because there are 22 parent industry categories
var color_scale_range = color_scale.range();
color_scale_range.push("#e6550d","#6baed6")
radiusScale = d3.scale.sqrt()
.domain([d3.min(dataset, function(d) { return d['n_workers_y']; }), d3.max(dataset, function(d) { return d['n_workers_y']; }) ])
.range([3, 15]);
svg.append("defs")
.append("pattern")
.attr("id", "background")
.attr("width", width)
.attr("height", height)
.append("image")
.attr("xlink:href", "http://www.e-pint.com/epint.jpg")
.attr("width", width)
.attr("height", height);
var rect = svg.append("rect")
.attr("class", "background")
.attr("pointer-events", "all")
//.attr("fill","none")
.attr("fill","url(#background)")
.attr("width", width)
.attr("height", height)
.call(d3.behavior.zoom().x(xScale).y(yScale).on("zoom", redraw));
// Tooltips for Dots
set_tooltip_label = function (d) {
var company_name;
tooltip.html(d.category + "<br><strong>N Workers in 2010 (thousands)</strong>: " + d['n_workers_y'] + "<br><strong>Med. Wkly Earnings in 2010 ($)</strong>: " + d.earnings_y + "<br><strong> Category</strong>: " + d.parent_name );
if (!(event === undefined)) {
tooltip.style("top", (event.pageY - 10) + "px").style("left", (event.pageX + 10) + "px")
}
};
var circles = svg.selectAll("circle")
.data(dataset)
.enter()
.append("circle")
.attr("clip-path", "url(#clip)")
// Set cx, cy in the redraw function
.attr("r", function(d) {
return radiusScale(d['n_workers_y']);
})
.attr("fill", function(d) {
return color_scale(d.parent_id)
})
.on("mouseover", function () {
return tooltip.style("visibility", "visible")
}).on("mousemove", function (d) {
set_tooltip_label(d);
}).on("mouseout", function () {
tooltip.style("visibility", "hidden");
});
// Define X axis
var xAxis = d3.svg.axis()
.scale(xScale)
.orient("bottom")
.ticks(5)
.tickSize(-height)
.tickFormat(d3.format("s"));
// Define Y axis
var yAxis = d3.svg.axis()
.scale(yScale)
.orient("left")
.ticks(10)
.tickFormat(function(d) { return d + " %"; })
.tickSize(-width);
// Create X axis
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + (height) + ")")
.call(xAxis);
// Create Y axis
svg.append("g")
.attr("class", "y axis")
.attr("transform", "translate(" + 0 + ",0)")
.call(yAxis);
// Add Label to X Axis
svg.append("text")
.attr("class", "x label")
.attr("text-anchor", "middle")
.attr("x", width - width/2)
.attr("y", height + margin.bottom/2)
.text("Percent Change in Number of Workers in Industry");
// Add label to Y Axis
svg.append("text")
.attr("class", "y label")
.attr("text-anchor", "middle")
.attr("y", -margin.left + 5)
.attr("x", 0 - (height/2))
.attr("dy", "1em")
.attr("transform", "rotate(-90)")
.text("Percent Change in Inflation Adjusted Median Weekly Earnings");
// Add title
svg.append("text")
.attr("class", " title")
.attr("text-anchor","middle")
.attr("x", width/2)
.attr("y", -margin.top/2)
.text("Changes in Employment and Salary by Industry, 2003 - 2010");
// Add subtitle
svg.append("text")
.attr("class", "subtitle")
.attr("text-anchor","middle")
.attr("x", width/2)
.attr("y", -margin.top/2 + 15)
.text("Scroll and drag to zoom/pan, hover for details.");
var objects = svg.append("svg")
.attr("class", "objects")
.attr("width", width)
.attr("height", height);
//Create main 0,0 axis lines:
hAxisLine = objects.append("svg:line")
.attr("class", "axisLine hAxisLine");
vAxisLine = objects.append("svg:line")
.attr("class", "axisLine vAxisLine");
// Zoom/pan behavior:
function redraw(duration) {
var duration = typeof duration !== 'undefined' ? duration : 0;
if (d3.event){
//console.log("In the zoom function now");
//console.log(d3.event.scale);
//console.log(d3.event.translate);
svg.select(".x.axis").call(xAxis);
svg.select(".y.axis").call(yAxis);
}
hAxisLine.transition().duration(duration)
.attr("x1",0)
.attr("y1",0)
.attr("x2",width)
.attr("y2",0)
.attr("transform", "translate(0," + (yScale(0)) + ")");
vAxisLine.transition().duration(duration)
.attr("x1",xScale(0))
.attr("y1",yScale(height))
.attr("x2",xScale(0))
.attr("y2",yScale(-height));
circles.transition().duration(duration)
.attr("cx", function(d) {
return xScale(d['n_workers_change']);
})
.attr("cy", function(d) {
return yScale(d['earnings_change']);
})
}; // <-------- End of zoom function
redraw(0); // call zoom to place elements
}); // end of json loading section
};
You need to define the background image as a pattern and then fill the rect with that pattern:
svg.append("defs")
.append("pattern")
.attr("id", "background")
.attr("width", width)
.attr("height", height)
.append("image")
.attr("xlink:href", "http://www.e-pint.com/epint.jpg")
.attr("width", width)
.attr("height", height);
svg.append("rect")
.attr("fill", "url(#background)");

Categories

Resources