1 __VERSION__="ete2-2.0rev104"
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25 try:
26 from PyQt4 import QtCore, QtGui
27 except:
28 import QtCore, QtGui
29
30 import numpy
31
32 aafgcolors = {
33 'A':"#000000" ,
34 'R':"#000000" ,
35 'N':"#000000" ,
36 'D':"#000000" ,
37 'C':"#000000" ,
38 'Q':"#000000" ,
39 'E':"#000000" ,
40 'G':"#000000" ,
41 'H':"#000000" ,
42 'I':"#000000" ,
43 'L':"#000000" ,
44 'K':"#000000" ,
45 'M':"#000000" ,
46 'F':"#000000" ,
47 'P':"#000000" ,
48 'S':"#000000" ,
49 'T':"#000000" ,
50 'W':"#000000" ,
51 'Y':"#000000" ,
52 'V':"#000000" ,
53 'B':"#000000" ,
54 'Z':"#000000" ,
55 'X':"#000000",
56 '.':"#000000",
57 '-':"#000000",
58 }
59
60 aabgcolors = {
61 'A':"#C8C8C8" ,
62 'R':"#145AFF" ,
63 'N':"#00DCDC" ,
64 'D':"#E60A0A" ,
65 'C':"#E6E600" ,
66 'Q':"#00DCDC" ,
67 'E':"#E60A0A" ,
68 'G':"#EBEBEB" ,
69 'H':"#8282D2" ,
70 'I':"#0F820F" ,
71 'L':"#0F820F" ,
72 'K':"#145AFF" ,
73 'M':"#E6E600" ,
74 'F':"#3232AA" ,
75 'P':"#DC9682" ,
76 'S':"#FA9600" ,
77 'T':"#FA9600" ,
78 'W':"#B45AB4" ,
79 'Y':"#3232AA" ,
80 'V':"#0F820F" ,
81 'B':"#FF69B4" ,
82 'Z':"#FF69B4" ,
83 'X':"#BEA06E",
84 '.':"#FFFFFF",
85 '-':"#FFFFFF",
86 }
87
88 ntfgcolors = {
89 'A':'#000000',
90 'G':'#000000',
91 'I':'#000000',
92 'C':'#000000',
93 'T':'#000000',
94 'U':'#000000',
95 '.':"#000000",
96 '-':"#000000",
97 ' ':"#000000"
98
99 }
100
101 ntbgcolors = {
102 'A':'#A0A0FF',
103 'G':'#FF7070',
104 'I':'#80FFFF',
105 'C':'#FF8C4B',
106 'T':'#A0FFA0',
107 'U':'#FF8080',
108 '.':"#FFFFFF",
109 '-':"#FFFFFF",
110 ' ':"#FFFFFF"
111
112 }
113
114 __all__ = ["add_face_to_node", "Face", "TextFace", "AttrFace", "ImgFace", "ProfileFace", "ValidationFace", "SequenceFace"]
115
116 try:
117 import psyco
118 pysco.full()
119 except:
120 pass
121
123 """ Links a node with a given face instance. """
124
125 if column >= len(node.img_style["faces"]):
126 for i in xrange(len(node.img_style["faces"]), column+1):
127 node.img_style["faces"].append([])
128
129 node.img_style["faces"][column].append([face, aligned, None])
130
132 """ Standard definition of a face node object.
133
134 This class is not functional and it should only be used to create
135 other faces objects. By inheriting this class, you set all the
136 essential attributes, however the update_pixmap() function is
137 required to be reimplemented for convenience.
138
139 """
140
142 self.node = None
143 self.type = "pixmap"
144 self.name = "unknown"
145 self.xmargin = 0
146 self.ymargin = 0
147 self.pixmap = None
148
149
151 if self.pixmap:
152 return self._width(),self._height()
153 else:
154 return 0, 0
155
157 if self.pixmap:
158 return self.pixmap.width()
159 else:
160 return 0
161
163 if self.pixmap:
164 return self.pixmap.height()
165 else:
166 return 0
167
169 self.pixmap = QtGui.QPixmap(filename)
170
173
174 -class TextFace(Face):
175 """ Creates a new text face object.
176
177 Arguments description
178 ---------------------
179 text: Text to be drawn
180 ftype: Font type, e.g. Arial, Verdana, Courier, (default="Verdana")
181 fsize: Font size, e.g. 10,12,6, (default=10)
182 fgcolor: Foreground font color in RGB name format, e.g. #FF00DD,#000000 (default="#000000")
183 bgcolor: Backgroung font color in RGB name format, e.g. #FFFFFF,#DDDDDD, (default=None)
184 penwidth: Penwdith used to draw the text. (default is 0)
185 """
186
187 - def __init__(self, text, ftype="Verdana", fsize=10, fgcolor="#000000", bgcolor=None, penwidth=0):
188 Face.__init__(self)
189
190 if bgcolor is None:
191 bgcolor = QtCore.Qt.transparent
192 self.pixmap = None
193 self.type = "text"
194 self.text = str(text)
195 self.pen = QtGui.QPen(QtGui.QColor(fgcolor))
196 self.pen.setWidth(penwidth)
197 if not bgcolor:
198 self.bgcolor = QtGui.QColor(None)
199 else:
200 self.bgcolor = QtGui.QColor(bgcolor)
201 self.fgcolor = QtGui.QColor(fgcolor)
202 self.font = QtGui.QFont(ftype,fsize)
203
205 fm = QtGui.QFontMetrics(self.font)
206 h = fm.boundingRect(QtCore.QRect(), \
207 QtCore.Qt.AlignLeft, \
208 self.get_text()).height()
209 return h
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
231 fm = QtGui.QFontMetrics(self.font)
232 return fm.size(QtCore.Qt.AlignTop, self.text).width()
233
234 - def get_text(self):
236
238 """ Creates a new text attribute face object.
239
240 Arguments description
241 ---------------------
242 name: Face's name
243 attr: Node's attribute that will be drawn as text
244 ftype: Font type, e.g. Arial, Verdana, Courier, (default="Verdana")
245 fsize: Font size, e.g. 10,12,6, (default=10)
246 fgcolor: Foreground font color in RGB name format, e.g. #FF00DD,#000000 (default="#000000")
247 bgcolor: Backgroung font color in RGB name format, e.g. #FFFFFF,#DDDDDD, (default=None)
248 penwidth: Penwdith used to draw the text. (default is 0)
249 """
250
251 - def __init__(self, attr, ftype="Verdana", fsize=10, fgcolor="#000000", bgcolor=None, penwidth=0):
252 Face.__init__(self)
253 TextFace.__init__(self, "", ftype, fsize, fgcolor, bgcolor, penwidth)
254 self.attr = attr
255 self.type = "text"
256
258 text = str(getattr(self.node, self.attr))
259 fm = QtGui.QFontMetrics(self.font)
260 return fm.size(QtCore.Qt.AlignTop,text).width()
261
262 - def get_text(self):
263 return str(getattr(self.node, self.attr))
264
265
266
268 """ Creates a new image face object.
269
270 Arguments description
271 ---------------------
272
273 img_file: Image file in png,jpg,bmp format
274 """
276 Face.__init__(self)
277 self.img_file = img_file
278 self.name = "ImageFile"
279
282
283
285 """ Creates a new vector profile face object.
286
287 Arguments description
288 ---------------------
289
290 max_v: maximum value used to build the build the plot scale.
291 max_v: manimum value used to build the build the plot scale.
292 center_v: Center value used to scale plot and heat map.
293 width: Plot width in pixels. (defaulf=200)
294 height: Plot width in pixels. (defaulf=40)
295 style: Plot style: "lines", "bars", "cbars" or "heatmap". (default="lines")
296 """
297 - def __init__(self,max_v,min_v,center_v,width=200,height=40,style="lines",colorscheme=2):
298 Face.__init__(self)
299
300 self.width = width
301 self.height = height
302 self.max_value = max_v
303 self.min_value = min_v
304 self.center_v = center_v
305 self.xmargin = 1
306 self.ymargin = 1
307 self.style = style
308 self.colorscheme = colorscheme
309
319
321 colors = []
322 if self.colorscheme == 0:
323
324 for a in xrange(100,0,-1):
325 color=QtGui.QColor()
326 color.setRgb( 200-2*a,255,200-2*a )
327 colors.append(color)
328 for a in xrange(0,100):
329 color=QtGui.QColor()
330 color.setRgb( 200-2*a,200-2*a,255 )
331 colors.append(color)
332
333
334
335
336 elif self.colorscheme == 1:
337 for a in xrange(100,0,-1):
338 color=QtGui.QColor()
339 color.setRgb( 200-2*a,255,200-2*a )
340 colors.append(color)
341
342 for a in xrange(0,100):
343 color=QtGui.QColor()
344 color.setRgb( 255,200-2*a,200-2*a )
345 colors.append(color)
346
347
348
349
350 else:
351
352 for a in xrange(100,0,-1):
353 color=QtGui.QColor()
354 color.setRgb( 200-2*a,200-2*a,255 )
355 colors.append(color)
356 for a in xrange(0,100):
357 color=QtGui.QColor()
358 color.setRgb( 255,200-2*a,200-2*a )
359 colors.append(color)
360
361
362
363 colors.append(QtGui.QColor("white"))
364
365 return colors
366
368
369 mean_vector = self.node.profile
370 deviation_vector = self.node.deviation
371
372 if mean_vector is None:
373 return
374
375 colors = self.get_color_gradient()
376
377 vlength = len(mean_vector)
378
379 profile_width = self.width - self.xmargin*2 - 40
380 profile_height= self.height - self.ymargin*2
381
382 x_alpha = float( profile_width / (len(mean_vector)) )
383 y_alpha = float ( profile_height / (self.max_value-self.min_value) )
384
385
386 self.pixmap = QtGui.QPixmap(self.width,self.height)
387 self.pixmap.fill(QtGui.QColor("white"))
388 p = QtGui.QPainter(self.pixmap)
389
390 x2 = self.xmargin
391 y = self.ymargin
392
393
394 mean_line_y = y + profile_height/2
395 line2_y = mean_line_y + profile_height/4
396 line3_y = mean_line_y - profile_height/4
397
398
399 p.setPen(QtGui.QColor("black"))
400 p.drawRect(x2,y,profile_width, profile_height-1)
401 p.setFont(QtGui.QFont("Verdana",8))
402 p.drawText(self.xmargin+profile_width,y+10,"%0.3f" %self.max_value)
403 p.drawText(self.xmargin+profile_width,y+profile_height,"%0.3f" %self.min_value)
404
405 dashedPen = QtGui.QPen(QtGui.QBrush(QtGui.QColor("#ddd")), 0)
406 dashedPen.setStyle(QtCore.Qt.DashLine)
407
408
409 p.setPen(dashedPen)
410 p.drawLine(x2+1, mean_line_y, profile_width-2, mean_line_y )
411 p.drawLine(x2+1, line2_y, profile_width-2, line2_y )
412 p.drawLine(x2+1, line3_y, profile_width-2, line3_y )
413
414
415
416 for pos in xrange(vlength):
417
418 x1 = x2
419 x2 = x1 + x_alpha
420
421 dev1 = self.fit_to_scale( deviation_vector[pos] )
422 mean1 = self.fit_to_scale( mean_vector[pos] )
423
424
425 if not numpy.isfinite(mean1):
426 continue
427
428
429 if mean1>self.center_v:
430 color_index = int(abs(((self.center_v-mean1)*100)/(self.max_value-self.center_v)))
431 customColor = colors[100+color_index]
432 elif mean1<self.center_v:
433 color_index = int(abs(((self.center_v-mean1)*100)/(self.min_value-self.center_v)))
434 customColor = colors[100-color_index]
435 else:
436 customColor = colors[0]
437
438
439 mean_y1 = int ( (mean1 - self.min_value) * y_alpha)
440
441
442 p.setPen(QtGui.QColor("black"))
443
444
445 p.fillRect(x1+3,profile_height-mean_y1, x_alpha-4, mean_y1-1, QtGui.QBrush(customColor))
446
447
448 if dev1 != 0:
449 dev_up_y1 = int((mean1+dev1 - self.min_value) * y_alpha)
450 dev_down_y1 = int((mean1-dev1 - self.min_value) * y_alpha)
451 p.drawLine(x1+x_alpha/2, profile_height-dev_up_y1 ,x1+x_alpha/2, profile_height-dev_down_y1 )
452 p.drawLine(x1-1+x_alpha/2, profile_height-dev_up_y1, x1+1+x_alpha/2, profile_height-dev_up_y1 )
453 p.drawLine(x1-1+x_alpha/2, profile_height-dev_down_y1, x1+1+x_alpha/2, profile_height-dev_down_y1 )
454
456
457 mean_vector = self.node.profile
458 deviation_vector = self.node.deviation
459
460 if mean_vector is None:
461 return
462
463 colors = self.get_color_gradient()
464
465 vlength = len(mean_vector)
466
467 profile_width = self.width - self.xmargin*2 - 40
468 profile_height= self.height - self.ymargin*2
469
470 x_alpha = float( profile_width / (len(mean_vector)) )
471 y_alpha_up = float ( (profile_height/2) / (self.max_value-self.center_v) )
472 y_alpha_down = float ( (profile_height/2) / (self.min_value-self.center_v) )
473
474
475 self.pixmap = QtGui.QPixmap(self.width,self.height)
476 self.pixmap.fill(QtGui.QColor("white"))
477 p = QtGui.QPainter(self.pixmap)
478
479 x2 = self.xmargin
480 y = self.ymargin
481
482
483 mean_line_y = y + profile_height/2
484 line2_y = mean_line_y + profile_height/4
485 line3_y = mean_line_y - profile_height/4
486
487
488 p.setPen(QtGui.QColor("black"))
489 p.drawRect(x2,y,profile_width, profile_height-1)
490 p.setFont(QtGui.QFont("Verdana",8))
491 p.drawText(self.xmargin+profile_width,y+10,"%0.3f" %self.max_value)
492 p.drawText(self.xmargin+profile_width,y+profile_height,"%0.3f" %self.min_value)
493 p.drawText(self.xmargin+profile_width,mean_line_y,"%0.3f" %self.center_v)
494
495 dashedPen = QtGui.QPen(QtGui.QBrush(QtGui.QColor("#ddd")), 0)
496 dashedPen.setStyle(QtCore.Qt.DashLine)
497
498
499 p.setPen(dashedPen)
500 p.drawLine(x2+1, mean_line_y, profile_width-2, mean_line_y )
501 p.drawLine(x2+1, line2_y, profile_width-2, line2_y )
502 p.drawLine(x2+1, line3_y, profile_width-2, line3_y )
503
504
505
506 for pos in xrange(vlength):
507
508 x1 = x2
509 x2 = x1 + x_alpha
510
511 dev1 = self.fit_to_scale( deviation_vector[pos] )
512 mean1 = self.fit_to_scale( mean_vector[pos] )
513
514
515 if not numpy.isfinite(mean1):
516 continue
517
518
519 if mean1>self.center_v:
520 color_index = int(abs(((self.center_v-mean1)*100)/(self.max_value-self.center_v)))
521 customColor = colors[100+color_index]
522 elif mean1<self.center_v:
523 color_index = int(abs(((self.center_v-mean1)*100)/(self.min_value-self.center_v)))
524 customColor = colors[100-color_index]
525 else:
526 customColor = colors[0]
527
528
529 if mean1<self.center_v:
530 mean_y1 = int(abs((mean1 - self.center_v) * y_alpha_down))
531 else:
532 mean_y1 = int(abs((mean1 - self.center_v) * y_alpha_up))
533
534
535 p.setPen(QtGui.QColor("black"))
536
537
538 if mean1<self.center_v:
539 p.fillRect(x1+3, mean_line_y, x_alpha-4, mean_y1, QtGui.QBrush(customColor))
540 else:
541 p.fillRect(x1+3, mean_line_y-mean_y1, x_alpha-4, mean_y1+1, QtGui.QBrush(customColor))
542
543
544 if dev1 != 0:
545 if mean1<self.center_v:
546 dev_up_y1 = int((mean1+dev1 - self.center_v) * y_alpha_down)
547 dev_down_y1 = int((mean1-dev1 - self.center_v) * y_alpha_down)
548 p.drawLine(x1+x_alpha/2, mean_line_y+dev_up_y1 ,x1+x_alpha/2, mean_line_y+dev_down_y1 )
549 p.drawLine(x1-1+x_alpha/2, mean_line_y+dev_up_y1 ,x1+1+x_alpha/2, mean_line_y+dev_up_y1 )
550 p.drawLine(x1-1+x_alpha/2, mean_line_y+dev_down_y1 ,x1+1+x_alpha/2, mean_line_y+dev_down_y1 )
551 else:
552 dev_up_y1 = int((mean1+dev1 - self.center_v) * y_alpha_up)
553 dev_down_y1 = int((mean1-dev1 - self.center_v) * y_alpha_up)
554 p.drawLine(x1+x_alpha/2, mean_line_y-dev_up_y1 ,x1+x_alpha/2, mean_line_y-dev_down_y1 )
555 p.drawLine(x1-1+x_alpha/2, mean_line_y-dev_up_y1 ,x1+1+x_alpha/2, mean_line_y-dev_up_y1 )
556 p.drawLine(x1-1+x_alpha/2, mean_line_y-dev_down_y1 ,x1+1+x_alpha/2, mean_line_y-dev_down_y1 )
557
559
560 mean_vector = self.node.profile
561 deviation_vector = self.node.deviation
562 if mean_vector is None:
563 return
564
565 vlength = len(mean_vector)
566
567 profile_width = self.width - self.xmargin*2 - 40
568 profile_height= self.height - self.ymargin*2
569
570
571 x_alpha = float( profile_width / (len(mean_vector)-1) )
572 y_alpha = float ( profile_height / (self.max_value-self.min_value) )
573
574
575 self.pixmap = QtGui.QPixmap(self.width,self.height)
576 self.pixmap.fill(QtGui.QColor("white"))
577 p = QtGui.QPainter(self.pixmap)
578
579 x2 = self.xmargin
580 y = self.ymargin
581
582
583 mean_line_y = (self.center_v - self.min_value) * y_alpha
584 line2_y = ((self.center_v+abs(self.min_value/2)) - self.min_value) * y_alpha
585 line3_y = ((self.center_v-abs(self.max_value/2)) - self.min_value) * y_alpha
586
587
588 p.setPen(QtGui.QColor("black"))
589 p.drawRect(x2,y,profile_width, profile_height-1)
590 p.setFont(QtGui.QFont("Verdana",8))
591 p.drawText(self.xmargin+profile_width,y+10,"%0.3f" %self.max_value)
592 p.drawText(self.xmargin+profile_width,y+profile_height,"%0.3f" %self.min_value)
593 p.drawText(self.xmargin+profile_width,mean_line_y+5,"%0.3f" %self.center_v)
594
595 dashedPen = QtGui.QPen(QtGui.QBrush(QtGui.QColor("#ddd")), 0)
596 dashedPen.setStyle(QtCore.Qt.DashLine)
597
598
599 p.setPen(dashedPen)
600 p.drawLine(x2+1, mean_line_y, profile_width-2, mean_line_y )
601 p.drawLine(x2+1, line2_y, profile_width-2, line2_y )
602 p.drawLine(x2+1, line3_y, profile_width-2, line3_y )
603
604
605 for pos in xrange(0,vlength-1):
606 dev1 = self.fit_to_scale( deviation_vector[pos] )
607 dev2 = self.fit_to_scale( deviation_vector[pos+1] )
608 mean1 = self.fit_to_scale( mean_vector[pos] )
609 mean2 = self.fit_to_scale( mean_vector[pos+1] )
610
611 x1 = x2
612 x2 = x1 + x_alpha
613
614
615 if x2 < profile_width:
616 p.setPen(dashedPen)
617 p.drawLine(x2, y+1, x2, profile_height-2)
618
619
620 if not numpy.isfinite(mean1) or not numpy.isfinite(mean2):
621 continue
622
623
624 mean_y1 = (mean1 - self.min_value) * y_alpha
625
626 mean_y2 = (mean2 - self.min_value) * y_alpha
627
628 p.setPen(QtGui.QColor("blue"))
629 p.drawLine(x1,mean_y1, x2, mean_y2)
630
631 if dev1!= 0 and dev2!=0:
632
633 dev_up_y1 = (mean1+dev1 - self.min_value) * y_alpha
634 dev_down_y1 = (mean1-dev1 - self.min_value) * y_alpha
635
636 dev_up_y2 = (mean2+dev2 - self.min_value) * y_alpha
637 dev_down_y2 = (mean2-dev2 - self.min_value) * y_alpha
638
639 p.setPen(QtGui.QColor("red"))
640 p.drawLine(x1,dev_up_y1, x2, dev_up_y2)
641 p.setPen(QtGui.QColor("red"))
642 p.drawLine(x1,dev_down_y1, x2, dev_down_y2)
643
644
646
647 vector = self.node.profile
648 deviation = self.node.deviation
649
650 if vector is None:
651 return
652
653 colors = self.get_color_gradient()
654
655 leaves = self.node.get_leaves()
656
657 vlength = len(vector)
658
659 img_height = self.height * len(leaves)
660 profile_width = self.width - self.xmargin*2
661 profile_height= img_height - self.ymargin*2
662
663 x_alpha = float( profile_width / (len(vector)) )
664
665
666 self.pixmap = QtGui.QPixmap(self.width,img_height)
667 self.pixmap.fill(QtGui.QColor("white"))
668 p = QtGui.QPainter(self.pixmap)
669
670 x2 = self.xmargin
671 y = self.ymargin
672 y_step = self.height
673 for leaf in leaves:
674 mean_vector = leaf.profile
675 deviation_vector = leaf.deviation
676
677 for pos in xrange(vlength):
678
679 x1 = x2
680 x2 = x1 + x_alpha
681 dev1 = self.fit_to_scale( deviation_vector[pos] )
682 mean1 = self.fit_to_scale( mean_vector[pos] )
683
684 if not numpy.isfinite(mean1):
685 customColor = QtGui.QColor("#000000")
686 elif mean1>self.center_v:
687 color_index = int(abs(((self.center_v-mean1)*100)/(self.max_value-self.center_v)))
688 customColor = colors[100+color_index]
689 elif mean1<self.center_v:
690 color_index = int(abs(((self.center_v-mean1)*100)/(self.min_value-self.center_v)))
691 customColor = colors[100-color_index]
692 else:
693 customColor = colors[-1]
694
695
696 p.fillRect(x1, y, x_alpha, y_step, QtGui.QBrush(customColor))
697 y+= y_step
698 x2 = self.xmargin
699
701 if v<self.min_value:
702 return float(self.min_value)
703 elif v>self.max_value:
704 return float(self.max_value)
705 else:
706 return float(v)
707
709 """ Creates a new clustering validation face """
710
712 Face.__init__(self)
713 self.seq = seq
714 self.name = "validation"
715 self.fsize= fsize
716 self.font = QtGui.QFont("Courier",self.fsize)
717 self.style = seqtype
718
721
723 """ Creates a new molecular sequence face object.
724
725 Arguments description
726 ---------------------
727 seq: Sequence string to be drawn
728 seqtype: Type of sequence: "nt" or "aa"
729 fsize: Font size, (default=10)
730 """
731
733 Face.__init__(self)
734 self.seq = seq
735 self.name = "sequence"
736 self.fsize= fsize
737 self.font = QtGui.QFont("Courier", self.fsize)
738 self.style = seqtype
739 self.aafg = aafg
740 self.aabg = aabg
741 self.ntfg = ntfg
742 self.ntbg = ntbg
743
745
746
747 fm = QtGui.QFontMetrics(self.font)
748 height = fm.leading() + fm.overlinePos() + fm.underlinePos()
749 width = fm.size(QtCore.Qt.AlignTop, self.seq).width()
750
751 self.pixmap = QtGui.QPixmap(width,height)
752 self.pixmap.fill()
753 p = QtGui.QPainter(self.pixmap)
754 x = 0
755 y = height - fm.underlinePos()*2
756
757 p.setFont(self.font)
758
759 for letter in self.seq:
760 letter = letter.upper()
761 if self.style=="nt":
762 letter_brush = QtGui.QBrush(QtGui.QColor(self.ntbg.get(letter,"#ffffff" )))
763 letter_pen = QtGui.QPen(QtGui.QColor(self.ntfg.get(letter, "#000000")))
764 else:
765 letter_brush = QtGui.QBrush(QtGui.QColor(self.aabg.get(letter,"#ffffff" )))
766 letter_pen = QtGui.QPen(QtGui.QColor(self.aafg.get(letter,"#000000" )))
767
768 p.setPen(letter_pen)
769 p.fillRect(x,0,width, height,letter_brush)
770 p.drawText(x, y, letter)
771 x += float(width)/len(self.seq)
772 p.end()
773