How can values be shown on the links/paths of a Sankey Graph in R programming?

Story

While attempting to recreate a Sankey graph similar to the one shown in the image below, I aimed to assign specific values (10, 20, 30, 40) to the paths connecting different nodes.

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

My Approach

Initially, I used the Python Plotly library for this task. However, I discovered that Plotly does not provide direct support for setting values along the links or paths of a Sankey graph. Subsequently, I switched to R due to its wider range of resources available. Nevertheless, I encountered the same issue even in R. Despite consulting various tutorials and Q&A threads on Stack Overflow related to Sankey graphs in R (such as this one), I have been unable to find a solution where the path values are displayed.

Main Concern

I am seeking guidance on how to showcase values on the links/paths of a Sankey Graph using R.

Please Note: The questions on Stack Overflow mentioned here (link1 and link2) appear relevant, but I am struggling to implement their solutions in my own code snippets.

Sample Code Snippet (excerpted from here)

# install.packages('networkD3')
library(networkD3)
nodes = data.frame("name" = 
 c("Node A", # Node 0
 "Node B", # Node 1
 "Node C", # Node 2
 "Node D"))# Node 3
links = as.data.frame(matrix(c(
 0, 1, 10, # Each row represents a link. The first number
 0, 2, 20, # represents the node being conntected from. 
 1, 3, 30, # the second number represents the node connected to.
 2, 3, 40),# The third number is the value of the node
 byrow = TRUE, ncol = 3))
names(links) = c("source", "target", "value")


 sankeyNetwork(Links = links, Nodes = nodes,
 Source = "source", Target = "target",
 Value = "value", NodeID = "name",
 fontSize= 50, nodeWidth = 30)

Answer №1

To implement this functionality, you can utilize custom JavaScript code by injecting it during the rendering process using htmlwidgets::onRender(). The following example demonstrates how to initially position the link labels correctly. However, if the nodes are manually rearranged, the link labels will not automatically adjust accordingly. To address this issue, you may need to override the default behavior of dragmove.

library(htmlwidgets)
library(networkD3)

nodes <- 
  data.frame(
    name = c("Node A", "Node B", "Node C", "Node D")
  )

links <- 
  data.frame(
    source = c(0, 0, 1, 2),
    target = c(1, 2, 3, 3),
    value = c(10, 20, 30, 40)
  )

p <- sankeyNetwork(Links = links, Nodes = nodes,
                   Source = "source", Target = "target",
                   Value = "value", NodeID = "name",
                   fontSize= 20, nodeWidth = 30)

htmlwidgets::onRender(p, '
  function(el) { 
    var nodeWidth = this.sankey.nodeWidth();
    var links = this.sankey.links();
        
    links.forEach((d, i) => {
      var startX = d.source.x + nodeWidth;
      var endX = d.target.x;
      
      var startY = d.source.y + d.sy + d.dy / 2;
      var endY = d.target.y + d.ty + d.dy / 2;
      
      d3.select(el).select("svg g")
        .append("text")
        .attr("text-anchor", "middle")
        .attr("alignment-baseline", "middle")
        .attr("x", startX + ((endX - startX) / 2))
        .attr("y", startY + ((endY - startY) / 2))
        .text(d.value);
    })
  }
')

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

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

What is the reason behind the effectiveness of this prime number verifier?

Take a look at this code snippet that effectively checks whether a number is prime: var num = parseInt(prompt("Enter a number:")); var result = "Prime"; for (var i = 2; i < num; i++) { if (num % i === 0) { result = "Not Prime"; break; } } ...

When using node.js, the initial request yields no response while the subsequent request provides the expected data

Currently, I am in the process of setting up a node.js API using Express, Body-parser, and MySQL. An issue I am encountering is that when making a GET request to a route for the first time, it returns blank. However, on the second attempt, it retrieves th ...

Stop inserting repeatedly if there is no new data available

I'm looking for a simple way to implement an if-else statement in my AJAX code to display new data only once it's found, without repeating the same data. Also, I need to figure out how to store the last ID as a variable so that I can use it when ...

Is it possible for Javascript to detect your IP address?

Question About Getting Client IP Address: Get Client IP using just Javascript? I am aware that PHP can retrieve the client's IP address using <?php echo $_SERVER['REMOTE_ADDR']; ?> Is there a way for JavaScript to accomplish the ...

Inquiry regarding the ng-disabled directive in AngularJS

<div ng-app="myApp" ng-controller="myCtrl"> <button type="submit" class="btn btn-primary pull-left" ng- disabled="captchaError">Submit</button> </div> <script> var app = angular.module('myApp', []); app.controller( ...

Ways to incorporate a dynamic value into a chart created with chart.js?

I want to create a doughnut chart representing the number of individuals who have tested positive for Coronavirus and the number of deaths related to it. How can I transfer the same data from the top container into the chart? The confirmedCases and deaths ...

Is there a way for me to iterate through an array of objects within a Redux reducer file in order to remove a specific user?

I am facing a challenge while trying to remove a user in redux. The issue arises when I use the map function in the reducer.js file and encounter a 'state.users.map is not a function' error. Upon investigation, I realized that the array consists ...

Encountering an abundance of concurrent requests using NodeJS and request-promise

I am currently working on a NodeJS project that involves a large array of about 9000 elements containing URLs. These URLs need to be requested using the "request-promise" package. However, making 9000 concurrent GET requests to the same website from the sa ...

Setting up web pack with flag-icon-css integration

I have successfully set up a webpack project using https://github.com/teroauralinna/webpack-guide. Now, I am looking to integrate https://github.com/lipis/flag-icon-css into my project. To do so, I followed these steps: npm install flag-icon-css --save T ...

Tips for making a DIV span the entire width of a page when it is within a column with the Bootstrap class 'col-md-6'

I'm having a little trouble arranging divs next to each other on a page. Specifically, I want to ensure that if there is only one instance of the col-xs-12 col-md-6 div class on the page, it should take up the full width (100%) instead of just 50%. Th ...

Begin by checking off all checkboxes

My HTML page includes jQuery code that allows me to set all checkboxes to a 'checked' state when clicking on a 'check all' checkbox. However, I want to have all checkboxes checked by default when the page loads, without needing to click ...

Issues with Angular Routes handling JSON array routes

Encountering an Issue with Angular Routing I'm relatively new to Angular and making good progress. I want Angular's routing functions to be dynamic so I created a small api for Angular to fetch from, returning an array. However, when I iterate o ...

What is the default parameter type in react-native?

Currently, I am delving into React-native framework. While browsing through the Facebook ListView sample page, I stumbled upon the below code snippet. _renderRow: function(rowData: string, sectionID: number, rowID: number) { .... Interestingly, I have n ...

Issue with Express/Node.js route unable to access key values within an object

I am currently struggling with creating a node/express route that fetches data from a MongoDB collection and facing an infuriating issue. The collection in question is named nba_players_v2, and I've tried crafting the following route: router.get(&apo ...

What is the process of triggering an action from within getInitialProps?

I've been struggling to integrate Redux into a Next.js app, particularly when trying to use the dispatch function within getInitialProps. For some reason, the store keeps returning as undefined and I can't seem to pinpoint the issue. I've fo ...

Utilize jQuery.ajaxComplete to identify the location of the AJAX request

I have an event: $(document).ajaxComplete that is functioning perfectly. Yet, I am looking to determine whether ajax took place at a particular spot within the document. Is there a method to identify which ajax call was made? $(document).ajaxComplete(fu ...

Charts in Angular using Chart.js fail to update with data changes unless the console is open

I'm currently developing an Angular application that utilizes Chart.js to display charts. Although the charts render correctly initially, they fail to update when the data changes without accessing the browser's console. Below are important segm ...

Switch up the information upon button click using reactjs and Material UI

The current website is in the development phase and is being built using Reactjs and Material UI. To display different components based on the address change, switch statements have been utilized. Buttons are expected to update the URL using 'Link to ...

Utilizing ES6 promises in node.js to send a null response

I'm looking for assistance on how to execute a query using ES6 native promises in node.js. The code I have below is what I've been working with: let arr= []; conn.query('select * from table1', (err, b) => { for (let i = 0; i ...

AJAX cannot be used with the current session

I am facing an issue with a directory containing files that are used only as modal. These PHP files have the following format: "modal.filename.php". Here is an example: "modal.user.php": <?php session_start(); $_SESSION['test'] = 1; echo & ...