mermaid-js / mermaid

Generation of diagrams like flowcharts or sequence diagrams from text in a similar manner as markdown
https://mermaid.js.org
MIT License
68.72k stars 6.07k forks source link

Feature request: Pedigree chart type #1589

Open craxal opened 3 years ago

craxal commented 3 years ago

I've used flowcharts to represent pedigrees/family lines, but I can never quite get the results I want. A pedigree chart type would be fantastic for something like this.

Sample syntax:

A[John Doe]
B[Jane Maidenname]

A + B
  C[Michael Doe]
  D[Mary Doe]
  E[Meridith Anne Doe]

F[Adam Emery] + D
  G[Nick Emery]

H[Bernard Frank] + I[Brittany Maidenname]
  J[Oscar Frank]

H + K[Brenda Secondmarriage]
 L[Jasmine Frank]

J + L
gergobalogh commented 3 years ago

Hey! I want to do something similar. Any news on this?

xijiang commented 1 year ago

second also.

piperdeck commented 1 year ago

I would use this

nirname commented 1 year ago

@craxal @piperdeck @xijiang @gergobalogh how do you think it should look like? Is it possible that it is just an enhancement of current diagram? Looking forward to hearing

piperdeck commented 1 year ago

I've made a mockup based on the sample syntax that @craxal provided. Co-parents are linked by a non-directed edge on the same tier when possible, while siblings are linked to their parents' shared edge by a directed branching tree, and also sit on the same tier as each other, but one tier lower than their parents.

And of course, the renderer will have to get creative as the chart gets complicated. As the user adds families with lots of children, and each of those childrens' spouses have families above them, the renderer will have to start drawing lines with more complex routing. For example, in this example chart, imagine if Adam Emery's parents were also in the chart. Would the renderer place Mary Doe on the end? Would it raise Mary's parents up higher and spread out her siblings to make room for Adam's family in the middle of all of it? I don't know.

mermaid-genealogy-sample

(I'm not sure if craxal meant to have Bernard Frank's own children of different parents marrying each other in their example syntax, but of course the diagram would need to be able to accommodate occurrences like this.)

craxal commented 1 year ago

@piperdeck You beat me to the mock up 😄. It is a very good example of what I envisioned.

I do realize certain situations get interesting:

It may be useful to consider options for limiting what's rendered. For example, it's common to be interested only in the ancestor and/or descendent lines of a single person, so you could make one node the "focus" and configure additionally to see only descendants or ancestors.

One thing to keep in mind is I don't think it's Mermaid's job to take just any data in and instantly produce a beautiful chart. The chart writer needs to be thoughtful and sculpt the data they're trying to display, or it's going to be a mess no matter how smart the data visualization tool is. The same would be true in the case of pedigrees. While there are certainly some odd situations even in small pedigrees, I think it's worth considering a set of simple rules to see how they handle those situations. For example, maybe the best way to show families where one or more spouses was married multiple times is to create separate charts for each pairing.

@nirname I tried doing something like this with existing chart types, but it was very difficult to get all the edges to line up properly. It's also difficult to tell from the text what I'm actually trying to represent. That's why I proposed this feature. I believe the whole point of Mermaid is to generate relatively clean charts from an equally clean textual representation. A pedigree chart type fits very well into this purpose and would be very useful, because (1) it would draw things more precisely than another chart type, and (2) allows for a much clearer textual representation of pedigree data.

jgreywolf commented 10 months ago

I am interested in this as well. Would save me alot of time playing around in Photoshop as I have been doing (not liking the look/feel of other software)

I am going to play around with some potential syntax over the next week and I will present back here for discussion

nirname commented 10 months ago

I would not call it pedigree chart type, since it can represent any species which method of reproduction requires 2 parents. That being said it is:

Obviously that is applied to humans as well.

This basically works for 2 genders. There are some exceptions when we are talking about laboratory experiments, though. Nevertheless, should we attach "gender" property to a node?

In some cases only 1 parent is known. Should not we also add some special type of node called "unknown", that will not be grouped with any other "unknowns"?

John, :
  Jane

Jane, :
  Jim
graph
John --> Jane
Unknown1["?"] --> Jane
Jane --> Jim
Unknown2["?"] --> Jim

Or may be add a config option for that and simply allow nodes with only one parent

---
genealogy:
  displayMissingParents: true
---

John:
  Jane

Jane:
  Jim

Should we (by some obscure reason, I don't know why) allow more than two parents?

This graph is directed, we also need to ensure that there is no loops in it. By saying "no loops" I mean that a specimen cannot give a birth to either of his parents. That's obvious, but must be written.

Some edge cases are also possible, like this one

A + B
B + C
A + C

We have to take it consideration when planning rendering strategy.

JKrag commented 10 months ago

For inspiration, I can show a little graph I made of the breeding lines of my cats going back 30 years, (mis)using the flowchart type.

Mermaid live.

This diagram shows only the cats that are important to a specific story-telling, and each litter of kittens in reality has typically between 3 and 8 kittens but for this purpose they weren't of interest. Also, I am only tracing back lines that I have been involved in. Had I done the full pedigree for those 11 generations, we would be at thousands of cats, but I would never expect Mermaid to be useful for something like that.

Another important aspect, when dealing with animal pedigrees like cats, is that it is much more likely to find "cross generation" breeding than in humans. I.e. A male cat breeding with a female that is partially related, but separated by maybe 3 or 4 generations on one side. Yes, breeding a individual to one of its great-great-grandparents could happen, and might pose a challenge to rendering :-)

craxal commented 10 months ago

@nirname The word "pedigree" is still quite relevant, as it does not exclusively refer to human ancestry. For example, the term is often used in reference to cats and dogs (as @JKrag has demonstrated). The term "genealogy" is at least equally valid.

Does gender need to be a property on a node, or can it simply be a styling choice? That is, let the user apply classes and styles themselves? Or perhaps authors can use parentheses similar to other chart types, for example [Male] and (Female).

In cases where the parent isn't known, I don't think they need to be called out at all. For example:

A
  B
  C

Here, B and C are children of A due to the indentation. If unknown parents do need to be called out, authors can create unique nodes with the same label:

A[?] + B[?]
  C
  D
nirname commented 10 months ago

@craxal My point about having unknown parent, is that you can actually avoid this unnecessary "naming" for missing parents and assigning them with the same label. You can omit node name at all. Assigning unique node names can be done automatically

A + ?
  C

B + ?
  D

In that case ? is not a "common unknown parent", they are 2 different parents by default:

graph
A --> C
A2[?] --> C

B --> D
B2[?] --> D

And if one wants to emphasize that tho guys have common unknown parent one can add the node name

A + X?
  C

B + X?
  D
graph
A --> C
X --> C
B --> D
X --> D
X[?]
JKrag commented 10 months ago

One of the things I found quite nice, when creating the pedigree example I have shared above, was the ability to define and style all the individual (cats) first, and then use their simplified labels in the following section when defining the actual graph. This makes it much easier to change things like the display name or style of an individual in one place, so I think this "feature" should also be kept in a new genealogy/pedigree graph type.

dicaeffe commented 9 months ago

There is an issue about a tree dieagram (#3989) is not exactly the same but are similar as requirements.

This can be an example on how to show the different generations

stateDiagram-v2
    classDef gen2 fill:#f55
    classDef gen1 fill:#c95
    classDef gen0 fill:#990
    classDef you fill:#f00
    classDef gen_1 fill:#660
    classDef gen_2 fill:#099

    state couple1da <<choice>>
    aunt_d --> couple1da
    uncle_d --> couple1da
    couple1da --> cousin:::gen0

    state couple2m <<choice>>
    granpa_m --> couple2m
    granma_m --> couple2m
    couple2m --> mom:::gen1
    couple2m --> uncle_m:::gen1

    state couple2d <<choice>>
    granpa_d --> couple2d
    granma_d --> couple2d
    couple2d --> dad:::gen1
    couple2d --> aunt_d:::gen1
    class granma_m,granpa_m,granma_d,granpa_d  gen2

    state couple1b <<choice>>
    brother --> couple1b
    systerInLaw_b --> couple1b
    couple1b --> nephew:::gen_1

    state couple1 <<choice>>
    dad --> couple1
    mom --> couple1
    couple1 --> brother:::gen0
    couple1 --> syster:::gen0
    couple1 --> you:::you

    state couple1m <<choice>>
    dadInLaw --> couple1m
    momInLaw --> couple1m
    couple1m --> brotherInLaw_m:::gen0
    couple1m --> systerInLaw_m:::gen0
    couple1m --> mate:::gen0
    class systerInLaw_b gen0
    class uncle_d,momInLaw, dadInLaw  gen1

    state couple+1s <<choice>>
    son --> couple+1s
    daughterInLaw --> couple+1s
    couple+1s --> grandson_s:::gen_2
    couple+1s --> granddaughter_s:::gen_2

    state couple0 <<choice>>
    you --> couple0
    mate --> couple0
    couple0 --> son:::gen_1
    couple0 --> daughter:::gen_1

    state couple+1d <<choice>>
    daughter --> couple+1d
    sonInLaw --> couple+1d
    couple+1d --> grandchild:::gen_2

    class sonInLaw,daughterInLaw gen_1