Creating a clustered bar graph utilizing the power of d3.js

I'm new to visualizing data with d3.js and I'm struggling to create a grouped bar chart. I attempted something, but it doesn't seem quite right. I want the x-axis to show months and the y-axis to display the count of groups (Mars and Jupiter), similar to this example.

var svg = d3.select("svg"),
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;

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

var g = svg.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");

var data = [
        {"Group":"Mars","count":10,"months":"June"},
        {"Group":"Jupiter","count":50,"months":"June"},
{"Group":"Mars","count":70,"months":"July"},
        {"Group":"Jupiter","count":60,"months":"July"}];
 

     var ymaxdomain=d3.max(d,function(d){return d.count;});
  x.domain(d.map(function(d) {return d.months}));
y.domain([0,ymaxdomain]);
   

 var x1=d3.scaleBand().rangeRound([0, x.bandwidth()]);
         x1.domain(d.map(function(d) {return d.months;}));

   

    g.selectAll(".bar")
        .data(data)
        .enter().append("rect")
        .attr("x", function(d,i) {console.log(d,i); return (x(d.months))}
        .attr("y", function(d) {return y(d.count); })
        .attr("width",x1.bandwidth())
        .attr("height", function(d) { return height - y(d.count); })

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


g.append("g")
.attr("class", "axis")
.call(d3.axisLeft(y).ticks(null, "s"))
.append("text")
.attr("x", 2)
.attr("y", y(y.ticks().pop()) + 0.5)
.attr("dy", "0.32em")
.attr("fill", "#000")
.attr("font-weight", "bold")
.attr("text-anchor", "start")
.text("count");
<style>

.bar {
  fill: steelblue;
  stroke:black
}

</style>
<!DOCTYPE html>
<svg width="600" height="600"></svg>
<body><script src="//d3js.org/d3.v4.min.js"></script></body>

Answer №1

To create a grouped bar chart, you need to define 2 scales for the x position:

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

var x1 = d3.scaleBand()
  .rangeRound([0, x.bandwidth()])
  .padding(0.05);

Next, add groups using the first scale...

var groups = g.selectAll(null)
  .data(data)
  .enter()
  .append("g")
  .attr("transform", function(d) {
    return "translate(" + x(d.months) + ",0)";
  })

... and within each group, insert rectangles using the second scale.

Check out this demo:

var svg = d3.select("svg"),
  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;

var color = d3.scaleOrdinal(d3.schemeCategory10);

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

var g = svg.append("g")
  .attr("transform", "translate(" + margin.left + "," + margin.top + ")");

var data = [{
  "Group": "Mars",
  "count": 10,
  "months": "June"
}, {
  "Group": "Jupiter",
  "count": 50,
  "months": "June"
}, {
  "Group": "Mars",
  "count": 70,
  "months": "July"
}, {
  "Group": "Jupiter",
  "count": 60,
  "months": "July"
}];

var ymaxdomain = d3.max(data, function(d) {
  return d.count;
});
x.domain(data.map(function(d) {
  return d.months
}));
y.domain([0, ymaxdomain]);

var x1 = d3.scaleBand()
  .rangeRound([0, x.bandwidth()])
  .padding(0.05)
  .domain(data.map(function(d) {
    return d.Group;
  }));

color.domain(data.map(function(d) {
  return d.Group;
}));

var groups = g.selectAll(null)
  .data(data)
  .enter()
  .append("g")
  .attr("transform", function(d) {
    return "translate(" + x(d.months) + ",0)";
  })

var bars = groups.selectAll(null)
  .data(function(d) {
    return [d]
  })
  .enter()
  .append("rect")
  .attr("x", function(d, i) {
    return x1(d.Group)
  })
  .attr("y", function(d) {
    return y(d.count);
  })
  .attr("width", x1.bandwidth())
  .attr("height", function(d) {
    return height - y(d.count);
  })
  .attr("fill", function(d) {
    return color(d.Group)
  })

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

g.append("g")
  .attr("class", "axis")
  .call(d3.axisLeft(y).ticks(null, "s"))
  .append("text")
  .attr("x", 2)
  .attr("y", y(y.ticks().pop()) + 0.5)
  .attr("dy", "0.32em")
  .attr("fill", "#000")
  .attr("font-weight", "bold")
  .attr("text-anchor", "start")
  .text("count");
.bar {
  fill: steelblue;
  stroke: black
}
<svg width="600" height="600"></svg>
<script src="//d3js.org/d3.v4.min.js"></script>

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

The method mongoose.connect() is not defined

Having a bit of trouble connecting to my MongoDB using Mongoose - keep getting this error. const { mongoose } = require('mongoose'); const db = 'dburl.com/db' mongoose.connect(db, { useNewUrlParser: true }) .then(() => console ...

How can I rearrange the output produced from a form by utilizing arrays?

The following code snippet generates the output: Apple,Orange Sliced,Diced Option1 Option2 Option3 Option4 ,Option1 Option2 Option3 Option4 Desired output: Apple Sliced Option1 Option2 Option3 Option4 Orange Diced Option1 Option2 Option ...

PHP: run a function when a button is clicked

I am currently developing a PHP & mySQLi CRUD application. Within a functions.php file, I have implemented a function that handles deleting individual users: function delte_single_user() { if (isset($_GET['id'])) { global $con; $us ...

How to distinguish if a background tab is open using JavaScript or jQuery

Is there a way to determine if a new tab with target set to "_blank" was opened from the current page using JavaScript or jQuery? I want to increment a counter in the original window every time a background tab is opened. For example, if a link is clicked ...

The POST response I received was garbled and corrupted

Operating under the name DownloadZipFile, my service compiles data and constructs a Zip file for easy downloading. This particular service provides a response that contains the stream leading to the file. A Glimpse of the Service: [HttpPost] public Actio ...

display a new feature immediately upon the user's login

I encountered a scenario where the user is supposed to log in, and upon successful login, another component should be displayed. However, this functionality is not working as expected for me. I have to click the login button again or refresh the page to vi ...

Utilizing Web Scraping within a Chrome Extension: Harnessing the Power of JavaScript and Chrome APIs

How can I incorporate web scraping capabilities into a Google Chrome Extension using JavaScript and various other technologies? I am open to utilizing additional JavaScript libraries as well. The key requirement is to ensure that the scraping process mimi ...

Developing a Multi-Stage Pop-Up with Jquery

I am interested in creating a custom multi-step modal This particular div has dynamically generated classes $('.modal-content').append('<div class="modal-body step step-' + key + '" data-step="'+key+'"></div> ...

Retrieving the output from a nested function within a function in a Node.js application connected to a

I'm currently working on a basic web application that interacts with a database by performing INSERT and SELECT operations on a single table. While I have utilized a function from various tutorials, I am struggling to retrieve the results from the SEL ...

Duplicate user scrolling input within a specified div container

I am attempting to recreate a horizontal scrolling effect on a div element that mirrors the input scroll. When the user scrolls along the input, I want the div element to scroll in sync. The issue I am encountering is specific to Chrome, where the input b ...

Creating effective test cases for Angular JS controllers

Our team has recently taken on the task of writing test cases for our application, specifically focusing on controllers. Utilizing Mocha, Chai, and Sinon libraries, we are looking for guidance on how to effectively write these test cases. We have shared a ...

The process of obtaining points through accurate responses using form inputs

My task is to create a unique quiz consisting of 10 questions. Half of the questions are multiple choice, which require radio inputs, while the other half are written answers that need text inputs. To ensure accuracy and provide a scoring system, I came ac ...

There seems to be a caching issue in ReactJS and Spring Data Rest that could be causing problems with

Encountering an unusual caching problem here. Just recently wiped out my database. While adding new users to the system, an old user mysteriously reappeared. This user has not been recreated and is not in the current database whatsoever. I'm at a lo ...

Tips on obtaining the data count from using the $.get method

Here is the code I'm currently working with: $.get('getstatsAccepted' + tickerid, {tickerid: tickerid}, function(data) { alert(data.length); }, 'json'); I am interested in obtaining the numbe ...

Using Javascript to Swap the Content of an Element

Recently, I've been delving into the world of javascript and have hit a roadblock. I understand how to instruct javascript to set a specific value for an ID, but now I have a new challenge: I want to create javascript code that can retrieve informati ...

Detecting browser or tab closure in Node/Express Application: A comprehensive guide

As I'm developing a Node + Express MVC application, I am looking for a way to automatically shut down the Express server when the browser or tab is closed. While I know I can achieve this using a vanilla JS script with the 'beforeunload' eve ...

Aligning container divs at the center in various screen resolutions

I recently constructed a portfolio website using Bootstrap and Isotope JS. In my layout, I have a container div which works perfectly when viewed on a desktop browser - displaying 3 divs in one line. However, the issue arises when the resolution changes an ...

Getting an attribute parameter within a directive: A step-by-step guide

I am currently working on injecting the name from the myController scope into the myObj directive as a custom attribute called nameAttr. Even though I have set name: '=nameAttr' in the directive's scope, it doesn't seem to be functioni ...

What is the response of Express when it encounters numerous identical asynchronous requests from the same origin?

Currently, I am utilizing Express.js for my project. There is an async function that performs a task that can take anywhere from 20 to 30 seconds to complete. Once the task is done, it increases a user's counter in the database. However, users are req ...

Unresolved error causing promise to throw an exception

My code is causing an error when resolve is called: Possibly unhandled Error: undefined at Promise$_rejecter (c:\projects\Test\promiseftp\node_modules\bluebird\js\main\promise.js:602:58) at WriteStream.<a ...