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:
@@ -1298,7 +1298,32 @@ class ENCODEPeak( Interval ):
|
||||
return False
|
||||
|
||||
def get_track_type( self ):
|
||||
return "FeatureTrack", {"data": "tabix", "index": "summary_tree"}
|
||||
return "FeatureTrack", {"data": "tabix", "index": "summary_tree"}
|
||||
|
||||
class ChromatinInteractions( Interval ):
|
||||
'''
|
||||
Chromatin interactions obtained from 3C/5C/Hi-C experiments.
|
||||
'''
|
||||
|
||||
file_ext = "chrint"
|
||||
|
||||
column_names = [ 'Chrom', 'Start1', 'End1', 'Start2', 'End2', 'Value' ]
|
||||
|
||||
"""Add metadata elements"""
|
||||
MetadataElement( name="chromCol", default=1, desc="Chrom column", param=metadata.ColumnParameter )
|
||||
MetadataElement( name="start1Col", default=2, desc="Start1 column", param=metadata.ColumnParameter )
|
||||
MetadataElement( name="end1Col", default=3, desc="End1 column", param=metadata.ColumnParameter )
|
||||
MetadataElement( name="start2Col", default=2, desc="Start2 column", param=metadata.ColumnParameter )
|
||||
MetadataElement( name="end2Col", default=3, desc="End2 column", param=metadata.ColumnParameter )
|
||||
MetadataElement( name="columns", default=3, desc="Number of columns", readonly=True, visible=False )
|
||||
|
||||
def sniff( self, filename ):
|
||||
return False
|
||||
|
||||
def get_track_type( self ):
|
||||
return "DiagonalHeatmapTrack", {"data": "tabix", "index": "summary_tree"}
|
||||
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
import doctest, sys
|
||||
|
||||
@@ -19,7 +19,7 @@ from galaxy.util.lrucache import LRUCache
|
||||
from galaxy.visualization.tracks.summary import *
|
||||
import galaxy_utils.sequence.vcf
|
||||
from galaxy.datatypes.tabular import Vcf
|
||||
from galaxy.datatypes.interval import Interval, Bed, Gff, Gtf, ENCODEPeak
|
||||
from galaxy.datatypes.interval import Interval, Bed, Gff, Gtf, ENCODEPeak, ChromatinInteractions
|
||||
|
||||
from pysam import csamtools, ctabix
|
||||
|
||||
@@ -146,6 +146,9 @@ class TracksDataProvider( object ):
|
||||
{ 'name' : attrs[ 'name' ], 'type' : column_types[viz_col_index], \
|
||||
'index' : attrs[ 'index' ] } )
|
||||
return filters
|
||||
|
||||
def get_default_max_vals( self ):
|
||||
return 5000;
|
||||
|
||||
#
|
||||
# -- Base mixins and providers --
|
||||
@@ -1268,6 +1271,67 @@ class ENCODEPeakTabixDataProvider( TabixDataProvider, ENCODEPeakDataProvider ):
|
||||
'tool_id': 'Filter1',
|
||||
'tool_exp_name': 'c9' } )
|
||||
return filters
|
||||
|
||||
#
|
||||
# -- ChromatinInteraction data providers --
|
||||
#
|
||||
class ChromatinInteractionsDataProvider( TracksDataProvider ):
|
||||
def process_data( self, iterator, start_val=0, max_vals=None, **kwargs ):
|
||||
"""
|
||||
Provides
|
||||
"""
|
||||
|
||||
rval = []
|
||||
message = None
|
||||
for count, line in enumerate( iterator ):
|
||||
if count < start_val:
|
||||
continue
|
||||
if max_vals and count-start_val >= max_vals:
|
||||
message = ERROR_MAX_VALS % ( max_vals, "interactions" )
|
||||
break
|
||||
|
||||
feature = line.split()
|
||||
length = len( feature )
|
||||
|
||||
s1 = int( feature[1] ),
|
||||
e1 = int( feature[2] ),
|
||||
c = feature[3],
|
||||
s2 = int( feature[4] ),
|
||||
e2 = int( feature[5] ),
|
||||
v = float( feature[6] )
|
||||
|
||||
# Feature initialization.
|
||||
payload = [
|
||||
# GUID is just a hash of the line
|
||||
hash( line ),
|
||||
# Add start1, end1, chr2, start2, end2, value.
|
||||
s1, e1, c, s2, e2, v
|
||||
]
|
||||
|
||||
rval.append( payload )
|
||||
|
||||
return { 'data': rval, 'message': message }
|
||||
|
||||
def get_default_max_vals( self ):
|
||||
return 50000;
|
||||
|
||||
class ChromatinInteractionsTabixDataProvider( TabixDataProvider, ChromatinInteractionsDataProvider ):
|
||||
def get_iterator( self, chrom, start, end ):
|
||||
"""
|
||||
"""
|
||||
# Modify start as needed to get earlier interactions with start region.
|
||||
start = max( 0, int( start) - 1000000 )
|
||||
def filter( iter ):
|
||||
for line in iter:
|
||||
feature = line.split()
|
||||
s1 = int( feature[1] ),
|
||||
e1 = int( feature[2] ),
|
||||
c = feature[3]
|
||||
s2 = int( feature[4] ),
|
||||
e2 = int( feature[5] ),
|
||||
if ( ( c == chrom ) and ( s1 < end and e1 > start ) and ( s2 < end and e2 > start ) ):
|
||||
yield line
|
||||
return filter( TabixDataProvider.get_iterator( self, chrom, start, end ) )
|
||||
|
||||
#
|
||||
# -- Helper methods. --
|
||||
@@ -1283,7 +1347,9 @@ dataset_type_name_to_data_provider = {
|
||||
Gtf: GtfTabixDataProvider,
|
||||
ENCODEPeak: ENCODEPeakTabixDataProvider,
|
||||
Interval: IntervalTabixDataProvider,
|
||||
"default" : TabixDataProvider },
|
||||
ChromatinInteractions: ChromatinInteractionsTabixDataProvider,
|
||||
"default" : TabixDataProvider
|
||||
},
|
||||
"interval_index": IntervalIndexDataProvider,
|
||||
"bai": BamDataProvider,
|
||||
"bam": SamDataProvider,
|
||||
|
||||
@@ -345,7 +345,7 @@ class TracksController( BaseUIController, UsesVisualizationMixin, UsesHistoryDat
|
||||
return { "status": messages.DATA, "valid_chroms": valid_chroms }
|
||||
|
||||
@web.json
|
||||
def data( self, trans, hda_ldda, dataset_id, chrom, low, high, start_val=0, max_vals=5000, **kwargs ):
|
||||
def data( self, trans, hda_ldda, dataset_id, chrom, low, high, start_val=0, max_vals=None, **kwargs ):
|
||||
"""
|
||||
Provides a block of data from a dataset.
|
||||
"""
|
||||
@@ -401,6 +401,10 @@ class TracksController( BaseUIController, UsesVisualizationMixin, UsesHistoryDat
|
||||
deps = dataset.get_converted_dataset_deps( trans, tracks_dataset_type )
|
||||
data_provider = data_provider_class( converted_dataset=converted_dataset, original_dataset=dataset, dependencies=deps )
|
||||
|
||||
# Allow max_vals top be data provider set if not passed
|
||||
if max_vals is None:
|
||||
max_vals = data_provider.get_default_max_vals()
|
||||
|
||||
# Get and return data from data_provider.
|
||||
result = data_provider.get_data( chrom, low, high, int( start_val ), int( max_vals ), **kwargs )
|
||||
result.update( { 'dataset_type': tracks_dataset_type, 'extra_info': extra_info } )
|
||||
|
||||
@@ -4346,6 +4346,84 @@ extend(LineTrack.prototype, Drawable.prototype, TiledTrack.prototype, {
|
||||
}
|
||||
});
|
||||
|
||||
var DiagonalHeatmapTrack = function (view, container, obj_dict) {
|
||||
var track = this;
|
||||
this.display_modes = ["Heatmap"];
|
||||
this.mode = "Heatmap";
|
||||
TiledTrack.call(this, view, container, obj_dict);
|
||||
|
||||
// This all seems to be duplicated
|
||||
this.hda_ldda = obj_dict.hda_ldda;
|
||||
this.dataset_id = obj_dict.dataset_id;
|
||||
this.original_dataset_id = this.dataset_id;
|
||||
this.left_offset = 0;
|
||||
|
||||
// Define track configuration
|
||||
this.config = new DrawableConfig( {
|
||||
track: this,
|
||||
params: [
|
||||
{ key: 'name', label: 'Name', type: 'text', default_value: this.name },
|
||||
{ key: 'pos_color', label: 'Positive Color', type: 'color', default_value: "4169E1" },
|
||||
{ key: 'negative_color', label: 'Negative Color', type: 'color', default_value: "FF8C00" },
|
||||
{ key: 'min_value', label: 'Min Value', type: 'float', default_value: 0 },
|
||||
{ key: 'max_value', label: 'Max Value', type: 'float', default_value: 1 },
|
||||
{ key: 'mode', type: 'string', default_value: this.mode, hidden: true },
|
||||
{ key: 'height', type: 'int', default_value: 500, hidden: true }
|
||||
],
|
||||
saved_values: obj_dict.prefs,
|
||||
onchange: function() {
|
||||
track.set_name(track.prefs.name);
|
||||
track.vertical_range = track.prefs.max_value - track.prefs.min_value;
|
||||
track.set_min_value(track.prefs.min_value);
|
||||
track.set_max_value(track.prefs.max_value);
|
||||
}
|
||||
});
|
||||
|
||||
this.prefs = this.config.values;
|
||||
this.visible_height_px = this.config.values.height;
|
||||
this.vertical_range = this.config.values.max_value - this.config.values.min_value;
|
||||
};
|
||||
extend(DiagonalHeatmapTrack.prototype, Drawable.prototype, TiledTrack.prototype, {
|
||||
/**
|
||||
* Action to take during resize.
|
||||
*/
|
||||
on_resize: function() {
|
||||
this.request_draw(true);
|
||||
},
|
||||
/**
|
||||
* Set track minimum value.
|
||||
*/
|
||||
set_min_value: function(new_val) {
|
||||
this.prefs.min_value = new_val;
|
||||
this.tile_cache.clear();
|
||||
this.request_draw();
|
||||
},
|
||||
/**
|
||||
* Set track maximum value.
|
||||
*/
|
||||
set_max_value: function(new_val) {
|
||||
this.prefs.max_value = new_val;
|
||||
this.tile_cache.clear();
|
||||
this.request_draw();
|
||||
},
|
||||
|
||||
/**
|
||||
* Draw LineTrack tile.
|
||||
*/
|
||||
draw_tile: function(result, ctx, mode, resolution, tile_index, w_scale) {
|
||||
// Paint onto canvas.
|
||||
var
|
||||
canvas = ctx.canvas,
|
||||
tile_bounds = this._get_tile_bounds(tile_index, resolution),
|
||||
tile_low = tile_bounds[0],
|
||||
tile_high = tile_bounds[1],
|
||||
painter = new painters.DiagonalHeatmapPainter(result.data, tile_low, tile_high, this.prefs, mode);
|
||||
painter.draw(ctx, canvas.width, canvas.height, w_scale);
|
||||
|
||||
return new Tile(this, tile_index, resolution, canvas, result.data);
|
||||
}
|
||||
});
|
||||
|
||||
var FeatureTrack = function(view, container, obj_dict) {
|
||||
//
|
||||
// Preinitialization: do things that need to be done before calling Track and TiledTrack
|
||||
@@ -4878,6 +4956,7 @@ exports.View = View;
|
||||
exports.DrawableGroup = DrawableGroup;
|
||||
exports.LineTrack = LineTrack;
|
||||
exports.FeatureTrack = FeatureTrack;
|
||||
exports.DiagonalHeatmapTrack = DiagonalHeatmapTrack;
|
||||
exports.ReadTrack = ReadTrack;
|
||||
exports.VcfTrack = VcfTrack;
|
||||
exports.CompositeTrack = CompositeTrack;
|
||||
@@ -6041,12 +6120,224 @@ extend(ArcLinkedFeaturePainter.prototype, FeaturePainter.prototype, LinkedFeatur
|
||||
}
|
||||
});
|
||||
|
||||
// Color stuff from less.js
|
||||
|
||||
var Color = function (rgb, a) {
|
||||
/**
|
||||
* The end goal here, is to parse the arguments
|
||||
* into an integer triplet, such as `128, 255, 0`
|
||||
*
|
||||
* This facilitates operations and conversions.
|
||||
*/
|
||||
if (Array.isArray(rgb)) {
|
||||
this.rgb = rgb;
|
||||
} else if (rgb.length == 6) {
|
||||
this.rgb = rgb.match(/.{2}/g).map(function (c) {
|
||||
return parseInt(c, 16);
|
||||
});
|
||||
} else {
|
||||
this.rgb = rgb.split('').map(function (c) {
|
||||
return parseInt(c + c, 16);
|
||||
});
|
||||
}
|
||||
this.alpha = typeof(a) === 'number' ? a : 1;
|
||||
};
|
||||
Color.prototype = {
|
||||
eval: function () { return this },
|
||||
|
||||
//
|
||||
// If we have some transparency, the only way to represent it
|
||||
// is via `rgba`. Otherwise, we use the hex representation,
|
||||
// which has better compatibility with older browsers.
|
||||
// Values are capped between `0` and `255`, rounded and zero-padded.
|
||||
//
|
||||
toCSS: function () {
|
||||
if (this.alpha < 1.0) {
|
||||
return "rgba(" + this.rgb.map(function (c) {
|
||||
return Math.round(c);
|
||||
}).concat(this.alpha).join(', ') + ")";
|
||||
} else {
|
||||
return '#' + this.rgb.map(function (i) {
|
||||
i = Math.round(i);
|
||||
i = (i > 255 ? 255 : (i < 0 ? 0 : i)).toString(16);
|
||||
return i.length === 1 ? '0' + i : i;
|
||||
}).join('');
|
||||
}
|
||||
},
|
||||
|
||||
toHSL: function () {
|
||||
var r = this.rgb[0] / 255,
|
||||
g = this.rgb[1] / 255,
|
||||
b = this.rgb[2] / 255,
|
||||
a = this.alpha;
|
||||
|
||||
var max = Math.max(r, g, b), min = Math.min(r, g, b);
|
||||
var h, s, l = (max + min) / 2, d = max - min;
|
||||
|
||||
if (max === min) {
|
||||
h = s = 0;
|
||||
} else {
|
||||
s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
|
||||
|
||||
switch (max) {
|
||||
case r: h = (g - b) / d + (g < b ? 6 : 0); break;
|
||||
case g: h = (b - r) / d + 2; break;
|
||||
case b: h = (r - g) / d + 4; break;
|
||||
}
|
||||
h /= 6;
|
||||
}
|
||||
return { h: h * 360, s: s, l: l, a: a };
|
||||
},
|
||||
|
||||
toARGB: function () {
|
||||
var argb = [Math.round(this.alpha * 255)].concat(this.rgb);
|
||||
return '#' + argb.map(function (i) {
|
||||
i = Math.round(i);
|
||||
i = (i > 255 ? 255 : (i < 0 ? 0 : i)).toString(16);
|
||||
return i.length === 1 ? '0' + i : i;
|
||||
}).join('');
|
||||
},
|
||||
|
||||
mix: function (color2, weight) {
|
||||
color1 = this;
|
||||
|
||||
var p = weight; // .value / 100.0;
|
||||
var w = p * 2 - 1;
|
||||
var a = color1.toHSL().a - color2.toHSL().a;
|
||||
|
||||
var w1 = (((w * a == -1) ? w : (w + a) / (1 + w * a)) + 1) / 2.0;
|
||||
var w2 = 1 - w1;
|
||||
|
||||
var rgb = [color1.rgb[0] * w1 + color2.rgb[0] * w2,
|
||||
color1.rgb[1] * w1 + color2.rgb[1] * w2,
|
||||
color1.rgb[2] * w1 + color2.rgb[2] * w2];
|
||||
|
||||
var alpha = color1.alpha * p + color2.alpha * (1 - p);
|
||||
|
||||
return new Color(rgb, alpha);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// End colors from less.js
|
||||
|
||||
var LinearRamp = function( start_color, end_color, start_value, end_value ) {
|
||||
/**
|
||||
* Simple linear gradient
|
||||
*/
|
||||
this.start_color = new Color( start_color );
|
||||
this.end_color = new Color( end_color );
|
||||
this.start_value = start_value;
|
||||
this.end_value = end_value;
|
||||
this.value_range = end_value - start_value;
|
||||
}
|
||||
LinearRamp.prototype.map_value = function( value ) {
|
||||
value = Math.max( value, this.start_value );
|
||||
value = Math.min( value, this.end_value );
|
||||
value = ( value - this.start_value ) / this.value_range;
|
||||
// HACK: just red for now
|
||||
// return "hsl(0,100%," + (value * 100) + "%)"
|
||||
return this.start_color.mix( this.end_color, 1 - value ).toCSS();
|
||||
}
|
||||
|
||||
var SplitRamp = function( start_color, middle_color, end_color, start_value, end_value ) {
|
||||
/**
|
||||
* Two gradients split away from 0
|
||||
*/
|
||||
this.positive_ramp = new LinearRamp( middle_color, end_color, 0, end_value );
|
||||
this.negative_ramp = new LinearRamp( middle_color, start_color, 0, -start_value );
|
||||
this.start_value = start_value;
|
||||
this.end_value = end_value;
|
||||
}
|
||||
SplitRamp.prototype.map_value = function( value ) {
|
||||
value = Math.max( value, this.start_value );
|
||||
value = Math.min( value, this.end_value );
|
||||
if ( value >= 0 ) {
|
||||
return this.positive_ramp.map_value( value )
|
||||
} else {
|
||||
return this.negative_ramp.map_value( -value )
|
||||
}
|
||||
}
|
||||
|
||||
var DiagonalHeatmapPainter = function(data, view_start, view_end, prefs, mode) {
|
||||
Painter.call( this, data, view_start, view_end, prefs, mode );
|
||||
if ( this.prefs.min_value === undefined ) {
|
||||
var min_value = Infinity;
|
||||
for (var i = 0, len = this.data.length; i < len; i++) {
|
||||
min_value = Math.min( min_value, this.data[i][5] );
|
||||
}
|
||||
this.prefs.min_value = min_value;
|
||||
}
|
||||
if ( this.prefs.max_value === undefined ) {
|
||||
var max_value = -Infinity;
|
||||
for (var i = 0, len = this.data.length; i < len; i++) {
|
||||
max_value = Math.max( max_value, this.data[i][5] );
|
||||
}
|
||||
this.prefs.max_value = max_value;
|
||||
}
|
||||
};
|
||||
|
||||
DiagonalHeatmapPainter.prototype.default_prefs = {
|
||||
min_value: undefined,
|
||||
max_value: undefined,
|
||||
mode: "Heatmap",
|
||||
pos_color: "4169E1",
|
||||
neg_color: "FF8C00"
|
||||
};
|
||||
|
||||
DiagonalHeatmapPainter.prototype.draw = function(ctx, width, height, w_scale) {
|
||||
var
|
||||
min_value = this.prefs.min_value,
|
||||
max_value = this.prefs.max_value,
|
||||
value_range = max_value - min_value,
|
||||
height_px = height,
|
||||
view_start = this.view_start,
|
||||
view_range = this.view_end - this.view_start,
|
||||
mode = this.mode,
|
||||
data = this.data,
|
||||
invsqrt2 = 1 / Math.sqrt(2);
|
||||
|
||||
var ramp = ( new SplitRamp( this.prefs.neg_color, "FFFFFF", this.prefs.pos_color, min_value, max_value ) );
|
||||
|
||||
var d, s1, e1, s2, e2, value;
|
||||
|
||||
var scale = function( p ) { return ( p - view_start ) * w_scale };
|
||||
|
||||
ctx.save();
|
||||
|
||||
// Draw into triangle, then rotate and scale
|
||||
ctx.rotate(-45 * Math.PI / 180);
|
||||
ctx.scale( invsqrt2, invsqrt2 );
|
||||
|
||||
// Paint track.
|
||||
for (var i = 0, len = data.length; i < len; i++) {
|
||||
|
||||
d = data[i];
|
||||
|
||||
// Ensure the cell is visible
|
||||
// if ( )
|
||||
|
||||
s1 = scale( d[1] );
|
||||
e1 = scale( d[2] );
|
||||
s2 = scale( d[4] );
|
||||
e2 = scale( d[5] );
|
||||
value = d[6];
|
||||
|
||||
ctx.fillStyle = ( ramp.map_value( value ) )
|
||||
|
||||
ctx.fillRect( s1, s2, ( e1 - s1 ), ( e2 - s2 ) );
|
||||
}
|
||||
|
||||
ctx.restore();
|
||||
};
|
||||
|
||||
exports.Scaler = Scaler;
|
||||
exports.SummaryTreePainter = SummaryTreePainter;
|
||||
exports.LinePainter = LinePainter;
|
||||
exports.LinkedFeaturePainter = LinkedFeaturePainter;
|
||||
exports.ReadPainter = ReadPainter;
|
||||
exports.ArcLinkedFeaturePainter = ArcLinkedFeaturePainter;
|
||||
exports.DiagonalHeatmapPainter = DiagonalHeatmapPainter;
|
||||
|
||||
// End painters_module encapsulation
|
||||
};
|
||||
|
||||
@@ -67,6 +67,7 @@ var addable_objects = {
|
||||
"FeatureTrack": FeatureTrack,
|
||||
"VcfTrack": VcfTrack,
|
||||
"ReadTrack": ReadTrack,
|
||||
// "DiagonalHeatmapTrack": DiagonalHeatmapTrack,
|
||||
"CompositeTrack": CompositeTrack,
|
||||
"DrawableGroup": DrawableGroup };
|
||||
|
||||
|
||||
Reference in New Issue
Block a user