D3 bar chart not showing first element in array
You have this in your HTML:
<div class="project">
<div class="project__bar-chart"></div>
</div>
Thus, when you do:
d3.select(".project").selectAll(".project__bar-chart")
You are selecting one previously existing <div>
in your selectAll
, and your "enter" selection will have one element less.
Solution: remove the div with class project__bar-chart
:
<div class="project">
//look Ma, no div
</div>
Here is your Pen: https://codepen.io/anon/pen/bgKxXG?editors=1010
And here is a Stack snippet:
var data = [10, 23, 14, 5, 6, 6, 6, 22, 17 ]; //The data that we're working with
d3.select(".project") //bring our focus to the container containing this class .selectAll(".project__bar-chart") .data(data) //the data is in line 1 .enter() .append("div") // Shove the data (defined in line 1) into the Div in the HTML .attr("class", "project__bar-chart") .style("width", function(d) {return d + "rem";}) //we're inserting a function in this style attribute to make sure that the width of the div reflects the value given. .text(function(d) {return d;}) //this is what it will look like
.project { color: black; font: 1rem; font-family: sans-serif; margin: .1rem:; text-align: right;}
.project__bar-chart { background: #be3c3c; border: 1px solid #802828 }
<head> <script src="https://d3js.org/d3.v4.js"></script> <script type="text/javascript" src="index.js"></script> </head> <body> <div class="project"> </div>
d3.js bar graph is not showing bars
Your scaleBand().domain()
has to be an array for the Xscale
. In my solution I choose to have the indexes of the values as the array. You could map your data (usually an array of objects) to other values of the objects in an array.
Additionally there were several other issues with the scaling in terms of height and width of the actual bars and their positioning. Keep in mind that the SVG origin is the top left corner and everything is with respect to that.
I have updated the code below which makes necessary changes to produce a bar graph. Please go through it and let me know if there is anything that you do not understand.
var data = [1, 2, 3, 4, 5];var svg = d3.select("svg");var margin = 100, width = svg.attr("width") - margin, height = svg.attr("height") - margin;var Xscale = d3.scaleBand() .domain(data.map((e,i) => i)) //returns array [0,1,2,3,4] for the index of the values .range([0, width]) .padding(0.2);var dmax = d3.max(data) //calculates the max value of the datavar Yscale = d3.scaleLinear() .domain([0, dmax]) .range([height, 0]); var g = svg.append("g") .attr("transform", "translate(" + 50 + "," + 50 + ")");
var x = g.append("g") .attr("transform", "translate(0," + height + ")") .call(d3.axisBottom(Xscale).tickFormat(function(d) { return d; }).ticks(10)) .append("text") .attr("x", 6) .attr("text-anchor", "end") .text("index");
var y = g.append("g") .call(d3.axisLeft(Yscale).tickFormat(function(d) { return d; }).ticks(10)) .append("text") .attr("y", 6) .attr("dy", "0.71em") .attr("text-anchor", "end") .text("value");
g.selectAll(".bar") .data(data) .enter().append("rect") .attr("class", "bar") .attr("x", function(d, i){ return Xscale(i)}) //move the bar to the x position where it should appear .attr("y", function(d, i) { return Yscale(d); }) //move the bar from the top down to the level of the value. .attr("width", Xscale.bandwidth() ) //the width of the bar is the width between the points on the x-axis .attr("height", function(d, i) { return Yscale(dmax-d); }); // the height of the points is calculated based on the scale and the difference between this point and the max value of the data.
<html lang="en">
<head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta http-equiv="X-UA-Compatible" content="ie=edge" /> <title>Bar chart with D3.js</title> <link href="https://fonts.googleapis.com/css?family=Open+Sans" rel="stylesheet"> <script src="https://d3js.org/d3.v5.min.js"></script>
</head>
<body> <div id='layout'> <h2>Bar chart example</h2> <div class='container'> <svg class="chart" height="500" width="1000" /> </div> </div> <p>Why this is not working?? </p></body>
</html>
Bars on D3 Bar Graph not showing up
The data passed in to D3 must be in the form of an array. As your code stands you are passing in a single value. I am answering with the assumption that you only want to plot a single bar, the value of 'mx'.
Simply by changing your code like below, the line shows up.
Change the value passed in to be an array.
bardata = {
...
"mx":[3683],
...
}
And change the scale function to use the first index of the 'mx' array.
var vGuideScale = d3.scale.linear()
.domain([0, bardata[i].aggs.srvbsy.mx[0]]) // <-- here
.range([height, 0])
http://jsfiddle.net/u7zs3jwo/2/
d3 stacked bar chart values not showing up on chart
You have to change this line
.data(function(d) { return d.ages; })
to actually give data()
your data. If you have an array with all the ages named ages
, then it would be:
.data(ages)
The d
argument in function(d)
references nothing since data()
is actually the method where you input your data.
D3.JS chart not showing
This might help, and it has a mouseover tooltip and the fill colour changes.
<!DOCTYPE html><meta charset="utf-8">
<body> <style> .bars:hover { fill: blue; } .legend:hover { fill: blue; } /* tooltip for bar chart */ div.tooltip { position: absolute; text-align: center; width: 50px; height: 60px; padding: 2px; font: 12px sans-serif; background: lightsteelblue; border: 0px; border-radius: 8px; pointer-events: none; } </style> <div id="bar_chart"> </div> <script src="https://d3js.org/d3.v4.min.js"></script> <script> // d3.json("data.json", function(error, data) { // if (error) throw error; // var parseTime = d3.timeParse("%M:%S"); // var timeformat = d3.timeFormat("%M:%S")
data = [{ "Wuc": "23A", "Nomenclature": "Engine, Basic (F117-PW)", "Hours": 155899.90 }, { "Wuc": "23V", "Nomenclature": "Fan Thrust Reverser", "Hours": 56576 } ]
data.forEach(function(d) { // d.atime = parseTime(d.atime); d.Hours = +d.Hours; }); var margin = { top: 70, right: 50, bottom: 100, left: 80 }, width = 600 - margin.left - margin.right, height = 600 - margin.top - margin.bottom; //Define the div for the tooltip var div = d3.select("body").append("div") .attr("class", "tooltip") .style("opacity", 0); var x = d3.scaleBand() .domain(data.map(function(d) { return d.Wuc })) .range([0, width]) .padding([0.8]); //sets decimal of the space between bar centres var y = d3.scaleLinear() .domain([0, d3.max(data, function(d) { return d.Hours })]) .range([height, 0]); var svg = d3.select("#bar_chart") .data(data) .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 + ")"); // Add the X Axis svg.append("g") .attr("class", "axis") .attr("transform", "translate(0," + height + ")") .call(d3.axisBottom(x)); // text label for the x axis svg.append("text") .attr("x", width / 2) .attr("y", margin.top + height) .style("text-anchor", "middle") .style("font-weight", "bold") .text("x-Axis Title"); // Add the Y Axis svg.append("g") .attr("class", "axis") .call(d3.axisLeft(y) .ticks(5)); // text label for the y axis svg.append("text") .attr("class", "blah") .attr("transform", "rotate(-90)") .attr("x", 0 - height / 2) .attr("y", -50) .style("text-anchor", "middle") .style("font-weight", "bold") .text("y-Axis Title"); // graph main title svg.append("text") .attr("x", width / 2) .attr("y", -20) .style("text-anchor", "middle") .style("font-weight", "bold") .style("font-size", "20px") .text("Main Title"); //********* Bar Chart **************** var rects = svg.selectAll('rect') .data(data) .enter(); rects.append('rect') .on("mouseover", function(d, i, node) { //this is repeated should be in a function div.transition() .duration(200) .style("opacity", .85); div.html("<strong> Name:</strong> " + d.Wuc + "</br><strong> Value:</strong> " + d.Hours) .style("left", (d3.event.pageX + 5) + "px") .style("top", (d3.event.pageY - 28) + "px"); d3.select(this) .style("fill", "blue"); }) .on("mouseout", function(d) { div.transition() .duration(500) .style("opacity", 0); d3.select(this) .style("fill", "lightblue"); }) .attr("class", "bars") //should fill blue on mouseover, not working??? .attr('x', function(d, i) { return x(d.Wuc); }) .attr('y', function(d, i) { return y(d.Hours); }) .attr('height', function(d, i) { return height - y(d.Hours) }) .attr('width', x.bandwidth()) .attr("transform", "translate(0,0)") .style('fill', 'lightblue') .style('stroke', 'lightgray'); // }); //closes function d3.json("data.json", function(error, data) {..... </script>
D3 stack() skipping first object in my data array
Well, d3.stack()
is not skipping the first object in your data array.
The problem is that this code...
const keys = _.remove(_.keys(_.extend.apply({}, chartDataWorkingCopy)), (d) => {
return d !== 'timestamp'
})
... is not only getting the keys, but also modifying your chartDataWorkingCopy
array, which still points to your chartData
array.
Right now, you may think that you're cloning your original array here:
let chartDataWorkingCopy = [...chartData];
But, unfortunately, you're not. You cannot clone an array of objects with the spread operator. The documentation says:
Typically the spread operators in ES2015 goes one level deep while copying an array. Therefore, they are unsuitable for copying multidimensional arrays. It's the same case with Object.assign() and Object spread operators. Look at the example below for a better understanding.
So, in your code, any change to chartDataWorkingCopy
also changes chartData
.
Solution 01
You can get the keys without modifying the array, using vanilla JS or D3, you don't need lodash for this. For instance, this is a very simple way to get the keys you want using only D3 and without modifying the source array:
const keys = d3.keys(chartDataWorkingCopy[0]).filter(d => d != "timestamp");
Solution 02
If you want to keep your lodash function, use a method that really copies a deep array, like this:
let chartDataWorkingCopy = JSON.parse(JSON.stringify(chartData));
In this demo, I'm keeping your code (with lodash), just changing the code that makes a copy of the original array. Now the values are correct:
var chartData = [ { timestamp: "2006", source1: "20", source2: "20", source3: "20", source4: '20'}, { timestamp: "2007", source1: "70", source2: "50", source3: "10", source4: '70'}, { timestamp: "2008", source1: "80", source2: "50", source3: "60", source4: '40'}, { timestamp: "2009", source1: "30", source2: "20", source3: "40", source4: '50'}, { timestamp: "2010", source1: "70", source2: "20", source3: "90", source4: '20'} ];
let chartDataWorkingCopy = JSON.parse(JSON.stringify(chartData));
const keys = _.remove(_.keys(_.extend.apply({}, chartDataWorkingCopy)), (d) => { return d !== 'timestamp'})
const stack = d3.stack().keys(keys)
const layers = stack(chartData);
console.log(layers);
<script src="https://d3js.org/d3.v4.min.js"></script><script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.4/lodash.min.js"></script>
D3.js Bars not showing up
OK here's the result: https://plnkr.co/edit/ouXS42g8JRPfo4IRN66g?p=preview
I've changed your parse function to
function parse(d) {
var value = { date: parseDate(d.Day) }; // turn the date string into a date object
// adding calculated data to each count in preparation for stacking
value.total = +d.Trips
value.counts = [{y0:0,y1:value.total}];
return value;
}
Because in
.data(function(d) {return d.total; })
it is expecting d.total to be an array and it wasn't. So I changed it with the
.data(function(d) {return d.counts; })
which I defined in the parse function. And I made small adjustments to height and y accordingly:
.attr("y", function(d) {return y(d.y1); })
.attr("height", function(d) { return y(d.y0) - y(d.y1);})
Related Topics
Displaying a Div Only on Tumblr Blog Homepage
How to Make Each Letter in Text a Different Random Color in JavaScript
Detecting Physical Screen Dimensions of Webkit Devices in JavaScript
Get CSS Not-Computed Property-Value with JavaScript Only
Grunt Plugin for Assets Versioning
Google Map API Route Request Limit
Make :Focus Change CSS of Another Class
Is JavaScript Execution Deferred Until CSSom Is Built or Not
Angular - Ngfor* Four Elements on Row
Replacing Normal File Upload Input with an Image
JavaScript - Page Has to Be Refreshed to Show Particle-Slider Logo Effect
Avoid Having to Double-Click to Toggle Bootstrap Dropdown
Dropdown Image Not Visible in Chrome and Ie
Uncaught Domexception: Failed to Read the 'Rules' Property from 'Cssstylesheet'
CSS in My JavaScript Widget Colliding with Target Page CSS
Screen Zooms in When a Bootstrap Modal Is Opened on iOS 9 Safari
Laravel 8 + Nginx - App.CSS and App.Js Resources from Public/ Not Loading - 404 Not Found