Created
June 10, 2016 12:01
-
-
Save jhcepas/2a37d1aa08cc2c3ffe3a4746e11d8a31 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# pp = painter | |
# node_links = a list of node links | |
# a = node a | |
# b = node b | |
# a_mode, b_mode: mode 0= node to node. mode 1: if node is internal cover also the descendants | |
# bg = background color | |
# lw = linewidth | |
# opa = opacity | |
# text, fsize, fcolor, ftype = defines text following the curve | |
# node_zoom_positions is a dictionary that does not exist in treeview, but the used values can be inferred from ETE's treeview scene: | |
# _rot = node rotation (angle) | |
# _rad = radius for the node positionb | |
# (the two values above are polar positions that could converted to cartesian or viceversa) | |
# _astart = angle start | |
# _aend = angle end | |
# (the angle covered by a given node, internal or leaf) | |
def draw_circ_node_links(pp, node_links, cx, cy, node_zoom_positions): | |
link_paths = [] | |
#max_rad = max([reg[_rad] for reg in node_zoom_positions]) | |
for a, b, a_mode, b_mode, bg, lw, opa, text, fsize, fcolor, ftype in node_links: | |
if node_zoom_positions[a._id][_rot] > node_zoom_positions[b._id][_rot]: | |
a, b = b, a | |
if b in set(a.get_ancestors()): ############ CACHE THIS! | |
b_mode = 0 | |
elif a in set(b.get_ancestors()): | |
a_mode = 0 | |
if not a.is_leaf() and a_mode == 1: | |
a_max_rad = 0 | |
a_min_rot = 360 | |
a_max_rot = 0 | |
for lf in a.iter_leaves(): | |
a_max_rad = max(a_max_rad, node_zoom_positions[lf._id][_rad]) | |
a_min_rot = min(a_min_rot, node_zoom_positions[lf._id][_astart]) | |
a_max_rot = max(a_max_rot, node_zoom_positions[lf._id][_aend]) | |
a1x, a1y = get_absolute_coords(a_max_rad, a_min_rot, cx, cy) | |
a2x, a2y = get_absolute_coords(a_max_rad, a_max_rot, cx, cy) | |
acx, acy = get_absolute_coords(a_max_rad, a_min_rot +(a_max_rot-a_min_rot)/2, cx, cy) | |
else: | |
a_pos = node_zoom_positions[a._id] | |
a_max_rad = a_pos[_rad] | |
a_min_rot = a_max_rot = a_pos[_rot] | |
a1x, a1y = get_absolute_coords(a_pos[_rad], a_pos[_rot], cx, cy) | |
a2x, a2y = a1x, a1y | |
acx, acy = a1x, a1y | |
if not b.is_leaf() and b_mode == 1: | |
b_max_rad = 0 | |
b_min_rot = 360 | |
b_max_rot = 0 | |
for lf in b.iter_leaves(): | |
b_max_rad = max(b_max_rad, node_zoom_positions[lf._id][_rad]) | |
b_min_rot = min(b_min_rot, node_zoom_positions[lf._id][_astart]) | |
b_max_rot = max(b_max_rot, node_zoom_positions[lf._id][_aend]) | |
b1x, b1y = get_absolute_coords(b_max_rad, b_min_rot, cx, cy) | |
b2x, b2y = get_absolute_coords(b_max_rad, b_max_rot, cx, cy) | |
bcx, bcy = get_absolute_coords(b_max_rad, b_min_rot + (b_max_rot-b_min_rot)/2, cx, cy) | |
else: | |
b_pos = node_zoom_positions[b._id] | |
b_max_rad = b_pos[_rad] | |
b_min_rot = b_max_rot = b_pos[_rot] | |
b1x, b1y = get_absolute_coords(b_pos[_rad], b_pos[_rot], cx, cy) | |
b2x, b2y = b1x, b1y | |
bcx, bcy = b1x, b1y | |
path = QPainterPath() | |
path.moveTo(a2x, a2y) | |
path.quadTo(cx, cy, b1x, b1y) | |
pp.setBrush(get_qbrush(None)) | |
pp.setPen(get_qpen(bg, lw, 0, Qt.FlatCap)) | |
if b1x != b2x or b1y != b2y: | |
path.arcTo(cx - b_max_rad, cy - b_max_rad, | |
b_max_rad*2, b_max_rad*2, | |
-b_min_rot, -(b_max_rot-b_min_rot)) | |
path.quadTo(cx, cy, a1x, a1y) | |
pp.setPen(get_qpen(bg, 0, 0, Qt.FlatCap)) | |
pp.setBrush(get_qbrush(bg)) | |
else: | |
path.quadTo(cx, cy, a1x, a1y) | |
if a1x != a2x or a1y != a2y: | |
path.arcTo(cx - a_max_rad, cy - a_max_rad, | |
a_max_rad*2, a_max_rad*2, | |
-a_min_rot, -(a_max_rot-a_min_rot)) | |
pp.setPen(get_qpen(bg, 0, 0, Qt.FlatCap)) | |
pp.setBrush(get_qbrush(bg)) | |
pp.setOpacity(opa) | |
pp.drawPath(path) | |
if bcx < acx: | |
acx, acy, bcx, bcy = bcx, bcy, acx, acy | |
txtpath = QPainterPath() | |
txtpath.moveTo(acx, acy) | |
txtpath.quadTo(cx, cy, bcx, bcy) | |
draw_text_in_path(pp, "Esto es una prueba muy muy larga para ver que pasa con las curvas", | |
txtpath, ftype, fcolor, fsize) | |
#draw_rings(pp, cx, cy, node_zoom_positions, node_links) | |
def draw_text_in_path(pp, text, follow_path, ftype, fcolor, fsize): | |
length = follow_path.length() | |
pp.setPen(get_qpen(fcolor)) | |
font = get_qfont(ftype, fsize, False) | |
pp.setFont(font) | |
fm = QFontMetrics(font) | |
text_width = fm.width(text) | |
# approx center text in path | |
current_length = (length/2) - (text_width/2) | |
for letter in text: | |
perc = follow_path.percentAtLength(current_length) | |
point = QPointF(follow_path.pointAtPercent(perc)) | |
angle = follow_path.angleAtPercent(perc) | |
current_length += fm.width(letter) | |
pp.save() | |
pp.translate(point) | |
pp.rotate(-angle) | |
pp.drawText(QPoint(0, 0), letter) | |
pp.restore() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
does not work alone, but this is the relevant code used under a different project to draw HGT events using ETE circular trees.
Examples and discussion here: etetoolkit/ete#161