Skip to content

Commit

Permalink
Show newick tree on pan-genome panel
Browse files Browse the repository at this point in the history
Still WIP
  • Loading branch information
drpowell committed Sep 5, 2018
1 parent fb972df commit ba0a4ec
Show file tree
Hide file tree
Showing 6 changed files with 92 additions and 32 deletions.
1 change: 1 addition & 0 deletions .gitignore
Expand Up @@ -3,6 +3,7 @@ pan.proteinortho
pan.strains
pan.js
pan.roary
pan.tree
mds-plot.js
mds-worker.js
gene-matrix.js
Expand Down
4 changes: 2 additions & 2 deletions pan.css
Expand Up @@ -85,7 +85,7 @@ body {
}

#colour-legend {
max-height: 100px;
max-height: 95px;
overflow: scroll;
}

Expand Down Expand Up @@ -182,7 +182,7 @@ circle.brushed,text.brushed { fill: red !important; font-weight: bold; }
}

#mds-bargraph {
margin: 10px 0 30px 0;
margin: 10px 0 10px 0;
}

#mds-bargraph .bar-chart .bar { fill: steelblue; }
Expand Down
4 changes: 4 additions & 0 deletions pan.html
Expand Up @@ -69,6 +69,10 @@ <h4>Index of FriPans</h4>
<option value="_fixed">Input order</option>
</select>
</div>
<div>
<label for='show-newick'>Newick Tree</label>
<input id='show-newick' type='checkbox' />
</div>
<div>
<label for="strain-colour">Strain colour:</label>
<select id="strain-colour">
Expand Down
9 changes: 9 additions & 0 deletions src/newick.coffee
Expand Up @@ -13,6 +13,15 @@ class Node
class Newick
constructor: (str) ->
@top = @parse(str)
@nodes = []
@flatten(@top, @nodes, 0)

flatten: (node, ret_nodes, depth) ->
node.dist ?= 0
node.depth = node.dist + depth
if !node.leaf()
node.children.forEach((c) => @flatten(c, ret_nodes, node.depth))
ret_nodes.push(node)

parse: (str) ->
toks = str.split(/([():,;])/).filter((s) -> s.length>0)
Expand Down
62 changes: 43 additions & 19 deletions src/pan-chart.coffee
Expand Up @@ -110,7 +110,7 @@ class PanChart
create_elems: () ->
tot_width = $(@elem).width()
tot_height = @bh * @matrix.strains().length + 200
margin = {top: 150, right: 10, bottom: 10, left: 140}
margin = {top: 150, right: 10, bottom: 10, left: 240}
margin2 = {top: 30, right: margin.right, bottom: tot_height - 100, left: margin.left}
@width = tot_width - margin.left - margin.right
@height = tot_height - margin.top - margin.bottom
Expand Down Expand Up @@ -213,9 +213,12 @@ class PanChart
.append("g")
.attr('class','label-scale')
.attr("transform", "scale(1,#{@vscale})")
# set up label area
@labels.attr('display','none')

# set up tree area
@tree_width = margin.left
@tree = @svg.append("g")
.attr("transform", "translate(#{margin.left-100},#{margin.top})")
.attr("transform", "translate(0,#{margin.top})")
.append("g")
.attr('class','label-scale')
.attr("transform", "scale(1,#{@vscale})")
Expand All @@ -238,6 +241,8 @@ class PanChart
@draw_boxes(@mini)
@draw_boxes(@focus)
@draw_labels(@labels)
if @tree_newick?
@draw_tree(@tree, @tree_newick)

# Collapse the 'off' regions in a set of boxes with x and len
collapse_off: (strain_id) ->
Expand Down Expand Up @@ -309,27 +314,32 @@ class PanChart
################################################################################
# Tree

_process_node: (node, ret_nodes) ->
node.dist ?= 0
set_tree: (tree) ->
@tree_newick = tree
@draw_tree(@tree, @tree_newick)

_set_node_y_pos: (node) ->
if node.leaf()
strain = @matrix.strains().filter((s) -> s.name == node.name)
if strain.length!=1
Util.log_warn("Expected to find 1 strain, found : ",strain)
node.y = 0
else
node.y = strain[0].pos
ret_nodes.push(node)
else
cs = node.children.forEach((c) => @_process_node(c, ret_nodes))
node.y = d3.mean(d3.extent(node.children.map((c) -> c.y)))
ret_nodes.push(node)

show_tree: (tree) ->
nodes = []
@_process_node(tree.top, nodes)
console.log "tree",tree,nodes
draw_tree: (elem, tree_newick) ->
if (!tree_newick?)
elem.html('')
return
nodes = tree_newick.nodes
nodes.forEach((n) => @_set_node_y_pos(n))
#console.log "nodes",nodes

x = (n) => 1000*n.dist
max_depth = d3.max(nodes.map((n) -> n.depth))
depth2x = d3.scale.linear().range([0, @tree_width-80]).domain([0, max_depth])
x = (n) => depth2x(n.depth)
y = (n) => (n.y+1)*@bh
node2line = (n) =>
res = []
Expand All @@ -339,23 +349,38 @@ class PanChart
res.push({x:x(n), y:y(c)})
res

bh = @bh
mk_line = d3.svg.line()
.x((d) -> d.x)
.y((d) -> d.y)
.y((d) -> d.y - bh/2)

# Draw the dendrogram
g = @tree
g.selectAll('path.link').remove()
g = elem
links = g.selectAll('path.link')
.data(nodes)
.data(nodes.filter((n) -> !n.leaf()))
links.exit().remove()
links.enter()
.append('path')
.attr('class', (d) -> 'link '+d.name)
.attr('class', 'link')
.attr("stroke", (d) -> "black") # d.colour)
.attr('d', (d) -> mk_line(node2line(d)))
# .on('mouseover', (d) => @_mouseover(node_info, d))
# .on('mouseout', (d) => @_mouseout(node_info, d))

lbls = g.selectAll('text.label')
.data(nodes.filter((n) -> n.children.length==0), (n) -> n.name)
lbls.exit().remove()
lbls.enter()
.append('text')
.attr('class', (n) => s=@strains.find_strain_by_name(n.name); "label strain-#{s.id}")
.attr('text-anchor','start')
.text((n) -> n.name)
.on("mouseover", (n) => s=@strains.find_strain_by_name(n.name); @highlight(s); @show_strain_info(s))
.on("mouseout", () => @unhighlight(); @show_strain_info(null))
lbls.transition()
.attr('y', (n) -> y(n) - 2)
.attr('x', (n) -> x(n))

################################################################################

# Draw the strain labels
Expand Down Expand Up @@ -426,7 +451,6 @@ class PanChart
@tooltip.style("display", "none")
return
info = @strains.find_strain_by_name(s.name)
window.xx = info
str = ""
for k,v of info
if k not in ['id','name']
Expand Down
44 changes: 33 additions & 11 deletions src/pan.coffee
Expand Up @@ -294,6 +294,31 @@ class Pan
@reorder_genes(sel)
)

$('#show-newick').on('change', (e) =>
if (!e.target.checked)
$('#strain-sort').removeAttr('disabled')
@sort_order = $('select#strain-sort option:selected').val()
@reorder()
@panChart.set_tree(null)
else
$('#strain-sort').attr('disabled','true')
@sort_order = '_off'
@mds.enable_sort(false)
tree = $('#show-newick').data()

# Sort strains by order in newick tree
strain_ids = {}
@strains.as_array().map((s) -> strain_ids[s.name] = s.id)
sort_order = []
tree.nodes.forEach((n) ->
if n.leaf()
sort_order.push(strain_ids[n.name])
)
@matrix.set_strain_order(sort_order)

@panChart.set_tree(tree)
)

@sort_order = $('select#strain-sort option:selected').val()
@panChart.draw_chart()
@reorder()
Expand Down Expand Up @@ -399,10 +424,8 @@ class Pan
@mds.enable_sort(true)
else if @sort_order=='_mds'
@mds.enable_sort('once')
else if @sort_order=='_tree'
@mds.enable_sort(false)
tree = $('select#strain-sort option:selected').data()
@panChart.show_tree(tree)
else if @sort_order=='_off'
#pass
else
@mds.enable_sort(false)
fld = @sort_order
Expand Down Expand Up @@ -528,6 +551,7 @@ load_desc = (matrix) ->
load_strains = (strainInfo) ->
d3.tsv("#{get_stem()}.strains", (data) ->
return if !data?
data = data.filter((s) -> s.ID) # Delete rows with no ID
strainInfo.set_info(data)

# Add a separator to the "select" groups
Expand Down Expand Up @@ -589,18 +613,16 @@ load_index = () ->
)

load_tree = () ->
$('#show-newick').hide()
d3.text("#{get_stem()}.tree", (data) ->
return if !data?
tree = new Newick.Newick(data)
Util.log_info("Loaded tree :\n#{tree.top.to_string()}")

# Add a separator to the "select" groups
$('select#strain-sort').append("<option disabled>──────────</option>")

# Add a selector for each column of strain info
opt = $("<option value='_tree'>Tree</option>")
$('select#strain-sort').append(opt)
opt.data(tree)
$('#show-newick').show()
$('#show-newick').data(tree)
$('#show-newick').prop('checked', true)
$("#show-newick").trigger("change")
)

setup_download = (sel) ->
Expand Down

0 comments on commit ba0a4ec

Please sign in to comment.