I have a simple bar chart here that should nicely transition all the bars over slightly to the left to make room for a new bar to appear on the right of the graph whenever new data is submitted via a button click event, however they all seem to fire over to the left side on top of each other.
Here is my code for my transition:
bars.transition()
.duration(1000)
.attr("x", function(d, i) {
return x(i);
})
.attr("y", function(d) {
return y(d.count);
})
.attr("width", x.rangeBand())
.attr("height", function(d) {
return height - y(d.count);
});
Here is a jsfiddle of the code so far: https://jsfiddle.net/foL2Lcg1/1/
The test data for entry on the button submission I'm using is 'Service: blah' and 'Count: 60000' which you can enter below the graph.
Any suggestions?
From the example here : https://bl.ocks.org/RandomEtc/cff3610e7dd47bef2d01
I have created this fiddle with your data : https://jsfiddle.net/thatOneGuy/foL2Lcg1/5/
I have added a draw function which you pass data. So instead of rewriting code as you were, you start by calling this function, and once you add/remove some data, you call this function again with the new set of data and it updates. Here is the function :
function draw(data) {
// measure the domain (for x, unique letters) (for y [0,maxFrequency])
// now the scales are finished and usable
x.domain(data.map(function(d) { return d.service; }));
y.domain([0, d3.max(data, function(d) { return d.count; })]);
// another g element, this time to move the origin to the bottom of the svg element
// someSelection.call(thing) is roughly equivalent to thing(someSelection[i])
// for everything in the selection\
// the end result is g populated with text and lines!
svg.select('.x.axis').transition().duration(300).call(xAxis);
// same for yAxis but with more transform and a title
svg.select(".y.axis").transition().duration(300).call(yAxis)
// THIS IS THE ACTUAL WORK!
var bars = svg.selectAll(".bar").data(data) // (data) is an array/iterable thing, second argument is an ID generator function
bars.exit()
.transition()
.duration(300)
.attr("y", y(0))
.attr("height", height - y(0))
.style('fill-opacity', 1e-6)
.remove();
// data that needs DOM = enter() (a set/selection, not an event!)
bars.enter().append("rect")
.attr("class", "bar")
.attr("y", function(d) {
return y(d.count);
})
.attr("height", function(d) {
return height - y(d.count);
})
// the "UPDATE" set:
bars.transition().duration(300).attr("x", function(d) { return x(d.service); }) // (d) is one item from the data array, x is the scale object from above
.attr("width", x.rangeBand()) // constant, so no callback function(d) here
.attr("y", function(d) { return y(d.count); })
.attr("height", function(d) { return height - y(d.count); }); // flip the height, because y's domain is bottom up, but SVG renders top down
}
Now update as you were on button click :
d3.select("button")
.attr("id", "submit")
.on("click", function() {
var service = document.getElementById("service").value;
var count = document.getElementById("count").value;
var json = {
"count": count,
"service": service
};
data.push(json);
draw(data)
})
Here is working code if fiddle isn't working :
var data = [
{
service: "QA",
count: "25262"
}, {
service: "QB",
count: "42386"
}, {
service: "QUERY_NOTICICATIONS",
count: "14042"
}, {
service: "TTL",
count: "4088"
}
];
// Mike Bostock "margin conventions"
var margin = {top: 20, right: 20, bottom: 30, left: 40},
width = window.innerWidth - margin.left - margin.right,
height = window.innerHeight/1.5 - margin.top - margin.bottom;
// D3 scales = just math
// x is a function that transforms from "domain" (data) into "range" (usual pixels)
// domain gets set after the data loads
var x = d3.scale.ordinal()
.rangeRoundBands([0, width], .1);
var y = d3.scale.linear()
.range([height, 0]);
// D3 Axis - renders a d3 scale in SVG
var xAxis = d3.svg.axis()
.scale(x)
.orient("bottom");
var yAxis = d3.svg.axis()
.scale(y)
.orient("left")
//.ticks(10, "%");
// create an SVG element (appended to body)
// set size
// add a "g" element (think "group")
// annoying d3 gotcha - the 'svg' variable here is a 'g' element
// the final line sets the transform on <g>, not on <svg>
var svg = d3.select(".chart")
.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("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
svg.append("g")
.attr("class", "y axis")
.append("text") // just for the title (ticks are automatic)
.attr("transform", "rotate(-90)") // rotate the text!
.attr("y", 6)
.attr("dy", ".71em")
.style("text-anchor", "end")
.text("Frequency");
// d3.tsv is a wrapper around XMLHTTPRequest, returns array of arrays (?) for a TSV file
// type function transforms strings to numbers, dates, etc.
draw(data);
function type(d) {
// + coerces to a Number from a String (or anything)
d.count = +d.count;
return d;
}
function draw(data) {
// measure the domain (for x, unique letters) (for y [0,maxFrequency])
// now the scales are finished and usable
x.domain(data.map(function(d) { return d.service; }));
y.domain([0, d3.max(data, function(d) { return d.count; })]);
// another g element, this time to move the origin to the bottom of the svg element
// someSelection.call(thing) is roughly equivalent to thing(someSelection[i])
// for everything in the selection\
// the end result is g populated with text and lines!
svg.select('.x.axis').transition().duration(300).call(xAxis);
// same for yAxis but with more transform and a title
svg.select(".y.axis").transition().duration(300).call(yAxis)
// THIS IS THE ACTUAL WORK!
var bars = svg.selectAll(".bar").data(data) // (data) is an array/iterable thing, second argument is an ID generator function
bars.exit()
.transition()
.duration(300)
.attr("y", y(0))
.attr("height", height - y(0))
.style('fill-opacity', 1e-6)
.remove();
// data that needs DOM = enter() (a set/selection, not an event!)
bars.enter().append("rect")
.attr("class", "bar")
.attr("y", function(d) {
return y(d.count);
})
.attr("height", function(d) {
return height - y(d.count);
})
// the "UPDATE" set:
bars.transition().duration(300).attr("x", function(d) { return x(d.service); }) // (d) is one item from the data array, x is the scale object from above
.attr("width", x.rangeBand()) // constant, so no callback function(d) here
.attr("y", function(d) { return y(d.count); })
.attr("height", function(d) { return height - y(d.count); }); // flip the height, because y's domain is bottom up, but SVG renders top down
}
d3.select("button")
.attr("id", "submit")
.on("click", function() {
var service = document.getElementById("service").value;
var count = document.getElementById("count").value;
var json = {
"count": count,
"service": service
};
data.push(json);
draw(data)
})
#tooltip {
position: absolute;
width: 200px;
height: auto;
padding: 10px;
background-color: white;
-webkit-border-radius: 10px;
-moz-border-radius: 10px;
border-radius: 10px;
-webkit-box-shadow: 4px 4px 10px rgba(0, 0, 0, 0.4);
-moz-box-shadow: 4px 4px 10px rgba(0, 0, 0, 0.4);
box-shadow: 4px 4px 10px rgba(0, 0, 0, 0.4);
pointer-events: none;
}
#tooltip.hidden {
display: none;
}
#tooltip p {
margin: 0;
font-family: sans-serif;
font-size: 16px;
line-height: 20px;
}
.chart rect {
fill: steelblue;
}
.chart text {
font: 10px sans-serif;
text-anchor: end;
}
.axis text {
font: 10px sans-serif;
}
.axis path,
.axis line {
fill: none;
stroke: #000;
shape-rendering: crispEdges;
}
svg text {
pointer-events: none;
}
rect {
-moz-transition: all 0.3s;
-o-transition: all 0.3s;
-webkit-transition: all 0.3s;
transition: all 0.3s;
}
rect:hover {
fill: orange;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
<body>
<svg class="chart"></svg>
<div class="input">
<p>Service :
<input id="service" type="text"></input> Count :
<input id="count" type="text"></input>
</p>
<br/>
<button id="submit">Submit</button>
</div>
<div id="tooltip" class="hidden">
<p><strong>Tooltip</strong></p>
<p><span id="service"></span></p>
<p><span id="count"></span></p>
</div>
</body>
There is a small mistake in your code. Use x(d.service) instead of x(i) to calculate x position of bars in click function.
bars.transition()
.duration(1000)
.attr("x", function(d, i) {
return x(d.service); //instead of x(i);
})
.attr("y", function(d) {
return y(d.count);
})
.attr("width", x.rangeBand())
.attr("height", function(d) {
return height - y(d.count);
});
var data = [
{
service: "QA",
count: "25262"
}, {
service: "QB",
count: "42386"
}, {
service: "QUERY_NOTICICATIONS",
count: "14042"
}, {
service: "TTL",
count: "4088"
}
];
var width = 960,
barHeight = 500;
var margin = {
top: 20,
right: 30,
bottom: 50,
left: 60
},
width = 960 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom;
var x = d3.scale.ordinal()
.rangeRoundBands([0, width], .1);
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 chart = d3.select(".chart")
.attr("width", width + margin.right + margin.left)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
x.domain(data.map(function(d) {
return d.service;
}));
y.domain([0, d3.max(data, function(d) {
return d.count
})]);
chart.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
chart.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");
chart.selectAll(".bar")
.data(data)
.enter().append("rect")
.attr("class", "bar")
.attr("x", function(d) {
return x(d.service);
})
.attr("y", function(d) {
return y(d.count);
})
.attr("height", function(d) {
return height - y(d.count);
})
.attr("width", x.rangeBand())
.on("mouseover", function(d) {
var xPos = parseFloat(d3.select(this).attr("x")) + x.rangeBand() / 2;
var yPos = parseFloat(d3.select(this).attr("y")) / 2 + height / 2;
//update tooltip positiom
d3.select("#tooltip")
.style("left", xPos + "px")
.style("top", yPos + "px")
.select("#service")
.text("Service: " + d.service);
d3.select("#tooltip")
.style("left", xPos + "px")
.style("top", yPos + "px")
.select("#count")
.text("Count: " + d.count);
//show tooltip
d3.select("#tooltip").classed("hidden", false);
})
.on("mouseout", function() {
d3.select("#tooltip").classed("hidden", true);
});
d3.select("button")
.attr("id", "submit")
.on("click", function() {
var service = document.getElementById("service").value;
var count = document.getElementById("count").value;
var json = {
"count": count,
"service": service
};
data.push(json);
console.log(data);
x.domain(data.map(function(d) {
return d.service;
}));
y.domain([0, d3.max(data, function(d) {
return d.count
})]);
chart.select(".x.axis")
.transition()
.duration(1000)
.call(xAxis);
chart.select(".y.axis")
.transition()
.duration(1000)
.call(yAxis);
var bars = chart.selectAll(".bar")
.data(data);
bars.enter().append("rect");
bars.attr("class", "bar")
.attr("x", function(d) {
return x(d.service);
})
.attr("y", function(d) {
return y(d.count);
})
.attr("height", function(d) {
return height - y(d.count);
})
.attr("width", x.rangeBand())
.on("mouseover", function(d) {
var xPos = parseFloat(d3.select(this).attr("x")) + x.rangeBand() / 2;
var yPos = parseFloat(d3.select(this).attr("y")) / 2 + height / 2;
//update tooltip positiom
d3.select("#tooltip")
.style("left", xPos + "px")
.style("top", yPos + "px")
.select("#service")
.text("Service: " + d.service);
d3.select("#tooltip")
.style("left", xPos + "px")
.style("top", yPos + "px")
.select("#count")
.text("Count: " + d.count);
//show tooltip
d3.select("#tooltip").classed("hidden", false);
})
.on("mouseout", function() {
d3.select("#tooltip").classed("hidden", true);
});
bars.transition()
.duration(1000)
.attr("x", function(d, i) {
return x(d.service);
})
.attr("y", function(d) {
return y(d.count);
})
.attr("width", x.rangeBand())
.attr("height", function(d) {
return height - y(d.count);
});
})
#tooltip {
position: absolute;
width: 200px;
height: auto;
padding: 10px;
background-color: white;
-webkit-border-radius: 10px;
-moz-border-radius: 10px;
border-radius: 10px;
-webkit-box-shadow: 4px 4px 10px rgba(0, 0, 0, 0.4);
-moz-box-shadow: 4px 4px 10px rgba(0, 0, 0, 0.4);
box-shadow: 4px 4px 10px rgba(0, 0, 0, 0.4);
pointer-events: none;
}
#tooltip.hidden {
display: none;
}
#tooltip p {
margin: 0;
font-family: sans-serif;
font-size: 16px;
line-height: 20px;
}
.chart rect {
fill: steelblue;
}
.chart text {
font: 10px sans-serif;
text-anchor: end;
}
.axis text {
font: 10px sans-serif;
}
.axis path,
.axis line {
fill: none;
stroke: #000;
shape-rendering: crispEdges;
}
svg text {
pointer-events: none;
}
rect {
-moz-transition: all 0.3s;
-o-transition: all 0.3s;
-webkit-transition: all 0.3s;
transition: all 0.3s;
}
rect:hover {
fill: orange;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
<svg class="chart"></svg>
<div class="input">
<p>Service :
<input id="service" type="text" />Count :
<input id="count" type="text" />
</p>
<br/>
<button id="submit">Submit</button>
</div>
<div id="tooltip" class="hidden">
<p><strong>Tooltip</strong>
</p>
<p><span id="service"></span>
</p>
<p><span id="count"></span>
</p>
</div>
Related
I am trying to animate the bars when the user clicks on the legend. I've built the update function - but I am unsure on how to do the required filter and animation for this feature
http://jsfiddle.net/0ht35rpb/211/
function update(){
console.log("data", data);
var barData = data.filter(function(d1) {
console.log("d1", d1);
return !d1.disabled;
});
console.log("barData", barData);
var bar = chartHolder.selectAll(".bar")
.data(data)
console.log("bar", bar);
bar.transition()
.attr("width", x0.rangeBand())
.attr("y", function(d) {
return 0;
//return y(d.value);
})
.attr("height", function(d) {
return 0;
//return height - y(d.value);
});
bar.exit().remove();
/*
var bar = bar.selectAll("rect")
bar.transition()
//.attr("id", function(d){ return 'tag'+d.state.replace(/\s|\(|\)|\'|\,+/g, '');})
.attr("x", function(d) { return x1(d.name); })
.attr("width", x0.rangeBand())
.attr("y", function(d) {
return 0;
//return y(d.value);
})
.attr("height", function(d) {
return 0;
//return height - y(d.value);
});
//bar.exit().remove();
*/
This code var bar = chartHolder.selectAll(".bar") returns empty selection. You should select all .bars apply new data with method data, after that select all react, set animation parameters transition, duration, delay and set new values for approptiate attributes.
I rewrite your code - http://jsfiddle.net/168x28p3/1/ Here, I simply animate height of bars after click on legend. But this way you can create the another animation which you need.
var $this = document.querySelector('.chart');
var data = [{
label: "a",
"Current Period": 20,
"Prior Year": 10
}, {
label: "b",
"Current Period": 15,
"Prior Year": 30
}, {
label: "c",
"Current Period": 25,
"Prior Year": 40
}, {
label: "d",
"Current Period": 5,
"Prior Year": 60
}];
var configuration = [{
"yLabel": "People Count"
}];
var w = 660;
var h = 500;
function colores_google(n) {
var colores_g = ["#f7b363", "#448875", "#c12f39", "#2b2d39", "#f8dd2f", "#8bf41b"];
return colores_g[n % colores_g.length];
}
var margin = {
top: 20,
right: 110,
bottom: 30,
left: 20
},
width = w - margin.left - margin.right,
height = h - margin.top - margin.bottom;
var svg = d3.select($this).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 axisHolder = svg.append("g")
.attr("class", "axis");
var chartHolder = svg.append("g")
.attr("class", "chart");
var legendHolder = svg.append("g")
.attr("class", "legend");
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 xAxis = d3.svg.axis()
.scale(x0)
.orient("bottom");
var yAxis = d3.svg.axis()
.scale(y)
.orient("left")
.tickFormat(d3.format(".2s"));
var divTooltip = d3.select("body").append("div").attr("class", "toolTip");
var options = d3.keys(data[0]).filter(function(key) {
return key !== "label";
});
data.forEach(function(d) {
d.valores = options.map(function(name) {
return {
name: name,
value: +d[name]
};
});
});
x0.domain(data.map(function(d) {
return d.label;
}));
x1.domain(options).rangeRoundBands([0, x0.rangeBand()]);
y.domain([0, d3.max(data, function(d) {
return d3.max(d.valores, function(d) {
return d.value;
});
})]);
axisHolder.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
axisHolder.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(configuration[0].yLabel);
var bar = chartHolder.selectAll(".bar")
.data(data)
.enter().append("g")
.attr("class", "bars")
.attr("transform", function(d) {
return "translate(" + x0(d.label) + ",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, i) {
return colores_google(i);
});
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.label) + "<br>" + elementData.name + "<br>" + elementData.value + "%");
});
bar
.on("mouseout", function(d) {
divTooltip.style("display", "none");
});
var legend = legendHolder.selectAll(".legend")
.data(options.slice())
.enter().append("g")
.attr("class", "legend")
.attr("transform", function(d, i) {
return "translate(" + margin.right + "," + i * 20 + ")";
});
legend.append("rect")
.attr("x", width - 18)
.attr("width", 18)
.attr("height", 18)
.style("fill", function(d, i) {
return colores_google(i);
})
.on("click", function(d) {
console.log("d", d);
d.disabled = !d.disabled;
update();
});
legend.append("text")
.attr("x", width - 24)
.attr("y", 9)
.attr("dy", ".35em")
.style("text-anchor", "end")
.text(function(d) {
return d;
});
function update() {
var barData = data.map(item => {
item.valores = item.valores.map(valor => {
return Object.assign({}, valor, { value: Math.random() * 40 })
})
return item;
})
var bar = chartHolder.selectAll(".bars")
.data(barData)
var rect = bar.selectAll("rect")
.data(function(d) {
return d.valores;
})
rect
.transition()
.duration(1000)
.delay(100)
.attr("width", x0.rangeBand() / 2)
.attr("y", function(d) {
return y(d.value);
})
.attr("height", function(d) {
return height - y(d.value);
});
}
* {
margin: 0;
padding: 0;
border: 0;
}
body {
background: #ffd;
}
body {
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
position: relative;
}
text {
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
}
.toolTip {
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
position: absolute;
display: none;
width: auto;
height: auto;
background: none repeat scroll 0 0 white;
border: 0 none;
border-radius: 8px 8px 8px 8px;
box-shadow: -3px 3px 15px #888888;
color: black;
font: 12px sans-serif;
padding: 5px;
text-align: center;
}
.legend {
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
font-size: 60%;
}
rect {
stroke-width: 2;
}
text {
font: 10px sans-serif;
}
.axis text {
font: 10px sans-serif;
}
.axis path {
fill: none;
stroke: #000;
}
.axis line {
fill: none;
stroke: #000;
shape-rendering: crispEdges;
}
.axis .tick line {
stroke-width: 1;
stroke: rgba(0, 0, 0, 0.2);
}
.axisHorizontal path {
fill: none;
}
.axisHorizontal line {
fill: none;
stroke: #000;
shape-rendering: crispEdges;
}
.axisHorizontal .tick line {
stroke-width: 1;
stroke: rgba(0, 0, 0, 0.2);
}
.bar {
fill: steelblue;
fill-opacity: .9;
}
/*
.x.axis path {
display: none;
}*/
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
<div class="chart"></div>
I used the code below to make a multiple line graph in d3 with a linear x-axis and it works just fine. Now I want to make the x-axis ordinal, but I have no clue how to do this. Any help would be amazing!
Code:
<!DOCTYPE html>
<html>
<body>
<center><h1>ZNF expression DFC</h1></center>
<meta charset="utf-8">
<style>
.axis--x path {
display: none;
}
.line {
fill: none;
stroke: steelblue;
stroke-width: 3.0px;
}
div.tooltip {
position: absolute;
text-align: center;
width: 60px;
height: 18px;
padding: 2px;
font: 12px sans-serif;
background: lightsteelblue;
border: 0px;
border-radius: 8px;
pointer-events: none;
}
</style>
<svg width="1560" height="1000"></svg>
<script src="//d3js.org/d3.v4.min.js"></script>
<script src="http://labratrevenge.com/d3-tip/javascripts/d3.tip.v0.6.3.js"></script>
<script>
var svg = d3.select("svg"),
margin = {top: 20, right: 80, bottom: 30, left: 50},
width = svg.attr("width") - margin.left - margin.right,
height = svg.attr("height") - margin.top - margin.bottom,
g = svg.append("g").attr("transform", "translate(" + margin.left + "," + margin.top + ")");
var x = d3.scaleLinear().range([0, width]),
y = d3.scaleLinear().range([height, 0]),
z = d3.scaleOrdinal(d3.schemeCategory20);
// Define the div for the tooltip
var div = d3.select("body").append("div")
.attr("class", "tooltip")
.style("opacity", 0);
var line = d3.line()
.x(function(d) { return x(d.Age); })
.y(function(d) { return y(d.expression); });
d3.csv("expression_ZNF_ages.csv", function(error, data) {
if (error) throw error;
var znfs = data.columns.slice(1).map(function(id) {
return {
id: id,
values: data.map(function(d) {
return {Age: d.Age, expression: d[id]};
})
};
});
x.domain([0, data.length]).range([0, width]);
y.domain([0, 40]).range([height,0]);
z.domain(znfs.map(function(c) { return c.id; }));
g.append("g")
.attr("class", "axis axis--x")
.attr("transform", "translate(0," + height + ")")
.call(d3.axisBottom(x));
g.append("g")
.attr("class", "axis axis--y")
.call(d3.axisLeft(y))
.append("text")
.attr("transform", "rotate(-90)")
.attr("y", 6)
.attr("dy", "0.71em")
.attr("fill", "#000")
.text("expression" );
var city = g.selectAll(".city")
.data(znfs)
.enter().append("g")
.attr("class", "city");
city.append("path")
.attr("class", "line")
.attr("d", function(d) { return line(d.values); })
.style("stroke", function(d) { return z(d.id); })
.on("mouseover", function(d) {
div.transition()
.duration(200)
.style("opacity", .9);
div .html(d.id)
.style("left", (d3.event.pageX) + "px")
.style("top", (d3.event.pageY - 28) + "px");
})
.on("mouseout", function(d) {
div.transition()
.duration(500)
.style("opacity", 0);
});
});
</script>
</body>
</html>
The data with which I want to work is a csv file and looks like this:
Age, ZNF8, ZNF18, ZNF136, ZNF140 .... ZNF778,
"8pwc", 13.654, 12.643, 10.593, 8,124, .... 9.900,
"9pwc", 4.364, 1.004, 3.576, 0.032, .... 5.512,
"2yrs", 65.345, 53.278, 33.001, 68.844, .... 54.544,
....
Thank you!
In this particular case, you have to use a point scale, which is a type of ordinal scale:
Point scales are a variant of band scales with the bandwidth fixed to zero. Point scales are typically used for scatterplots with an ordinal or categorical dimension.
A point scale will allow you to map a categorical (qualitative) variable to a continuous numeric output.
Thus, your scale should be:
var x = d3.scalePoint().range([0, width])
And its domain should be defined with a map:
x.domain(data.map(d=>d.Age));
Here is the working code: https://plnkr.co/edit/2nOLP5fEIHbs2U8OQB2y?p=preview
I've got this d3js v3 chart and was wondering if it's possible to append the values in a text format to both the bar and the donut chart, and if so, how you would go about doing it?
Here is the code:
<!DOCTYPE html>
<html>
<meta charset="utf-8">
<head>
<style>
body {
font-family:arial;
font-size:10px;
margin:auto;
width:1100px;
}
.axis text {
font: 10px sans-serif;
}
.axis line,
.axis path {
fill: none;
stroke: #000;
shape-rendering: crispEdges;
}
select {
background-color: #fff;
border: 1px solid #fff;
border-bottom: 1px solid #ccc;
color: #000;
padding: 3px 3px;
text-align: center;
text-decoration: none;
font-size: 10px;
margin: 2px 2px;
cursor: pointer;
}
select:focus {outline:0;}
.Row
{
display: table;
width: 100%;
table-layout: fixed;
}
.Column
{
display: table-cell;
position:relative;
}
</style>
</head>
<body>
<div class="Row">
<div class="Column" id="chart"></div>
</div>
<script src="//d3js.org/d3.v3.min.js"></script>
<script>
var dispatch = d3.dispatch("load", "statechange");
var groups = [
"Team 1",
"Team 2",
"Team 3"
];
d3.csv("data.csv", type, function(error, states) {
if (error) throw error;
var stateById = d3.map();
states.forEach(function(d) { stateById.set(d.id, d); });
dispatch.load(stateById);
dispatch.statechange(stateById.get("CA"));
});
// A drop-down menu for selecting a state; uses the "menu" namespace.
dispatch.on("load.menu", function(stateById) {
var select = d3.select("#chart")
.append("div")
.append("select")
.on("change", function() { dispatch.statechange(stateById.get(this.value)); });
select.selectAll("option")
.data(stateById.values())
.enter().append("option")
.attr("value", function(d) { return d.id; })
.text(function(d) { return d.id; });
dispatch.on("statechange.menu", function(state) {
select.property("value", state.id);
});
});
// A bar chart to show total population; uses the "bar" namespace.
dispatch.on("load.bar", function(stateById) {
var margin = {top: 20, right: 20, bottom: 30, left: 40},
width = 80 - margin.left - margin.right,
height = 290 - margin.top - margin.bottom;
var y = d3.scale.linear()
.domain([0, d3.max(stateById.values(), function(d) { return d.total; })])
.rangeRound([height, 0])
.nice();
var yAxis = d3.svg.axis()
.scale(y)
.orient("left")
.tickFormat(d3.format(".2s"));
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 + ")");
svg.append("g")
.attr("class", "y axis")
.call(yAxis);
var rect = svg.append("rect")
.attr("x", 4)
.attr("width", width - 4)
.attr("y", height)
.attr("height", 0)
.style("fill", "#aaa");
dispatch.on("statechange.bar", function(d) {
rect.transition()
.attr("y", y(d.total))
.attr("height", y(0) - y(d.total));
});
});
// A pie chart to show population by age group; uses the "pie" namespace.
dispatch.on("load.pie", function(stateById) {
var width = 260,
height = 300,
radius = Math.min(width, height) / 2;
var color = d3.scale.ordinal()
.domain(groups)
.range(["steelblue", "lightblue", "darkorange"]);
var arc = d3.svg.arc()
.outerRadius(radius - 10)
.innerRadius(radius - 60);
var pie = d3.layout.pie()
.sort(null);
var svg = d3.select("#chart").append("svg")
.attr("width", width)
.attr("height", height)
.append("g")
.attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");
var path = svg.selectAll("path")
.data(groups)
.enter().append("path")
.style("fill", color)
.each(function() { this._current = {startAngle: 0, endAngle: 0}; });
dispatch.on("statechange.pie", function(d) {
path.data(pie.value(function(g) { return d[g]; })(groups)).transition()
.attrTween("d", function(d) {
var interpolate = d3.interpolate(this._current, d);
this._current = interpolate(0);
return function(t) {
return arc(interpolate(t));
};
});
});
});
// Coerce population counts to numbers and compute total per state.
function type(d) {
d.total = d3.sum(groups, function(k) { return d[k] = +d[k]; });
return d;
}
</script>
</body>
</html>
And here's the dataset:
id,Team 1,Team 2,Team 3
AL,3105,5523,2590
AK,5208,8564,4215
AZ,5159,8286,3626
AR,2020,3432,1572
CA,2704,4499,2159
CO,3582,5871,2617
CT,2116,4036,1969
DE,5931,9949,4741
DC,3635,5043,2522
FL,1140,1938,9250
GA,7405,1250,5578
HI,8720,1340,6401
You have to create the label :
var label = svg.append("text")
.attr("x", 4)
.attr("y", height)
.attr("dy", ".35em")
.text(function(d) { return "0"; });
Then add a transition on this new text
label.transition()
.attr("y", y(d.total) + 5)
.text(d.total);
See https://plnkr.co/edit/wtq96BAZ3Zh1SaczjLT6?p=preview
This is a question already asked, but none of the solutions worked for me so putting up again.
1.I am trying to change the color of the bar in my D3 bar chart, based on a certain threshold value(if the bar exceeds a particular value on the y axis say 30 in this case) How can I change the color of the bar to something else say blue.
I also want to draw a horizontal line at y= 30.
Data for this is a data.tsv file
letter frequency attachdate
a 13 12-May-2016
b 14 11-May-2016
body {
font: 10px sans-serif;
}
.axis path,
.axis line {
fill: none;
stroke: #000;
shape-rendering: crispEdges;
}
.bar {
fill: orange;
}
.bar:hover {
fill: orangered ;
}
.x.axis path {
display: none;
}
.d3-tip {
line-height: 1;
font-weight: bold;
padding: 12px;
background: rgba(0, 0, 0, 0.8);
color: #fff;
border-radius: 2px;
}
/* Creates a small triangle extender for the tooltip */
.d3-tip:after {
box-sizing: border-box;
display: inline;
font-size: 10px;
width: 100%;
line-height: 1;
color: rgba(0, 0, 0, 0.8);
content: "\25BC";
position: absolute;
text-align: center;
}
/* Style northward tooltips differently */
.d3-tip.n:after {
margin: -1px 0 0 0;
top: 100%;
left: 0;
}
</style>
var margin = {top: 40, right: 20, bottom: 160, left: 50},
width = 960 - margin.left - margin.right,
height = 600 - margin.top - margin.bottom;
var formatPercent = d3.format(".0%");
var x = d3.scale.ordinal()
.rangeRoundBands([0, width], .1);
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 tip = d3.tip()
.attr('class', 'd3-tip')
.offset([-10, 0])
.html(function(d) {
return "<strong>Number of days:</strong> <span style='color:red'>" + d.frequency + "</span>"+"</b><br/>Attach date: " + d.attachdate;
})
var svg = d3.select("body").append("svg")
.attr("align","center")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
svg.call(tip);
d3.tsv("data.tsv", type, function(error, data) {
x.domain(data.map(function(d) { return d.letter; }));
y.domain([0, 60]);
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0,400)")
.call(xAxis)
.selectAll("text")
.style("text-anchor", "end")
.attr("dx", "-.8em")
.attr("dy", ".15em")
.attr("transform", "rotate(-65)");
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 days");
svg.selectAll(".bar")
.data(data)
.enter().append("rect")
.attr("class", "bar")
.attr("x", function(d) { return x(d.letter); })
.attr("width", x.rangeBand())
.attr("y", function(d) { return y(d.frequency); })
.attr("height", function(d) { return height - y(d.frequency); })
.on('mouseover', tip.show)
.on('mouseout', tip.hide)
});
svg.append("text")
.attr("x", (width / 2))
.attr("y", 0 - (margin.top / 2))
.attr("text-anchor", "middle")
.style("font-size", "18px" )
.style("text-decoration", "underline")
.style("fill", "red")
.text("Some heading");
function type(d) {
d.frequency = +d.frequency;
return d;
}
</script>
</body>
Any reason not to do the obvious:
svg.selectAll(".bar")
.data(data)
.enter().append("rect")
.attr("class", function(d) {d.frequency < threshold ? 'bar' : 'bar bar-special';})
etc.
As #Stephen told you can basically make use of the class attribute to manage the color of your bars. Another approach is to use the fill attribute and use a function to return the desired value.
svg.selectAll(".bar")
.data(data)
.enter().append("rect")
.attr("class", "bar")
.attr("x", function(d) { return x(d.letter); })
.attr("width", x.rangeBand())
.attr("y", function(d) { return y(d.frequency); })
.attr("height", function(d) { return height - y(d.frequency); })
.attr("fill", function(d) {
if (d.frequency >= 30) {
return 'red';
}
return 'green';
});
As for the line you want to draw you might do something like this:
svg.append("line")
.attr("x1", 0)
.attr("y1", y(30))
.attr("x2", width)
.attr("y2", y(30))
.style("stroke", "#828282")
.attr('stroke-dasharray', '2,2')
.attr('stroke-width', '1')
Here is a plunker with code similar to yours: https://plnkr.co/edit/3danSMezWDsbnJZXEUTH?p=preview
I want to create stacked bar chart with d3.
I have this data in CSV file:
Type Sum Color
Regular 29756.85897 green
Regular 9756.85897 blue
and I want that each row will appear above the other in Y axis.
for example in this photo, the blue area should start in y=9756 until y=39512.
what should I change?
this is the relevant html code:
the whole code:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<style>
body {
font: 10px sans-serif;
margin:auto;
}
.axis path,
.axis line {
fill: none;
stroke: #000;
shape-rendering: crispEdges;
}
.bar1 {
fill: #00FF66;
}
.bar1:hover {
fill: black ;
}
.x.axis path {
display: none;
}
.d3-tip {
line-height: 1;
font-weight: bold;
padding: 12px;
background: rgba(0, 0, 0, 0.8);
color: #fff;
border-radius: 2px;
}
/* Creates a small triangle extender for the tooltip */
.d3-tip:after {
box-sizing: border-box;
display: inline;
font-size: 10px;
width: 100%;
line-height: 1;
color: rgba(0, 0, 0, 0.8);
content: "\25BC";
position: absolute;
text-align: center;
}
/* Style northward tooltips differently */
.d3-tip.n:after {
margin: -1px 0 0 0;
top: 100%;
left: 0;
}
</style>
<body>
<script src="http://d3js.org/d3.v3.min.js"></script>
<script src="http://labratrevenge.com/d3-tip/javascripts/d3.tip.v0.6.3.js"></script>
<script>
var margin = {top: 80, right: 90, bottom: 30, left: 90},
width = 1000 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom;
var formatPercent = d3.format(".0%");
//יצירת X
//יאכלס את סוגי הרכב השונים
var x = d3.scale.ordinal()
.rangeRoundBands([0, width], .1);
//יצירת ציר y
//יציג בר עבור מחיר הרכב המוצע לדילרים
var y = d3.scale.linear()
.range([height, 0]);
var xAxis = d3.svg.axis()
.scale(x)
.orient("bottom");
//יצירת ציר הY
//והצמדתו לצד שמאל
var yAxis = d3.svg.axis()
.scale(y)
.orient("left").ticks(4)
var tip = d3.tip()
.attr('class', 'd3-tip')
.offset([-10, 0])
.html(function(d) {
return "<strong></strong>"+d.Type+"<br><strong></strong> <span style='color:#00FF66'>" + d.Sum + "</span>";
})
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 + ")");
svg.call(tip);
//קליטת הטבלה והגדרת הטווחים על הצירים
d3.csv("Targil2.csv", type, function(error, data) {
x.domain(data.map(function(d) { return d.Type; }));
y.domain([0, d3.max(data, function(d) { return d.Sum*2; })]);
var stack = d3.layout.stack();
.x(function(d) { return d.Type }) // tell d3 to use Type as x value
.y(function(d) { return d.Sum }); // tell d3 to use Sum as y value
var stackData = stack(data);
//הוספה של 2 הצירים
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
svg.append("g")
.attr("class", "y axis axisLeft")
.attr("transform", "translate(0,0)")
.call(yAxis)
.append("text")
.attr("y", 6)
.attr("dy", "-2em")
.style("text-anchor", "end")
.style("text-anchor", "end")
.text("Price");
//הוספת בר הנתונים
svg.selectAll(".bar")
.data(data)
.enter().append("rect")
.attr("x", function(d) { return x(d.Type); })
.attr("width", x.rangeBand())
.attr("y", function(d) { return d.y0 })
.attr("height", function(d) { return (height - y(d.Sum)); })
.style("fill", function(d){
if(d["Color"] == "green"){ return "green";}
else return "#0066FF";})
.on('mouseover', tip.show)
.on('mouseout', tip.hide)
});
function type(d) {
d.Sum = +d.Sum;
return d;
}
</script>
</body>
</html>
I tried to use that stack function as you told me, and changed the attribute of "y" , but it's not work for me now. I think I did something wrong.
Here you go.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<style>
body {
font: 10px sans-serif;
margin:auto;
}
.axis path,
.axis line {
fill: none;
stroke: #000;
shape-rendering: crispEdges;
}
.bar1 {
fill: #00FF66;
}
.bar1:hover {
fill: black ;
}
.x.axis path {
display: none;
}
.d3-tip {
line-height: 1;
font-weight: bold;
padding: 12px;
background: rgba(0, 0, 0, 0.8);
color: #fff;
border-radius: 2px;
}
/* Creates a small triangle extender for the tooltip */
.d3-tip:after {
box-sizing: border-box;
display: inline;
font-size: 10px;
width: 100%;
line-height: 1;
color: rgba(0, 0, 0, 0.8);
content: "\25BC";
position: absolute;
text-align: center;
}
/* Style northward tooltips differently */
.d3-tip.n:after {
margin: -1px 0 0 0;
top: 100%;
left: 0;
}
</style>
<body>
<script src="http://d3js.org/d3.v3.min.js"></script>
<script src="http://labratrevenge.com/d3-tip/javascripts/d3.tip.v0.6.3.js"></script>
<script>
var margin = {top: 80, right: 90, bottom: 30, left: 90},
width = 1000 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom;
var formatPercent = d3.format(".0%");
//יצירת X
//יאכלס את סוגי הרכב השונים
var x = d3.scale.ordinal()
.rangeRoundBands([0, width], .1);
//יצירת ציר y
//יציג בר עבור מחיר הרכב המוצע לדילרים
var y = d3.scale.linear()
.range([height, 0]);
var xAxis = d3.svg.axis()
.scale(x)
.orient("bottom");
//יצירת ציר הY
//והצמדתו לצד שמאל
var yAxis = d3.svg.axis()
.scale(y)
.orient("left").ticks(4)
var tip = d3.tip()
.attr('class', 'd3-tip')
.offset([-10, 0])
.html(function(d) {
return "<strong></strong>"+d.Type+"<br><strong></strong> <span style='color:#00FF66'>" + d.Sum + "</span>";
})
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 + ")");
svg.call(tip);
//קליטת הטבלה והגדרת הטווחים על הצירים
d3.csv("Targil2.csv", type, function(error, data) {
window.dataSet = data;
data.sort(function(x,y){
var a = x.Sum;
var b = y.Sum;
return a > b ? -1 : a < b ? 1 : 0
})
x.domain(data.map(function(d) { return d.Type; }));
y.domain([0, d3.max(data, function(d) { return d.Sum*2; })]);
var stack = d3.layout.stack()
.x(function(d) { return d.Type }) // tell d3 to use Type as x value
.y(function(d) { return d.Sum }); // tell d3 to use Sum as y value
// var stackData = stack(data);
//הוספה של 2 הצירים
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
svg.append("g")
.attr("class", "y axis axisLeft")
.attr("transform", "translate(0,0)")
.call(yAxis)
.append("text")
.attr("y", 6)
.attr("dy", "-2em")
.style("text-anchor", "end")
.style("text-anchor", "end")
.text("Price");
var stackSoFar = 0;
//הוספת בר הנתונים
svg.selectAll(".bar")
.data(data)
.enter().append("rect")
.attr("x", function(d) { return x(d.Type); })
.attr("width", x.rangeBand())
.attr("y", function(d){
d3.select(this)
.attr("height", function(d2){
var thisHeight = height - y(d.Sum);
stackSoFar += thisHeight
return thisHeight
});
return (height - stackSoFar)
})
.style("fill", function(d){
if(d["Color"] == "green"){ return "green";}
else return "#0066FF";})
.on('mouseover', tip.show)
.on('mouseout', tip.hide)
});
function type(d) {
d.Sum = +d.Sum;
return d;
}
</script>
</body>
</html>
first of all, I guess that when you say
for example in this photo, the blue area should start in y=9756 until
y=39512
You actually mean
for example in this photo, the blue area should start in y=29756 until
y=39512
What happens is that your green area is painted from 0 to 29756 then your blue area on top of it from 0 to 9756. You need to shift each area on top of the previous one.
Easiest is to preprocess your data to do it.
D3.js can do it for you, see Stack Layout. This computes the y0 and y for all of your layers.
EDIT:
var stack = d3.layout.stack()
.x(function(d) { return d.Type }) // tell d3 to use Type as x value
.y(function(d) { return d.Sum }); // tell d3 to use Sum as y value
var stackData = stack(data);
After that, you data is augmented, i.e. each entry contains an additional y and y0 values that you can use directly to plot (in your y and height attribute).