PeWu / topola

Topola – online genealogy visualization
Apache License 2.0
95 stars 28 forks source link

Whole family chart #1

Closed dddpt closed 5 years ago

dddpt commented 6 years ago

Hello PeWu!

I had a look at your library and website and it's a neat piece of software. My job is to build a web-app allowing one to build his family tree for close kins, allowing to show, in addition to grand-parents or grand-children, other relatives up to cousins or the spouse's parents. This would be an extension of the hourglass chart as defined in topola. I'd call it "Whole family chart"

Of course, with uncle and cousins, the layout becomes non-trivial, we're no longer in subset of a d3-tree/flextree layout. Do you have any plans of implementing such a layout? Or any idea of how to proceed? I was thinking to play with d3-force to do the job.

I'd be happy to contribute to topola. The web-app will include an UI to manually add nodes to the tree, that'll definitely be relevant to topola., tell me if you're interested ;-)

PeWu commented 6 years ago

Hi,

Creating an "whole family chart" is one of my goals but not the highest priority right now.

I once authored a report for the GenealogyJ app that draws an all-in-one chart (see here). A similar method can be used with d3 by composing flextree multiple times. If you're interested, I can explain in more detail.

You can try d3-force but my intuition is that it will give you unpredictable results that are difficult to interpret. Maybe you could tweak the algorithm to make it look good.

If you'd like to contribute, I'd be happy to help. Let me know what you'd like to do. Being able to dynamically change the family tree is one of the things I wanted this library to provide. My motivation is the ability to "browse" the family tree by expanding branches but modification is also a good use case.

Cheers, Przemek

dddpt commented 6 years ago

I'd be really interested in your idea on how to do it with nested flextrees.

Well, I'd be happy to contribute with a whole family chart and growing the tree. I am unfamiliar with both browserify and typescript, that'd be the challenge for me.

Another question I have the impression topola is not very "d3-y" in the interface it's exposing. You give topola the id of the svg you want to draw to, a renderer and a few options and topola does the rest. What would you think of letting topola expose more of the middle-steps? For example, I would love to get nodes positioning and links traces in a d3-like grammar: for example calling topola.ancestorChart(myParsedGedCom) and get back an array of d3-like datums with positions and content, as you would to draw a d3-flextree. What would you say of that?

PeWu commented 6 years ago

I'll try to describe how the algorithm in the GenealogyJ all-in-one report works.

I created a GEDCOM file with random names (zipped in family.zip).

Here is the output of the all-in-one report: family

Here is a breakdown of parts of the layout: all-in-one layout

1, 2, 3, 4 are parts that are laid out similarly to d3-flextree. V, X, Y, Z are all ancestors of the main couple (Bonifacy Gibbs and Jarmila Valenta) A, B, C, D, E, F is a custom recursive layout, which is created like this: all-in-one description

This works fine for showing all blood relatives of a couple. Nonetheless, this layout could be improved. See that A and B could be drawn side by side. Also, D and E could be drawn side by side. Maybe d3-flextree could be used to lay out ancestors with their descendants, i.e. treat the following set as nodes: {A, B, (V+2), (X+3), (Y+4), Z}. However, I don't know yet how to make the links always be drawable.

(I'll answer about d3-ifying the API in a separate post later)

dddpt commented 6 years ago

I see, nice&simple alglorithm to ensure you get it working for any family tree. However, as you note I find it a bit confusing to have generations not stick to the same y-coordinates. Having one color per generation allows to partly alleviate that but I don't find it totally satisfactory...

I try with d3-force/other and I come back to you if I find something interesting ;-)

PeWu commented 6 years ago

Regarding the d3 interface, my intention was to keep d3 as an implementation detail when trying to do something simple. Nonetheless, I don't see any objections to exposing a lower-level d3-compatible interface. Do you have a specific example where you would use the d3-like API?

dddpt commented 6 years ago

A good example is the d3ize() function of the parse-gedcom package. It gives you nodes and links that are d3 compatible, from there it is easy to create a force graph as shown in parse-gedcom's live example: https://tmcw.github.io/parse-gedcom/live/

In this setting, the api to get an hourglass chart nodes' and links' positionning would look something like:

var rootNodeId = "@I500005@"
var d3izedGedcom = parse.d3ize(parsedGedcom)
var graph = topola.hourglassChart()
    .nodeRenderer(myNodeRenderer) // to get each node's box size, defaults to the default topola nodeRenderer 
    .root(rootNodeId)
    .gedcom(d3izedGedcom)

graph then has one nodes and one links properties (both arrays as for d3ize()). nodes have x and y coordinates (plus maybe some other rendering properties). links have x1,y1,x2,y2 coordinates.

With that in hand, any programmer can use either use the default topola rendering tools or adapt the drawing as he wishes with the d3 grammar he's used to. It was straightforward for me to tinker with parse-gedcom live example to test my ideas on how to layout a family-tree with forces.

Btw, I think I found an interesting way to hack a not-to-messy layout, more info soon ;-)

dddpt commented 6 years ago

I just uploaded my attempt at whole-family's-chart with d3-force here: https://github.com/tartakower/jsftree If you wanna try, ftree-d3-force.html & ftree-d3-force.js are the good place to toy with the layout.

The idea is to find an horizontal ordering of nodes (that minimizes line-crossings) for each generation, give each generation a fixed depth (=y position), set nodes' initial x-positions according to their ordering, and then let d3-force improve the x-positions.

There are still 2 issues at the moment: 1) my algorithm for the horizontal ordering in _computeNodesRowOrder() still creates avoidable crossings in a few cases. 2) parameters for d3-force must be chosen carefully. The ones I chose in applyForces() are good for small trees, but not large ones. With large trees, d3-force risks messing up the horizontal ordering as forces are too powerful. Hence, parameters in applyForces() must be adapted for larger trees.

In any case, it's already sufficient for my use-case as my trees shouldn't be too big. At the moment, I switch to adding nodes to the family tree. I might improve the layout later on.

Comments/ideas welcome ;-)

PeWu commented 6 years ago

I took a look at your solution. It does a good job for not very complicated families. However, have a look at the output for the GEDCOM I posted above (zipped in family.zip). You can use it as a benchmark to improve your algorithm – the family graph is quite simple but it is not trivial to find a good layout. In my own genealogy data I have several types of cycles which are the most difficult to handle :-)

PeWu commented 5 years ago

I added a "Relatives Chart". Below is the layout produced for the sample data mentioned above. image