Force directed graph: using node and link attributes

We’ve slowly been adding more functionality onto our graph. It’s not quite useable yet, but not far off.

Today’s topic: incorporating node attributes and link attributes into our graph.

It’ll really bring our graph to life!

Attributes Link to heading

When you specify data for nodes and links you can put in whatever fields you like.

Let’s look at an example.

Here’s some data. I’ve taken some of the characters from the fantastic online serial Twig and mapped out some relationships between them.

//Characters
var nodes_data =  [
    {"name": "Lillian", "sex": "F"},
    {"name": "Gordon", "sex": "M"},
    {"name": "Sylvester", "sex": "M"},
    {"name": "Mary", "sex": "F"},
    {"name": "Helen", "sex": "F"},
    {"name": "Jamie", "sex": "M"},
    {"name": "Jessie", "sex": "F"},
    {"name": "Ashton", "sex": "M"},
    {"name": "Duncan", "sex": "M"},
    {"name": "Evette", "sex": "F"},
    {"name": "Mauer", "sex": "M"},
    {"name": "Fray", "sex": "F"},
    {"name": "Duke", "sex": "M"},
    {"name": "Baron", "sex": "M"},
    {"name": "Infante", "sex": "M"},
    {"name": "Percy", "sex": "M"},
    {"name": "Cynthia", "sex": "F"}
]

//Relationships
//type: A for Ally, E for Enemy
var links_data = [
    {"source": "Sylvester", "target": "Gordon", "type":"A" },
    {"source": "Sylvester", "target": "Lillian", "type":"A" },
    {"source": "Sylvester", "target": "Mary", "type":"A"},
    {"source": "Sylvester", "target": "Jamie", "type":"A"},
    {"source": "Sylvester", "target": "Jessie", "type":"A"},
    {"source": "Sylvester", "target": "Helen", "type":"A"},
    {"source": "Helen", "target": "Gordon", "type":"A"},
    {"source": "Mary", "target": "Lillian", "type":"A"},
    {"source": "Ashton", "target": "Mary", "type":"A"},
    {"source": "Duncan", "target": "Jamie", "type":"A"},
    {"source": "Gordon", "target": "Jessie", "type":"A"},
    {"source": "Sylvester", "target": "Fray", "type":"E"},
    {"source": "Fray", "target": "Mauer", "type":"A"},
    {"source": "Fray", "target": "Cynthia", "type":"A"},
    {"source": "Fray", "target": "Percy", "type":"A"},
    {"source": "Percy", "target": "Cynthia", "type":"A"},
    {"source": "Infante", "target": "Duke", "type":"A"},
    {"source": "Duke", "target": "Gordon", "type":"A"},
    {"source": "Duke", "target": "Sylvester", "type":"A"},
    {"source": "Baron", "target": "Duke", "type":"A"},
    {"source": "Baron", "target": "Sylvester", "type":"E"},
    {"source": "Evette", "target": "Sylvester", "type":"E"},
    {"source": "Cynthia", "target": "Sylvester", "type":"E"},
    {"source": "Cynthia", "target": "Jamie", "type":"E"},
    {"source": "Mauer", "target": "Jessie", "type":"E"}
]

Nodes represent characters. Every node has a character name and their sex attached to it.

The relationships between characters are represented by links. Every link has a type of relationship: “A” for ally and “E” for enemy.

We’re going to create a graph that has male characters as blue circles and female characters as pink circles. Green links are ally connections and red links are enemy connections. It’s just like the picture above!

About time. I’m a bit sick of the red monochrome from the previous examples.

Let’s jazz it up!

Pretty colours Link to heading

Most of the code is the same as our previous examples. I’m not going to go through the bulk of it here.

Here’s the important bit.

Before now when we’ve appended circles to the svg element we’ve hardcoded the colour with something like .attr("fill","red").

Now we’re going to use a function that chooses the colour of the circle, depending on the attribute we pass into it.

Our function is called circleColour.

var node = svg.append("g")
        .attr("class", "nodes")
        .selectAll("circle")
        .data(nodes_data)
        .enter()
        .append("circle")
        .attr("r", 10)
        .attr("fill", circleColour);

Here it is:

//Function to choose what color circle we have
//Let's return blue for males and red for females
function circleColour(d){
	if(d.sex =="M"){
		return "blue";
	} else {
		return "pink";
	}
}

We pass in the node as a parameter d. We read the sex attribute (through using d.sex) and then return the appropriate colour.

It’s a similar story for the links.

Just define a function that takes in the link as a parameter and then returns whatever colour you like.

//draw lines for the links 
var link = svg.append("g")
      .attr("class", "links")
    .selectAll("line")
    .data(links_data)
    .enter().append("line")
      .attr("stroke-width", 2)
      .style("stroke", linkColour);

Here’s the function:

//Function to choose the line colour and thickness 
//If the link type is "A" return green 
//If the link type is "E" return red 
function linkColour(d){
	console.log(d);	
	if(d.type == "A"){
		return "green";
	} else {
		return "red";
	}
}

Keep in mind that you’re not limited to just mapping attributes to colours.  You could change the size of the circle, the outline thickness, the shape of the object, the thickness of the lines…there’s really no limit.

You can do anything you like with attributes.  How good’s your imagination?


Hope you found that useful! Click here to view to the rest of the force directed graph series.