How would one create collapsable force nodes when the data isn't a tree?

1,376 views
Skip to first unread message

DerNalia

unread,
Jul 6, 2012, 7:27:51 PM7/6/12
to d3...@googlegroups.com
In this example: http://bl.ocks.org/1062288
a data tree is used to make collapsable subtrees. The example is pretty clear for that specific situation.

But what if the data isn't a tree? and certain nodes down in the hierarchy branch over to other subtrees?

Here is how I "think" it would have to work:
nodes = [ object_0, object_1 ]
links = [
 {"source": 0, "target": 1}
]
^ just how I might format my data. 
currently (in the code posted later in this post), I do something like in this example: http://bl.ocks.org/1153292 and let d3 create the the nodes for me
regardless, the next step is the same:

on node/circle click:
   - find all links where the clicked node/circle is the source
     - recursively hide all these nodes and links (somehow) unless the node is part of another subtree (in my case, another super genre / blue cicle) 
   - somehow unhind them when the super tree / genre is clicked again

I tried to implement part of this example. Here: http://jsfiddle.net/DerNalia/6R93M/
currently, when I click a node, all of the nodes are copied and the old ones are still there.
I've included some thoughts on my data structures (the way I'm doing the links and nodes), and may change them.

Any comments / suggestions / tips are welcome. I'll be updating this example as I figure things out (re: collapsableness)

DerNalia

unread,
Jul 7, 2012, 2:49:25 AM7/7/12
to d3...@googlegroups.com

changes:  
- nodes json now include a .data attribute which has all the track / artist info that was previously being stored in a third json structure.
- links json is now the indices of the nodes in the nodes structure.

hopefully, this more traditional way of storing data for d3 will make my goal easier. I have no idea yet.

Ger Hobbelt

unread,
Jul 8, 2012, 1:40:14 PM7/8/12
to d3...@googlegroups.com
See http://bl.ocks.org/3071239 for an example of a graph+behaviour similar to yours; the code is derived from the D3.js example force_cluster (by giving it the behaviour of the force_collapsible example (which is identical to gist http://bl.ocks.org/1062288 ) and a few tweaks & tugs to make it look nice.

The key is always to have some function (here, it's called 'network()') which produces the nodes[] and links[] arrays for the force layout; whenever something changes (e.g. due to a user clicking on a node and us wishing to implement a collapse or expand ~ a nodeset change then), you need to regenerate the nodes[] and links[] arrays.

All the layout.force examples have in common that the nodes[] elements are always references to the original nodes as loaded via JSON/CSV/whathaveyou, so that layout.force.init() and friends writing any .x, .y, .size, .source, .target or other object attribute into those nodes will implicitly store those values in the loaded 'orginal' json/csv/whatever data tree. Consequently, throwing way a nodes[][ and/or links[] array and generating new ones from the original data set at any time doesn't hurt your existing visual layout (which uses those layout.force calculated .x/.y/etc.), as the .x/.y/etc. are again available in the new nodes[]/links[] arrays.

The easiest way is to mimic this approach, so basically you'll then have a few object attributes which are sorta 'reserved' for layout.force use/alteration. (Pro Tip: You can of course do a 'pre-layout' by providing .x and .y values in your server-provided node set: layout.force will then go and start with those instead of randomly positioning the nodes.)


Met vriendelijke groeten / Best regards,

Ger Hobbelt

--------------------------------------------------
web:    http://www.hobbelt.com/
        http://www.hebbut.net/
mail:   g...@hobbelt.com
mobile: +31-6-11 120 978
--------------------------------------------------

DerNalia

unread,
Jul 8, 2012, 8:23:30 PM7/8/12
to d3...@googlegroups.com
thanks, this is immensely helpful, in a couple of ways, cause I wanted to do that color grouping, too (though differently - grouping nodes together by category).

thanks!

Frank Guerino

unread,
Jul 8, 2012, 11:21:55 PM7/8/12
to d3...@googlegroups.com
Hello Ger,

This is very impressive.  Question:  Does this (or any other Force Layout you're aware of) handle multiple relationships between any two nodes or multiple circular relationships between one node?

Thanks,

Frank

DerNalia

unread,
Jul 10, 2012, 9:18:53 PM7/10/12
to d3...@googlegroups.com
I'm having trouble understanding the code with the groups / hulls. If you could help, that would be great.

I've forced group / cluster "1" to always be visible (in the network() function), but I'm having issues with getting that node to render. 

DerNalia

unread,
Jul 10, 2012, 10:03:33 PM7/10/12
to d3...@googlegroups.com
I've added text so it's easier to see what nodes are missing. http://jsfiddle.net/DerNalia/GAkvW/9/
(the nodes defined first in the data object are the ones without groups. 

DerNalia

unread,
Jul 10, 2012, 10:34:31 PM7/10/12
to d3...@googlegroups.com
Ok, so, I've gotten the not-grouped nodes visible again. http://jsfiddle.net/DerNalia/GAkvW/10/

Now, I need to make nodes without a group not be bound to a hull.

I'm hoping this ends up helping someone in the future.

DerNalia

unread,
Jul 10, 2012, 11:19:10 PM7/10/12
to d3...@googlegroups.com
Finished what I was kind of trying to do http://jsfiddle.net/DerNalia/GAkvW/14/
- Now, hulls are always open (for category visualization)
- Nodes without a group / hull are rendered.

Hope this helps.

Frank Guerino

unread,
Jul 10, 2012, 11:34:26 PM7/10/12
to d3...@googlegroups.com
Hi,

May I please ask:

1) How are you dealing with multiple relationships between two nodes?

and

2) How are you dealing with multiple circular relationships between a single node?

At a glance, I don't see anything in your code that attempts to address either?  Am I just missing it?

Thanks,

Frank

DerNalia

unread,
Jul 11, 2012, 1:49:28 AM7/11/12
to d3...@googlegroups.com
1) How are you dealing with multiple relationships between two nodes?
Do you mean A -> B and B -> A? 
I'm not, I'm just drawing straight lines, so if A-> and B->A were a couple of links, the lines would just be drawn on top of eachother.
but there is an example here http://bl.ocks.org/1153292 of how to do directionality.

2) How are you dealing with multiple circular relationships between a single node?
I plan to just not render a line. I'll post updated code here, once I clean up and humanify the mess I've been working on.

Frank Guerino

unread,
Jul 11, 2012, 1:20:45 PM7/11/12
to d3...@googlegroups.com
Hi,

For multiple relationships/dependencies between "two" nodes, you can have things like this...

Peter is Son of John [source: "Peter", relationship: "is Son of", target: "John"]
John is Father of Peter [source: "John", relationship: "is Father of", target: "Peter"]
Peter is a Legal Dependent of John [source: "Peter", relationship: "is a Legal Dependent of", target: "John"]
Peter Lives With John [source: "Peter", relationship: "Lives With", target: "John"]

For circular relationships/dependences between "one" node, you can have things like this...

John Supplies Sustenance For John [source: "John", relationship: "Supplies Sustenance For", target: "John"]
John Supplies Income For John [source: "John", relationship: "Supplies Income For", target: "John"]
John is Employed by John [source: "John", relationship: "is Employed by", target: "John"]

I know the circular relationships are uncommon in most applications but they become very common in things like Software Development, between Software Configuration Items.

Anyhow, I hope this helps clarify.

My Best,

Frank

DerNalia

unread,
Jul 11, 2012, 4:56:54 PM7/11/12
to d3...@googlegroups.com
I see, so I think it would be achieved the same way as in the Directed Graph example, except, you'd probably want to put a class on the connection between your nodes so you can render them differently.
Personally, I would use different amounts of Arch for each line... unless there is n-number of lines, then things get complicated.
 - You'd probably want to, upon connection processing, determine what number connection it is, 1 for first, 2 for second, etc, and then use those numbers as  multiplier for the arch of the line. 

Hope this helps.

Frank Guerino

unread,
Jul 13, 2012, 7:11:50 AM7/13/12
to d3...@googlegroups.com
Yes, there is always the case of "n" lines, which yields the complexity of having to dynamically calculate new and different arcs with every new relationship between any two nodes, even if the source and target nodes are the same node.

Yes, I agree that the approach is probably, at a minimum, to keep track of each relationship/connection.  It seems like the only logical way to calculate new and different dynamic arcs.

My Best,

Frank

Ger Hobbelt

unread,
Jul 14, 2012, 1:34:33 PM7/14/12
to d3...@googlegroups.com
Sorry, I was for the duration due to a heavy fever. Climbing up through the remainder of that, I might have something interesting, but that's for another mail.

In answer to your question: no, all (force-like) layouts that I know of in D3 itself assume single relationships, in that they all expect one A->B link, not many.

When you dive into the gory details, then you'll note that at least d3.layout.force _does_ accept a link array where multiple entries are A->B links, but all of them will be treated equal, so it's rather useless, unless you have some very specific thing in mind with those links later on. (And then why not bundle their 'features' into a single link fed to the force.links() call, eh?)


Taking off from there:

I the last several weeks I've been trying a couple of different things to get me to render a force layout with multiple, visually separated, A->B links (and not just the arc hacks you see in the Apple,etc. law suit example!) and apparently I need a bit of a fever to spark an idea that works - http://bl.ocks.org/3104394 (breaks! Mike's been notified) == gist https://gist.github.com/3104394


Met vriendelijke groeten / Best regards,

Ger Hobbelt

--------------------------------------------------
web:    http://www.hobbelt.com/
        http://www.hebbut.net/
mail:   g...@hobbelt.com
mobile: +31-6-11 120 978
--------------------------------------------------



QB

unread,
Nov 4, 2020, 7:17:28 AM11/4/20
to d3-js
Hi Ger and all,

In your last implementation, I tried to visualize the direction of the edges and show the node's label without success. I tried to look at DerNalia implementation too, but I'm still not able to show the labels and direction in Ger's implementation. I don't have much experience with javascript, so I can you help me with the direction of the edges and the nodes' labels?

Thank you so much

Reply all
Reply to author
Forward
0 new messages