Combining various datasets with identical X values in a D3 bar graph

I'm currently working on creating a grouped bar chart to display performance test results using D3 for the first time.

The X axis should represent parallelism, indicating the number of threads used, while the Y axis will show the duration in milliseconds. If there are multiple records with the same parallelism value, they should be displayed together, ideally sorted by duration although sorting is not critical.

I found inspiration in this code snippet:

After spending over an hour tweaking the code, I am still struggling to get the grouping right. The issue seems to lie in how I define the fx and x functions, and in how I assign

.attr("x", d => marginLeft + fx(d.duration))
. Despite trying numerous variations, I haven't been successful yet.

const runData = [
      {"duration":74950.52171194553,"parallelism":1},
      {"duration":88687.86499893665,"parallelism":0,"exitCode":0},
      {"duration":60000,"parallelism":1,"exitCode":0},
      {"duration":90000,"parallelism":0,"exitCode":0},
      {"duration":90000,"parallelism":0,"exitCode":0}
  ];

  const width = 700;
  const height = 400;
  const marginTop = 10;
  const marginRight = 10;
  const marginBottom = 20;
  const marginLeft = 40;
  // Create the SVG container.
  const svg = d3.select("#ca")
    .append("svg")
    .attr("width", width)
    .attr("height", height);

  const paralelismSet = new Set(runData.map(x=>x.parallelism));
  const paralelismList = runData.map(x=>x.parallelism);
  paralelismList.sort();
  const durationSet = new Set(runData.map(x=>x.duration));

  const minDuration = Math.min(...durationSet);
  const maxDuration = Math.max(...durationSet);

  // Sorting by duration but grouping by parallelism attempt
  const fx = d3.scaleBand()
      .domain(durationSet)
      .rangeRound([marginLeft, width - marginRight])
      .paddingInner(0.1);

  const x = d3.scaleBand()
      .domain(paralelismList)
      .rangeRound([0, fx.bandwidth()])
      .padding(0.05);

  const color = d3.scaleLinear([minDuration, maxDuration], ["green", "red"]);

  // Y encodes the height of the bars
  const y = d3.scaleLinear()
      .domain([0, maxDuration]).nice()
      .rangeRound([height - marginBottom, marginTop]);

  svg.append("g")
    .selectAll()
    .data(d3.group(runData, d => d.parallelism))
    .join("g")
      .attr("transform", ([parallelism]) => `translate(${x(parallelism)},0)`)
    .selectAll()
    .data(([, d]) => d)
    .join("rect")
      .attr("x", d => marginLeft + fx(d.duration))
      .attr("y", d => y(d.duration))
      .attr("width", x.bandwidth())
      .attr("height", d => y(0) - y(d.duration))
      .attr("fill", d => color(d.duration));

  svg.append("g")
      .attr("transform", `translate(${marginLeft},${height - marginBottom})`)
      .call(d3.axisBottom(x));

  svg.append("g")
      .attr("transform", `translate(${marginLeft},0)`)
      .call(d3.axisLeft(y).ticks(null, "s"))
      .call(g => g.selectAll(".domain").remove());
<div id="ca">
</div>
<script src="https://d3js.org/d3.v6.min.js"></script>

Answer №1

The example plot you are following seems overly complex to me. It does not adhere to the standard d3 graph structure, with excessive manipulation of margins and data that could benefit from cleaning up.

That being said, I have made significant modifications to your code. Here is an overview of the changes:

<!DOCTYPE html>

<html>
  <head>
    <script src="https://d3js.org/d3.v6.min.js"></script>
  </head>

  <body>
    <div id="ca"></div>
    <script>
      const runData = [
        { duration: 74950.52171194553, parallelism: 1 },
        { duration: 88687.86499893665, parallelism: 0, exitCode: 0 },
        { duration: 60000, parallelism: 1, exitCode: 0 },
        { duration: 90000, parallelism: 0, exitCode: 0 },
        { duration: 90000, parallelism: 0, exitCode: 0 },
      ];

      // Standard d3 plot configuration
      var margin = {top: 30, right: 30, bottom: 70, left: 60},
          width = 460 - margin.left - margin.right,
          height = 400 - margin.top - margin.bottom;

      // Container creation with axis margins
      var svg = d3.select("#ca")
        .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 + ")");

      const groupedData = d3.group(runData, d => d.parallelism); 
      const durationDomain = d3.extent(runData, d => d.duration); 
      const innerDomain = d3.range(0, d3.max(groupedData, d => d[1].length)); 
      const outerDomain = Array.from(groupedData.keys()).sort(); 

      // Scale for groups
      const fx = d3
        .scaleBand()
        .domain(outerDomain)
        .rangeRound([0, width])
        .paddingInner(0.1);

      // Scale within group
      const x = d3
        .scaleBand()
        .domain(innerDomain)
        .rangeRound([0, fx.bandwidth()])
        .padding(0.05);

      // Color assignment for bars by index
      const color = d3
        .scaleLinear()
        .domain(innerDomain)
        .range(['orange', 'steelblue', 'brown']);

      // Y-scale for duration
      const y = d3
        .scaleLinear()
        .domain([0, durationDomain[1]])
        .nice()
        .rangeRound([height, 0]);

      svg
        .append('g')
        .selectAll()
        .data(groupedData)
        .join('g')
        .attr('transform', (d) => `translate(${fx(d[0])},0)`)
        .selectAll()
        .data(([, d]) => d)
        .join('rect')
        .attr('x', (d,i) => x(i))
        .attr('y', (d) => y(d.duration))
        .attr('width', x.bandwidth())
        .attr('height', (d) => y(0) - y(d.duration))
        .attr('fill', (d,i) => color(i));

      svg
        .append('g')
        .attr("transform", "translate(0," + height + ")")
        .call(d3.axisBottom(fx));

      svg
        .append('g')
        .call(d3.axisLeft(y));

    </script>
  </body>
</html>

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

problem encountered while attempting to transmit data to multer in React

I was attempting to upload an image to the backend using Multer. I have reviewed the backend code multiple times and it appears to be correct. Could there be an issue with my front-end code? Here is a POST code snippet: const response = await fetch(' ...

Error with YouTube API in Internet Explorer 8: Video not found

While using the iframe youtube api to handle video, everything runs smoothly on Chrome and Firefox. However, when trying to implement it on Internet Explorer 8, an error saying 'video' is undefined pops up. Any suggestions on how to resolve this ...

JavaScript encountering issues when parsing a string that was serialized using Gson in Java

This question is unique and differs from this one as it specifically addresses the representation of JSON strings serialized from Java in literal form in JavaScript, with a focus beyond just double quotes. In my scenario, I am serializing a JSON object in ...

Adjusting the outline color of a Material UI Select component in outlined mode to a different color when the dropdown is activated (currently shown as blue)

Is there a way to change the outline color of Material-UI select component outlined variant correctly? I need help changing the default blue color to red, any assistance would be greatly appreciated Click here for an image reference Reference code snippe ...

The order of execution is not maintained for $.getJSON() calls within the $.each() loop

As I iterate through an HTML table, I am making a $.getJSON() request based on the data in each row. My goal is to retrieve the data from that $.getJSON call and update the corresponding row with it. Unfortunately, when I run my code, it seems to be execu ...

When attempting to browse for image files, Postman fails to display images

While trying to upload image files through Postman, I encountered an issue where the browser did not display any image files. It's important to note that I am using Ubuntu as my operating system. When I clicked on "select files," the option appeared ...

Generating a JavaScript object based on an array of keys

I'm currently grappling with a task that is proving to be quite challenging. I have a set of arrays structured like this: ['key1', 'key2', 'key3'] ['key1', 'key2', 'key4'] ['key1', ...

retrieve the identification number associated with a specific value

How can I retrieve the value of this ID, which is sent from the controller and displayed in the table? https://i.sstatic.net/UbdxT.png This is my HTML code: <tbody class="no-border-x"> <tr> <td id="id"></td> <td i ...

When crafting an XPATH expression, I am able to navigate within the #document element. Within this element, I must specify the path to the HTML body of my web page

I need assistance with my HTML page, can someone please help? Here is the XPath code I am using: (//span[text()='Information']//following::div[contains(@class,'edit-area')])[1]/iframe However, when I run my script, it says that there ...

The icon for the weather on openweathermap is currently not displaying

Take a look at what my webpage looks like: http://prntscr.com/dg6dmm and also check out my codepen link: http://codepen.io/johnthorlby/pen/dOmaEr I am trying to extract the weather icon from the api call and display that icon (e.g. "02n") on the page base ...

Simple methods to minimize the iteration of array loops in Node.js

First, retrieve the "grid_id" from the "grids" array ( Step 1 ) Next, verify if this "grid_id" is present in the "variationsDB" array ( Step 2 ) Once you have this "grid_id", use it to fetch the "var ...

AngularJS is encountering an issue with the callback function, resulting in an error

Currently, I am utilizing the $timeout service in Angular to decrease a variable from 100 to 1 in increments of 1/10 seconds. Although I understand that using the $interval service would be a simpler solution, for this particular scenario, I am focused on ...

developing a custom modal using a button in a React project with Material UI

Hello everyone, I have a question regarding React. I am fairly new to React and need some assistance with adding a new function that creates a Modal. I want to call this function onClick when the add icon is pressed (line 43). Any help would be appreciated ...

How can you check the boolean value of a checkbox using jQuery?

I have a checkbox on my webpage. <input id="new-consultation-open" type="checkbox" /> My goal is to store the state of this checkbox in a variable as a boolean value. consultation.save({ open: $("#new-consultation-open").val() }); Unfortunate ...

What is the best way to refresh a page after rotating the web page?

Struggling with a challenge in Next JS - can't seem to figure out how to automatically refresh the page when it rotates const app () => { useEffect(()=>{ window.addEventListener("orientationchange", function() { window.locati ...

Refresh the Content of a Page Using AJAX by Forcing a Full Reload

I have a webpage that automatically updates a section using jQuery AJAX every 10 seconds. Whenever I modify the CSS or JavaScript of that page, I would like to include a script in the content fetched via AJAX to trigger a full page reload. The page is ac ...

Is it possible to change XML using Ajax technology?

Is it possible to update a value in an XML file using JavaScript/Ajax? I've managed to access the XML file with Ajax and utilize its values in my script. Now, I want to send any updates made by the script back to the XML file on the server using Ajax ...

Vue.js seems to be leading me down a long and steady path of progress at a snail

I've exhausted all efforts to resolve the file paths for Home and App. I even turned to AI to help me out, but still no luck. Code snippet from main.js in the src folder: import Home from '@views/Home.vue'; // Using alias import App from ...

Disabling the scrollbar in Selenium screenshots

When using Chromedriver to capture screenshots of webpages, my code effectively does the job. However, I am now facing an issue with removing the unsightly scrollbars from the image. Is it feasible to inject CSS into the webpage in order to achieve this? W ...

Parsing JSON sub items in Android application using Java

Here is a snippet of my PHP file: <?php $myObj = array( "name"=>"John" , "age"=>"30" , "post"=>[ "title"=>"What is WordPress" , "excerpt"=>"WordPress is a popular blogging platform" , ...