What is the best way to name a force-directed Graph using d3?

I'm struggling to label the nodes in my force-directed graph created with d3.js. Despite trying various solutions from StackOverflow and online tutorials, I believe my issues stem from a lack of fundamental understanding of JavaScript. https://i.sstatic.net/1jSxJ.png

I've experimented with different combinations of .attr/.append/.text functions to display the source and target text on the nodes, but nothing seems to work.

Here's the part causing trouble:

node.append("title")
    .text(function (d) {return d.target});

node.append("text")
    .attr("dy", -3)
    .text(function (d) {return d.source})
    .attr("class", "font");

Below is a simplified snippet of the styles:

<style>

.node {
    fill: #ccc; /* Circle fill color */
    stroke: #ffffff;
    stroke-width: 2px;
}

.font {
    font: 10px;
    font-family: sans-serif;
}

.link {
    stroke: #777; /* Line color */
    stroke-width: 2px;
}
</style>

Next is an excerpt from the script:

var width = 640,
    height = 480;

var links = [
    // Array of links
    {source: "Germany", target: "name1"},
    {source: "Germany", target: "name2"},
    ...

// Node setup

var svg = d3.select("body").append("svg")
    ...

var node = svg.selectAll(".node")
    ...
    
// Adding text elements to nodes
node.append("title")
    ...

node.append("text")
    ...

function tick(e) {
    ...
}
</script>

I'm encountering difficulties without any error messages for guidance. Any assistance would be greatly appreciated. Thank you!

Answer №1

There seem to be two issues in the code provided.

The first problem lies in the selection of the node:

var node = svg.selectAll(".node")
    .data(force.nodes())
    .enter().append("circle") 
    //etc...

It appears that you are selecting circles as nodes, so trying to append a <text> element to a <circle> element will not work.

A common solution is to make your node selection a group (<g>) instead, where you can append both circles and texts.

The second issue pertains to the data associated with the nodes. The code snippet includes:

node.append("text")
    .text(function (d) {return d.source})

However, there is no property named source in the data. The correct property to use is name.

Please find below the updated code reflecting these corrections:

var width = 640,
  height = 480;

var links = [
  {
    source: "Germany",
    target: "name1"
  },
  {
    source: "Germany",
    target: "name2"
  },
  {
    source: "Nigeria",
    target: "name3"
  },
  {
    source: "Environment",
    target: "name4"
  }
];

var nodes = {};

links.forEach(function(link) {
  link.source = nodes[link.source] ||
    (nodes[link.source] = {
      name: link.source
    });
  link.target = nodes[link.target] ||
    (nodes[link.target] = {
      name: link.target
    });
});

var svg = d3.select("body").append("svg")
  .attr("width", width)
  .attr("height", height);

var force = d3.layout.force()
  .size([width, height])
  .nodes(d3.values(nodes))
  .links(links)
  .on("tick", tick)
  .linkDistance(300)
  .start();

var link = svg.selectAll(".link")
  .data(links)
  .enter().append('line')
  .attr("class", "link");

var node = svg.selectAll(".node")
  .data(force.nodes())
  .enter().append("g");

node.append("circle")
  .attr("class", "node")
  .attr("r", width * 0.03);

node.append("text")
  .attr("dy", -3)
  .text(function(d) {
    return d.name
  })
  .attr("class", "font");

function tick(e) {
  node.attr("transform", function(d) {
      return "translate(" + [d.x, d.y] + ")"
    })
    .call(force.drag);

  link.attr("x1", function(d) {
      return d.source.x;
    })
    .attr("y1", function(d) {
      return d.source.y;
    })
    .attr("x2", function(d) {
      return d.target.x;
    })
    .attr("y2", function(d) {
      return d.target.y;
    })
}
.node {
  fill: #ccc;
  stroke: #ffffff;
  stroke-width: 2px;
}

.font {
  font: 10px;
  font-family: sans-serif;
}

.link {
  stroke: #777;
  stroke-width: 2px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.17/d3.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

Utilize the id in AngularJS to bring attention to a specific row within a table

I am brand new to using angularjs. I currently have a table structured like this: HTML <table class="table table-striped" id="manageResumeTable"> <thead class="text-center text-info text-capitalize"> <th class="text-center col- ...

Ajax implementation for handling URL action parameters

I am currently facing challenges in passing data from a view to a controller using parameters. My goal is to pass these parameters when I select a row from a table and click on a button that triggers the ShowTasks() function. Here is the C# controller cod ...

Troubleshooting: React js Project console.logs are not being displayed in the browser's

When working on my current project, I noticed that any time I try to use console.log in the dev tools, it shows as cleared. Strangely, console.log works fine in my other projects. Does anyone have an idea how to resolve this issue? Here is a screenshot of ...

Send a quick message with temporary headers using Express Post

When creating a response for a post request in Express that returns a simple text, I encountered an issue. var express = require('express'); var app = express(); var bodyParser = require("body-parser"); var multer = require('multer') ...

Incorporating .json files into an HTML template with the help of an HTML form designed for selecting a particular

I am faced with a collection of various .json files that I wish to specify by name on an HTML page (local) form, enabling me to load this data onto a table. This is how my HTML form appears: <form> File: <input type="text" Id="file_name"&g ...

Using Node.js to parse JSON data fetched from the web

My current challenge involves retrieving and parsing JSON from a web API (https://api.coinmarketcap.com/v1/ticker/?limit=3) in order to extract the name and price_usd fields. For example: [ { ... sample data provided ... } ] The code snippet I am wo ...

Integrate the complete Mozilla pdf.js viewer into a Vue.js application using webpack through vue-cli

I am trying to integrate the full Mozilla pdf.js viewer into a Vue SPA. After reading a Stack Overflow post with an accepted solution, I still can't seem to get it to work. I keep encountering the 'Uncaught SyntaxError: Unexpected token <&apo ...

Struggling to create a line break within an SVG using the <tspan> element?

I have a pair of text lines that are wrapped in <tspan> tags. <tspan dy="-11.7890625">welcome</tspan> <tspan dy="16.8" x="285.75">text</tspan> I am trying to add a line break between them, but the <br> tag is not worki ...

Combine multiple arrays in JavaScript into a single array

Here is the array I am working with: array = ['bla', ['ble', 'bli'], 'blo', ['blu']] I need to transform it into this format: array = ['bla', 'ble', 'bli', 'blo', &a ...

Expanding cards with Material-UI and React seems to be a challenge when using an expander

I've recently integrated a Card component into my project, sourced from material-ui's official website. However, I'm encountering an issue where the CardHeader does not expand upon clicking. This is the structure of my Component : import ...

Encountering permission issues while attempting to add `@nuxtjs/sentry` in a Docker container running Node 16.14. Installation

While attempting to add @nuxtjs/sentry to my project by running npm install @nuxtjs/sentry, I encountered some issues. Here is the error message I received: npm ERR! code 1 npm ERR! path /app/node_modules/@sentry/cli npm ERR! command failed npm ERR! comm ...

What is the best way to format a date input field so that when a user enters a year (yyyy), a hyphen (-

Need help with date formatting in the format yyyy-mm-dd. Seeking a way to prompt user input for the year and automatically append "-" to the date as needed. Also utilizing a datepicker tool for selecting dates. ...

Creating markers from Mysql database is a simple and efficient process

On my website, I have an array of markers that I use to display locations on a Google map. The array format I currently use is: generateMarkers([['Location', lat, long], ['Location2', lat2, long2],['Location3', lat3, long]3]) ...

Activate Bootstrap datetimepicker by using the enter key to automatically populate the initial date

Check out the Bootstrap datetimepicker on this page: I'm trying to make it so that when the datetimepicker is first shown, pressing the enter key will hide the widget and insert the current date into the input field. I've experimented with a few ...

What options do I have for personalizing event listeners in d3.js?

I am currently working on a simple program that involves using a slider to move a rectangle across a webpage. I have set up the slider like this: <input type = "range" min = "5" max = "500" value = "5" id = "xvalue" > and I am able to access the sl ...

When you click on a list of links, a stylish image gallery will appear using fancybox

Can anyone lend a hand with this? I would greatly appreciate any assistance CSS <a id="fancybox" href="javascript:;">Gallery 1</a> <br /> <a id="fancybox" href="javascript:;">Gallery 2</a> <br /> <a id="fancybox" hr ...

I'm unable to modify the text within my child component - what's the reason behind this limitation?

I created a Single File Component to display something, here is the code <template> <el-link type="primary" @click="test()" >{{this.contentShow}}</el-link> </template> <script lang="ts"> imp ...

Encountering a "Module not found" error when trying to integrate NextJs 13.4 with React Query and the

I encountered some issues while working on a NextJs application that utilizes App Router. The problem arose when we decided to switch from traditional fetching to using React Query in server components. To address this, I created a file called api.ts withi ...

Error: The API_URL_KEY variable has not been declared

hardhat.config.js require("@nomicfoundation/hardhat-toolbox"); /** @type import('hardhat/config').HardhatUserConfig */ module.exports = { solidity: "0.8.18", }; /* @type import('hardhat/config').HardhatUserConfig* ...

Efficiently rearranging elements by adjusting their top values techniques

My iPhone lockscreen theme features various elements displaying weather facts such as text and small images. Currently, these elements are positioned in the middle of the screen and I want to move them all to the top. Each element has a unique position abs ...