0

I have to draw a graph by d3js. To represent a graph I use the adjacent list data structure. Every item in the adjacent list is the destination vertex of the edge (the source vertex is the vertex itself).

According to this representation, my data is:

data = [
        { id: 1, pos: [10, 50], adj: [
                       {id: 2, pos: [30, 60]},
                       {id: 3, pos: [20, 30]}
                               ]
        },
        { id: 2, pos: [30, 60], adj: [{id: 1, pos: [10, 50]}]},
        { id: 3, pos: [20, 30], adj: [{id: 1, pos: [10, 50]}]}
       ]

How can I draw this graph?

I tried this but it doesn't work

    var vertex = svg.selectAll("g").data(graph.vertices, function (d) { 
        return d.id; });

    // NEW
    vertex.enter().append("g")
    .attr("class", function(d) { return d.id });

    var edges = vertex.selectAll("line")
    .data(function(d) { return d.adj }, function(d,i) { 
        console.log(d); return d; });

    // UPDATE
    edges.classed("selected", function(d) { return d === selected; })
    .attr("x0", function(d) { 
        return d.pos[0]; })
    .attr("y1", function(d) { return d.pos[1]; })
    .attr("x1", function(d,i) { 
        return d.adj[i][0]; })
    .attr("y1", function(d,i) { return d.adj[i][1]; });

    // NEW
    edges.enter().append("line")
    .filter(function(d,i) { 
        return d.id < d.adj[i].id })
    .attr("class", "line")
    .attr("x0", function(d) { return d.pos[0]; })
    .attr("y0", function(d) { return d.pos[1]; })
    .attr("x1", function(d,i) { return d.adj[i].pos[0]; })
    .attr("y1", function(d,i) { return d.adj[i].pos[1]; });

    // OLD
    vertex.exit().remove();

P.S : I can't use the force layout.

6
  • 1
    You haven't specified what your adjacency list specifies, but you can do this somewhat clumsily with nested selections: jsfiddle.net/MR7sV Commented Feb 24, 2014 at 13:37
  • @LarsKotthoff I edited my question according to your comment Commented Feb 24, 2014 at 15:13
  • 1
    In that case it's even easier: jsfiddle.net/MR7sV/1 Commented Feb 24, 2014 at 15:19
  • Am I obligated to group the lines in a group? Commented Feb 24, 2014 at 15:50
  • It makes it easier with the data structure you have. But no, you're not in general. Commented Feb 24, 2014 at 15:54

1 Answer 1

1

You can do this by using nested selections. For the nodes, you don't even need that:

var vertex = svg.selectAll("circle").data(data, function (d) { return d.id; });

vertex.enter().append("circle")
  .attr("class", function(d) { return d.id })
  .attr("r", 5)
  .style("fill", "black")
  .attr("cx", function(d) { return d.pos[0]; })
  .attr("cy", function(d) { return d.pos[1]; });

Then to add the links the nested selection:

svg.selectAll("g.lines").data(data)
  .enter().append("g")
  .selectAll("line")
  .data(function(d) { return d.adj; })
  .enter().append("line")
  .attr("x1", function(d, i, j) { return data[j].pos[0]; })
  .attr("y1", function(d, i, j) { return data[j].pos[1]; })
  .attr("x2", function(d, i, j) { return d.pos[0]; })
  .attr("y2", function(d, i, j) { return d.pos[1]; });

Complete example here.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.