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

Exploring the concepts of AngularJS directives and resources

I've been experimenting with angularjs and rest service calls to display specific data sets, but I'm encountering challenges with custom directives and resources. Currently, I have a custom directive that loads a list of comments in an applicati ...

Displaying a div in Vue.js when a button is clicked and an array is filled with

Hey there! I'm having an issue with displaying weather information for a specific location. I want to show the weather details in a div only when a button is clicked. Despite successfully fetching data from the API, I'm struggling to hide the wea ...

The location of errors is not displayed in VueJS stack traces

My Current VueJS Setup Check out the Source Code here I am working on a project using VueJS with webpack. I have chosen not to use the vue-loader plugin or .vue files. My project structure resembles a typical Javascript webpack project where I import vu ...

Update the background image to be smoother, with no text overlay

I am working on a website where I need to smoothly change between background images. Here is the JavaScript code I currently have: var bg=[ 'images/best.jpg', 'images/61182.jpg', 'images/bg.jpg' ...

Converting JSON data to an array using an Ajax request

I am currently working on an HTML project where I have the following code: <div id="main"> <div id="blogcont"> <p></p> </div> <button class="nvgt" id="prev" >Previous</button> <button ...

Tips for adjusting column sizes in ag-grid

I'm a beginner with ag-grid and need some help. In the screenshot provided, I have 4 columns initially. However, once I remove column 3 (test3), there is empty space on the right indicating that a column is missing. How can I make sure that when a col ...

Best practices for securely storing JWT tokens from an API in next-auth

I followed an online tutorial to implement this in next-auth import NextAuth from "next-auth" import Providers from "next-auth/providers"; const https = require('https'); export default NextAuth({ providers: [ Providers ...

What is the reason for the denial of JSON permission within a Linux user's account?

Encountering issues with Laravel installation on Ubuntu 18.04 [ErrorException] Unable to create file (./composer.json): Permission denied ...

Display the current language in the Vue language dropdown

My component is called DropdownLanguage.vue Goal: I need to show the current active language by default in the :text="selectedOptionDropdown" attribute. For example, it should display "English" which corresponds to languages.name. I'm struggling with ...

Combining various array values into a single key in JSON格式

Issue: I am working on a sign-up form for new users using HTML. The goal is to store multiple arrays (each containing "username: username, password: password, topScore: 0) within one JSON key ("user" key). However, the current functionality only allows f ...

I need to use JavaScript to create HTML to PDF and then upload the PDF file to a SharePoint Document Library

Our current project requires us to convert HTML to PDF and save it in a SharePoint Document Library. While we have successfully converted the HTML to PDF using Kendo plugin, we are facing challenges with storing it in SharePoint. It's worth noting th ...

What is the best way to combine a string that is constructed across two separate callback functions using Mongoose in Node.js?

I am facing a situation where I have two interconnected models. When deleting a mongo document from the first model, I also need to delete its parent document. There is a possibility of an exception being thrown during the second deletion process. Regardl ...

Troubleshooting AngularJS form submission with missing data

Is there a way to modify AngularJS to save form data into a database using PHP as the backend? Below is the HTML form code: <form ng-submit="newContactSubmit()"> <label>FirstName<input type="text" name="contact_firstname" required n ...

What are the compatibility considerations for npm packages with Angular 2? How can I determine which packages will be supported?

When working with Angular 2, do NPM packages need to be modified for compatibility or can any existing package work seamlessly? If there are compatibility issues, how can one determine which packages will work? For instance, let's consider importing ...

Instead of using setTimeout in useEffect to wait for props, opt for an alternative

Looking for a more efficient alternative to using setTimeout in conjunction with props and the useEffect() hook. Currently, the code is functional: const sessionCookie = getCookie('_session'); const { verifiedEmail } = props.credentials; const [l ...

Inject $scope into ng-click to access its properties and methods efficiently

While I know this question has been asked before, my situation is a bit unique. <div ng-repeat="hello in hello track by $index"> <div ng-click="data($index)"> {{data}} </div> </div> $scope.data = function($index) { $scope.sweet ...

Attempting to display a base-64 encoded image in a Next.js application

After following this method, I successfully uploaded my image as a string: const [image, setImage] = useState(""); //------------------^^^^^^^^^^^^^^^^------------------------- const handleImage = (e) => { ...

To ensure responsiveness in JavaScript, adjust the width to 100%

Recently, I came across this piece of code: <div style="text-align:center; max-width:500px; width:100%; margin:auto"> <script type="text/javascript" src="transition_example.js"></script></div> Here is the content of transition ...

Is it feasible to create a doughnut chart with curved edges?

My goal is to create a doughnut chart, but my search for reliable CSS/SVG/Canvas solutions has not been successful. I want each segment to have fully rounded corners, which presents a unique challenge. ...

Using Jquery and AJAX to dynamically fill out an HTML form based on dropdown selection

My goal is to populate a form on my webpage with information pulled from a MySQL database using the ID of the drop-down option as the criteria in the SQL statement. The approach I have considered involves storing this information in $_SESSION['formBoo ...