d3 - trigger event on second click - javascript

I've somehow managed to do create a stacked bar chart for this post.
Instead of hover method i've chosen to get on with click event as i was facing some bug with the hover event like the elements were not disappearing properly when i hover on to a element.
When i click on a bar all the bars are getting disappeared and the width of the bar is getting increased. But that when I click on the bar that's been expanded i want to reset it's width to the original width.
I wanted to know how to get back to it's original width[when i was using hover method i defined the width manually]
Need to how to code for the send click event for the expanded bar.
Please help.
JS :
var width = 750,
height = 500;
var x = d3.scale.ordinal()
.rangeRoundBands([0, width], .1);
var y = d3.scale.linear()
.rangeRound([height, 0]);
var color = d3.scale.ordinal()
.range(["#D70B16", "#154CEF", "#1A8A55"]);
var xAxis = d3.svg.axis()
.scale(x)
.orient("bottom");
var yAxis = d3.svg.axis()
.scale(y)
.orient("left")
.tickFormat(d3.format(".2s"));
var svgContainer = d3.select("body")
.append("svg")
.attr("width", width)
.attr("height", height)
.append("g")
.attr("transform", "translate(" + 30 + "," + 30 + ")");
function movein() {
var allRect = d3.selectAll("rect")
// .transition()
// .duration(300)
.attr("opacity", 0)
.attr("display", "none")
d3.select(this)
.attr("opacity", 1)
.attr("display", "block")
d3.select(this)
.transition()
.delay(300)
.duration(500)
.attr("width", 300)
};
function moveout() {
d3.select(this)
.transition()
.duration(1000)
.attr("width", 150)
var allRect = d3.selectAll("rect")
.transition()
.delay(1000)
.duration(300)
.attr("opacity", 1)
.attr("display", "block")
};
d3.csv("data.csv", function(error, data) {
color.domain(d3.keys(data[0]).filter(function(key) { return key !== "circle"; }));
data.forEach(function(d) {
var y0 = 0;
d.hours = color.domain().map(function(name) { return {name: name, y0: y0, y1: y0 += +d[name]}; });
d.total = d.hours[d.hours.length - 1].y1;
});
x.domain(data.map(function(d) {return d.circle;}));
y.domain([0, d3.max(data, function(d) {return d.total;})])
svgContainer.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
svgContainer.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("Login Hours");
var circle = svgContainer.selectAll(".circle")
.data(data)
.enter().append("g")
.attr("class", "g")
.attr("transform", function(d) { return "translate(" + x(d.circle) + ",0)"; });
circle.selectAll("rect")
.data(function(d) { return d.hours; })
.enter()
.append("rect")
.attr("width", x.rangeBand())
.attr("y", function(d) { return y(d.y1); })
.attr("height", function(d) { return y(d.y0) - y(d.y1); })
.on("click", movein)
.on("click", moveout)
.style("fill", function(d) { return color(d.name); });
})
DATA :
state,value1, value2, value3
state1, 80, 10, 20
state2, 90, 5, 10
state3, 70, 15, 35
state4, 90, 3, 27
state5, 50, 25, 55
state6, 85, 8, 27

Related

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.

Apply zoom pan and axis rescale in d3

I have created scattered chart in D3.
It's working fine but I have a requirement to add zooming and axis rescaling to the chart.
Since I am pretty much new to d3 I am not able to do it.I have seen some example about it but I am able apply the zooming, panning etc code in my chart.
Here is my code-
var margin = {
top: 35,
right: 10,
bottom: 40,
left: 80
},
width = width - margin.left - margin.right,
height = height - margin.top - margin.bottom;
var xValue = function(d){
return d[measureArray[1]];
},
x = d3.scale.linear()
.range([0, width*.98]),
xMap = function(d,i) {
return x(xValue(d));
},
make_x_axis = function() {
return d3.svg.gridaxis()
.scale(x)
.orient("bottom")
},
xAxis = d3.svg.axis()
.scale(x)
.orient("bottom")
.tickFormat(function(d) {
return d;
});
var yValue = function(d){
return d[measureArray[0]];
},
y = d3.scale.linear()
.range([height*.98, 0]),
yMap = function(d,i){
return y(yValue(d));
},
make_y_axis = function() {
return d3.svg.gridaxis()
.scale(y)
.orient("left")
},
yAxis = d3.svg.axis()
.scale(y)
.orient("left")
.tickFormat(function(d) {
// if(typeof displayY !=="undefined" && displayY =="Yes"){
// if(yAxisFormat==""){
return d;
});
var zValue = function(d){
return d[measureArray[2]];
},
zScale = d3.scale.linear()
.range([height*.98, 0]),
zMap = function(d) {
return zScale(zValue(d));
};
var color = d3.scale.category10();
var svg = d3.select("body") .append("svg")
.attr("id", "svg_" + div)
.attr("viewBox", "0 0 "+(width + margin.left + margin.right)+" "+(height + margin.top + margin.bottom+ 17.5 )+" ")
.classed("svg-content-responsive", true)
.append("g")
.attr("transform", "translate(" + (margin.left*.7) + "," + (margin.top+3) + ")");
var tooltip = d3.select("#"+divId).append("div")
.attr("class", "tooltip")
.style("opacity", 0);
data.forEach(function(d) {
d[measureArray[2]] = +d[measureArray[2]]
d[measureArray[1]] = +d[measureArray[1]];
d[measureArray[0]] = +d[measureArray[0]];
});
x.domain([d3.min(data, xValue)-1, d3.max(data, xValue)+1]);
y.domain([d3.min(data, yValue)-1, d3.max(data, yValue)+1]);
// }
if(typeof chartData[divId]["displayX"]!="undefined" && chartData[divId]["displayX"]!="" && chartData[divId]["displayX"]!="Yes"){}else{
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis)
.append("text")
.attr("class", "label")
.attr("x", width)
.attr("y", -6)
.style("text-anchor", "end")
.text(measureArray[1]);
}
// y-axis
if(typeof chartData[divId]["displayY"]!="undefined" && chartData[divId]["displayY"]!="" && chartData[divId]["displayY"]!="Yes"){}else{
svg.append("g")
.attr("class", "y axis")
.call(yAxis)
.append("text")
.attr("class", "label")
.attr("transform", "rotate(-90)")
.attr("y", 6)
.attr("dy", ".71em")
.style("text-anchor", "end")
.text(measureArray[0]);
}
var max = maximumValue(data, measureArray[2]);
var min = minimumValue(data, measureArray[2]);
var temp = {};
temp["min"] = min;
temp["max"] = max;
svg.selectAll(".circle")
.data(data)
.enter().append("circle")
.attr("index_value", function(d, i) {
return "index-" + d[columns[1]].replace(/[^a-zA-Z0-9]/g, '', 'gi');
})
.attr("class", function(d, i) {
return "bars-Bubble-index-" + d[columns[1]].replace(/[^a-zA-Z0-9]/g, '', 'gi')+div;
})
.attr("r", function(d,i){
// var scale = d3.scale.linear().domain([temp["max"], temp["min"]]).range(["38", "12"]);
// var radius = scale(data[i][measureArray[2]]);
return 6;
})
.attr("cx", xMap)
.attr("cy", yMap)
.attr("opacity",".6")
.attr("fill", 'red')
.attr("id",function(d,i) {
return d[columns[0]]+":"+d[columns[1]];
})
.attr("onclick", fun);
Working fiddle.
You can do it like this:
//define zoom behavior
var zoom = d3.behavior.zoom()
.on("zoom", draw);
//make a rectangle for receiving all the zoom/pan action.
svg.append("rect")
.attr("class", "pane")
.attr("width", width)
.attr("height", height)
.call(zoom);
//make a clip path so that the circle don't go out of the graph.
svg.append("clipPath")
.attr("id", "clip")
.append("rect")
.attr("x", x(0))
.attr("y", y(1))
.attr("width", x(1) - x(0))
.attr("height", y(0) - y(1));
Add the following class to the style(so that the rectangle pane is not visible) note: that the fill is none:
rect.pane {
cursor: move;
fill: none;
pointer-events: all;
}
After defining the domain, set the zoom x and y
x.domain([d3.min(data, xValue) - 1, d3.max(data, xValue) + 1]);
y.domain([d3.min(data, yValue) - 1, d3.max(data, yValue) + 1]);
// set the zoom for x and y
zoom.x(x);
zoom.y(y);
Make a group for all the circle so that its within the clippath
circlegroup = svg.append("g").attr("clip-path", "url(#clip)");
circlegroup.selectAll(".circle")...
Define the draw function which will be called on zoom and pan:
function draw() {
svg.select("g.x.axis").call(xAxis);//zoom of x axis
svg.select("g.y.axis").call(yAxis);//zoom of y axis
//update the position of the circle on zoom/pan
svg.selectAll("circle").attr("cx", xMap)
.attr("cy", yMap)
}
working code here

d3js scatter plot auto update doesnt work

Need some help figuring out how to auto update 3djs scatter plot. The code looks fine ,however, when the update
function is running the graph gets updated but the scatter plot remains at place. I'm using svg.selectAll(".dot").remove() in order to remove the outdated ones but unable to find a way to added them back. I found a few solutions online but none of them worked for my code.
Any help would be much appreciated. thanks
DB structure:
dtg | temperature
2016-03-02 09:14:00 23
2016-03-02 09:10:00 22
Code:
<script>
// Set the dimensions of the canvas / graph
var margin = {top: 30, right: 20, bottom: 30, left: 40},
width = 400 - margin.left - margin.right,
height = 200 - margin.top - margin.bottom;
// Parse the date / time
var parseDate = d3.time.format("%Y-%m-%d %H:%M:%S").parse;
var formatTime = d3.time.format("%e %B %X");
// 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(5);
var yAxis = d3.svg.axis().scale(y)
.orient("left").ticks(5);
// Define the line
var valueline = d3.svg.line()
.x(function(d) { return x(d.dtg); })
.y(function(d) { return y(d.temperature); });
var div = d3.select("#chart1").append("div")
.attr("class", "tooltip")
.style("opacity", 0);
// Adds the svg canvas
var svg = d3.select("#chart1")
.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 + ")");
function make_x_axis() {
return d3.svg.axis()
.scale(x)
.orient("bottom")
.ticks(10)
}
function make_y_axis() {
return d3.svg.axis()
.scale(y)
.orient("left")
.ticks(10)
}
// Get the data
d3.json("2301data.php", function(error, data) {
data.forEach(function(d) {
d.dtg = parseDate(d.dtg);
d.temperature = +d.temperature;
});
// Scale the range of the data
x.domain(d3.extent(data, function(d) { return d.dtg; }));
y.domain([0, 60]); //
// y.domain([0, d3.max(data, function(d) { return d.temperature; })]);
// Add the valueline path.
svg.append("path")
.attr("class", "line")
.attr("d", valueline(data));
// draw the scatterplot
svg.selectAll(".dot")
.data(data)
.enter().append("circle")
.attr("class", "dot")
.filter(function(d) { return d.temperature > 30 })
.style("fill", "red")
.attr("r", 3.5)
.attr("cx", function(d) { return x(d.dtg); })
.attr("cy", function(d) { return y(d.temperature); })
// Tooltip stuff after this
.on("mouseover", function(d) {
div.transition()
.duration(500)
.style("opacity", 0);
div.transition()
.duration(200)
.style("opacity", .9);
div .html(
d.temperature + "C" + "<br>" +
formatTime(d.dtg))
.style("left", (d3.event.pageX + 8) + "px")
.style("top", (d3.event.pageY - 18) + "px");})
.on("mouseout", function(d) {
div.transition()
.duration(500)
.style("opacity", 0);
});
// Add the X Axis
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.style("font-size", "14px")
.call(xAxis);
// Add the Y Axis
svg.append("g")
.attr("class", "y axis")
.style("font-size", "14px")
.call(yAxis);
// Draw the grid 1
svg.append("g")
.attr("class", "grid")
.attr("transform", "translate(0," + height + ")")
.call(make_x_axis()
.tickSize(-height, 0, 0)
.tickFormat("")
)
// Draw the grid 2
svg.append("g")
.attr("class", "grid")
.call(make_y_axis()
.tickSize(-width, 0, 0)
.tickFormat("")
)
// Addon 3 // text label for the graph
svg.append("text")
.attr("x", (width / 2))
.attr("y", 0 - (margin.top / 2))
.attr("text-anchor", "middle")
.style("font-size", "14px")
.style("text-decoration", "underline")
.style('fill', 'white')
//.attr("class", "shadow") // using text css
.text("2301 Temperature read in the past 24h\n");
});
var inter = setInterval(function() {
updateData();
}, 5000);
// ** Update data section (Called from the onclick)
function updateData() {
// Get the data again
d3.json("2301data.php", function(error, data) {
data.forEach(function(d) {
d.dtg = parseDate(d.dtg);
d.temperature = +d.temperature;
//d.hum = +d.hum; // Addon 9 part 3
});
// Scale the range of the data again
x.domain(d3.extent(data, function(d) { return d.dtg; }));
y.domain([0, 60]);
var svg = d3.select("#chart1").transition();
// Make the changes
svg.selectAll(".dot").remove(); //remove old dots
svg.select(".line").duration(750).attr("d", valueline(data));
svg.select("x.axis").duration(750).call(xAxis);
svg.select("y.axis").duration(750).call(yAxis);
//update the scatterplot
svg.selectAll(".dotUpdate")
.data(data)
.attr("class", "dotUpdate")
.enter().append("circle")
.filter(function(d) { return d.temperature > 30 })
.style("fill", "red")
.attr("r", 3.5)
.attr("cx", function(d) { return x(d.dtg); })
.attr("cy", function(d) { return y(d.temperature); });
});
}
</script>
The first thing I did wrong was using the wrong d3js.. the following line has to be replaced
<script src="http://d3js.org/d3.v3.min.js"></script>
With the following or else svg.selectAll would not work.
<script type="text/javascript" src="http://d3js.org/d3.v3.js"></script>
Now, as far as the scatter plots update goes. I'm now using the code below which works fine with some databases. In my case it still does not work well and I'll be posting it as a sepearte question as stakoverflow guidlines requsts..
// ** Update data section (Called from the onclick)
function updateData() {
// Get the data again
data = d3.json("2301data.php", function(error, data) {
data.forEach(function(d) {
d.dtg = parseDate(d.dtg);
d.temperature = +d.temperature;
// d.hum = +d.hum; // Addon 9 part 3
});
// Scale the range of the data again
x.domain(d3.extent(data, function(d) { return d.dtg; }));
y.domain([0, 60]); // Addon 9 part 4
var svg = d3.select("#chart1")
var circle = svg.selectAll("circle").data(data)
svg.select(".x.axis") // change the x axis
.transition()
.duration(750)
.call(xAxis);
svg.select(".y.axis") // change the y axis
.transition()
.duration(750)
.call(yAxis);
svg.select(".line") // change the line
.transition()
.duration(750)
.attr("d", valueline(data));
circle.transition()
.duration(750)
.attr("cx", function(d) { return x(d.dtg); })
// enter new circles
circle.enter()
.append("circle")
.filter(function(d) { return d.temperature > 30 })
.style("fill", "red")
.attr("r", 3.5)
.attr("cx", function(d) { return x(d.dtg); })
// remove old circles
circle.exit().remove()
});
}

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)' });

X & Y Co-ordinates of selective bars in a stack graph

I have a stacked bar chart. And I'd like a draw a line like grouping few bars of a stacked bar chart.
Something like this.
So to do this I need to find the y coordinate of the 2nd and the last bar.
Some one please help in drawing those line using d3.
JS:
var width = 750,
height = 500;
var x = d3.scale.ordinal()
.rangeRoundBands([0, width], .1);
var y = d3.scale.linear()
.rangeRound([height, 0]);
var color = d3.scale.ordinal()
.range(["#D70B16", "#154CEF", "#1A8A55"]);
var xAxis = d3.svg.axis()
.scale(x)
.orient("bottom");
var yAxis = d3.svg.axis()
.scale(y)
.orient("left")
.tickFormat(d3.format(".2s"));
var tip = d3.tip()
.attr('class', 'd3-tip')
.offset([-10, 0])
.html(function(d) {
return "Value: " + (d.y1 - d.y0) + "";
})
var svgContainer = d3.select("body")
.append("svg")
.attr("width", width)
.attr("height", height)
.append("g")
.attr("transform", "translate(" + 30 + "," + 30 + ")");
d3.csv("data.csv", function(error, data) {
color.domain(d3.keys(data[0]).filter(function(key) { return key !== "circle"; }));
data.forEach(function(d) {
var y0 = 0;
d.hours = color.domain().map(function(name) { return {name: name, y0: y0, y1: y0 += +d[name]}; });
d3.select('body').append('pre')
.text(JSON.stringify(d.hours, null, ' '));
d.total = d.hours[d.hours.length - 1].y1;
});
x.domain(data.map(function(d) {return d.circle;}));
y.domain([0, d3.max(data, function(d) {return d.total;})])
svgContainer.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
svgContainer.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("Login Hours");
var circle = svgContainer.selectAll(".circle")
.data(data)
.enter().append("g")
.attr("class", "g")
.attr("transform", function(d) { return "translate(" + x(d.circle) + ",0)"; });
circle.selectAll("rect")
.data(function(d) { return d.hours; })
.enter()
.append("rect")
.attr("width", x.rangeBand())
.attr("y", function(d) { return y(d.y1); })
.attr("height", function(d) { return y(d.y0) - y(d.y1); })
.on("mouseover", tip.show)
.on("mouseout", tip.hide)
.style("fill", function(d) { return color(d.name); });
circle.selectAll("text")
.data(function(d) { return d.hours; })
.enter()
.append("text")
.attr("x", 75)
.attr("y", function(d, i) { return y(d.y1) ; })
.style("text-anchor", "middle")
.text("test")
})
How you determine those values (and the bars) depends on how you can identify them. In this particular case, you don't actually need to get the rect items because the underlying data gives you access to everything you need.
To, for example, get the y coordinate of the second bar in the first column, you can use the following code:
var yCoord = y(data[0].hours[1].y1);

Categories

Resources