Creating a vertical bar chart in D3 with a JSON data source embedded within the code

Struggling to generate a stacked bar graph in D3.js. The axes are displaying correctly, but the data on the graph is not showing up. Any suggestions on what could be causing this issue?

JS:

var svg = d3.select("#recovery__table"),
    margin = {top: 20, right: 20, bottom: 30, left: 40},
    width = +svg.attr("width") - margin.left - margin.right,
    height = +svg.attr("height") - margin.top - margin.bottom,
    aspect = width/height,
    g = svg.append("g").attr("transform", "translate(" + margin.left + "," + margin.top + ")");

var x = d3.scaleBand()
    .rangeRound([0, width])
    .padding(0.1)
    .align(0.1);

var y = d3.scaleLinear()
    .rangeRound([height, 0]);

var z = d3.scaleOrdinal()
    .range(["#717C8B", "#7FDDC3", "#39B3CD"]);

var stack = d3.stack();

data.forEach(function(d) {
    d.year = d['trades.closed_half_year_year'];
    d.loss = d['loss'];
    d.recovered = d['recovered'];
    d.recovery = d['in_recovery'];
    d.total = d.loss + d.recovery + d.recovered;
});

var div = d3.select("body").append("div")
    .attr("class", "tooltip3")
    .style("opacity", "0");

 x.domain(data.map(function(d) { return d.year; }));
 y.domain([0, d3.max(data, function(d) { return d.total; })]).nice();
 z.domain(d3.keys(data[0]).filter(function(key){ return key == 'loss' && key == 'recovered' && key == 'in_recovery' }));

 g.selectAll(".serie")
      .data(data)
      .enter().append("rect")
      .attr("class", "bar")
      .attr("fill", function(d){ return z(d.keys); })
      .attr("x", function(d) { return x(d.year); })
      .attr("width", x.bandwidth())
      .attr("y", function(d) { return y(d.total); })
      .attr("height", function(d) { return y[0] - y[1]; })
      .on("mouseover", function(d) {
        var value = parseInt($(this).attr('data-value'));
        div.transition()
          .duration(200)
          .style("opacity", .5);
        div.html(d.data.year + "<br/>£" + total.formatMoney())
          .style("left", (d3.event.pageX) + "px")
          .style("top", (d3.event.pageY - 28) + "px");
      })
      .on("mouseout", function(d) {
        div.transition()
          .duration(500)
          .style("opacity", 0);
      });
    ;

 g.append("g")
      .attr("class", "axis axis--x")
      .attr("transform", "translate(0," + height + ")")
      .attr('x', 20)
      .call(d3.axisBottom(x));

 g.append("g")
      .attr("class", "axis axis--y")
      .call(d3.axisLeft(y).ticks(5, "s"))
      .append("text")
      .attr("x", 2)
      .attr("y", y(y.ticks(10).pop()))
      .attr("dy", "0.35em")
      .attr("text-anchor", "start")
      .attr("fill", "#000");

 var legend = g.selectAll(".legend")
      .data(data)
      .enter().append("g")
      .attr('width', 100)
      .attr("class", "legend")
      .attr('transform', function(d, i) {
        var horz = 100*i;                       
        var vert = 0;
        if (horz >= width) {
          horz = 100 * (i - 3);
          vert = 40;
        }

        return 'translate(' + horz + ',' + vert + ')';        
      })
      .style("font", "10px sans-serif");

 legend.append("rect")
      .attr("x", "33%")
      .attr("width", 18)
      .attr("height", 18)
      .attr("fill", z);

 legend.append("text")
      .attr("x", "43%")
      .attr("y", 9)
      .attr("dy", ".35em")
      .attr("text-anchor", "end")
      .text(function(d) { return d; });

JSON example

[{"trades.closed_half_year_year":"2017","auctioncollectioninfos.total_advanced_amount_delinquent_and_collection_completed_gbp_daily":"£0.00","auctioncollectioninfos.total_crystallized_loss_gbp_daily":"£0.00","auctioncollectioninfos.total_outstanding_amount_delinquent_gbp_daily":"£","auctioncollectioninfos.total_advanced_amount_delinquent_gbp_daily":"£0.00","loss":"£0.00","recovered":"£0.00","in_recovery":"£0"},
{"trades.closed_half_year_year":"2016","auctioncollectioninfos.total_advanced_amount_delinquent_and_collection_completed_gbp_daily":"£123,456.78","auctioncollectioninfos.total_crystallized_loss_gbp_daily":"£0.00","auctioncollectioninfos.total_outstanding_amount_delinquent_gbp_daily":"£1,234,234","auctioncollectioninfos.total_advanced_amount_delinquent_gbp_daily":"£1,321,245.56","loss":"£0.00","recovered":"£457,468.31","in_recovery":"£1,890,567"},
{"trades.closed_half_year_year":"2015","auctioncollectioninfos.total_advanced_amount_delinquent_and_collection_completed_gbp_daily":"£3,345,768.54","auctioncollectioninfos.total_crystallized_loss_gbp_daily":"£555,555.08","auctioncollectioninfos.total_outstanding_amount_delinquent_gbp_daily":"£321,321","auctioncollectioninfos.total_advanced_amount_delinquent_gbp_daily":"£3,321,321.32","loss":"£456,324.33","recovered":"£2,324,234.345","in_recovery":"£333,333"}]

Looking to have the loss, recovery, and recovered values stacked on the graph, but so far no data is being displayed as mentioned earlier.

Any thoughts or suggestions would be appreciated!

Answer №1

It appears there is a small issue with the data being used as it is in JSON format, meaning the objects will receive values as strings that need to be correctly parsed into numbers. A simple method to achieve this is shown below:

d.loss = +d['loss'];

Even after parsing, there might still be problems with the dataset due to some numbers being formatted differently:

"loss":"£456,324.33" 

This formatting issue can lead to incorrect calculations such as:

d.total = "£456,324.33" + 0 + "£4,324.33"  // "£456,324.330£4,324.33"

Such operations can distort the scale of the chart.

y.domain([0, d3.max(data, function(d) {
   return d.total;
})]).nice(); // unusual domain here :S

To address these formatting issues and ensure correct data manipulation, consider the following adjustments to the dataset:

data.forEach(function(d) {
  d.year = +d['trades.closed_half_year_year'];
  d.loss = typeof d.loss === 'number' ? d.loss : +d['loss'].replace(/£|,/g, '')
  d.recovered = typeof d.recovered === 'number' ? d.recovered : +d['recovered'].replace(/£|,/g, '');
  d.in_recovery = typeof d.in_recovery === 'number' ? d.in_recovery : +d['in_recovery'].replace(/£|,/g, '');
  d.total = d.loss + d.in_recovery + d.recovered;
});

Once the dataset has been corrected, you can proceed with utilizing d3 and the stack layout:

var keys = ['loss', 'recovered', 'in_recovery']; // Define desired keys for stack
z.domain(keys); // Set them as z domain for color identification
var stackLayout = d3.stack().keys(keys)(data); // Create stack layout

The generated structure will enable the creation of bars based on key-blocks as illustrated in the code snippet.

For further details and working example, refer to: https://plnkr.co/edit/eTKsOz8jlaqm1Mf3Esej?p=preview

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Having trouble with testing axios web service promises to return results using Jest in a Vue.js application

In the process of developing a new application with Vue.js and axios, I am focusing on retrieving stock market details based on company names. To kickstart the application, I am compiling all the names of US-based S&p 500 companies into a JavaScript ar ...

Achieving the utilization of Ajax for two users at the same

When making an Ajax request, I need to retrieve information for user one and user two. Do I have to perform separate queries like this? $check = "SELECT * FROM user WHERE id='$user1_id'"; $check1 = mysqli_query($mysqli,$check); $resultArr = mysq ...

What is the best way to access the inner html of every cell within a table row that I have selected?

I want to implement a feature on my website where users can click a "save" button on a specific row in a table and save the entire row's innerHtml onto another page as their favorite hiking trails. I've been trying to achieve this by adding clic ...

Attach the JSON data to the dropdown menu using jQuery

On my asp.net website, I have generated a JSon string using the JavaScriptSerializer class in JavaScript. Then, I displayed the Json string within the HTML markup by utilizing the RegisterStartupScript method and here is how it appears: This is the C#.net ...

The scope of a JS array is being lost in Firebase

The Firebase data structure looks like this: -users --demo1 ---conid:1 -election --election1 ---conRegex:1 --election2 ---conRegex:1 Here is the code to retrieve election1 and election2: var conid; var conRegex; var electionArr = []; if(uidA ...

Guide to duplicating a json file using the webpack duplication tool and integrating the version from the package.json file

I am attempting to move my manifest.json file (which is used for web extensions) into the build/ directory and replace the version within that file with the version stated in the package.json file using webpack's DefinePlugin. Is there a way for me t ...

After a two-second period of inactivity, the buttons on the item should trigger an action

I have a scenario in mind that I want to implement: When the user clicks on either the "Plus" or "Minus" button. If the user doesn't click on any of those buttons within 2 seconds, then we assume that the current quantity should be sent to the server ...

Transforming the hide/show functionality from JQuery to Vue

I created some hide/show panels using jQuery that I want to implement in Vue. However, when I try to integrate the jQuery functions into Vue, the functionality doesn't seem to work properly. The panels are not hiding/showing as expected. Does anyone ...

Switching effortlessly between Fixed and Relative positioning

As I work on creating a unique scrolling experience, I aim to have elements stop at specific points and animate before returning to normal scroll behavior once the user reaches the final point of the page. Essentially, when div X reaches the middle of the ...

Upon successful authorization, the Node Express server will pass the access token to the React client app via OAuth in the callback

I am currently working on a node server that authenticates with a third party using oauth, similar to how Stack Overflow does. After authorizing the request and obtaining the access token and other essential information from the third party, my goal is to ...

Issue with Node.js xml2js module: Sitemap attributes are not being recognized during creation

Currently, my project involves utilizing node.js and xml2js to generate an XML sitemap.xml. Everything seems to be in order, but when I try to define attributes like: '$': { 'xmlns': 'http://www.sitemaps.org/schemas/sitemap/0 ...

Create a table by incorporating the information from the page along with additional content

I need to extract the data from a list and convert it into a table, add some additional content that I will provide, and then align the table accordingly. While I can easily align elements and already have the list, I am facing difficulty in converting it ...

Utilizing the $.ajax method to navigate to a webpage displaying only the results that correspond to the value in the json data

I'm in the process of creating a single page application that utilizes $.ajax. Here is the JSON data: { "restaurants": [ { "id": 1, "name": "Denny's", "location": "Los Angeles", "cuisine": "American", "image_ ...

The addition and deletion of classes can sometimes lead to disruptions in the DOM

I've been struggling to phrase this question for a while now. I'm working on a single-page e-commerce site that operates by modifying the HTML in divs and using CSS along with JQuery to show and hide those divs. My problem arises when, occasional ...

The jQuery load() callback triggering a POST request unexpectedly instead of a GET request

Utilizing jQuery's load() method, I am attempting to insert a page fragment into a new page. It appears that this can only be achieved with load(), as get() does not support page fragments. Upon completion of the load, it is necessary for me to invok ...

Error: Unable to decipher the specified token: ###

I am currently using Laravel 5.3 as the API for my iOS application. Whenever I attempt to make HTTP calls with headers and parameters, I encounter a 401 error message: message = "Could not decode token: The token \"Optional(\""eyJ0eXAiOiJKV1 ...

Prevent the use of unnecessary object properties

Currently, my project involves using Typescript and React in conjunction with Material-UI. Specifically, I am utilizing Material-UI's styling solution, which implements CSS in JS methodology in a Hook-like manner as outlined in their documentation: co ...

To avoid TS2556 error in TypeScript, make sure that a spread argument is either in a tuple type or is passed to a rest parameter, especially when using

So I'm working with this function: export default function getObjectFromTwoArrays(keyArr: Array<any>, valueArr: Array<any>) { // Beginning point: // [key1,key2,key3], // [value1,value2,value3] // // End point: { // key1: val ...

What is the process of creating a download link for a server file in a web browser?

I am attempting to create a straightforward download link for a PDF file that users can upload and then have the option to download. I would like this download feature to appear either in a pop-up box or simply on the Chrome download bar. Despite trying v ...

Customizing a tinyMCE button with a unique icon

I'm attempting to insert a Font-Awsome icon into a button that I included in tinyMCE using the following code: ed.addButton('youtube', { title: 'Add Video' , icon: 'icon-youtube', onclick: function () { ...