Skip to Content
Technical Articles

Network Graph Visualization in SAP Analytics Cloud Analytic App

In this quick tutorial, we will create an SAC Analytic App custom widget to visualize network graph force layout.

Network Graph

As highlighted in Fiori Design Guidelines, the network graph displays a large amount of data by highlighting the relationships between individual records. Records are displayed as nodes, and connectors (lines) show the relationships between them. Below is the screenshot of the network graph with force layout algorithms.

 

Prepare the Data

Let’s prepare the data in CSV format. I am getting the data from the SAPUI5 sample Force-Based Layout with Static Nodes. Save it to “data.csv”.

KEY,FROM,TO,TITLE,GROUP,STATUS,ICON,LABEL0,VALUE0,LABEL1,VALUE1
0,0,1,Iron Man,1,Error,sap-icon://key-user-settings,Release date,"May 2, 2008",Director,Jon Favreau
1,1,5,Iron Man 2,1,Error,sap-icon://key-user-settings,Release date,"May 7, 2010",Director,Jon Favreau
2,2,5,The Incredible Hulk,1,Error,sap-icon://theater,Release date,"June 13, 2008",Director,Louis Leterrier
3,3,5,Thor,1,Warning,sap-icon://wrenc,Release date,"May 6, 2011",Director,Kenneth Branagh
4,4,5,Captain America: The First Avenger,1,Success,sap-icon://unfavorite,Release date,"July 22, 2011",Director,Joe Johnston
5,5,6,Marvel's The Avengers,1,Error,sap-icon://text-color,Release date,"May 4, 2012",Director,Joss Whedon
6,5,7,Marvel's The Avengers,1,Error,sap-icon://text-color,Release date,"May 4, 2012",Director,Joss Whedon
7,5,8,Marvel's The Avengers,1,Error,sap-icon://text-color,Release date,"May 4, 2012",Director,Joss Whedon
8,5,19,Marvel's The Avengers,1,Error,sap-icon://text-color,Release date,"May 4, 2012",Director,Joss Whedon
9,6,10,Iron Man 3,2,Error,sap-icon://key-user-settings,Release date,"May 3, 2013",Director,Shane Black
10,7,10,Thor: The Dark World,2,Warning,sap-icon://wrench,Release date,"November 8, 2013",Director,Alan Taylor
11,8,10,Captain America: The Winter Soldier,2,Success,sap-icon://unfavorite,Release date,"April 4, 2014",Director,Anthony & Joe Russo
12,9,12,Doctor Strange,3,Error,sap-icon://activate,Release date,"November 4, 2016",Director,Scott Derrickson
13,10,12,Avengers: Age of Ultron,2,Error,sap-icon://text-color,Release date,"May 1, 2015",Director,Joss Whedon
14,10,13,Avengers: Age of Ultron,2,Error,sap-icon://text-color,Release date,"May 1, 2015",Director,Joss Whedon
15,10,14,Avengers: Age of Ultron,2,Error,sap-icon://text-color,Release date,"May 1, 2015",Director,Joss Whedon
16,10,19,Avengers: Age of Ultron,2,Error,sap-icon://text-color,Release date,"May 1, 2015",Director,Joss Whedon
17,,,Ant-Man and the Wasp,3,Error,sap-icon://chain-link,Release date,"July 6, 2018",Director,Peyton Reed
18,12,20,Thor: Ragnarok,3,Warning,sap-icon://wrench,Release date,"November 3, 2017",Director,Taika Waititi
19,13,11,Ant-Man,2,Error,sap-icon://chain-link,Release date,"July 17, 2015",Director,Peyton Reed
20,13,14,Ant-Man,2,Error,sap-icon://chain-link,Release date,"July 17, 2015",Director,Peyton Reed
21,14,16,Captain America: Civil War,3,Success,sap-icon://unfavorite,Release date,"May 6, 2016",Director,Anthony & Joe Russo
22,14,17,Captain America: Civil War,3,Success,sap-icon://unfavorite,Release date,"May 6, 2016",Director,Anthony & Joe Russo
23,15,18,Guardians of the Galaxy,2,Error,sap-icon://shield,Release date,"August 1, 2014",Director,James Gunn
24,16,20,Spider-Man: Homecoming,3,Error,sap-icon://tree,Release date,"July 7, 2017",Director,Jon Watts
25,17,20,Black Panther,3,Error,sap-icon://circle-task-2,Release date,"February 16, 2018",Director,Ryan Coogler
26,18,20,Guardians of the Galaxy Vol. 2,3,Error,sap-icon://shield,Release date,"May 5, 2017",Director,James Gunn
27,,,Avengers 4,3,Error,sap-icon://text-color,Release date,"May 3, 2019",Director,Anthony & Joe Russo
28,20,19,Avengers: Infinity War,3,Error,sap-icon://text-color,Release date,"April 27, 2018",Director,Anthony & Joe Russo

Expose the Data

Write an R script with Plumber library to expose the data as an REST API, so we can call it from the SAC custom widget app.

suppressMessages(library(plumber))
suppressMessages(library(dplyr))
suppressMessages(library(tidyr))
suppressMessages(library(sqldf))
suppressMessages(library(rlist))

#' @filter cors
cors <- function(req, res) {
  res$setHeader("Access-Control-Allow-Origin", "*")
  if (req$REQUEST_METHOD == "OPTIONS") {
    res$setHeader("Access-Control-Allow-Methods","*")
    res$setHeader("Access-Control-Allow-Headers", req$HTTP_ACCESS_CONTROL_REQUEST_HEADERS)
    res$status <- 200
    return(list())
  } else {
    plumber::forward()
  }
}

#* @param df data frame of variables
#* @get /hierarchy
#* @serializer unboxedJSON
function() {
  tryCatch({
    
    data <- read.csv("data.csv")
    dataset <- sqldf("SELECT * FROM data")
    totalrow = nrow(dataset)
    print(totalrow)
    
    node <- list()
    line <- list()
    group <- list()
    
    count_node <-1
    count <- 1
    
    # Getting nodes
    for(REC in 1:totalrow) {
      KEY <- dataset[REC,"KEY"]
      FROM <- dataset[REC,"FROM"]
      TO <- dataset[REC,"TO"]
      TITLE <- dataset[REC,"TITLE"]
      GROUP <- dataset[REC, "GROUP"]
      STATUS <- dataset[REC, "STATUS"]
      ICON <- dataset[REC, "ICON"]
      LABEL0 <- dataset[REC, "LABEL0"]
      VALUE0 <- dataset[REC, "VALUE0"]
      LABEL1 <- dataset[REC, "LABEL1"]
      VALUE1 <- dataset[REC, "VALUE1"]
      
      # Get attributes
      attr1 <- list()
      attr1 <- c(attr1, label=LABEL0)
      attr1 <- c(attr1, value=VALUE0)
      
      attr2 <- list()
      attr2 <- c(attr2, label=LABEL1)
      attr2 <- c(attr2, value=VALUE1)
      
      attrF <- list()
      attrF <- c(attrF, list(attr1))
      attrF <- c(attrF, list(attr2))     
      
      data <- list()
      data <- c(data, key=count_node-1)
      data <- c(data, title=TITLE)
      data <- c(data, group=GROUP)
      data <- c(data, status=STATUS)
      data <- c(data, icon=ICON)
      data <- c(data, attributes=list(attrF))

      if(REC > 1) {
        x <- list.find(node, title==TITLE, 1)
        
        if(length(x) == 0 ) {
          node[count_node] <- list(data)
          count_node <- count_node + 1
        }
      } else {
        node[count_node] <- list(data)
        count_node <- count_node + 1
      }
      
      # Get lines
      if(!is.na(FROM)) {
        data_line <- list()
        data_line <- c(data_line, from=FROM)
        data_line <- c(data_line, to=TO)
        line[count] <- list(data_line)
        count <- count + 1
      }
    }
    
    #group
    group1 <- list()
    group1 <- c(group1, key=1)
    group1 <- c(group1, title="Phase One")
    group1 <- list(group1)
    
    group2 <- list()
    group2 <- c(group2, key=2)
    group2 <- c(group2, title="Phase Two")
    group2 <- list(group2)
    
    group3 <- list()
    group3 <- c(group3, key=3)
    group3 <- c(group3, title="Phase Three")
    group3 <- list(group3)
    
    group <- list()
    group <- c(group, group1)
    group <- c(group, group2)
    group <- c(group, group3)
    
    # Getting final result
    dataF <- list()
    dataF <- c(dataF, nodes=list(node))
    dataF <- c(dataF, lines=list(line))
    dataF <- c(dataF, groups=list(group))
    
    list(dataF)
  }, error = function(err){
    print(err)
    list(err)
  })
}

Let’s execute the script to get the result.

SAC Analytic App Custom Widget

Finally, we’ll create a custom widget with SAPUI5 library sap.ui.core.mvc.XMLView andĀ  sap.suite.ui.commons.networkgraph.Graph. For more detailed steps how to create, you can refer to the blog in the “Reference” section.

On onInit() function, we execute the Ajax “GET” to request the data from the REST API.

onInit: function() {
    var this_ = this;

    if (that._firstConnection === 0) {

        that._firstConnection = 1;

        $.ajax({
            url: 'http://127.0.0.1:8856/hierarchy', //R Plumber REST API URL
            type: 'GET',
            async: true,
            timeout: 0,
            contentType: 'application/json',
            success: function(data) {
                var oGraph,
                    oModel = new JSONModel(data[0]);
                oModel.setSizeLimit(Number.MAX_SAFE_INTEGER);

                this_.getView().setModel(oModel, that.widgetName);

                this_.oModelSettings = new JSONModel({
                    maxIterations: 200,
                    maxTime: 500,
                    initialTemperature: 200,
                    coolDownStep: 1
                });
                this_.getView().setModel(this_.oModelSettings, "settings");

                this_.oGraph = this_.byId("graph_" + widgetName);
                this_.oGraph._fZoomLevel = 0.75;
            },
            error: function(e) {
                console.log("error: " + e);
                console.log(e);
            }
        });
    }
}

Create an Analytic app, load the widget and run it. You should see the output as shown below.

 

References

 

 

 

 

 

1 Comment
You must be Logged on to comment or reply to a post.
  • Thank you so much for sharing this information with us about network cloud infrastructure ,

    Network Graph Visualization in SAP Analytics Cloud Analytic App

    Thanks for this step by step information , i will definetly recommend to my friends also

    so they can lean something , like if you start a series Network Graph VisualizationĀ  PupilPath Login