d3js operates effectively after the encoding and decoding of data has been completed

Currently, I'm diving into creating a data visualization using d3js paired with hierarchical layout. The data I am working with has the following structure:

       0
     / | \
    /  |  \ 
   1   5   3
    \  |   |
     \ |   |
       4  /
       | /
       2

Since I am unable to create links to multiple parents, I have resorted to duplicating nodes for display purposes:

       0
     / | \
    /  |  \ 
   1   5   3
   |   |   |
   |   |   |
   4   4   |
   |   |   |
   2   2   2

To illustrate my issue, I have set up a fiddle demo:

  • Using the correct data in my JSON input results in the expected layout (graphic outlined in blue).
  • However, when I use a loop to parse my JSON input, it leads to a distorted graph (graphic outlined in green).

Here is the loop I utilized to parse the input:

for (i in root[2].Arcs){
  var d = root[1].Nodes[root[2].Arcs[i].D];
  var s = root[1].Nodes[root[2].Arcs[i].S];
  if (!d.children){
    d.children = [];
  }
  d.children.push(s);
}

Although the printed elements in the console appear to be the same, the layout render differs, possibly due to variations in object reference.

One workaround I discovered is to decode and encode my variable:

    var root = JSON.parse(JSON.stringify(root));

Following this approach, the script functions correctly. However, if 'root' is a lengthy array, the parsing process becomes time-consuming...

Any insights on why encoding/decoding is necessary to display identical content would be greatly appreciated.

Thanks

Answer №1

If you're looking to optimize your code, consider replacing your for loop with the following approach. It may offer better performance. Check out the solution on jsfiddle

traverse(root[1].Nodes[0]);
function traverse(node) {
    for (i in root[2].Arcs) {
        var d = root[1].Nodes[root[2].Arcs[i].D];
        if (node.name === root[2].Arcs[i].D) {
            var s = root[1].Nodes[root[2].Arcs[i].S];
            var sCopy={
                "name": s.name
            }
            traverse(sCopy);
            if (!node.children) {
               node.children = [];
            }
            node.children.push(sCopy);
        }
    }
}

Answer №2

If you want to avoid shallow copy when encoding/decoding JSON, it's important to understand the difference between deepcopy and shallowcopy. You can learn more about it by visiting this link: What is the difference between a deep copy and a shallow copy?

Using

var root = JSON.parse(JSON.stringify(root));
is an incorrect method to prevent shallow copy. Instead, you can utilize jQuery's clone method or JavaScript's slice method to create a deep copy of a JavaScript array.

For example:

var d=[1,2,3,4,5,6];//create array
var b=d;//copy array into another array (shallow copy/reference copy)
var e=d.slice();//clone array in another variable (deep copy)
d[0]=9; //change array element
console.log(d)// result : [9,2,3,4,5,6] (changed array)
console.log(b)// result : [9,2,3,4,5,6] (changed array due to reference)
console.log(e)// result : [1,2,3,4,5,6] (unchanged array due to deep copy)

Another solution is to use underscore. You can pick the cloning portion from the underscore library without needing the full JavaScript code.

In underscore, you can clone an object array using:

var a = [{f: 1}, {f:5}, {f:10}];
var b = _.map(a, _.clone);       // <----
b[1].f = 55;
console.log(JSON.stringify(a));

It will output:

[{"f":1},{"f":5},{"f":10}]

Answer №3

Note: The performance may not be as efficient as the original post, refer to the comments below. This method is designed to be scalable, ensuring it works regardless of the object or flag configurations.

Solution

Here is an alternative approach to the "deep copy" technique suggested by @transcranial and @LaxmikantDange.

I recommend utilizing jQuery (personally, I prefer this approach for its simplicity) and leveraging the extend method:

<<load jquery>>

root = $.extend(true, {}, root[1].Nodes[0]);
graph(root2,svg);
graph(root,svg2);

Ensure that the first argument is set to true as demonstrated in the documentation here or in this discussion regarding efficient deep cloning in JavaScript (top answer).

I cannot confirm the performance implications, but I encourage you to test and share your results with me!

Keep in mind that deep copying might have limitations based on your application (such as broken links). For example, in a recent React project where I shared events between graphs, certain interactions like zoom events were not automatically synchronized due to the separate object instances.

Answer №4

To ensure proper functionality when adding new nodes (which are objects) to your arrays of children nodes, you must deep copy these objects before pushing them into the array. Simply reassigning "=" will not work for objects, as it does for string or number arrays. Deep copying the children nodes before adding them to the array will resolve any layout and rendering issues.

Here is your original code for adding children nodes to the array:

for (i in root[2].Arcs){
  var d = root[1].Nodes[root[2].Arcs[i].D];
  var s = root[1].Nodes[root[2].Arcs[i].S];
  if (!d.children){
    d.children = [];
  }
  d.children.push(s);
}

Updated code:

for (i in root[2].Arcs){
  var d = root[1].Nodes[root[2].Arcs[i].D];
  var s = root[1].Nodes[root[2].Arcs[i].S];
  if (!d.children){
    d.children = [];
  }
  d.children.push(JSON.parse(JSON.stringify(s)));
}

Give it a try here: JSFiddle.

Furthermore, it should be noted that d3 hierarchical layouts, including cluster, do not naturally support nodes with multiple parents. In such cases, consider utilizing a force graph layout.

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

Creating a Vue application without the use of vue-cli and instead running it on an express

Vue has an interesting feature where vue-cli is not necessary for running it without a server. Initially, I thought otherwise. The Vue installation page at https://v2.vuejs.org/v2/guide/installation.html mentions using a script under CDN. <script src=&q ...

Retrieving form output number using JQuery

Hello, I'm new to this site and have no prior experience with javascript coding. Here is what I have in my javascript file: $(document).ready(function() { $("input").click(function(event) { updateTotal(); }); }); function updateTotal() { var to ...

How to eliminate a particular validator from a form group in Angular

My goal is to eliminate the specific validator from the validator array so that I can reconfigure the controls when certain values have changed. I am aware of the traditional solution where I would need to repeatedly set validators. checked(event: MatC ...

Is it possible to incorporate JavaScript files into a TypeScript (ts, tsx) project that has already been built?

Recently, I was given a task to incorporate additional pages into the current project which has been developed using the following technologies: Laravel: 8.12 React: 17.0.2 NextJS: 10.0.9 Tailwind CSS: 2.0.4 React Query: 3.13.0 [ REST] TypeScript: 4.2.3 M ...

JQuery div not cooperating with other JavaScript/jQuery functions

I used the $(select).append() method to add one div inside another div, but I wanted to close it on click of an image. So I added an image and another $(select).button().click( { $(select).hide() }) to achieve this functionality. However, when clicking t ...

Error message encountered: "Node.js Object [object Object] does not support the method"

My application uses Express.js and mongodb, including the mongodb Native driver. I have created a model with two functions for retrieving posts and comments: // Retrieve single Post exports.posts = function(id,callback){ MongoClient.connect(url, fun ...

Tips for displaying a view with data fetched from various sources

I'm currently working on a project using backbone.js and I've encountered an issue with a model that doesn't need to synchronize with the server. This particular model is only meant to fetch user data for initializing other views; it acts as ...

Iterate over the table data and present it in the form of a Google

I'm struggling to extract data from a table and display it in a google chart. I need some guidance on how to properly loop through the information. HTML <tr> <th>Date</th> <th>Score</th> <th>Result< ...

Parameter for Ajax URL

As a beginner in the world of Ajax, I'm on a mission to grasp the inner workings of this technology. I came across a tutorial on w3schools that sparked my curiosity. In the code snippet below, the 'url' is defined as demo_ajax_load.txt. Wil ...

Is there a way to send multiple parameters in an array to a route?

I am working on deleting multiple rows from a MySQL database using checkboxes in my ejs view with node.js and React app. I have successfully deleted a single row, but I am struggling to figure out how to pass an array of parameters for deleting multiple ro ...

The jQuery response appears blank in the browser, despite the fact that it works fine with

Utilizing jQuery's .ajax() function to communicate with a local Django runserver and retrieve a response. Observing the server console, the JSON request is received properly, a correct JSON response is generated, and all appears in order. However, i ...

"Unraveling nested data structures in React using JSON parsing

When attempting to fetch data in React from a MySQL database, I have encountered an issue where MySQL auto-escapes my values, including nested objects. While I am able to use the .json() function successfully on the top-level, I have run into problems when ...

What is the procedure for importing material UI components into the main class?

Hey there! I'm currently working on integrating a "SimpleAppBar" element into my React app design. Below is the code snippet for this element sourced directly from the Material UI official website: import React from 'react'; import PropType ...

Is the && operator being utilized as a conditional statement?

While following a tutorial, I came across this code snippet that uses the 'and' operator in an unusual way. Is this related to React? Can someone provide an explanation or share documentation that clarifies it? {basket?.length > 0 && ...

How can I automatically redirect a React page once I receive a response from Express?

I'm facing an issue with redirecting from one page to another in React. The setup involves an Express server serving the required data to React, and upon receiving the data in React, the goal is to display that result on another page by triggering a r ...

An error was encountered when trying to read property '0' of an undefined object in a for loop

Currently, I am working on a project to create a mastermind game. Everything is progressing smoothly, except for one issue that keeps popping up - I keep encountering the error: "uncaught typeerror cannot read property '0' of undefined." fun ...

A guide to using jqGrid: Retrieve the value of a particular cell by double clicking on a row

Is there a way to implement a feature where users can double click on any part of a row and have it open a new HTML page based on the specific content in a cell? For example, I have a table with different counties in New York listed in separate rows: Coun ...

showcasing JSON data in an HTML table with pure JavaScript

I am currently utilizing vanilla JS to send a client request to a REST web service that I have designed. The GET method I have implemented returns a list of books (List) in JSON format: 0: {name: "To Pimp a Butterfly", isbn: "ACBCDDSA", availableCopies: 1 ...

Node.js - Passport authentication consistently results in redirection to failure route

I am currently working on creating a login form using passportJs, but I keep encountering the issue of failureRedirect. Despite searching on stack overflow for a solution, I have not found the correct answer yet. Below is my code: Here is how I am crea ...

Leverage and repurpose OOP objects

I am exploring how to inherit from Button using prototypes. Despite my efforts, the alerted name remains "Sarah" as it is the last Child created. I believe the Creator Class should be responsible for setting the name using a Method in Button. Check out m ...