mirror of
https://github.com/galaxyproject/galaxy.git
synced 2026-09-24 16:30:27 +08:00
Automated merge with https://bitbucket.org/galaxy/galaxy-central
This commit is contained in:
@@ -12,7 +12,7 @@ repository = http://eggs.g2.bx.psu.edu
|
||||
no_auto = pbs_python DRMAA_python
|
||||
|
||||
[eggs:platform]
|
||||
bx_python = 0.7.0
|
||||
bx_python = 0.7.1
|
||||
Cheetah = 2.2.2
|
||||
ctypes = 1.0.2
|
||||
DRMAA_python = 0.2
|
||||
@@ -67,7 +67,7 @@ Whoosh = 0.3.18
|
||||
psycopg2 = _8.4.2_static
|
||||
pysqlite = _3.6.17_static
|
||||
MySQL_python = _5.1.41_static
|
||||
bx_python = _494c2d1d68b3_rebuild1
|
||||
bx_python = _7b95ff194725
|
||||
GeneTrack = _dev_48da9e998f0caf01c5be731e926f4b0481f658f0
|
||||
SQLAlchemy = _dev_r6498
|
||||
pysam = _kanwei_b10f6e722e9a
|
||||
|
||||
@@ -50,4 +50,4 @@ def main():
|
||||
st.write(out_fname)
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
main()
|
||||
|
||||
@@ -2,14 +2,15 @@
|
||||
Data providers for tracks visualizations.
|
||||
"""
|
||||
|
||||
import sys
|
||||
from math import ceil, log
|
||||
import sys, time
|
||||
from math import ceil, log, sqrt
|
||||
import pkg_resources
|
||||
pkg_resources.require( "bx-python" )
|
||||
if sys.version_info[:2] == (2, 4):
|
||||
pkg_resources.require( "ctypes" )
|
||||
pkg_resources.require( "pysam" )
|
||||
pkg_resources.require( "numpy" )
|
||||
import numpy
|
||||
from galaxy.datatypes.util.gff_util import *
|
||||
from galaxy.util.json import from_json_string
|
||||
from bx.interval_index_file import Indexes
|
||||
@@ -740,40 +741,73 @@ class BBIDataProvider( TracksDataProvider ):
|
||||
# Bigwig has the possibility of it being a standalone bigwig file, in which case we use
|
||||
# original_dataset, or coming from wig->bigwig conversion in which we use converted_dataset
|
||||
f, bbi = self._get_dataset()
|
||||
|
||||
|
||||
# If the stats kwarg was provide, we compute overall summary data for
|
||||
# the entire chromosome, but no reduced data -- currently only
|
||||
# providing values used by trackster to determine the default range
|
||||
if 'stats' in kwargs:
|
||||
all_dat = bbi.query(chrom, 0, 2147483647, 1)
|
||||
# FIXME: use actual chromosome size
|
||||
summary = bbi.summarize( chrom, 0, 214783647, 1 )
|
||||
f.close()
|
||||
if all_dat is None:
|
||||
if summary is None:
|
||||
return None
|
||||
|
||||
all_dat = all_dat[0] # only 1 summary
|
||||
return { 'data' : { 'max': float( all_dat['max'] ), \
|
||||
'min': float( all_dat['min'] ), \
|
||||
'total_frequency': float( all_dat['coverage'] ) } \
|
||||
}
|
||||
|
||||
else:
|
||||
# Does the summary contain any defined values?
|
||||
valid_count = summary.valid_count[0]
|
||||
if summary.valid_count < 1:
|
||||
return None
|
||||
|
||||
# Compute $\mu \pm 2\sigma$ to provide an estimate for upper and lower
|
||||
# bounds that contain ~95% of the data.
|
||||
mean = summary.sum_data[0] / valid_count
|
||||
var = summary.sum_squares[0] - mean
|
||||
if valid_count > 1:
|
||||
var /= valid_count - 1
|
||||
sd = numpy.sqrt( var )
|
||||
|
||||
return dict( data=dict( min=summary.min_val[0], max=summary.max_val[0], mean=mean, sd=sd ) )
|
||||
|
||||
start = int(start)
|
||||
end = int(end)
|
||||
|
||||
# The following seems not to work very well, for example it will only return one
|
||||
# data point if the tile is 1280px wide. Not sure what the intent is.
|
||||
|
||||
# The first zoom level for BBI files is 640. If too much is requested, it will look at each block instead
|
||||
# of summaries. The calculation done is: zoom <> (end-start)/num_points/2.
|
||||
# Thus, the optimal number of points is (end-start)/num_points/2 = 640
|
||||
# num_points = (end-start) / 1280
|
||||
num_points = (end-start) / 1280
|
||||
if num_points < 1:
|
||||
num_points = end - start
|
||||
else:
|
||||
num_points = min(num_points, 500)
|
||||
#num_points = (end-start) / 1280
|
||||
#if num_points < 1:
|
||||
# num_points = end - start
|
||||
#else:
|
||||
# num_points = min(num_points, 500)
|
||||
|
||||
data = bbi.query(chrom, start, end, num_points)
|
||||
# For now, we'll do 1000 data points by default However, the summaries
|
||||
# don't seem to work when a summary pixel corresponds to less than one
|
||||
# datapoint, so we prevent that.
|
||||
# FIXME: need to switch over to using the full data at high levels of
|
||||
# detail.
|
||||
num_points = min( 1000, end - start )
|
||||
|
||||
summary = bbi.summarize( chrom, start, end, num_points )
|
||||
f.close()
|
||||
|
||||
pos = start
|
||||
step_size = (end - start) / num_points
|
||||
|
||||
result = []
|
||||
if data:
|
||||
for dat_dict in data:
|
||||
result.append( (pos, float_nan(dat_dict['mean']) ) )
|
||||
|
||||
if summary:
|
||||
mean = summary.sum_data / summary.valid_count
|
||||
|
||||
## Standard deviation by bin, not yet used
|
||||
## var = summary.sum_squares - mean
|
||||
## var /= minimum( valid_count - 1, 1 )
|
||||
## sd = sqrt( var )
|
||||
|
||||
pos = start
|
||||
step_size = (end - start) / num_points
|
||||
|
||||
for i in range( num_points ):
|
||||
result.append( (pos, float_nan( mean[i] ) ) )
|
||||
pos += step_size
|
||||
|
||||
return { 'data': result }
|
||||
|
||||
@@ -528,6 +528,7 @@ class TracksController( BaseUIController, UsesVisualization, UsesHistoryDatasetA
|
||||
if not standalone_provider.has_data( chrom ):
|
||||
return messages.NO_DATA
|
||||
valid_chroms = standalone_provider.valid_chroms()
|
||||
|
||||
|
||||
# Have data if we get here
|
||||
return { "status": messages.DATA, "valid_chroms": valid_chroms }
|
||||
@@ -1041,4 +1042,4 @@ def _get_highest_priority_msg( message_list ):
|
||||
return_message = message
|
||||
elif return_message == None and message == messages.PENDING:
|
||||
return_message = message
|
||||
return return_message
|
||||
return return_message
|
||||
|
||||
@@ -231,6 +231,10 @@ div.form-row-error-message {
|
||||
padding: 3px 0 0 1em;
|
||||
}
|
||||
|
||||
.form-row .help {
|
||||
color: #666;
|
||||
}
|
||||
|
||||
select, input, textarea {
|
||||
font: inherit;
|
||||
}
|
||||
|
||||
@@ -43,6 +43,7 @@ div.form-row label.inline{display:inline;}
|
||||
div.form-row-input{float:left;}
|
||||
div.form-row-input label{font-weight:normal;display:inline;}
|
||||
div.form-row-error-message{width:300px;float:left;color:red;font-weight:bold;padding:3px 0 0 1em;}
|
||||
.form-row .help{color:#666;}
|
||||
select,input,textarea{font:inherit;}
|
||||
select,textarea,input[type="text"],input[type="file"],input[type="password"]{-webkit-box-sizing:border-box;max-width:300px;}
|
||||
.errormessagelarge,.warningmessagelarge,.donemessagelarge,.infomessagelarge{padding:10px;padding-left:52px;min-height:32px;border:1px solid #AA6666;background-color:#FFCCCC;background-image:url(error_message_icon.png);background-repeat:no-repeat;background-position:10px 10px;}
|
||||
|
||||
@@ -23,9 +23,11 @@ div.unified-panel-body{position:absolute;top:2em;bottom:0;width:100%;margin-top:
|
||||
.panel-header-button:hover{color:black;background-color:#ccc;}
|
||||
.panel-header-button:active{color:white;background-color:#aaaaaa;}
|
||||
#overlay{position:fixed;top:0;left:0;width:100%;height:100%;z-index:20000;}
|
||||
#overlay.modal #overlay-background{background:rgba(0,0,0,0.5);}
|
||||
.dialog-box-container{position:relative;margin-top:80px;margin-right:auto;margin-left:auto;}
|
||||
.dialog-box-wrapper{position:relative;padding:1em;background-color:rgba(0,0,0,0.5);-moz-border-radius:1em;-webkit-border-radius:1em;}
|
||||
.dialog-box{border:solid #999 1px;background:white;z-index:80000;}
|
||||
#overlay.modal .dialog-box .body{min-width:600px;}
|
||||
.dialog-box .body{padding:5px;overflow:auto;max-height:500px;min-width:300px;}
|
||||
.dialog-box .buttons{padding:5px;}
|
||||
.panel-error-message,.panel-warning-message,.panel-done-message,.panel-info-message{height:24px;line-height:24px;color:#303030;padding:0px;padding-left:26px;background-color:#FFCCCC;background-image:url(error_small.png);background-repeat:no-repeat;background-position:6px 50%;}
|
||||
|
||||
@@ -3,30 +3,9 @@
|
||||
.content{font:10px verdana;}
|
||||
.nav-controls{text-align:center;padding:1px 0;}
|
||||
.nav-controls input{margin:0 5px;}
|
||||
.menu-button{padding: 0px 4px 0px 4px;}
|
||||
#zoom-in,#zoom-out{display:inline-block;height:16px;width:16px;margin-bottom:-3px;cursor:pointer;}
|
||||
#zoom-out{background:transparent url(../images/fugue/magnifier-zoom-out.png) center center no-repeat;}
|
||||
#zoom-in{margin-left:10px;background:transparent url(../images/fugue/magnifier-zoom.png) center center no-repeat;}
|
||||
.overview-icon{background:transparent url(../images/fugue/application-dock-270-bw.png) no-repeat;}
|
||||
.overview-icon:hover{background:transparent url(../images/fugue/application-dock-270.png) no-repeat;}
|
||||
.settings-icon{background:transparent url(../images/fugue/gear-bw.png) no-repeat;}
|
||||
.settings-icon:hover{background:transparent url(../images/fugue/gear.png) no-repeat;}
|
||||
.tools-icon{background:transparent url(../images/fugue/toolbox-bw.png) no-repeat;}
|
||||
.tools-icon:hover{background:transparent url(../images/fugue/toolbox.png) no-repeat;}
|
||||
.filters-icon{background:transparent url(../images/fugue/ui-slider-050-bw.png) no-repeat;}
|
||||
.filters-icon:hover{background:transparent url(../images/fugue/ui-slider-050.png) no-repeat;}
|
||||
.remove-icon,.overview-close{background:transparent url(../images/fugue/cross-small-bw.png) no-repeat;}
|
||||
.remove-icon:hover,.overview-close:hover{background:transparent url(../images/fugue/cross-circle.png) no-repeat;}
|
||||
#close-icon{background:transparent url(../images/fugue/cross-circle-bw.png) no-repeat;margin-right:0px;}
|
||||
#close-icon:hover{background:transparent url(../images/fugue/cross-circle.png) no-repeat;}
|
||||
#add-tracks-icon{background:transparent url(../images/fugue/plus-button-bw.png) no-repeat;}
|
||||
#add-tracks-icon:hover{background:transparent url(../images/fugue/plus-button.png) no-repeat;}
|
||||
#add-group-icon{background:transparent url(../images/fugue/block--plus-bw.png) no-repeat;}
|
||||
#add-group-icon:hover{background:transparent url(../images/fugue/block--plus.png) no-repeat;}
|
||||
#bookmarks-icon{background:transparent url(../images/fugue/bookmarks-bw.png) no-repeat;}
|
||||
#bookmarks-icon:hover{background:transparent url(../images/fugue/bookmarks.png) no-repeat;}
|
||||
#save-icon{background:transparent url(../images/fugue/disk--arrow-bw.png) no-repeat;}
|
||||
#save-icon:hover{background:transparent url(../images/fugue/disk--arrow.png) no-repeat;}
|
||||
.nav-input{font-size:12px;width:30em;z-index:1000;}
|
||||
.location{display:inline-block;width:15em;margin:0 10px;}
|
||||
.draghandle{margin-top:2px;cursor:move;float:left;background:transparent url(../images/visualization/draggable_horizontal.png) center center no-repeat;width:10px;height:12px;}
|
||||
@@ -65,16 +44,39 @@
|
||||
input{font:10px verdana;}
|
||||
.dynamic-tool,.filters{margin-left:0.25em;padding-bottom:0.5em;}
|
||||
.dynamic-tool{width:410px;}
|
||||
.filters>.sliders,.display-controls{float:left;margin:1em;}
|
||||
.filters > .sliders,.display-controls{float:left;margin:1em;}
|
||||
.sliders{width:410px;}
|
||||
.display-controls{border-left:solid 2px #DDDDDD;padding-left:1em}
|
||||
.filter-row{margin-top:0.4em;}
|
||||
.display-controls{border-left:solid 2px #DDDDDD;padding-left:1em
|
||||
}
|
||||
.filter-row {
|
||||
margin-top:0.4em;}
|
||||
.slider-row{margin-left:1em;}
|
||||
.elt-label{float:left;font-weight:bold;margin-right:1em;}
|
||||
.slider{float:right;width:200px;position:relative;}
|
||||
.tool-name{font-size:110%;font-weight:bold;}
|
||||
.param-row{margin-top:0.2em;margin-left:1em;}
|
||||
.param-label{float:left;font-weight:bold;padding-top:0.2em;}
|
||||
.menu-button{padding:0px 4px 0px 4px;}
|
||||
.settings-icon{background:transparent url(../images/fugue/gear-bw.png) no-repeat;}
|
||||
.settings-icon:hover{background:transparent url(../images/fugue/gear.png) no-repeat;}
|
||||
.overview-icon{background:transparent url(../images/fugue/application-dock-270-bw.png) no-repeat;}
|
||||
.overview-icon:hover{background:transparent url(../images/fugue/application-dock-270.png) no-repeat;}
|
||||
.tools-icon{background:transparent url(../images/fugue/toolbox-bw.png) no-repeat;}
|
||||
.tools-icon:hover{background:transparent url(../images/fugue/toolbox.png) no-repeat;}
|
||||
.filters-icon{background:transparent url(../images/fugue/ui-slider-050-bw.png) no-repeat;}
|
||||
.filters-icon:hover{background:transparent url(../images/fugue/ui-slider-050.png) no-repeat;}
|
||||
.remove-icon,.overview-close{background:transparent url(../images/fugue/cross-small-bw.png) no-repeat;}
|
||||
.remove-icon:hover,.overview-close:hover{background:transparent url(../images/fugue/cross-circle.png) no-repeat;}
|
||||
#close-icon{background:transparent url(../images/fugue/cross-circle-bw.png) no-repeat;margin-right:0px;}
|
||||
#close-icon:hover{background:transparent url(../images/fugue/cross-circle.png) no-repeat;}
|
||||
#add-tracks-icon{background:transparent url(../images/fugue/plus-button-bw.png) no-repeat;}
|
||||
#add-tracks-icon:hover{background:transparent url(../images/fugue/plus-button.png) no-repeat;}
|
||||
#add-group-icon{background:transparent url(../images/fugue/block--plus-bw.png) no-repeat;}
|
||||
#add-group-icon:hover{background:transparent url(../images/fugue/block--plus.png) no-repeat;}
|
||||
#bookmarks-icon{background:transparent url(../images/fugue/bookmarks-bw.png) no-repeat;}
|
||||
#bookmarks-icon:hover{background:transparent url(../images/fugue/bookmarks.png) no-repeat;}
|
||||
#save-icon{background:transparent url(../images/fugue/disk--arrow-bw.png) no-repeat;}
|
||||
#save-icon:hover{background:transparent url(../images/fugue/disk--arrow.png) no-repeat;}
|
||||
.child-track-icon{background:url('../images/fugue/arrow-000-small-bw.png') no-repeat;width:30px;cursor:move;}
|
||||
.track-resize{background:white url('../images/visualization/draggable_vertical.png') no-repeat top center;position:absolute;right:3px;bottom:-4px;width:14px;height:7px;border:solid #999 1px;z-index:100;}
|
||||
.bookmark{background:white;border:solid #999 1px;border-right:none;margin:0.5em;margin-right:0;padding:0.5em;}
|
||||
@@ -85,4 +87,5 @@ input{font:10px verdana;}
|
||||
.icon.more-across{background:url('../images/fugue/arrow-transition-bw.png') no-repeat 0px 0px;}
|
||||
.intro{padding:1em;}
|
||||
.intro > .action-button{background-color:#CCC;padding:1em;}
|
||||
.feature-popup{background-color:#DDD;position:absolute;z-index:1000}
|
||||
.feature-popup{position:absolute;z-index:1000;padding:5px;font-size:10px;filter:alpha(opacity=80);background-repeat:no-repeat;background-image:url(../images/tipsy.gif);background-position:top center;}
|
||||
.feature-popup-inner{padding:5px 8px 4px 8px;background-color:black;color:white;}
|
||||
|
||||
@@ -161,6 +161,10 @@ div.unified-panel-body {
|
||||
z-index: 20000;
|
||||
}
|
||||
|
||||
#overlay.modal #overlay-background {
|
||||
background: rgba(0,0,0,0.5);
|
||||
}
|
||||
|
||||
.dialog-box-container {
|
||||
position: relative;
|
||||
margin-top: 80px;
|
||||
@@ -182,6 +186,10 @@ div.unified-panel-body {
|
||||
z-index: 80000;
|
||||
}
|
||||
|
||||
#overlay.modal .dialog-box .body {
|
||||
min-width: 600px;
|
||||
}
|
||||
|
||||
.dialog-box .body {
|
||||
padding: 5px;
|
||||
overflow: auto;
|
||||
|
||||
@@ -405,8 +405,19 @@ input {
|
||||
background-color: #CCC;
|
||||
padding: 1em;
|
||||
}
|
||||
.feature-popup{
|
||||
background-color: #DDD;
|
||||
|
||||
.feature-popup {
|
||||
position: absolute;
|
||||
z-index: 1000
|
||||
z-index: 1000;
|
||||
padding: 5px;
|
||||
font-size: 10px;
|
||||
filter: alpha(opacity=80);
|
||||
background-repeat: no-repeat;
|
||||
background-image: url(../images/tipsy.gif);
|
||||
background-position: top center;
|
||||
}
|
||||
.feature-popup-inner {
|
||||
padding: 5px 8px 4px 8px;
|
||||
background-color: black;
|
||||
color: white;
|
||||
}
|
||||
|
||||
@@ -163,13 +163,23 @@ function make_right_panel( panel_el, center_el, border_el ) {
|
||||
// Modal dialog boxes
|
||||
|
||||
function hide_modal() {
|
||||
$(".dialog-box-container" ).fadeOut( function() {
|
||||
$(".dialog-box-container" ).hide( 0, function() {
|
||||
$("#overlay").hide();
|
||||
$("#overlay").removeClass( "modal" );
|
||||
$( ".dialog-box" ).find( ".body" ).children().remove();
|
||||
} );
|
||||
};
|
||||
|
||||
function show_modal( title, body, buttons, extra_buttons, init_fn ) {
|
||||
function show_modal() {
|
||||
$("#overlay").addClass( "modal" );
|
||||
_show_modal.apply( this, arguments );
|
||||
}
|
||||
|
||||
function show_message() {
|
||||
_show_modal.apply( this, arguments );
|
||||
}
|
||||
|
||||
function _show_modal( title, body, buttons, extra_buttons, init_fn ) {
|
||||
if ( title ) {
|
||||
$( ".dialog-box" ).find( ".title" ).html( title );
|
||||
$( ".dialog-box" ).find( ".unified-panel-header" ).show();
|
||||
@@ -205,7 +215,7 @@ function show_modal( title, body, buttons, extra_buttons, init_fn ) {
|
||||
$( ".dialog-box" ).find( ".body" ).html( body );
|
||||
if ( ! $(".dialog-box-container").is( ":visible" ) ) {
|
||||
$("#overlay").show();
|
||||
$(".dialog-box-container").fadeIn();
|
||||
$(".dialog-box-container").show();
|
||||
}
|
||||
// Fix min-width so that modal cannot shrink considerably if
|
||||
// new content is loaded.
|
||||
|
||||
+204
-39
@@ -701,7 +701,7 @@ extend(Drawable.prototype, {
|
||||
remove: function() {
|
||||
this.container.remove_drawable(this);
|
||||
|
||||
this.container_div.fadeOut('slow', function() {
|
||||
this.container_div.hide(0, function() {
|
||||
$(this).remove();
|
||||
// HACK: is there a better way to update the view?
|
||||
view.update_intro_div();
|
||||
@@ -1027,6 +1027,7 @@ extend( View.prototype, DrawableCollection.prototype, {
|
||||
// Only act on x axis scrolling if we see if, y will be i
|
||||
// handled by the browser when the event bubbles up
|
||||
if ( dx ) {
|
||||
dx *= 50;
|
||||
var delta_chrom = Math.round( - dx / view.viewport_container.width() * (view.high - view.low) );
|
||||
view.move_delta( delta_chrom );
|
||||
}
|
||||
@@ -1255,7 +1256,7 @@ extend( View.prototype, DrawableCollection.prototype, {
|
||||
DrawableCollection.prototype.remove_drawable.call(this, drawable);
|
||||
if (hide) {
|
||||
var view = this;
|
||||
drawable.container_div.fadeOut('slow', function() {
|
||||
drawable.container_div.hide(0, function() {
|
||||
$(this).remove();
|
||||
view.update_intro_div();
|
||||
});
|
||||
@@ -2114,8 +2115,14 @@ extend(DrawableConfig.prototype, {
|
||||
build_form: function() {
|
||||
var track_config = this;
|
||||
var container = $("<div />");
|
||||
$.each( this.params, function( index, param ) {
|
||||
if ( ! param.hidden ) {
|
||||
var param;
|
||||
// Function to process parameters recursively
|
||||
function handle_params( params, container ) {
|
||||
for ( var index = 0; index < params.length; index++ ) {
|
||||
param = params[index];
|
||||
// Hidden params have no representation in the form
|
||||
if ( param.hidden ) { continue; }
|
||||
// Build row for param
|
||||
var id = 'param_' + index;
|
||||
var value = track_config.values[ param.key ];
|
||||
var row = $("<div class='form-row' />").appendTo( container );
|
||||
@@ -2127,18 +2134,19 @@ extend(DrawableConfig.prototype, {
|
||||
} else if ( param.type === 'color' ) {
|
||||
var input = $('<input />').attr("id", id ).attr("name", id ).val( value );
|
||||
// Color picker in tool tip style float
|
||||
var tip = $( "<div class='tipsy tipsy-north' style='position: absolute;' />" ).hide();
|
||||
var tip = $( "<div class='tipsy tipsy-west' style='position: absolute;' />" ).hide();
|
||||
// Inner div for padding purposes
|
||||
var tip_inner = $("<div style='background-color: black; padding: 10px;'></div>").appendTo(tip);
|
||||
var farb_container = $("<div/>")
|
||||
.appendTo(tip_inner)
|
||||
.farbtastic( { width: 100, height: 100, callback: input, color: value });
|
||||
|
||||
// Outer div container input and tip for hover to work
|
||||
$("<div />").append( input ).append( tip ).appendTo( row ).bind( "click", function ( e ) {
|
||||
tip.css( {
|
||||
left: $(this).position().left + ( $(input).width() / 2 ) - 60,
|
||||
top: $(this).position().top + $(this.height)
|
||||
// left: $(this).position().left + ( $(input).width() / 2 ) - 60,
|
||||
// top: $(this).position().top + $(this.height)
|
||||
left: $(this).position().left + $(input).width() + 5,
|
||||
top: $(this).position().top - ( $(tip).height() / 2 ) + ( $(input).height() / 2 )
|
||||
} ).show();
|
||||
$(document).bind( "click.color-picker", function() {
|
||||
tip.hide();
|
||||
@@ -2150,8 +2158,15 @@ extend(DrawableConfig.prototype, {
|
||||
else {
|
||||
row.append( $('<input />').attr("id", id ).attr("name", id ).val( value ) );
|
||||
}
|
||||
// Help text
|
||||
if ( param.help ) {
|
||||
row.append( $("<div class='help'/>").text( param.help ) );
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
// Handle top level parameters in order
|
||||
handle_params( this.params, container );
|
||||
// Return element containing constructed form
|
||||
return container;
|
||||
},
|
||||
update_from_form: function( container ) {
|
||||
@@ -2229,7 +2244,16 @@ FeatureTrackTile.prototype.predisplay_actions = function() {
|
||||
// Only show popups in Pack mode.
|
||||
if (tile.mode !== "Pack") { return; }
|
||||
|
||||
$(this.canvas).mousemove(function (e) {
|
||||
$(this.canvas).hover( function() {
|
||||
this.hovered = true;
|
||||
$(this).mousemove();
|
||||
}, function() {
|
||||
this.hovered = false;
|
||||
// Clear popup if it is still hanging around (this is probably not needed)
|
||||
$(this).siblings(".feature-popup").remove();
|
||||
} ).mousemove(function (e) {
|
||||
// Use the hover plugin to get a delay before showing popup
|
||||
if ( !this.hovered ) { return; }
|
||||
// Get feature data for position.
|
||||
var
|
||||
this_offset = $(this).offset(),
|
||||
@@ -2270,8 +2294,8 @@ FeatureTrackTile.prototype.predisplay_actions = function() {
|
||||
// Build popup.
|
||||
|
||||
var popup = $("<div/>").attr("id", feature_uid).addClass("feature-popup"),
|
||||
key, value,
|
||||
table = $("<table/>").appendTo(popup), row;
|
||||
table = $("<table/>"),
|
||||
key, value, row;
|
||||
for (key in feature_dict) {
|
||||
value = feature_dict[key];
|
||||
row = $("<tr/>").appendTo(table);
|
||||
@@ -2279,6 +2303,7 @@ FeatureTrackTile.prototype.predisplay_actions = function() {
|
||||
$("<td/>").attr("align", "left").appendTo(row)
|
||||
.text(typeof(value) == 'number' ? round(value, 2) : value);
|
||||
}
|
||||
popup.append( $("<div class='feature-popup-inner'>").append( table ) );
|
||||
popups[feature_uid] = popup;
|
||||
}
|
||||
|
||||
@@ -2289,7 +2314,7 @@ FeatureTrackTile.prototype.predisplay_actions = function() {
|
||||
// parseInt strips "px" from left, top measurements. +7 so that mouse pointer does not
|
||||
// overlap popup.
|
||||
var
|
||||
popupX = offsetX + parseInt( tile.canvas.css("left") ) + 7,
|
||||
popupX = offsetX + parseInt( tile.canvas.css("left") ) - popup.width() / 2,
|
||||
popupY = offsetY + parseInt( tile.canvas.css("top") ) + 7;
|
||||
popup.css("left", popupX + "px").css("top", popupY + "px")
|
||||
}
|
||||
@@ -2331,6 +2356,12 @@ var Track = function(name, view, container, show_header, prefs, data_url, data_q
|
||||
this.data_url_extra_params = {}
|
||||
this.data_query_wait = (data_query_wait ? data_query_wait : DEFAULT_DATA_QUERY_WAIT);
|
||||
this.dataset_check_url = converted_datasets_state_url;
|
||||
|
||||
// FIXME: this should be a saved setting
|
||||
this.content_visible = true;
|
||||
|
||||
if (!Track.id_counter) { Track.id_counter = 0; }
|
||||
this.id = Track.id_counter++;
|
||||
|
||||
//
|
||||
// Create HTML element structure for track.
|
||||
@@ -2346,6 +2377,9 @@ var Track = function(name, view, container, show_header, prefs, data_url, data_q
|
||||
this.icons_div = $("<div/>").css("float", "left").appendTo(this.header_div).hide();
|
||||
|
||||
// Track icons.
|
||||
this.toggle_icon = $("<a/>").attr("href", "javascript:void(0);").attr("title", "Hide/show track content")
|
||||
.addClass("icon-button toggle").tipsy( {gravity: 's'} )
|
||||
.appendTo(this.icons_div);
|
||||
this.settings_icon = $("<a/>").attr("href", "javascript:void(0);").attr("title", "Edit settings")
|
||||
.addClass("icon-button settings-icon").tipsy( {gravity: 's'} )
|
||||
.appendTo(this.icons_div);
|
||||
@@ -2365,6 +2399,21 @@ var Track = function(name, view, container, show_header, prefs, data_url, data_q
|
||||
|
||||
// Suppress double clicks in header so that they do not impact viz.
|
||||
this.header_div.dblclick( function(e) { e.stopPropagation(); } );
|
||||
|
||||
// Toggle icon hides or shows the track content
|
||||
this.toggle_icon.click( function() {
|
||||
if ( track.content_visible ) {
|
||||
track.toggle_icon.addClass("toggle-expand").removeClass("toggle");
|
||||
track.hide_contents();
|
||||
track.mode_div.hide();
|
||||
track.content_visible = false;
|
||||
} else {
|
||||
track.toggle_icon.addClass("toggle").removeClass("toggle-expand");
|
||||
track.content_visible = true;
|
||||
track.mode_div.show();
|
||||
track.show_contents();
|
||||
}
|
||||
});
|
||||
|
||||
// Clicking on settings icon opens track config.
|
||||
this.settings_icon.click( function() {
|
||||
@@ -2551,6 +2600,26 @@ extend(Track.prototype, Drawable.prototype, {
|
||||
|
||||
this.update_icons();
|
||||
},
|
||||
/**
|
||||
* Hide any elements that are part of the tracks contents area. Should
|
||||
* remove as approprite, the track will be redrawn by show_contents.
|
||||
*/
|
||||
hide_contents : function () {
|
||||
// Clear contents by removing any elements that are contained in
|
||||
// the tracks content_div
|
||||
this.content_div.children().remove();
|
||||
// Hide the content div
|
||||
this.content_div.hide();
|
||||
// And any y axis labels (common to several track types)
|
||||
this.container_div.find(".yaxislabel, .track-resize").hide()
|
||||
},
|
||||
show_contents : function() {
|
||||
// Show the contents div and labels (if present)
|
||||
this.content_div.show();
|
||||
this.container_div.find(".yaxislabel, .track-resize").show()
|
||||
// Request a redraw of the content
|
||||
this.request_draw();
|
||||
},
|
||||
/**
|
||||
* Additional initialization required before drawing track for the first time.
|
||||
*/
|
||||
@@ -2682,6 +2751,11 @@ extend(TiledTrack.prototype, Drawable.prototype, Track.prototype, {
|
||||
*/
|
||||
_draw: function(force, clear_after) {
|
||||
if (!this.enabled) { return; }
|
||||
|
||||
// TODO: There should probably be a general way to disable content drawing
|
||||
// for all drawables. However the button to toggle this is currently
|
||||
// only present for Track instances.
|
||||
if (!this.content_visible) { return; }
|
||||
|
||||
// HACK: ReferenceTrack can draw without dataset ID, but other tracks cannot.
|
||||
if ( !(this instanceof ReferenceTrack) && (!this.dataset_id) ) { return; }
|
||||
@@ -2694,7 +2768,7 @@ extend(TiledTrack.prototype, Drawable.prototype, Track.prototype, {
|
||||
w_scale = width / range,
|
||||
resolution = this.view.resolution,
|
||||
parent_element = $("<div style='position: relative;'></div>");
|
||||
|
||||
|
||||
// For overview, adjust high, low, resolution, and w_scale.
|
||||
if (this.is_overview) {
|
||||
low = this.view.max_low;
|
||||
@@ -3028,7 +3102,8 @@ var LineTrack = function (name, view, container, hda_ldda, dataset_id, prefs) {
|
||||
|
||||
this.min_height_px = 16;
|
||||
this.max_height_px = 400;
|
||||
this.height_px = 80;
|
||||
// Default height for new tracks, should be a defined constant?
|
||||
this.height_px = 32;
|
||||
this.hda_ldda = hda_ldda;
|
||||
this.dataset_id = dataset_id;
|
||||
this.original_dataset_id = dataset_id;
|
||||
@@ -3076,8 +3151,10 @@ extend(LineTrack.prototype, Drawable.prototype, TiledTrack.prototype, {
|
||||
var drag_control = $( "<div class='track-resize'>" )
|
||||
// Control shows on hover over track, stays while dragging
|
||||
$(track.container_div).hover( function() {
|
||||
in_handle = true;
|
||||
drag_control.show();
|
||||
if ( track.content_visible ) {
|
||||
in_handle = true;
|
||||
drag_control.show();
|
||||
}
|
||||
}, function() {
|
||||
in_handle = false;
|
||||
if ( ! in_drag ) { drag_control.hide(); }
|
||||
@@ -3108,9 +3185,20 @@ extend(LineTrack.prototype, Drawable.prototype, TiledTrack.prototype, {
|
||||
track.container_div.addClass( "line-track" );
|
||||
var data = result.data;
|
||||
if ( isNaN(parseFloat(track.prefs.min_value)) || isNaN(parseFloat(track.prefs.max_value)) ) {
|
||||
track.prefs.min_value = data.min;
|
||||
track.prefs.max_value = data.max;
|
||||
// Compute default minimum and maximum values
|
||||
var min_value = data.min
|
||||
var max_value = data.max
|
||||
// If mean and sd are present, use them to compute a ~95% window
|
||||
// but only if it would shrink the range on one side
|
||||
min_value = Math.floor( Math.min( 0, Math.max( min_value, data.mean - 2 * data.sd ) ) )
|
||||
max_value = Math.ceil( Math.max( 0, Math.min( max_value, data.mean + 2 * data.sd ) ) )
|
||||
// Update the prefs
|
||||
track.prefs.min_value = min_value;
|
||||
track.prefs.max_value = max_value;
|
||||
// Update the config
|
||||
// FIXME: we should probably only save this when the user explicately sets it
|
||||
// since we lose the ability to compute it on the fly (when changing
|
||||
// chromosomes for example).
|
||||
$('#track_' + track.dataset_id + '_minval').val(track.prefs.min_value);
|
||||
$('#track_' + track.dataset_id + '_maxval').val(track.prefs.max_value);
|
||||
}
|
||||
@@ -3179,7 +3267,8 @@ var FeatureTrack = function(name, view, container, hda_ldda, dataset_id, prefs,
|
||||
{ key: 'name', label: 'Name', type: 'text', default_value: name },
|
||||
{ key: 'block_color', label: 'Block color', type: 'color', default_value: get_random_color() },
|
||||
{ key: 'label_color', label: 'Label color', type: 'color', default_value: 'black' },
|
||||
{ key: 'show_counts', label: 'Show summary counts', type: 'bool', default_value: true },
|
||||
{ key: 'show_counts', label: 'Show summary counts', type: 'bool', default_value: true,
|
||||
help: 'Show the number of items in each bin when drawing summary histogram' },
|
||||
{ key: 'mode', type: 'string', default_value: this.mode, hidden: true },
|
||||
],
|
||||
saved_values: prefs,
|
||||
@@ -3527,7 +3616,7 @@ extend(FeatureTrack.prototype, Drawable.prototype, TiledTrack.prototype, {
|
||||
var filter_height_scaler = (this.filters_manager.height_filter ? new FilterScaler(this.filters_manager.height_filter) : null);
|
||||
// HACK: ref_seq will only be defined for ReadTracks, and only the ReadPainter accepts that argument
|
||||
var painter = new (this.painter)(filtered, tile_low, tile_high, this.prefs, mode, filter_alpha_scaler, filter_height_scaler, ref_seq);
|
||||
var required_height = Math.max(MIN_TRACK_HEIGHT, painter.get_required_height(slots_required));
|
||||
var required_height = Math.max(MIN_TRACK_HEIGHT, painter.get_required_height(slots_required,width));
|
||||
var canvas = this.view.canvas_manager.new_canvas();
|
||||
var feature_mapper = null;
|
||||
|
||||
@@ -4057,6 +4146,7 @@ var FeaturePositionMapper = function(slot_height) {
|
||||
this.feature_positions = {};
|
||||
this.slot_height = slot_height;
|
||||
this.translation = 0;
|
||||
this.y_translation = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -4078,7 +4168,7 @@ FeaturePositionMapper.prototype.map_feature_data = function(feature_data, slot,
|
||||
*/
|
||||
FeaturePositionMapper.prototype.get_feature_data = function(x, y) {
|
||||
// Find slot using Y.
|
||||
var slot = Math.floor( y/this.slot_height ),
|
||||
var slot = Math.floor( (y-this.y_translation)/this.slot_height ),
|
||||
feature_dict;
|
||||
|
||||
// May not be over a slot due to padding, margin, etc.
|
||||
@@ -4108,15 +4198,23 @@ var FeaturePainter = function(data, view_start, view_end, prefs, mode, alpha_sca
|
||||
FeaturePainter.prototype.default_prefs = { block_color: "#FFF", connector_color: "#FFF" };
|
||||
|
||||
extend(FeaturePainter.prototype, {
|
||||
get_required_height: function(rows_required) {
|
||||
get_required_height: function(rows_required, width) {
|
||||
// y_scale is the height per row
|
||||
var required_height = y_scale = this.get_row_height(), mode = this.mode;
|
||||
// If using a packing mode, need to multiply by the number of slots used
|
||||
if (mode === "no_detail" || mode === "Squish" || mode === "Pack") {
|
||||
required_height = rows_required * y_scale;
|
||||
}
|
||||
return required_height + this.get_top_padding(width) + this.get_bottom_padding(width);
|
||||
},
|
||||
/** Extra padding before first row of features */
|
||||
get_top_padding: function(width) {
|
||||
return 0;
|
||||
},
|
||||
/** Extra padding after last row of features */
|
||||
get_bottom_padding: function(width) {
|
||||
// Pad bottom by half a row, at least 5 px
|
||||
return required_height + Math.max( Math.round( y_scale / 2 ), 5 );
|
||||
return Math.max( Math.round( this.get_row_height() / 2 ), 5 )
|
||||
},
|
||||
/**
|
||||
* Draw data on ctx using slots and within the rectangle defined by width and height. Returns
|
||||
@@ -4153,6 +4251,7 @@ extend(FeaturePainter.prototype, {
|
||||
}
|
||||
|
||||
ctx.restore();
|
||||
feature_mapper.y_translation = this.get_top_padding(width);
|
||||
return feature_mapper;
|
||||
},
|
||||
/**
|
||||
@@ -4179,6 +4278,10 @@ var DENSE_TRACK_HEIGHT = 10,
|
||||
|
||||
var LinkedFeaturePainter = function(data, view_start, view_end, prefs, mode, alpha_scaler, height_scaler) {
|
||||
FeaturePainter.call(this, data, view_start, view_end, prefs, mode, alpha_scaler, height_scaler);
|
||||
// Whether to draw a single connector in the background that spans the entire feature (the intron fishbone)
|
||||
this.draw_background_connector = true;
|
||||
// Whether to call draw_connector for every pair of blocks
|
||||
this.draw_individual_connectors = false;
|
||||
};
|
||||
|
||||
extend(LinkedFeaturePainter.prototype, FeaturePainter.prototype, {
|
||||
@@ -4216,7 +4319,7 @@ extend(LinkedFeaturePainter.prototype, FeaturePainter.prototype, {
|
||||
f_end = Math.ceil( Math.min(width, Math.max(0, (feature_end - tile_low) * w_scale)) ),
|
||||
draw_start = f_start,
|
||||
draw_end = f_end,
|
||||
y_center = (mode === "Dense" ? 0 : (0 + slot)) * y_scale,
|
||||
y_center = (mode === "Dense" ? 0 : (0 + slot)) * y_scale + this.get_top_padding(width),
|
||||
thickness, y_start, thick_start = null, thick_end = null,
|
||||
// TODO: is there any reason why block, label color cannot be set at the Painter level?
|
||||
block_color = this.prefs.block_color,
|
||||
@@ -4279,38 +4382,51 @@ extend(LinkedFeaturePainter.prototype, FeaturePainter.prototype, {
|
||||
// needed. This ensures that whole feature, regardless of whether it starts with
|
||||
// a block, is visible.
|
||||
//
|
||||
|
||||
// Draw whole feature as connector/intron.
|
||||
|
||||
// Compute y axis center position and height
|
||||
var cur_y_center, cur_height;
|
||||
if (mode === "Squish" || mode === "Dense") {
|
||||
ctx.fillStyle = CONNECTOR_COLOR;
|
||||
cur_y_center = y_center + Math.floor(SQUISH_FEATURE_HEIGHT/2) + 1;
|
||||
cur_height = 1;
|
||||
}
|
||||
else { // mode === "Pack"
|
||||
if (feature_strand) {
|
||||
var cur_y_center = y_center;
|
||||
var cur_height = thick_height;
|
||||
if (feature_strand === "+") {
|
||||
ctx.fillStyle = ctx.canvas.manager.get_pattern( 'right_strand' );
|
||||
} else if (feature_strand === "-") {
|
||||
ctx.fillStyle = ctx.canvas.manager.get_pattern( 'left_strand' );
|
||||
}
|
||||
cur_y_center = y_center;
|
||||
cur_height = thick_height;
|
||||
}
|
||||
else {
|
||||
ctx.fillStyle = CONNECTOR_COLOR;
|
||||
cur_y_center += (SQUISH_FEATURE_HEIGHT/2) + 1;
|
||||
cur_height = 1;
|
||||
}
|
||||
}
|
||||
ctx.fillRect(f_start, cur_y_center, f_end - f_start, cur_height);
|
||||
|
||||
// Draw whole feature as connector/intron.
|
||||
if ( this.draw_background_connector ) {
|
||||
if (mode === "Squish" || mode === "Dense") {
|
||||
ctx.fillStyle = CONNECTOR_COLOR;
|
||||
}
|
||||
else { // mode === "Pack"
|
||||
if (feature_strand) {
|
||||
if (feature_strand === "+") {
|
||||
ctx.fillStyle = ctx.canvas.manager.get_pattern( 'right_strand' );
|
||||
} else if (feature_strand === "-") {
|
||||
ctx.fillStyle = ctx.canvas.manager.get_pattern( 'left_strand' );
|
||||
}
|
||||
}
|
||||
else {
|
||||
ctx.fillStyle = CONNECTOR_COLOR;
|
||||
}
|
||||
}
|
||||
ctx.fillRect(f_start, cur_y_center, f_end - f_start, cur_height);
|
||||
}
|
||||
|
||||
// Draw blocks.
|
||||
var start_and_height;
|
||||
for (var k = 0, k_len = feature_blocks.length; k < k_len; k++) {
|
||||
var block = feature_blocks[k],
|
||||
block_start = Math.floor( Math.max(0, (block[0] - tile_low) * w_scale) ),
|
||||
block_end = Math.ceil( Math.min(width, Math.max((block[1] - tile_low) * w_scale)) );
|
||||
block_end = Math.ceil( Math.min(width, Math.max((block[1] - tile_low) * w_scale)) ),
|
||||
last_block_start, last_block_end;
|
||||
|
||||
// Skip drawing if block not on tile.
|
||||
if (block_start > block_end) { continue; }
|
||||
@@ -4341,6 +4457,12 @@ extend(LinkedFeaturePainter.prototype, FeaturePainter.prototype, {
|
||||
ctx.fillRect(block_thick_start, y_center + 1, block_thick_end - block_thick_start, thick_height );
|
||||
}
|
||||
}
|
||||
// Draw individual connectors if required
|
||||
if ( this.draw_individual_connectors && last_block_start ) {
|
||||
this.draw_connector( ctx, last_block_start, last_block_end, block_start, block_end, y_center );
|
||||
}
|
||||
last_block_start = block_start;
|
||||
last_block_end = block_end;
|
||||
}
|
||||
|
||||
// FIXME: Height scaling only works in Pack mode right now.
|
||||
@@ -4673,11 +4795,54 @@ extend(ReadPainter.prototype, FeaturePainter.prototype, {
|
||||
}
|
||||
});
|
||||
|
||||
var ArcLinkedFeaturePainter = function(data, view_start, view_end, prefs, mode, alpha_scaler, height_scaler) {
|
||||
LinkedFeaturePainter.call(this, data, view_start, view_end, prefs, mode, alpha_scaler, height_scaler);
|
||||
// Need to know the longest feature length for adding spacing
|
||||
this.longest_feature_length = this.calculate_longest_feature_length();
|
||||
this.draw_background_connector = false;
|
||||
this.draw_individual_connectors = true;
|
||||
};
|
||||
|
||||
extend(ArcLinkedFeaturePainter.prototype, FeaturePainter.prototype, LinkedFeaturePainter.prototype, {
|
||||
|
||||
calculate_longest_feature_length: function () {
|
||||
var longest_feature_length = 0;
|
||||
for (var i = 0, len = this.data.length; i < len; i++) {
|
||||
var feature = this.data[i], feature_start = feature[1], feature_end = feature[2];
|
||||
longest_feature_length = Math.max( longest_feature_length, feature_end - feature_start );
|
||||
}
|
||||
return longest_feature_length;
|
||||
},
|
||||
|
||||
get_top_padding: function( width ) {
|
||||
var view_range = this.view_end - this.view_start,
|
||||
w_scale = width / view_range;
|
||||
return Math.min( 128, Math.ceil( ( this.longest_feature_length / 2 ) * w_scale ) );
|
||||
},
|
||||
|
||||
draw_connector: function( ctx, block1_start, block1_end, block2_start, block2_end, y_center ) {
|
||||
// Arc drawing -- from closest endpoints
|
||||
var x_center = ( block1_end + block2_start ) / 2,
|
||||
radius = block2_start - x_center;
|
||||
// For full half circles
|
||||
var angle1 = Math.PI, angle2 = 0;
|
||||
if ( radius > 0 ) {
|
||||
ctx.beginPath();
|
||||
ctx.arc( x_center, y_center, block2_start - x_center, Math.PI, 0 );
|
||||
ctx.stroke();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
|
||||
|
||||
exports.Scaler = Scaler;
|
||||
exports.SummaryTreePainter = SummaryTreePainter;
|
||||
exports.LinePainter = LinePainter;
|
||||
exports.LinkedFeaturePainter = LinkedFeaturePainter;
|
||||
exports.ReadPainter = ReadPainter;
|
||||
exports.ArcLinkedFeaturePainter = ArcLinkedFeaturePainter;
|
||||
|
||||
// End painters_module encapsulation
|
||||
};
|
||||
@@ -4708,4 +4873,4 @@ exports.ReadPainter = ReadPainter;
|
||||
for ( key in modules.trackster ) {
|
||||
target[key] = modules.trackster[key];
|
||||
}
|
||||
})(window);
|
||||
})(window);
|
||||
|
||||
@@ -42,7 +42,7 @@ ${parent.javascripts()}
|
||||
<script type='text/javascript' src="${h.url_for('/static/scripts/excanvas.js')}"></script>
|
||||
<![endif]-->
|
||||
|
||||
${h.js( "galaxy.base", "galaxy.panels", "json2", "jquery", "jstorage", "jquery.event.drag", "jquery.mousewheel", "jquery.autocomplete", "trackster", "trackster_ui", "jquery.ui.sortable.slider", "farbtastic", "jquery.tipsy" )}
|
||||
${h.js( "galaxy.base", "galaxy.panels", "json2", "jquery", "jstorage", "jquery.event.drag", "jquery.event.hover","jquery.mousewheel", "jquery.autocomplete", "trackster", "trackster_ui", "jquery.ui.sortable.slider", "farbtastic", "jquery.tipsy" )}
|
||||
|
||||
<script type="text/javascript">
|
||||
//
|
||||
|
||||
@@ -213,7 +213,7 @@
|
||||
show_workflow_parameters();
|
||||
},
|
||||
beforeSubmit: function( data ) {
|
||||
show_modal( "Loading workflow", "progress" );
|
||||
show_message( "Loading workflow", "progress" );
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -650,7 +650,7 @@
|
||||
};
|
||||
|
||||
var save_current_workflow = function ( eventObj, success_callback ) {
|
||||
show_modal( "Saving workflow", "progress" );
|
||||
show_message( "Saving workflow", "progress" );
|
||||
workflow.check_changes_in_active_form();
|
||||
if (!workflow.has_changes) {
|
||||
hide_modal();
|
||||
|
||||
Reference in New Issue
Block a user