D3 Bar Chart Not Showing First Element in Array

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": "F‌​an 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



Leave a reply



Submit