Aggregate X and Y values based on a key in a scatter plot using dc.js

Here is a glimpse of my dataset:

var items = [
    {name: "X", duration: 1, quantity: 2},
    {name: "X", duration: 2, quantity: 1},
    {name: "Y", duration: 1, quantity: 4},
    {name: "X", duration: 3, quantity: 1},
    {name: "Y", duration: 1, quantity: 1},
];

Using dc.js, I'm attempting to construct a scatter plot that aggregates the sum of both values (duration and quantity) based on the item's name. In this scenario, I expect the scatter plot to display only two data points, depicted like so:

https://i.sstatic.net/oSUNi.png

I suspect there might be an issue with either the dimension or group setup because none of my points are showing up on the plot.

var cf = crossfilter(items),
    dim = cf.dimension(d => d.name),
    grp = dim.group().reduce(
        (previousValue, currentValue) => [ previousValue[0] + currentValue.duration, previousValue[1] + currentValue.quantity ],
        (previousValue, currentValue) => [ previousValue[0] - currentValue.duration, previousValue[1] - currentValue.quantity ],
        () => [0, 0]
    );
var chart = dc.scatterPlot("#scatter_plot");
chart
    .dimension(dim)
    .group(grp)
    .x(d3.scaleLinear());

I believe the reduce function is accurate. The output of grp.all() shows the correct aggregated datasets.

https://i.sstatic.net/Tvzre.png

However, despite this, my plot remains empty as mentioned earlier.

Answer №1

To successfully implement this solution, a series of clever strategies need to be employed.

Initially, it is crucial to have the coordinates in the key rather than the value. This can be achieved by utilizing a "fake group" to interchange key and value dynamically:

function flip_key_value(group) {
  return {
    all: () => group.all().map(({key, value}) => ({key: value, value: key}))
  };
}

chart
  .group(flip_key_value(grp))

Subsequently, color mapping based on the value (now the name) becomes necessary:

chart
  .colorAccessor(({value}) => value)

Both scales must be set up, with elastic and padding features for convenience, along with axis labels:

chart
  .x(d3.scaleLinear())
  .y(d3.scaleLinear())
  .elasticX(true).elasticY(true)
  .xAxisPadding(0.25).yAxisPadding(0.25)
  .xAxisLabel('duration').yAxisLabel('quantity')

Additionally, a custom .legendables() method needs to be defined to ensure each dot has its own unique color:

chart.legendables = () => chart.group().all()
    .map(({key, value}) => ({chart, name: value, color: chart.colors()(value)}));

Furthermore, margins should be adjusted to accommodate the legend on the right side, and the legend itself needs to be declared:

chart
  .margins({left: 35, top: 0, right: 75, bottom: 30})
  .legend(dc.legend().x(425).y(50));

A screenshot is provided for reference, highlighting potential Xs and Ys orientation discrepancies in the desired output:

https://i.sstatic.net/cLAJA.png

Explore a demonstration of the solution through this Fiddle demo.

Enabling Filtering Functionality

In dc.js and crossfilter, filtering functionality hinges on setting filters on dimensions when users make selections.

Given the altered keys, inconsistencies arise between dimension and displayed group data, leading to invalid filtering operations that wipe out all other chart data.

To address this issue, identification of points within the selection box and filtering based on the original keys (now values) is imperative:

chart.filterHandler((dimension, filters) => {
  if(filters.length === 0) {
    dimension.filter(null);
    return filters;
  }
  console.assert(filters.length && filters[0].filterType === 'RangedTwoDimensionalFilter');
  const filterFun = filters[0].isFiltered;
  const itemsInside = chart.group().all().filter(({key}) => filterFun(key));
  const origKeys = itemsInside.map(({value}) => value);
  if(origKeys.length === 1)
    dimension.filterExact(origKeys[0]);
  else
    dimension.filterFunction(k => origKeys.includes(k));
  return filters;
});

Discover an updated version with functional selections in this New fiddle version.

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

Using PHP and XML with Ajax can run into problems with the getElementsByTagName function in Internet

Encountering a problem with getElementsByTagName specifically in IE versions 7 and 8. An address lookup generates suggested addresses as XML strings stored in a PHP session variable. These are then accessed using an AJAX function to retrieve the desired s ...

Mastering the art of redirection in Node.js

Encountering an issue with redirecting between directories - having trouble directing to another file in a different directory. Here is my directory structure: -views -add_user.jade -routes -index.js Attempting to redirect to add_user.jade from inde ...

Issue with Sliding Transition in React Material UI Drawer Component

I developed a custom drawer component for my React application const CustomSidebar = () => { return ( <Drawer open={drawerOpen} onClose={() => setDrawerOpen(false)} > <Box> <Navigator / ...

Unleashing the power of React: Integrating raw HTML <a href> tags with JavaScript

I am currently working on a small web app that mimics browsing WikiPedia by fetching raw HTML content of WikiPedia articles through its API. I then display this HTML in my app using "dangerouslySetInnerHTML". I am faced with the challenge of enabling a us ...

How can a CSS class be used to toggle the visibility of a DIV element with JavaScript?

I've been researching and came across several scripts that allow for toggling the contents of a DIV by clicking on a button, however, they all use IDs. What I am looking to achieve is similar but using classes instead of IDs. This way, if I want to h ...

In Javascript, create a variable that dynamically updates for every child element

While this might appear to be a simple question, it has been troubling me for some time now. Let me elaborate on what I am trying to accomplish. I have a collection of images in a gallery, and my goal is to center each image vertically within its contain ...

Is it possible to deceive Array.isArray?

Although I have a good understanding of prototypes, I encountered some confusion when I attempted the following: var obj = {}; Object.setPrototypeOf(obj, Array.prototype); console.log(Array.isArray(obj)); // false? What's even more perplexing: var ar ...

Datatables ajax response not loading data into table

I don't have much experience with JavaScript, so I believe there may be a misconfiguration or something that I'm overlooking. My current setup involves using Datatables v1.10.7. I have a table with the required parts - a thead, tfoot, and a tbod ...

The module ~/assets/images/flags/undefined.png could not be found in the directory

When I use the img tag with a dynamic address filled using require, it works well in the component. However, when I try to write a test for it, an error is thrown. console.error Error: Configuration error: Could not locate module ~/assets/ima ...

Utilize multiple classes in inline styling within HTML

I'm trying to dynamically apply the "more" CSS class directly to an inline style tag, but I haven't had success with my current approach. Unfortunately, in my situation, I can't create a class. The method is working for <p> tags but no ...

Struggle with registering fonts in Canvas using JavaScript

I've been struggling to add a custom font to my canvas for hosting the bot. Even though I'm not encountering any errors, the font fails to display on the host. Below is the code snippet: const { AttachmentBuilder } = require('discord.js&apos ...

Utilizing JSON format for processing HTTP requests in JavaScript with Node.js

I'm working with a snippet that retrieves data in JSON format, but I'm interested in manipulating the data instead of just outputting it to the console. var request = require('request'); var headers = { 'Connection': ' ...

Scale the cylinder in Three.js from a specific point

Can a cylinder be resized along the Y-axis starting from a particular point? Instead of the cylinder expanding from its center in both directions to the new scale, is it possible for it to grow upwards/downwards only like a bar chart? Current code : fu ...

"How to dynamically fill a text input field from a table using jQuery when a specific value is selected, potentially involving multiple rows (possibly

Scenario I created a form that allows users to place orders for articles. These articles are displayed in a table within another form, where each article is listed with its code, description, and price. The goal is for users to select an article from th ...

`In Node.js, retry attempts resulted in an HTTP 504 status code.`

I have a scenario where my http server always returns a 504 status code: const express = require('express') const app = express() app.get('/', (req, res) => { console.log('I AM HERE'); res.status(504).send('N ...

Creating an empty array within an object in JavaScript

Consider the following scenario: var form = { header: { value: null, isValid: false, type: 'textinput', rules: { isRequired: true, ...

Instructions for showcasing a 404 error page in the event that a back-end GET request to an API fails due to the absence of a user. This guide will detail the process of separating the

I am currently working on an application that combines JavaScript with Vue.js on the front-end and PHP with Laravel on the back-end. When a GET request is made from the front-end to the back-end at URL /getSummoner/{summonerName}, another GET request is t ...

Trigger the jQuery function based on the ID modification executed by jQuery

Is it possible to change the id of an HTML element using this function? $("#test").attr('id', 'test2'); Here is an example of the code: $("#test").click(function() { $("#test").attr('id', 'test2'); alert(& ...

Discovering more about this topic

Looking for a way to create an expandable box that enlarges when "read more" is clicked, revealing text below it. And also looking to add a button that closes the expanded text back up. Experimented with the toggletext JavaScript command, as found on this ...

What is the best way to extract URL query parameters and store them in a MySQL database using Node.js and Express

I am working on a project where I need to store specific information like names and widths from the URL query into my MySQL database. The format of the URL query should resemble this: /register?name=XXXX&width=###.### However, I seem to be facing ch ...