Need Help in Graph Visualization

Hi team,

@Jon_Herke

We were actually researching on graph and we came across something interesting. If you see [link], you will see a graph. We downloaded its json file (screenshot attached) and we could see that data is being provided which assigns the relationship.

However, so far we haven’t been able to identify if Tigergraph Captures relationships between nodes and edges in json. For every query output, it just gives the output of nodes after running the query.

Can you please guide us through if we are missing something.
Capture

Hi,

Blockquote so far we haven’t been able to identify if Tigergraph Captures relationships between nodes and edges in json

Just to clarify, are you talking about loading data into TigerGraph via a JSON file? I am not sure if it is supported right now. If it is not supported and if the JSON file is small enough, you can turn it into a CSV file using Pandas or some CSV library.

Blockquote For every query output, it just gives the output of nodes after running the query.

If you would like the edges to also show up, you can maintain a SetAccum and print it out at the end of the query body, like so:
Screen Shot 2020-08-20 at 12.04.07 PM

In the above example, I am using all the vertices of type MST_C7 and traversing across the edge MST_C7_HAS_EDGE. By printing out the SetAccum @@edges, the graph studio ui display showed the edges between nodes as well.

By the way, the [link] is not working for me. Not sure if its working for others or not.

Just to verify @Urvashi, you have JSON data that is already “graph-like” and you want to insert this data into TigerGraph. Is that correct?

@Jon_Herke @Ramki_Pitchala

Thanks for response. The json which we are talking about is the json which we get after running query in Tigergraph Studio. So we are basically trying to consume the rest API of Tigergraph and create different visualizations. Below is the query I am executing in GraphStudio, so it is giving only nodes. I want to print the associated Edges as well.

For example, here Client is related to CAG node and Contract Node. While executing below query, I can at max print edge of how Client is related to CAG as per suggestion of (@Ramki_Pitchala), but if I want to show the relationship between Client and Contract, CAG and Contract, I cannot do that (I am attaching the snapshot of data model).

Also, the link I pasted earlier is here https://observablehq.com/@d3/disjoint-force-directed-graph?collection=@d3/d3-force

CREATE QUERY Active_Inactive_CAG(String Client_name,String Active_Inactive) FOR GRAPH CAG_Contract_Graph{
#Begin by initializing the set of all contracts
pp = {CAG.*};
#Get the number of specific type of CAG for a given client
speific_CAGs = SELECT p FROM pp:p WHERE pp.Search_Company == Client_name and pp.Active_or_InActive == Active_Inactive;
PRINT speific_CAGs;
}

If I understand you, then you need to query the edges you want into a structure and print it. Edges are not automatically added to the result set, you need to specifically query them.

In your case, I’m assuming you have a vertices for Contracts, so you’ll need to create queries for each of the edges you want and put them into accumulators. Then print the accumulators at the end.

If I’ve misunderstood then let me know!

@Urvashi
Ok - I understand. You can use a ListAccum of EDGES:

Visualization Example That’s Using TigerGraph:

Sample Query:

CREATE QUERY GrabEdge(STRING x) FOR GRAPH MyGraph { 
  /*  
	Sample Pub = 10.3201/eid1406.071467
	*/ 
	ListAccum<EDGE> @@edgeList;
	seed = {PUBLICATION.*};
	S1 = SELECT s
	     FROM seed:s -(PUB_HAS_AUTHOR:e) -:tgt
	     WHERE s.id == x
       ACCUM @@edgeList += e;
	
	PRINT  @@edgeList;
}

Blog Walkthrough:
https://towardsdatascience.com/designing-a-3d-healthcare-network-graph-291e4f75e9a5

Hi everyone.

Thanks for your response.

@Jon_Herke

I have 2 more questions on this.

  1. How do we handle case senstivity in Tigergraph. When I am searching for a client name say “Hertz”, I get the query result only when its mentioned exactly as “Hertz” and doesnt give any output when its “hertz”. How do we handle it?

  2. When we are printing the edges of certain vertices, how can we get the data of other associated vertex. For instance, in my case the relation is “CAG -associated_to-Contract”.
    Hence I am able to print “CAG” nodes and edges “associated_to” through below query and get json of the same, however, I am unable to get json of “Contract” vertex.
    I am attaching the data schema so that you can understand the query.


    Is there any way to achieve that? Below is the query

CREATE QUERY Active_Inactive_CAG_edge(String Client_name,String Active_Inactive) FOR GRAPH CAG_Contract_Graph{
#Begin by initializing the set of all contracts
SetAccum @@edges;
pp = {CAG.*};
#Get the number of specific type of CAG for a given client
pp = select s from pp: s - (associated_to:e) → :t
ACCUM @@edges += e;
speific_CAGs = SELECT p FROM pp:p WHERE pp.Search_Company == Client_name and pp.Active_or_InActive == Active_Inactive;
PRINT @@edges;
PRINT speific_CAGs;
}

@Jon_Herke can you please assist on above query?

  1. How do we handle case senstivity in Tigergraph. When I am searching for a client name say “Hertz”, I get the query result only when its mentioned exactly as “Hertz” and doesnt give any output when its “hertz”. How do we handle it?

TigerGraph will literally pass an exact string as your input. To customize to handle case-sensitivity you will want to create a C++ User Defined Function.

Simple google search for C++ sensitivity:
http://www.cplusplus.com/forum/beginner/198272/

  1. When we are printing the edges of certain vertices, how can we get the data of other associated vertex. For instance, in my case the relation is “CAG -associated_to-Contract”.
    Hence I am able to print “CAG” nodes and edges “associated_to” through below query and get json of the same, however, I am unable to get json of “Contract” vertex.
    I am attaching the data schema so that you can understand the query.

Are you looking for something like this? It starts at merchant than returns the edge and the target vertex (bank)

CREATE QUERY userAccount(/* Parameters here */) FOR GRAPH MyGraph { 
  
	ListAccum<EDGE> @@myEdge;
	
	seed = {merchant_account.*};
	
	S1 = SELECT tgt FROM seed:s -(:e)-bank:tgt ACCUM @@myEdge += e;
  PRINT S1, @@myEdge; 
}

@Urvashi try PRINT @@edges, pp;

You can accumulate the target vertices of the edges in the query where you get your edges:

So:

SetAccum <EDGE> @@edges;
SetAccum<Contract> @@my_contracts;

pp = {CAG.*};
#Get the number of specific type of CAG for a given client
pp = select s from pp: s - (associated_to:e) -> :t
ACCUM 
@@edges += e,
@@my_contracts;

PRINT @@edges, @@my_contracts;

Or you can select the targets directly:

tt = select t from pp: s - (associated_to:e) -> :t
    ACCUM 
    @@edges += e;


PRINT @@edges, tt;

Thanks @Jon_Herke I will try this.

One more thing, is there any way that we can specify an argument to be optional. For instance, in attached screenshot you can see that I have specified an arugument i.e. “Type_of_Contract” and when I give it value = “BASE” or “Amendment” it gives me specific nodes.

But when I dont give any data in this argumen, it doesn’t give any output. Is there any way that if I dont give any data in “Type_of_Contract”, it gives me the results specific to value I place in “Client_name” i.e. the idea is I want to make “Type_of_Contract” field optional. If I dont give it any value, it gives me entire data. Can we achieve this by making some changes in query or how do u suggest?

There are a couple of ways. One is to compose the WHERE clauses as a string, and use the eval() function.

Another is to add conditional logic to the WHERE clause e.g.

WHERE
Type_Of_Contract = “” OR pp.Contract_Type == Type_Of_Contract

thanks @Richard_Henderson

I was trying to insert 2 accumulators in a single query. Where am I getting wrong here?

Also, can you suggest me how we can handle case-sensitivity in gsql?

Thanks @Jon_Herke

Can you please suggest is there any other language other than C++ which can be used to handle case-sensitivity in Tigergraph data. Can we do that in GSQL using any function?

Also, if we have to use C++, can you please suggest how exactly do we integrate C++ code into Tigergraph. How is that User defined function deployed into Tigergraph?

@RavindraNitwal for visibility.

Thanks
Urvashi

1 Like

@Urvashi @RavindraNitwal
Users can define their own expression functions in C++ in <tigergraph.root.dir>/dev/gdk/gsql/src/QueryUdf/ExprFunctions.hpp. Only bool, int, float, double, and string (NOT std::string) are allowed as the return value type and the function argument type. However, any C++ type is allowed inside a function body. Once defined, the new functions will be added into GSQL automatically next time GSQL is executed.

If a user-defined struct or a helper function needs to be defined, define it in <tigergraph.root.dir>/dev/gdk/gsql/src/QueryUdf/ExprUtil.hpp.

STEP 1) Add – new code in ExprFunction.hpp

#include <algorithm>  // for std::reverse
inline bool greater_than_three (double x) {
  return x > 3;
}
inline string reverse(string str){
  std::reverse(str.begin(), str.end());
  return str;
}

STEP 2) Call – user defined expression function

CREATE QUERY udfExample() FOR GRAPH minimalNet {
  DOUBLE x;
  BOOL y;

  x = 3.5;
  PRINT greater_than_three(x);
  y = greater_than_three(2.5);
  PRINT y;

  PRINT reverse("abc");
}

STEP 3) Execute – udfExample.json Results

GSQL > RUN QUERY udfExample()
{
  "error": false,
  "message": "",
  "version": {
    "edition": "developer",
    "schema": 0,
    "api": "v2"
  },
  "results": [
    {"greater_than_three(x)": true},
    {"y": false},
    {"reverse(abc)": "cba"}
  ]
}

If any code in ExprFunctions.hpp or ExprUtil.hpp causes a compilation error, GSQL cannot install any GSQL query, even if the GSQL query doesn’t call any user-defined function. Therefore, please test each new user-defined expression function after adding it. One way of testing the function is creating a new cpp file test.cpp and compiling it by
g++ test.cpp
./a.out
You might need to remove the include header #include <gle/engine/cpplib/headers.hpp> in ExprFunction.hpp and ExprUtil.hpp in order to compile.

For Testing test.cpp

#include "ExprFunctions.hpp"
#include <iostream>
int main () {
  std::cout << to_string (123) << std::endl;    // to_string and str_to_int are two built-in functions in ExprFunction.hpp
  std::cout << str_to_int ("123") << std::endl;
  return 0;
}