diff options
Diffstat (limited to 'wqflask/wqflask/static/new/javascript/manhattan_plot.coffee')
-rw-r--r-- | wqflask/wqflask/static/new/javascript/manhattan_plot.coffee | 534 |
1 files changed, 534 insertions, 0 deletions
diff --git a/wqflask/wqflask/static/new/javascript/manhattan_plot.coffee b/wqflask/wqflask/static/new/javascript/manhattan_plot.coffee new file mode 100644 index 00000000..492c2f3f --- /dev/null +++ b/wqflask/wqflask/static/new/javascript/manhattan_plot.coffee @@ -0,0 +1,534 @@ +lodchart = () ->
+ width = 800
+ height = 500
+ margin = {left:60, top:40, right:40, bottom: 40, inner:5}
+ axispos = {xtitle:25, ytitle:30, xlabel:5, ylabel:5}
+ titlepos = 20
+ ylim = null
+ nyticks = 5
+ yticks = null
+ chrGap = 8
+ darkrect = "#F1F1F9"
+ lightrect = "#FBFBFF"
+ lodlinecolor = "darkslateblue"
+ linewidth = 2
+ pointcolor = "darkslateblue" # pink
+ pointhover = "#E9CFEC" # pink
+ pointsize = 2 # default = no visible points at markers
+ pointstroke = "black"
+ title = ""
+ xlab = "Chromosome"
+ ylab = "LOD score"
+ rotate_ylab = null
+ yscale = d3.scale.linear()
+ xscale = null
+ pad4heatmap = false
+ lodcurve = null
+ lodvarname = null
+ markerSelect = null
+ chrSelect = null
+ pointsAtMarkers = true
+
+ ## the main function
+ chart = (selection) ->
+ selection.each (data) ->
+
+ console.log("data:", data)
+
+ lodvarname = lodvarname ? data.lodnames[0]
+ data[lodvarname] = (Math.abs(x) for x in data[lodvarname]) # take absolute values
+ ylim = ylim ? [0, d3.max(data[lodvarname])]
+ lodvarnum = data.lodnames.indexOf(lodvarname)
+
+ # Select the svg element, if it exists.
+ svg = d3.select(this).selectAll("svg").data([data])
+
+ # Otherwise, create the skeletal chart.
+ gEnter = svg.enter().append("svg").append("g")
+
+ # Update the outer dimensions.
+ svg.attr("width", width+margin.left+margin.right)
+ .attr("height", height+margin.top+margin.bottom)
+
+ # Update the inner dimensions.
+ g = svg.select("g")
+
+ # box
+ g.append("rect")
+ .attr("x", margin.left)
+ .attr("y", margin.top)
+ .attr("height", height)
+ .attr("width", width)
+ .attr("fill", darkrect)
+ .attr("stroke", "none")
+
+ yscale.domain(ylim)
+ .range([height+margin.top, margin.top+margin.inner])
+
+ # if yticks not provided, use nyticks to choose pretty ones
+ yticks = yticks ? yscale.ticks(nyticks)
+
+ # reorganize lod,pos by chromosomes
+ data = reorgLodData(data, lodvarname)
+
+ # add chromosome scales (for x-axis)
+ data = chrscales(data, width, chrGap, margin.left, pad4heatmap)
+ xscale = data.xscale
+
+ # chr rectangles
+ chrSelect =
+ g.append("g").attr("class", "chrRect")
+ .selectAll("empty")
+ .data(data.chrnames)
+ .enter()
+ .append("rect")
+ .attr("id", (d) -> "chrrect#{d[0]}")
+ .attr("x", (d,i) ->
+ return data.chrStart[i] if i==0 and pad4heatmap
+ data.chrStart[i]-chrGap/2)
+ .attr("width", (d,i) ->
+ return data.chrEnd[i] - data.chrStart[i]+chrGap/2 if (i==0 or i+1 == data.chrnames.length) and pad4heatmap
+ data.chrEnd[i] - data.chrStart[i]+chrGap)
+ .attr("y", margin.top)
+ .attr("height", height)
+ .attr("fill", (d,i) ->
+ return darkrect if i % 2
+ lightrect)
+ .attr("stroke", "none")
+ .on("click", (d) ->
+ redraw_plot(d)
+ )
+
+ # x-axis labels
+ xaxis = g.append("g").attr("class", "x axis")
+ xaxis.selectAll("empty")
+ .data(data.chrnames)
+ .enter()
+ .append("text")
+ .attr("class", "chr_label")
+ .text((d) -> d[0])
+ .attr("x", (d,i) -> (data.chrStart[i]+data.chrEnd[i])/2)
+ .attr("y", margin.top+height+axispos.xlabel)
+ .attr("cursor", "pointer")
+ .on("click", (d) ->
+ redraw_plot(d)
+ )
+
+ xaxis.append("text").attr("class", "title")
+ .attr("y", margin.top+height+axispos.xtitle)
+ .attr("x", margin.left+width/2)
+ .text(xlab)
+
+ redraw_plot = (chr_ob) ->
+ console.log("chr_name is:", chr_ob[0])
+ console.log("chr_length is:", chr_ob[1])
+ $('#topchart').remove()
+ $('#chart_container').append('<div class="qtlcharts" id="topchart"></div>')
+ chr_plot = new Chr_Manhattan_Plot(600, 1200, chr_ob)
+
+
+ # y-axis
+ rotate_ylab = rotate_ylab ? (ylab.length > 1)
+ yaxis = g.append("g").attr("class", "y axis")
+ yaxis.selectAll("empty")
+ .data(yticks)
+ .enter()
+ .append("line")
+ .attr("y1", (d) -> yscale(d))
+ .attr("y2", (d) -> yscale(d))
+ .attr("x1", margin.left)
+ .attr("x2", margin.left+7)
+ .attr("fill", "none")
+ .attr("stroke", "white")
+ .attr("stroke-width", 1)
+ .style("pointer-events", "none")
+
+ yaxis.selectAll("empty")
+ .data(yticks)
+ .enter()
+ .append("text")
+ .attr("y", (d) -> yscale(d))
+ .attr("x", margin.left-axispos.ylabel)
+ .attr("fill", "blue")
+ .text((d) -> formatAxis(yticks)(d))
+
+ yaxis.append("text").attr("class", "title")
+ .attr("y", margin.top+height/2)
+ .attr("x", margin.left-axispos.ytitle)
+ .text(ylab)
+ .attr("transform", if rotate_ylab then "rotate(270,#{margin.left-axispos.ytitle},#{margin.top+height/2})" else "")
+
+ # lod curves by chr
+ #lodcurve = (chr, lodcolumn) ->
+ # d3.svg.line()
+ # .x((d) -> xscale[chr](d))
+ # .y((d,i) -> yscale(data.lodByChr[chr][i][lodcolumn]))
+
+ #add_plot_points: () ->
+ # @plot_point = @svg.selectAll("circle")
+ # .data(@plot_coordinates)
+ # .enter()
+ # .append("circle")
+ # .attr("cx", (d) =>
+ # return @x_scale(d[0])
+ # )
+ # .attr("cy", (d) =>
+ # return @y_scale(d[1])
+ # )
+ # .attr("r", (d) =>
+ # #if d[1] > 3
+ # # return 3
+ # #else
+ # return 2
+ # )
+ # .attr("fill", (d) =>
+ # #if d[1] > 3
+ # # return "white"
+ # #else
+ # return "black"
+ # )
+ # .attr("stroke", "black")
+ # .attr("stroke-width", "1")
+ # .attr("id", (d) =>
+ # return "point_" + String(d[2])
+ # )
+ # .classed("circle", true)
+ # .on("mouseover", (d) =>
+ # console.log("d3.event is:", d3.event)
+ # console.log("d is:", d)
+ # this_id = "point_" + String(d[2])
+ # d3.select("#" + this_id).classed("d3_highlight", true)
+ # .attr("r", 5)
+ # .attr("stroke", "none")
+ # .attr("fill", "blue")
+ # .call(@show_marker_in_table(d))
+ # )
+ # .on("mouseout", (d) =>
+ # this_id = "point_" + String(d[2])
+ # d3.select("#" + this_id).classed("d3_highlight", false)
+ # .attr("r", (d) =>
+ # #if d[1] > 2
+ # # return 3
+ # #else
+ # return 2
+ # )
+ # .attr("fill", (d) =>
+ # #if d[1] > 2
+ # # return "white"
+ # #else
+ # return "black"
+ # )
+ # .attr("stroke", "black")
+ # .attr("stroke-width", "1")
+ # )
+ # .append("svg:title")
+ # .text((d) =>
+ # return d[2]
+ # )
+
+ #curves = g.append("g").attr("id", "curves")
+
+ #for chr in data.chrnames
+ # curves.append("path")
+ # .datum(data.posByChr[chr])
+ # .attr("d", lodcurve(chr, lodvarnum))
+ # .attr("stroke", lodlinecolor)
+ # .attr("fill", "none")
+ # .attr("stroke-width", linewidth)
+ # .style("pointer-events", "none")
+
+ # points at markers
+ if pointsize > 0
+ markerpoints = g.append("g").attr("id", "markerpoints_visible")
+ markerpoints.selectAll("empty")
+ .data(data.markers)
+ .enter()
+ .append("circle")
+ .attr("cx", (d) -> xscale[d.chr](d.pos))
+ .attr("cy", (d) -> yscale(d.lod))
+ .attr("r", pointsize)
+ .attr("fill", pointcolor)
+ .attr("stroke", pointstroke)
+ .attr("pointer-events", "hidden")
+
+ # title
+ titlegrp = g.append("g").attr("class", "title")
+ .append("text")
+ .attr("x", margin.left+width/2)
+ .attr("y", margin.top-titlepos)
+ .text(title)
+
+ # another box around edge
+ g.append("rect")
+ .attr("x", margin.left)
+ .attr("y", margin.top)
+ .attr("height", height)
+ .attr("width", () ->
+ return(data.chrEnd[-1..][0]-margin.left) if pad4heatmap
+ data.chrEnd[-1..][0]-margin.left+chrGap/2)
+ .attr("fill", "none")
+ .attr("stroke", "black")
+ .attr("stroke-width", "none")
+
+ if pointsAtMarkers
+ # these hidden points are what gets selected...a bit larger
+ hiddenpoints = g.append("g").attr("id", "markerpoints_hidden")
+
+ markertip = d3.tip()
+ .attr('class', 'd3-tip')
+ .html((d) ->
+ [d.name, " LRS = #{d3.format('.2f')(d.lod)}"])
+ .direction("e")
+ .offset([0,10])
+ svg.call(markertip)
+
+ markerSelect =
+ hiddenpoints.selectAll("empty")
+ .data(data.markers)
+ .enter()
+ .append("circle")
+ .attr("cx", (d) -> xscale[d.chr](d.pos))
+ .attr("cy", (d) -> yscale(d.lod))
+ .attr("id", (d) -> d.name)
+ .attr("r", d3.max([pointsize*2, 3]))
+ .attr("opacity", 0)
+ .attr("fill", pointhover)
+ .attr("stroke", pointstroke)
+ .attr("stroke-width", "1")
+ .on "mouseover.paneltip", (d) ->
+ d3.select(this).attr("opacity", 1)
+ markertip.show(d)
+ .on "mouseout.paneltip", ->
+ d3.select(this).attr("opacity", 0)
+ .call(markertip.hide)
+
+ ## configuration parameters
+ chart.width = (value) ->
+ return width unless arguments.length
+ width = value
+ chart
+
+ chart.height = (value) ->
+ return height unless arguments.length
+ height = value
+ chart
+
+ chart.margin = (value) ->
+ return margin unless arguments.length
+ margin = value
+ chart
+
+ chart.titlepos = (value) ->
+ return titlepos unless arguments.length
+ titlepos
+ chart
+
+ chart.axispos = (value) ->
+ return axispos unless arguments.length
+ axispos = value
+ chart
+
+ chart.ylim = (value) ->
+ return ylim unless arguments.length
+ ylim = value
+ chart
+
+ chart.nyticks = (value) ->
+ return nyticks unless arguments.length
+ nyticks = value
+ chart
+
+ chart.yticks = (value) ->
+ return yticks unless arguments.length
+ yticks = value
+ chart
+
+ chart.chrGap = (value) ->
+ return chrGap unless arguments.length
+ chrGap = value
+ chart
+
+ chart.darkrect = (value) ->
+ return darkrect unless arguments.length
+ darkrect = value
+ chart
+
+ chart.lightrect = (value) ->
+ return lightrect unless arguments.length
+ lightrect = value
+ chart
+
+ chart.linecolor = (value) ->
+ return linecolor unless arguments.length
+ linecolor = value
+ chart
+
+ chart.linewidth = (value) ->
+ return linewidth unless arguments.length
+ linewidth = value
+ chart
+
+ chart.pointcolor = (value) ->
+ return pointcolor unless arguments.length
+ pointcolor = value
+ chart
+
+ chart.pointhover = (value) ->
+ return pointhover unless arguments.length
+ pointhover = value
+ chart
+
+ chart.pointsize = (value) ->
+ return pointsize unless arguments.length
+ pointsize = value
+ chart
+
+ chart.pointstroke = (value) ->
+ return pointstroke unless arguments.length
+ pointstroke = value
+ chart
+
+ chart.title = (value) ->
+ return title unless arguments.length
+ title = value
+ chart
+
+ chart.xlab = (value) ->
+ return xlab unless arguments.length
+ xlab = value
+ chart
+
+ chart.ylab = (value) ->
+ return ylab unless arguments.length
+ ylab = value
+ chart
+
+ chart.rotate_ylab = (value) ->
+ return rotate_ylab if !arguments.length
+ rotate_ylab = value
+ chart
+
+ chart.lodvarname = (value) ->
+ return lodvarname unless arguments.length
+ lodvarname = value
+ chart
+
+ chart.pad4heatmap = (value) ->
+ return pad4heatmap unless arguments.length
+ pad4heatmap = value
+ chart
+
+ chart.pointsAtMarkers = (value) ->
+ return pointsAtMarkers unless arguments.length
+ pointsAtMarkers = value
+ chart
+
+ chart.yscale = () ->
+ return yscale
+
+ chart.xscale = () ->
+ return xscale
+
+ #chart.lodcurve = () ->
+ # return lodcurve
+
+ chart.markerSelect = () ->
+ return markerSelect
+
+ chart.chrSelect = () ->
+ return chrSelect
+
+ # return the chart function
+ chart
+
+
+# reorganize lod/pos by chromosome
+# lodvarname==null -> case for multiple LOD columns (lodheatmap)
+# lodvarname provided -> case for one LOD column (lodchart)
+reorgLodData = (data, lodvarname=null) ->
+ data.posByChr = {}
+ data.lodByChr = {}
+
+ for chr,i in data.chrnames
+ data.posByChr[chr[0]] = []
+ data.lodByChr[chr[0]] = []
+ for pos, j in data.pos
+ if data.chr[j] == chr[0]
+ data.posByChr[chr[0]].push(pos)
+ data.lodnames = [data.lodnames] unless Array.isArray(data.lodnames)
+ lodval = (data[lodcolumn][j] for lodcolumn in data.lodnames)
+ data.lodByChr[chr[0]].push(lodval)
+
+
+ if lodvarname?
+ data.markers = []
+ for marker,i in data.markernames
+ if marker != ""
+ data.markers.push({name:marker, chr:data.chr[i], pos:data.pos[i], lod:data[lodvarname][i]})
+
+ data
+
+
+# calculate chromosome start/end + scales, for heat map
+chrscales = (data, width, chrGap, leftMargin, pad4heatmap) ->
+ # start and end of chromosome positions
+ chrStart = []
+ chrEnd = []
+ chrLength = []
+ totalChrLength = 0
+ maxd = 0
+ for chr in data.chrnames
+ d = maxdiff(data.posByChr[chr[0]])
+ maxd = d if d > maxd
+
+ rng = d3.extent(data.posByChr[chr[0]])
+ chrStart.push(rng[0])
+ chrEnd.push(rng[1])
+ L = rng[1] - rng[0]
+ chrLength.push(L)
+ totalChrLength += L
+
+ # adjust lengths for heatmap
+ if pad4heatmap
+ data.recwidth = maxd
+ chrStart = chrStart.map (x) -> x-maxd/2
+ chrEnd = chrEnd.map (x) -> x+maxd/2
+ chrLength = chrLength.map (x) -> x+maxd
+ totalChrLength += (chrLength.length*maxd)
+
+ # break up x axis into chromosomes by length, with gaps
+ data.chrStart = []
+ data.chrEnd = []
+ cur = leftMargin
+ cur += chrGap/2 unless pad4heatmap
+ data.xscale = {}
+ for chr,i in data.chrnames
+ data.chrStart.push(cur)
+ w = Math.round((width-chrGap*(data.chrnames.length-pad4heatmap))/totalChrLength*chrLength[i])
+ data.chrEnd.push(cur + w)
+ cur = data.chrEnd[i] + chrGap
+ # x-axis scales, by chromosome
+ data.xscale[chr[0]] = d3.scale.linear()
+ .domain([chrStart[i], chrEnd[i]])
+ .range([data.chrStart[i], data.chrEnd[i]])
+
+ # return data with new stuff added
+ data
+
+# maximum difference between adjacent values in a vector
+maxdiff = (x) ->
+ return null if x.length < 2
+ result = x[1] - x[0]
+ return result if x.length < 3
+ for i in [2...x.length]
+ d = x[i] - x[i-1]
+ result = d if d > result
+ result
+
+# determine rounding of axis labels
+formatAxis = (d) ->
+ d = d[1] - d[0]
+ ndig = Math.floor( Math.log(d % 10) / Math.log(10) )
+ ndig = 0 if ndig > 0
+ ndig = Math.abs(ndig)
+ d3.format(".#{ndig}f")
|