mtDNA突变树


13

背景:

MtDNA是人类DNA的一部分,是从母亲传给孩子的,很少发生突变。由于这对所有人类都是如此,因此有可能创建一棵巨大的树,以可视化方式将所有人类如何通过其母系关系彼此联系,一直到假设的EVE。当孩子出生时,MtDNA中的每个突变都会从其父树中的分支创建一个新的子分支。

在此处了解有关线粒体DNA(mtDNA)的更多信息:https://en.wikipedia.org/wiki/线粒体DNA

目的:

您的程序将获得mtDNA树枝突变计数列表,并且您的程序应提供它的树状视图

输入和输出示例:

输入是一个三列的分号分隔表,每个分支都有一行。例:

L0a'b'f'k;L0;14
L0a'b'f;L0a'b'f'k;23
L0;mtEVE;10
L0a'b;L0a'b'f;30
L0a;L0a'b;38
L0a1'4;L0a;39
L0a1;L0a1'4;40
L0a1a;L0a1;42
L0a1a NL;L0a1a;43
L0a1a1;L0a1a NL;44
L0a1a2;L0a1a NL;45
L0a1a3;L0a1a NL;44
L0a1 NL;L0a1;41
L0a1b;L0a1 NL;44
L0a1b NL;L0a1b;45
L0a1b1;L0a1b NL;46
L0a1b1a;L0a1b1;47
L0a1b1a1;L0a1b1a;48
L0a1b2;L0a1b NL;48
L0a1b2a;L0a1b2;50
L0a1c;L0a1 NL;45
L0a1d;L0a1 NL;44
L0a4;L0a1'4;55
L0a2;L0a;47
L0a2a;L0a2;49
L0a2a1;L0a2a;50
L0a2a1a;L0a2a1;51
L0a2a1a1;L0a2a1a;53
L0a2a1a2;L0a2a1a;53
L0a2a2;L0a2a;53
L0a2a2a;L0a2a2;54
L0a2b;L0a2;57
L0a2b1;L0a2b;58
L0a2c;L0a2;60
L0a2d;L0a2;49
L0a3;L0a;53
L0b;L0a'b;48
L0f;L0a'b'f;37
L0f1;L0f;61
L0f2;L0f;41
L0f2a;L0f2;46
L0f2a1;L0f2a;59
L0f2b;L0f2;63
L0k;L0a'b'f'k;39
L0k1;L0k;48
L0k2;L0k;54
L0d;L0;21
L0d1'2;L0d;25
L0d1;L0d1'2;30
L0d1 NL;L0d1;31
L0d1a;L0d1 NL;38
L0d1a1;L0d1a;41
L0d1c;L0d1 NL;39
L0d1c1;L0d1c;45
L0d1c1a;L0d1c1;46
L0d1c1b;L0d1c1;46
L0d1b;L0d1 NL;36
L0d1b1;L0d1b;40
L0d2;L0d1'2;31
L0d2a'b;L0d2;32
L0d2a;L0d2a'b;42
L0d2a1;L0d2a;43
L0d2b;L0d2a'b;46
L0d2c;L0d2;45
L0d3;L0d;39

您的程序应输出从左到右的树状视图,其中包括一些基于输入的数字。根据示例输入,这是有效的输出:

  0│ ┐                                                               mtEVE               [  0][ 63]
 10│ └♦♦♦♦♦♦♦♦♦┬────────────────┬─────────────────────────────────── L0                  [ 10][ 63]
 21│           │                └♦♦♦♦♦♦♦♦♦♦┬──────┬───────────────── L0d                 [ 11][ 46]
 39│           │                           │      └♦♦♦♦♦♦♦♦♦♦♦♦♦♦♦♦♦ L0d3                [ 18][ 39]
 25│           │                           └♦♦♦┐                     L0d1'2              [  4][ 46]
 30│           │                               ├♦♦♦♦┬─────────────── L0d1                [  5][ 46]
 31│           │                               │    └┬────┬┐         L0d1 NL             [  1][ 46]
 36│           │                               │     │    │└♦♦♦♦┬─── L0d1b               [  5][ 40]
 40│           │                               │     │    │     └♦♦♦ L0d1b1              [  4][ 40]
 38│           │                               │     │    └♦♦♦♦♦♦┬── L0d1a               [  7][ 41]
 41│           │                               │     │           └♦♦ L0d1a1              [  3][ 41]
 39│           │                               │     └♦♦♦♦♦♦♦┬────── L0d1c               [  8][ 46]
 45│           │                               │             └♦♦♦♦♦┬ L0d1c1              [  6][ 46]
 46│           │                               │                   ├ L0d1c1a             [  1][ 46]
 46│           │                               │                   └ L0d1c1b             [  1][ 46]
 31│           │                               └♦♦♦♦♦┬┬───────────── L0d2                [  6][ 46]
 45│           │                                     │└♦♦♦♦♦♦♦♦♦♦♦♦♦ L0d2c               [ 14][ 45]
 32│           │                                     └┬──┐           L0d2a'b             [  1][ 46]
 42│           │                                      │  └♦♦♦♦♦♦♦♦♦┬ L0d2a               [ 10][ 43]
 43│           │                                      │            └ L0d2a1              [  1][ 43]
 46│           │                                      └♦♦♦♦♦♦♦♦♦♦♦♦♦ L0d2b               [ 14][ 46]
 14│           └♦♦♦┬────────┐                                        L0a'b'f'k           [  4][ 63]
 39│               │        └♦♦♦♦♦♦♦♦♦♦♦♦♦♦♦♦♦♦♦♦♦♦♦♦┬─────┬──────── L0k                 [ 25][ 54]
 48│               │                                 │     └♦♦♦♦♦♦♦♦ L0k1                [  9][ 48]
 54│               │                                 └♦♦♦♦♦♦♦♦♦♦♦♦♦♦ L0k2                [ 15][ 54]
 23│               └♦♦♦♦♦♦♦♦┬──┐                                     L0a'b'f             [  9][ 63]
 30│                        │  └♦♦♦♦♦♦┬───────────┐                  L0a'b               [  7][ 60]
 48│                        │         │           └♦♦♦♦♦♦♦♦♦♦♦♦♦♦♦♦♦ L0b                 [ 18][ 48]
 38│                        │         └♦♦♦♦♦♦♦┬────┬─┬────────────── L0a                 [  8][ 60]
 53│                        │                 │    │ └♦♦♦♦♦♦♦♦♦♦♦♦♦♦ L0a3                [ 15][ 53]
 39│                        │                 │    └┬────┐           L0a1'4              [  1][ 55]
 40│                        │                 │     │    └┬────┬──── L0a1                [  1][ 50]
 42│                        │                 │     │     │    └♦┬── L0a1a               [  2][ 45]
 43│                        │                 │     │     │      └┬┐ L0a1a NL            [  1][ 45]
 44│                        │                 │     │     │       │├ L0a1a1              [  1][ 44]
 44│                        │                 │     │     │       │└ L0a1a3              [  1][ 44]
 45│                        │                 │     │     │       └♦ L0a1a2              [  2][ 45]
 41│                        │                 │     │     └┬────┬┐   L0a1 NL             [  1][ 50]
 44│                        │                 │     │      │    │└♦♦ L0a1d               [  3][ 44]
 45│                        │                 │     │      │    └♦♦♦ L0a1c               [  4][ 45]
 44│                        │                 │     │      └♦♦┬───── L0a1b               [  3][ 50]
 45│                        │                 │     │         └┬─┐   L0a1b NL            [  1][ 50]
 46│                        │                 │     │          │ └┬─ L0a1b1              [  1][ 48]
 47│                        │                 │     │          │  └┬ L0a1b1a             [  1][ 48]
 48│                        │                 │     │          │   └ L0a1b1a1            [  1][ 48]
 48│                        │                 │     │          └♦♦┬─ L0a1b2              [  3][ 50]
 50│                        │                 │     │             └♦ L0a1b2a             [  2][ 50]
 55│                        │                 │     └♦♦♦♦♦♦♦♦♦♦♦♦♦♦♦ L0a4                [ 16][ 55]
 47│                        │                 └♦♦♦♦♦♦♦♦┬─┬───┬────┬─ L0a2                [  9][ 60]
 49│                        │                          │ │   │    └♦ L0a2d               [  2][ 49]
 49│                        │                          │ │   └♦┬┬─── L0a2a               [  2][ 54]
 50│                        │                          │ │     │└┬── L0a2a1              [  1][ 53]
 51│                        │                          │ │     │ └┬─ L0a2a1a             [  1][ 53]
 53│                        │                          │ │     │  ├♦ L0a2a1a1            [  2][ 53]
 53│                        │                          │ │     │  └♦ L0a2a1a2            [  2][ 53]
 53│                        │                          │ │     └♦♦♦┬ L0a2a2              [  4][ 54]
 54│                        │                          │ │         └ L0a2a2a             [  1][ 54]
 57│                        │                          │ └♦♦♦♦♦♦♦♦♦┬ L0a2b               [ 10][ 58]
 58│                        │                          │           └ L0a2b1              [  1][ 58]
 60│                        │                          └♦♦♦♦♦♦♦♦♦♦♦♦ L0a2c               [ 13][ 60]
 37│                        └♦♦♦♦♦♦♦♦♦♦♦♦♦┬─┬─────────────────────── L0f                 [ 14][ 63]
 61│                                      │ └♦♦♦♦♦♦♦♦♦♦♦♦♦♦♦♦♦♦♦♦♦♦♦ L0f1                [ 24][ 61]
 41│                                      └♦♦♦┬───┬───────────────── L0f2                [  4][ 63]
 46│                                          │   └♦♦♦♦┬──────────── L0f2a               [  5][ 59]
 59│                                          │        └♦♦♦♦♦♦♦♦♦♦♦♦ L0f2a1              [ 13][ 59]
 63│                                          └♦♦♦♦♦♦♦♦♦♦♦♦♦♦♦♦♦♦♦♦♦ L0f2b               [ 22][ 63]

输入:详细信息

输入表未按任何特定顺序排序。如果我们随机重新排列输入行,则输出应保持不变。

输入中的每一行代表一个mtDNA树枝或一个假设的树枝。输入表的长度可以是任意数量的行。

输入:详细信息-列A(分支名称):

第一列是实际的分支名称。该名称将输入线分为两组线​​型,应该以彼此不同的方式处理(稍后说明):

  • 类型1:名称由任意'或后缀组成NL
  • 类型2:名称不包含任何'或后缀NL

名称最多可包含20个字符。

输入:详细信息-列B(父分支名称):

第二列包含指向父分支名称的指针。多个行(分支)可以共享同一父级。输入表中总是有1个唯一的父分支名称,它们指向在输入行中未表示的父节点,该父分支名称是树的根。在示例输入中,它是指向根的第三行:mtEVE。如果输入具有多个根或无限循环,则它是无效的输入。

输入:详细信息-C列(突变数):

第三列是特定分支从根开始计数的突变总数。从假设的母本根(人类/黑猩猩的祖先EVE)开始,人类mtDNA的单行突变没有超过100次,但是您的程序应该能够处理3位数的突变,最高可达999。

从输入中,您可以通过从父变量中减去突变数来计算唯一突变的分支数。

输出:详细信息

如果根据输入描述输入无效,则程序应输出3条不同错误消息中的1条。

  • 错误消息1,如果输入具有多个根: ERROR: Multiple roots
  • 错误消息2,如果输入父指针循环: ERROR: Endless loop
  • 错误消息3,其他与输入有关的无效信息: ERROR: Invalid input

如果输入没有错误,则程序应根据以下约束输出树:每行包括5个部分,A,B,C,D和E:

  • A:5个字符,3个字符右对齐的突变数,一个竖线字符:|和1个空格
  • B:[最大突变数]个字符,宽树+ 1个空格
  • C:20个字符,左对齐分支名称
  • D:封装在[和之间的分支的5个字符,3个字符的唯一突变的右对齐#]。(下面将解释唯一的突变)。
  • E:该分支以及封装在[和之间的所有子分支的总突变数的5个字符,右对齐的最大字符数为3个字符]

唯一突变的分支#是当前分支与其父分支具有的突变#之差。第一行是根,应该用0#突变和#唯一突变表示。

输出:明细-行顺序/分类

如果两个或多个子分支共享同一个父分支,则分支按子分支最大总突变数的降序排列。在我们的示例中L0a1'4L0a3L0a2共享父级:L0a

在树状视图中,从上到下的顺序是,子分支中括号内的总突变数的最大值:L0a3(53),L0a1'4(55),L0a2(60)。

如果两个或多个子分支在子分支上共享相同的最大突变数,则它们将垂直对齐并从同一位置从其父分支分支,这些子分支之间的行顺序按字母顺序排列。

输出:详细信息-树(B部分)

树应与以下ascii字符可以得出:

树的逻辑是应表示所有突变。来自母体分支的分支:代表1个突变。同一分支上的其他独特突变用:表示,并且必须将它们左对齐并放在第一个子分支之前。

子分支从其父级沿x轴分支,其位置由所有后续子分支中的最大突变数确定。

如前所述,输入具有2种不同类型的输入线。键入1且分支名称中带有任何'字符或NL后缀,不应在其行的最右边填充水平线,而应在最后一个子分支处以a结尾。在示例中,它应用于以下分支:

L0a'b'f'k;L0;14
L0a'b'f;L0a'b'f'k;23
L0a'b;L0a'b'f;30
L0a1'4;L0a;39
L0a1a NL;L0a1a;43
L0a1 NL;L0a1;41
L0a1b NL;L0a1b;45
L0d1'2;L0d;25
L0d1 NL;L0d1;31
L0d2a'b;L0d2;32

希望示例输入和输出能够回答有关如何绘制树的任何其他问题,将其视为弄清楚逻辑的挑战。

灵感

欢迎您试用我的(未发布的)JavaScript版本以获取灵感:http ://artificial.se/DNA/mtDNAmutationTree3.html (它没有错误检查功能,并且添加了一些统计信息,这些不是本次特殊挑战的一部分) 。

完整的mtDNA树版本[基于http://www.phylotree.org/ mtDNA树Build 16(2014年2月19日)]可在以下位置找到:

http://artificial.se/DNA/mtDNAfull.html

用于完整树的数据文件:

http://artificial.se/DNA/mtDNA_full.txt

这是一个代码高尔夫挑战。


L0d1L0d2根据排序规则,不应将其放置在前面:“ ...降序...”
guy777

L0a1'4不是(55)而是(39),L0a2不是(60)而是(47)...您能澄清一下吗?
guy777 2015年

L0d1和L0d2均为46,因此应用字母顺序
Plarsen

L0a4 55和L0a1'4的子代,因此L0a1'4的最大突变为55
Plarsen

我有几个问题:1)这是一个真实的项目吗?我的印象是,像这样的东西可能物有所值。2)您如何获得示例输出?3)为什么A部分有8个字符而不是5个字符?4)为什么D部分有6个字符而不是5个字符?5)为什么D部分的“ L0a1 NL”具有“ 4”?
aidtsu退出是因为SE为EVIL,2015年

Answers:


6

Python 3,925个字节

是的,不到1 KB!可能还有打高尔夫球的空间...

import sys
class L:
 def __init__(x,**k):x.__dict__.update(k)
m={}
def e(x):print('ERROR: '+x);exit()
try:
 for x in sys.stdin:a,b,c=x.split(';');m[a]=L(s=a,p=b,m=int(c),l=0)
except:e('Invalid input')
a=set()
def k(x):
 if x.l<0:e('Endless loop')
 if x.l<1:y=m.get(x.p);x.l=-1;k(y)if y else a.add(x.p);x.l=1
for x in m:k(m[x])
r=L(s=a.pop(),p=0,m=0)
if a:e('Multiple roots')
m[r.s]=r
c={}
def u(x):
 c[x.s]=[m[y]for y in m if m[y].p==x.s];x.x=x.m
 for y in c[x.s]:u(y);x.x=max(x.x,y.x)
u(r)
o=[]
def f(p,x,o=o):
 d=x.m-p.m;j=p.m+r.x-x.x;s=x.s;x.i=len(o);l=sorted(c[s],key=lambda t:(t.x,t.s));q=' '*j+'└'+'♦'*(d-1);z='─'
 if"'"in s or s[-2:]=='NL'or x==r:q+=z*(x.x-l[0].x);z=' '
 o+=list("%3d│ "%x.m+q+z*(r.x-len(q))+' %-20s[%3d][%3d]'%(s,d,x.x)),;j+=5;o[p.i][j]='┐┬'[o[p.i][j]in'─┬']
 for i in range(p.i+1,x.i):o[i][j]='├│'[o[i][j]in' │']
 for y in l:f(x,y)
f(r,r)
print('\n'.join(''.join(x)for x in o))
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.