0

As a beginner in d3.js, I've met a problem in network visualization. I was trying to fix it in many ways, but nothing works well unfortunately. So I really need an advice, would be happy if someone can help me. I'm getting an error in d3.v3.js:5624:

Uncaught TypeError: Cannot read property 'weight' of undefined

My json is generating in the controller and looks like this:

{ "nodes" : 
[{ "Name" : "One", "Weight" : 903 }, 
 { "Name" : "Two", "Weight" : 502 },
...
], 
"links" : 
[{ "Source" : "One", "Target" : "Two", "Volume" : 2 }, 
 { "Source" : "Two", "Target" : "Five", "Volume" : 1 }, 
...
]
}

So I'm calling

return Json(network, JsonRequestBehavior.AllowGet);

The class Network:

public class Network
        {
            public List<NetworkNodes> nodes {get; set;}
            public List<NetworkLinks> links{ get; set;}
            public Network(List<NetworkNodes> a, List<NetworkLinks> b)
            {
                nodes = a;
                links = b;
            }

        }

And script by itself:

$(document).ready(function () {

    var width = 1500,
        height = 1500;

    var force = d3.layout.force()
                .charge(-100)
                .linkDistance(30)
                .size([width, height]);

        var svg = d3.select("body").append("svg")
            .attr("width", width)
            .attr("height", height);

        $.getJSON('@Url.Action("BuildNetwork", "Query")', function (graph) {
        // Compute the distinct nodes from the links.
            force
                .nodes(graph.nodes)
                .links(graph.links)
                .start();

            var link = svg.selectAll(".link")
                .data(graph.links)
                .enter().append("line")
                .attr("class", "link")
                .style("stroke-width", function (d) { return Math.sqrt(d.Value); });

            var node = svg.selectAll(".node")
                .data(graph.nodes)
                .enter().append("circle")
                .attr("class", "node")
                .attr("r", 5)
                .call(force.drag);

            node.append("title")
                .text(function (d) { return d.Name; });

            force.on("tick", function () {
                link.attr("x1", function (d) { return d.Source.x; })
                    .attr("y1", function (d) { return d.Source.y; })
                    .attr("x2", function (d) { return d.Target.x; })
                    .attr("y2", function (d) { return d.Target.y; });

                node.attr("cx", function (d) { return d.x; })
                    .attr("cy", function (d) { return d.y; });
            });

         });
});

I know, there is some stupid mistake I have made, but I'm too stupid to understand where :(

tereško
  • 58,060
  • 25
  • 98
  • 150
  • what does `@Url.Action("BuildNetwork", "Query")` return? afaik, `$.getJSON` takes an URL to a file with the JSON... not sure if you can use it like that. Also, your error reports a `weight` value, where in your JSON, you have a `Weight` value... notice the case of the first letter... – Joum Aug 12 '13 at 11:02
  • Could it be that in the json Weight has a capital W but the error shown has a lowercase ? – BentOnCoding Aug 12 '13 at 11:23
  • I was trying all possible corrections, with "weight" as well. Unfortunately the problem is still here :( – Galina Bezobrazova Aug 12 '13 at 11:47

1 Answers1

0

The source and target properties of your link list should not point to node names, but rather to their position inside the array returned by force.nodes(). For example if "One" is linked to "Two" then (symbolically)

Nodes = ["One", "Two"]

and

Links = [{source: 0, target: 1}]

You can do a quick search on your node array to find the index of the node.

Also be careful with the Weight property of your node, some property names are reserved for D3 (see here)

Barnabé Monnot
  • 1,163
  • 1
  • 9
  • 19
  • thank you for the answer! But the point is that I've tried it already (I mean to change the fields with the "source" and "target" into integers with the nodes numbers), still the same problem occurs... Seems like a karma))) – Galina Bezobrazova Aug 12 '13 at 11:50
  • The field names should be in lowercase (`Target` -> `target` etc.). – MasterAM Aug 12 '13 at 11:55
  • It might not work but the source/target notation still has to reference the node index. As @MasterAM said you have to put it lowercase, in your `tick` function too. Don't forget to replace `weight` by something like `size`, but do not use `weight` in any case. – Barnabé Monnot Aug 12 '13 at 11:58
  • awww, works perfect now! Thank you! I'm so much relieved now :) – Galina Bezobrazova Aug 12 '13 at 12:02
  • 1
    You can also use "node mapping" (idea originally from [here](http://stackoverflow.com/a/14631808/268093)), see [this jsFiddle](http://jsfiddle.net/masteram/Kj4hE/) – MasterAM Aug 12 '13 at 12:07
  • That is great, very useful! I'll add it, thank you for your advices! But I guess I'm hopeless, labels with names of the nodes don't work :( – Galina Bezobrazova Aug 12 '13 at 12:20
  • [This](http://stackoverflow.com/questions/11102795/d3-node-labeling) should help you – Barnabé Monnot Aug 12 '13 at 12:22