d3 bars needs to move from bottom to up [duplicate] - javascript

This question already has an answer here:
reverse how vertical bar chart is drawn
(1 answer)
Closed 2 years ago.
This is a d3 bar graph.
I am trying to animate bars grow from bottom to upwards. how to achieve it?
also, how to make labels ie text of bars stay at the top of the bars and move along with them?
currently, bars are starting at top and going down to zero.
d3.select("body")
.append("h2")
.text("BAR GRAPH");
const dataset = [12, 31, 22, 17, 25, 18, 29, 14, 9];
const w = 500;
const h = 120;
const svg = d3
.select("body")
.append("svg")
.attr("width", w)
.attr("height", h);
var bars = svg
.selectAll("rect")
.data(dataset)
.enter()
.append("rect")
.attr("x", (d, i) => i * 30)
.attr("y", (d, i) => h - 3 * d)
.attr("width", 25)
.attr("height", (d, i) => 3 * d)
.attr("fill", "navy");
bars
.transition()
.duration(400)
.attr("y", h)
.attr("height", (d, i) => 3 * d);
svg
.selectAll("text")
.data(dataset)
.enter()
.append("text")
.text(d => d)
.attr("x", (d, i) => i * 30)
.attr("y", (d, i) => h - 3 * d - 3)
.style("font-size", "25px")
.style("fill", "red")
.append("title")
.text(d => d);
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>

Your code was almost on point for the bars, you just need to change the order of the affectation to the y attribute of bars and set the height attribute of bars to 0 at the start.
I just modified the three lines in your example and marked them with comments to show what to change to achieve your desired effect.
To make the labels follow the bars you can just add a transition on them with the same duration ! I added some lines in the last block and modified one to achieve the effect.
Hope it helps :)
d3.select("body")
.append("h2")
.text("BAR GRAPH");
const dataset = [12, 31, 22, 17, 25, 18, 29, 14, 9];
const w = 500;
const h = 120;
const svg = d3
.select("body")
.append("svg")
.attr("width", w)
.attr("height", h);
var bars = svg
.selectAll("rect")
.data(dataset)
.enter()
.append("rect")
.attr("x", (d, i) => i * 30)
.attr("y", h) // modified here
.attr("width", 25)
.attr("height", 0) // modified here
.attr("fill", "navy");
bars
.transition()
.duration(400)
.attr("y", (d, i) => h - 3 * d) // modified here
.attr("height", (d, i) => 3 * d);
// modified a bit here
var labels = svg
.selectAll("text")
.data(dataset)
.enter()
.append("text")
.text(d => d)
.attr("x", (d, i) => i * 30)
.attr("y", h) // modified here
.style("font-size", "25px")
.style("fill", "red");
labels
.append("title")
.text(d => d);
labels
.transition() // added here
.duration(400) // added here
.attr("y", (d, i) => h - 3 * d - 3) // added here
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>

Related

Why can't I display multiple graphs in one HTML page using D3?

Title. I'm a noob at this, and this has been frustrating me for 2 days now. Not sure what I'm doing wrong. D3 is frustrating....
I'm trying to create multiple graphs in one page. For now, only 1 bar graph displays. I have different divs each with their own unique ID's, so not sure what's going wrong here. In addition to that, for some strange reason I can't add any text to the bars in the bargraphs I'm trying to create.
<!DOCTYPE html>
<html lang="en">
<head>
<script src="https://d3js.org/d3.v4.min.js"></script>
</head>
TESTING
<body>
<div id="chart1" style = "position:static; left: 420px; bottom: 10px; float:left">
<h4>Positivity</h4>
<script>
const dataset1 = [32, 45, 22, 26, 23, 18, 29, 14, 9];
const w = 500;
const h = 100;
const chart1 = d3.select("#chart1")
.append("svg")
.attr("width", w)
.attr("height", h);
chart1.selectAll("rect")
.data(dataset1)
.enter()
.append("rect")
.attr("x", (d, i) => i * 30)
.attr("y", (d, i) => h - 3 * d)
.attr("width", 25)
.attr("height", (d, i) => 3 * d)
.attr("fill", "navy");
chart1.selectAll("text")
.data(dataset)
.enter()
.append("text")
.attr("x", (d,i)=>i*30)
.attr("y", (d,i)=>{return (h-(d*3)-3);})
.text(function (d){return d;});
</script>
</div>
<div id="chart2" style = "position:relative; left: 50px; bottom:0px; float:center">
<h4>Motivation</h4>
<script>
const dataset2 = [12, 31, 22, 17, 25, 18, 29, 14, 9];
const w = 500;
const h = 100;
const svg2 = d3.select("#chart2")
.append("svg")
.attr("width", w)
.attr("height", h);
svg2.selectAll("rect")
.data(dataset2)
.enter()
.append("rect")
.attr("x", (d, i) => i * 30)
.attr("y", (d, i) => h - 3 * d)
.attr("width", 25)
.attr("height", (d, i) => 3 * d)
.attr("fill", "navy");
svg2.selectAll("text")
.data(dataset)
.enter()
// Add your code below this line
.append("text")
.attr("x", (d,i)=>i*30)
.attr("y", (d,i)=>{return (h-(d*3)-3);})
.text(function (d){return d;});
// Add your code above this line
</script>
</div>
</body>
For your second bar chart you're selecting the wrong chart div.
Change this
d3.select("#chart1")
to
d3.select("#chart2")
And you should be good to go.
Multiple things
Change
const svg2 = d3.select("#chart1")
.append("svg")
.attr("width", w)
.attr("height", h);
to say d3.select("#chart2") ect.
Number 2, is that you define w and h twice, which causes errors because you used const.
Number 3
selectAll("text")
.data(dataset)
should use dataset1 and dataset2.
I will say that these errors (mostly) can be determined by looking at the errors in the console

Live Bar graph with d3 in js using data from realtime firebase

I am new to javascript and have been stuck at a problem for the better part of 2 weeks. I am trying to make a bar graph that updates in real time using data from Firebase. The structure of my database is:
title:
-------child1
-------child2
-------child3
-------child4
The data to firebase is provided from a python script that is working perfectly and is updating every child of title every 10 seconds.
I made a bar graph that is updating automatically via random number generation.
//Return array of 10 random numbers
var randArray = function() {
for(var i = 0, array = new Array(); i<10; i++) {
array.push(Math.floor(Math.random()*10 + 1))
}
return array
}
var initRandArray = randArray();
var newArray;
var w = 500;
var h = 200;
var barPadding = 1;
var mAx = d3.max(initRandArray)
var yScale = d3.scale.linear()
.domain([0, mAx])
.range([0, h])
var svg = d3.select("section")
.append("svg")
.attr("width", w)
.attr("height", h)
svg.selectAll("rect")
.data(initRandArray)
.enter()
.append("rect")
.attr("x", function(d,i) {return i*(w/initRandArray.length)})
.attr("y", function(d) {return h - yScale(d)})
.attr("width", w / initRandArray.length - barPadding)
.attr("height", function(d){return yScale(d)})
.attr("fill", function(d) {
return "rgb(136, 196, " + (d * 100) + ")";
});
svg.selectAll("text")
.data(initRandArray)
.enter()
.append("text")
.text(function(d){return d})
.attr("x", function(d, i){return (i*(w/initRandArray.length) + 20)})
.attr("y", function(d) {return h - yScale(d) + 15})
.attr("font-family", "sans-serif")
.attr("fill", "white")
setInterval(function() {
newArray = randArray();
var rects = svg.selectAll("rect")
rects.data(newArray)
.enter()
.append("rect")
rects.transition()
.ease("cubic-in-out")
.duration(2000)
.attr("x", function(d,i) {return i*(w/newArray.length)})
.attr("y", function(d) {return h - yScale(d)})
.attr("width", w / newArray.length - barPadding)
.attr("height", function(d){return yScale(d)})
.attr("fill", function(d) {
return "rgb(136, 196, " + (d * 100) + ")";
});
var labels = svg.selectAll("text")
labels.data(newArray)
.enter()
.append("text")
labels.transition()
.ease("cubic-in-out")
.duration(2000)
.text(function(d){return d})
.attr("x", function(d, i){return (i*(w/newArray.length) + 20)})
.attr("y", function(d) {return h - yScale(d) + 15})
.attr("font-family", "sans-serif")
.attr("fill", "white")
}, 3000)
Live bar chart on random number
I need to update the chart using the data from firebase. I already know how to connect firebase to js using the snapshot and have already tried it to no avail.
Also, need some help with the styling of the graph.
Please if anybody knows how I can finish this(its time sensitive).
Here's the code link in jsfiddle: Live bar chart d3
Thanks

d3.js creating two elements per data point

I'm wanting to add another rect element behind each bar, but I'm struggling to do this because d3.js isn't allowing me to add another element for each data point.
http://jsfiddle.net/g5hpwf0m/2/
var w = parseInt(d3.select(self).style("width")),
h = parseInt(d3.select(self).style("height")),
svg = d3.select(self)
.append("svg")
.attr("width", w)
.attr("height", h),
yScale = d3.scale.linear()
.domain([0, d3.max(dataset)])
.range([0,h]);
svg.selectAll("rect")
.data(dataset)
.enter()
.append("rect")
.attr("fill", "green")
.attr("x", function(d, i) {
return i * (w / dataset.length);
})
.attr("y", function(d) {
return h - yScale(d);
})
.attr("width", w / dataset.length - barPadding)
.attr("height", function(d){return yScale(d);});
I've tried adding this, but it doesn't do anything.
svg.selectAll("rect")
.data(dataset)
.enter()
.append("rect")
.attr("fill", "black")
.attr("x", function(d, i) {
return i * (w / dataset.length);
})
.attr("y", function(d) {
return h - yScale(d);
})
.attr("width", w / dataset.length - barPadding)
.attr("height", "100%");
You probably want to create a 'g' element and place the rects under each respective 'g' element.
var toprects = svg.append('g').attr('class','toprect');
var bottomrects = svg.append('g').attr('class','bottomrect');
bottomrects.selectAll("rect")....
toprects.selectAll("rect")....
http://jsfiddle.net/ermineia/g5hpwf0m/3/

How to update a bar chart with accompanying text in d3?

I'm creating a bar chart as part of a bigger data visualization in d3. I want to be able to change the data in one part of the visualization and all the charts will be updated. A simplified version of the chart is as follows.
var dataset = [1, 3, 5, 3, 3];
...
var svg = d3.select("body #container").append("svg")
.attr("width", width)
.attr("height", height);
var g = svg.append("g");
...
I create other charts like a map, circle etc with this svg element. The bar chart is implemented like this.
function bars(dataset) {
var barChart = g.selectAll("rect.bar")
.data(dataset)
.enter();
barChart.append("rect")
.attr("class", "bar")
.attr("x", function(d, i) { return i * 30 + 100; })
.attr("y", function(d) { return (height - 130) - d * 4;})
.attr("width", 25)
.attr("height", function(d) { return d * 4; });
barChart.append("text")
.text(function(d) { return d; })
.attr("x", function(d, i) { return i * 30 + 103; })
.attr("y", function(d) { return (height - 130) - d/10 - 5;})
.attr("font-family", "sans-serif")
.attr("font-size", "10px")
.attr("fill", "darkgray");
}
Now this renders the bar chart fine but there is a function
...
.on("click", function() {
...
var newdata = [5, 2, 6, 2, 4]; // new values
g.selectAll("rect.bar").remove(); // This removes the bars
g.selectAll("text").remove(); // Problem here: All texts are removed
bars(newdata);
}
I have tried to transition the bar chart with new values with the .remove() function. This works for the bar rectangles because there are no othe bar charts but when I tried to remove the value labels like shown above all the other text elements were also removed. Is there a way to only update the text associated with the bars?
Have you tried applying a class to the text and only selecting those ones for removal?
e.g.
barChart.append("text")
.attr('class','label')
.text(function(d) { return d; })
then
g.selectAll(".label").remove();
Incidentally, if not all of the elements are being deleted between updates, then instead of removing all of the elements, have you considered using enter() and exit() to bind the new data to the existing elements and only remove the elements that are changing?
EDIT Like this:
function bars(dataset) {
var bar = g.selectAll(".bar").data(dataset);
bar.exit().remove();
bar.enter().append("rect").attr("class", "bar");
bar
.attr("x", function(d, i) { return i * 30 + 100; })
.attr("y", function(d) { return (height - 130) - d * 4;})
.attr("width", 25)
.attr("height", function(d) { return d * 4; });
var label = g.selectAll(".label").data(dataset);
label.exit().remove();
label.enter().append("text").attr("class", "label");
label
.text(function(d) { return d; })
.attr("x", function(d, i) { return i * 30 + 103; })
.attr("y", function(d) { return (height - 130) - d/10 - 5;})
.attr("font-family", "sans-serif")
.attr("font-size", "10px")
.attr("fill", "darkgray");
}

How to set up a reference index on horizontal bar chart and transition control

here is my code
var w = ($ ( ".column" ).width());
var h = ($ ( ".column" ).width());
var barPadding = 15;
var dataset = [ ['Graphic Design' , 7], ['Branding' , 8], ['Digital Animation' , 10], ['Web Design' , 9], ['Typography' , 7], ['AV Production' , 9] ];
//Create SVG element
var bars = d3.select(".column")
.append("svg")
.attr("width", w)
.attr("height", h)
//starting rects
var graph = bars.selectAll("rect")
.data(dataset)
.enter()
.append("rect")
.attr("width", 0)
.attr("fill", "#636363");
//labels
var text = bars.selectAll("text")
.data(dataset)
.enter()
.append("text");
//Add SVG Text Element Attributes
var textLabels = text
.attr("x", 10)
.attr("y", function(d, i) {
return 35 + i * (h / dataset.length); })
.text( function (d) { return d[0]; })
.attr("font-family", "Quicksand, sans-serif;")
.attr("font-weight", "bold")
.attr("font-size", "0px")
.attr("fill", "#1c1d1e");
//transition at waypoint
$('#slide-4').waypoint(function(){
//transform the bars
graph.transition()
.duration(1000) // this is 1s
.delay(400) // this is 0.1s
.attr("y", function(d, i) {
return i * (h / dataset.length);
})
.attr("x", 0)
.attr("height", h / dataset.length - barPadding)
.attr("width", function(d) {
return (w * d[1] / 10);
})
.attr("fill", "#F05D5C");
//transform the labels
text.transition()
.duration(1000) // this is 1s
.delay(400) // this is 0.1s
.attr("font-size", "20px")
},{ offset: '-100%' }
);
And a little demo: http://jsfiddle.net/65qNa/6/
Everything works as it should be but if you follow the link you can see some bars and their labels spawning all together from nowhere.
1) I'd love those bars to have each one a reference index behind them in the shape of a plain boring grey rect the same height but with the width of the whole div containing the script.
I've tried a few solutions: creating another svg I was unable to put it behind my existing one; putting a div behind the div I'm working on didn't work well on my page for some reason.
2) It would also be lovely if those bars and labels could span one by one and not altogether.
Can you guys please help me?
Thank you!
2)
try something like (I haven't tested it):
graph.transition()
.duration(1000) // this is 1s
.delay(400*function(d,i) {return i;}) // this is 0.1s
.attr("y", function(d, i) {
return i * (h / dataset.length);
})
2)
because of how d3 handles data:
.delay(function(d,i){return i * 300}
Like this the rect at [0] won't have any transition though.
It's enough to tweak it manually and write:
.delay(function(d,i){return **300 +** i * 300}
to make it work.

Categories

Resources