trackster: Changing display mode from "Auto" now fetches additional detail data and displays features. Displays error messages in canvas elements if present. Limit number of features displayed in one tile due to above feature. Fix bugs in visualization creation from form

This commit is contained in:
Kanwei Li
2010-09-01 18:20:42 -04:00
parent 66bae6120f
commit 4ea8dd779b
6 changed files with 48 additions and 44 deletions
@@ -9,6 +9,8 @@ import pkg_resources; pkg_resources.require( "bx-python" )
from bx.interval_index_file import Indexes
from galaxy.datatypes.interval import Bed, Gff
MAX_VALS = 500 # only display first MAX_VALS features
class IntervalIndexDataProvider( object ):
def __init__( self, converted_dataset, original_dataset ):
self.original_dataset = original_dataset
@@ -20,8 +22,14 @@ class IntervalIndexDataProvider( object ):
source = open( self.original_dataset.file_name )
index = Indexes( self.converted_dataset.file_name )
results = []
count = 0
message = None
for start, end, offset in index.find(chrom, start, end):
if count >= MAX_VALS:
message = "Only the first %s features are being displayed." % MAX_VALS
break
count += 1
source.seek(offset)
feature = source.readline().split()
payload = [ offset, start, end ]
@@ -53,4 +61,4 @@ class IntervalIndexDataProvider( object ):
results.append(payload)
return results
return { 'data': results, 'message': message }
+2 -1
View File
@@ -291,7 +291,8 @@ class TracksController( BaseController, UsesVisualization ):
# Have to choose between indexer and data provider
indexer = dataset_type_to_data_provider[data_sources['index']]( dataset.get_converted_dataset(trans, data_sources['index']), dataset )
summary = indexer.get_summary( chrom, low, high, **kwargs )
if summary is not None:
if summary is not None and kwargs.get("mode", "Auto") == "Auto":
# Only check for summary if it's Auto mode (which is the default)
if summary == "no_detail":
kwargs["no_detail"] = True # meh
extra_info = "no_detail"
+18 -33
View File
@@ -228,7 +228,7 @@ class VisualizationController( BaseController, Sharable, UsesAnnotations, UsesVi
# Get session and visualization.
session = trans.sa_session
visualization = trans.sa_session.query( model.Visualization ).get( trans.security.decode_id( id ) )
visualization = self.get_visualization( trans, id, check_ownership=True )
# Do operation on visualization.
if 'make_accessible_via_link' in kwargs:
@@ -261,7 +261,7 @@ class VisualizationController( BaseController, Sharable, UsesAnnotations, UsesVi
def share( self, trans, id=None, email="", use_panels=False ):
""" Handle sharing a visualization with a particular user. """
msg = mtype = None
visualization = trans.sa_session.query( model.Visualization ).get( trans.security.decode_id( id ) )
visualization = self.get_visualization( trans, id, check_ownership=True )
if email:
other = trans.sa_session.query( model.User ) \
.filter( and_( model.User.table.c.email==email,
@@ -330,7 +330,7 @@ class VisualizationController( BaseController, Sharable, UsesAnnotations, UsesVi
@web.require_login( "get item name and link" )
def get_name_and_link_async( self, trans, id=None ):
""" Returns visualization's name and link. """
visualization = self.get_visualization( trans, id )
visualization = self.get_visualization( trans, id, check_ownership=False, check_accessible=True )
if self.create_item_slug( trans.sa_session, visualization ):
trans.sa_session.flush()
@@ -342,7 +342,7 @@ class VisualizationController( BaseController, Sharable, UsesAnnotations, UsesVi
""" Returns item content in HTML format. """
# Get visualization, making sure it's accessible.
visualization = self.get_visualization( trans, id, False, True )
visualization = self.get_visualization( trans, id, check_ownership=False, check_accessible=True )
if visualization is None:
raise web.httpexceptions.HTTPNotFound()
@@ -373,25 +373,26 @@ class VisualizationController( BaseController, Sharable, UsesAnnotations, UsesVi
visualization = model.Visualization()
visualization.title = visualization_title
visualization.slug = visualization_slug
visualization.dbkey = visualization_dbkey
visualization.type = 'trackster' # HACK: set visualization type to trackster since it's the only viz
visualization_annotation = sanitize_html( visualization_annotation, 'utf-8', 'text/html' )
self.add_item_annotation( trans, visualization, visualization_annotation )
visualization.user = user
# And the first (empty) visualization revision
visualization_revision = model.VisualizationRevision()
visualization_revision.title = visualization_title
visualization_revision.config = {}
visualization_revision.dbkey = visualization_dbkey
visualization_revision.visualization = visualization
# HACK: set visualization type to trackster; when we have multiple visualization types, we'll need to get type from the user.
visualization.type = 'trackster'
visualization.latest_revision = visualization_revision
# Visualization config is dbkey for now.
visualization.latest_revision.config = { 'dbkey' : visualization_dbkey }
visualization_revision.content = ""
# Persist
session = trans.sa_session
session.add( visualization )
session.add(visualization)
session.add(visualization_revision)
session.flush()
# Display the management visualization
## trans.set_message( "Visualization '%s' created" % visualization.title )
return trans.response.send_redirect( web.url_for( action='list' ) )
return trans.show_form(
@@ -414,12 +415,9 @@ class VisualizationController( BaseController, Sharable, UsesAnnotations, UsesVi
"""
Edit a visualization's attributes.
"""
encoded_id = id
id = trans.security.decode_id( id )
visualization = self.get_visualization( trans, id, check_ownership=True )
session = trans.sa_session
visualization = session.query( model.Visualization ).get( id )
user = trans.user
assert visualization.user == user
visualization_title_err = visualization_slug_err = visualization_annotation_err = ""
if trans.request.method == "POST":
if not visualization_title:
@@ -428,7 +426,7 @@ class VisualizationController( BaseController, Sharable, UsesAnnotations, UsesVi
visualization_slug_err = "Visualization id is required"
elif not VALID_SLUG_RE.match( visualization_slug ):
visualization_slug_err = "Visualization identifier must consist of only lowercase letters, numbers, and the '-' character"
elif visualization_slug != visualization.slug and trans.sa_session.query( model.Visualization ).filter_by( user=user, slug=visualization_slug, deleted=False ).first():
elif visualization_slug != visualization.slug and trans.sa_session.query( model.Visualization ).filter_by( user=visualization.user, slug=visualization_slug, deleted=False ).first():
visualization_slug_err = "Visualization id must be unique"
else:
visualization.title = visualization_title
@@ -449,7 +447,7 @@ class VisualizationController( BaseController, Sharable, UsesAnnotations, UsesVi
if not visualization_annotation:
visualization_annotation = ""
return trans.show_form(
web.FormBuilder( web.url_for( id=encoded_id ), "Edit visualization attributes", submit_text="Submit" )
web.FormBuilder( web.url_for( id=id ), "Edit visualization attributes", submit_text="Submit" )
.add_text( "visualization_title", "Visualization title", value=visualization_title, error=visualization_title_err )
.add_text( "visualization_slug", "Visualization identifier", value=visualization_slug, error=visualization_slug_err,
help="""A unique identifier that will be used for
@@ -460,18 +458,5 @@ class VisualizationController( BaseController, Sharable, UsesAnnotations, UsesVi
.add_text( "visualization_annotation", "Visualization annotation", value=visualization_annotation, error=visualization_annotation_err,
help="A description of the visualization; annotation is shown alongside published visualizations."),
template="visualization/create.mako" )
# @web.expose
# @web.require_login()
# def list( self, trans, *args, **kwargs ):
# return self.list_grid( trans, *args, **kwargs )
#@web.expose
#@web.require_admin
#def index( self, trans, *args, **kwargs ):
# # Build grid
# grid = self.list( trans, *args, **kwargs )
# # Render grid wrapped in panels
# return trans.fill_template( "visualization/index.mako", grid=grid )
File diff suppressed because one or more lines are too long
+17 -8
View File
@@ -951,9 +951,8 @@ $.extend( FeatureTrack.prototype, TiledTrack.prototype, {
var track = this,
key = "initial";
this.init_each({ low: track.view.max_low,
high: track.view.max_high, dataset_id: track.dataset_id,
chrom: track.view.chrom, resolution: this.view.resolution }, function (result) {
this.init_each({ low: track.view.max_low, high: track.view.max_high, dataset_id: track.dataset_id,
chrom: track.view.chrom, resolution: this.view.resolution, mode: track.mode }, function (result) {
track.mode_div.show();
track.data_cache.set(key, result);
track.draw();
@@ -1089,12 +1088,11 @@ $.extend( FeatureTrack.prototype, TiledTrack.prototype, {
break;
}
}*/
var k = (!this.initial_canvas ? "initial" : tile_low + '_' + tile_high);
var result = this.data_cache.get(k);
var cur_mode;
if (result === undefined) {
if (result === undefined || (this.mode !== "Auto" && result.dataset_type === "summary_tree")) {
this.data_queue[ [tile_low, tile_high] ] = true;
this.get_data(tile_low, tile_high);
return;
@@ -1112,7 +1110,7 @@ $.extend( FeatureTrack.prototype, TiledTrack.prototype, {
if (result.dataset_type === "summary_tree") {
required_height = this.summary_draw_height;
} else if (mode === "Dense") {
required_height = 15;
required_height = 25;
y_scale = 10;
} else {
// Calculate new slots incrementally for this new chunk of data and update height if necessary
@@ -1169,6 +1167,16 @@ $.extend( FeatureTrack.prototype, TiledTrack.prototype, {
return new_canvas;
}
if (result.message) {
new_canvas.css({
border: "solid red",
"border-width": "2px 2px 2px 0px"
});
ctx.fillStyle = "red";
ctx.textAlign = "left";
ctx.fillText(result.message, 100 + left_offset, y_scale);
}
var data = result.data;
var j = 0;
for (var i = 0, len = data.length; i < len; i++) {
@@ -1181,7 +1189,7 @@ $.extend( FeatureTrack.prototype, TiledTrack.prototype, {
if (feature_start <= tile_high && feature_end >= tile_low) {
var f_start = Math.floor( Math.max(0, (feature_start - tile_low) * w_scale) ),
f_end = Math.ceil( Math.min(width, Math.max(0, (feature_end - tile_low) * w_scale)) ),
y_center = (mode === "Dense" ? 0 : slots[feature_uid] * y_scale);
y_center = (mode === "Dense" ? 1 : (1 + slots[feature_uid])) * y_scale;
if (result.dataset_type === "bai") {
ctx.fillStyle = block_color;
@@ -1222,6 +1230,7 @@ $.extend( FeatureTrack.prototype, TiledTrack.prototype, {
// console.log(feature_uid, feature_start, feature_end, f_start, f_end, y_center);
if (no_detail) {
ctx.fillStyle = block_color;
ctx.fillRect(f_start + left_offset, y_center + 5, f_end - f_start, 1);
} else {
// Showing labels, blocks, details
@@ -1291,7 +1300,7 @@ $.extend( FeatureTrack.prototype, TiledTrack.prototype, {
ctx.fillStyle = LEFT_STRAND_INV;
}
ctx.fillRect(f_start + left_offset, y_center, f_end - f_start, 10);
ctx.fillStyle = prefs.block_color;
ctx.fillStyle = block_color;
}
}
}
+1
View File
@@ -41,6 +41,7 @@ ${h.css( "history", "autocomplete_tagging", "trackster" )}
<div class="unified-panel-header" unselectable="on">
<div class="unified-panel-header-inner">
<div style="float:left;" id="title"></div>
<a class="panel-header-button right-float" href="${h.url_for( controller='visualization', action='list' )}">Close</a>
<a id="save-button" class="panel-header-button right-float" href="javascript:void(0);">Save</a>
<a id="refresh-button" class="panel-header-button right-float" href="javascript:void(0);" onclick="view.update_options();return false;">Refresh</a>
</div>