Trackster: enable a tool to be run on complete dataset or a visible region.

This commit is contained in:
Jeremy Goecks
2011-05-04 10:20:54 -04:00
parent 36017bc964
commit faafc762bf
3 changed files with 118 additions and 81 deletions
+55 -56
View File
@@ -645,16 +645,17 @@ class TracksController( BaseController, UsesVisualization, UsesHistoryDatasetAss
return self.tracks_grid( trans, **kwargs )
@web.expose
def run_tool( self, trans, dataset_id, chrom, low, high, tool_id, **kwargs ):
def run_tool( self, trans, dataset_id, tool_id, chrom=None, low=None, high=None, **kwargs ):
"""
Run a tool on a subset of input data to produce a new output dataset that
corresponds to a dataset that a user is currently viewing.
"""
# Parameter checks.
if not chrom or not low or not high:
return messages.NO_DATA
low, high = int( low ), int( high )
# Run tool on region if region is specificied.
run_on_region = False
if chrom and low and high:
run_on_region = True
low, high = int( low ), int( high )
# Dataset check.
original_dataset = self.get_dataset( trans, dataset_id, check_ownership=False, check_accessible=True )
@@ -678,27 +679,23 @@ class TracksController( BaseController, UsesVisualization, UsesHistoryDatasetAss
tool_params = tool.params_from_strings( tool_params, self.app )
#
# Convert input datasets so that region of dataset can be quickly
# extracted.
# TODO: Is it useful/necessary to create data subsets for all input
# datasets or only the original dataset (aka the dataset that the user
# is viewing)? Currently we create data subsets for all input datasets
# because this provides the best performance as the tool runs on small
# datasets.
# If running tool on region, convert input datasets (create indices) so
# that can regions of data can be quickly extracted.
#
messages_list = []
for jida in original_job.input_datasets:
input_dataset = jida.dataset
# TODO: put together more robust way to determine if a dataset can be indexed.
if hasattr( input_dataset, 'get_track_type' ):
# Can index dataset.
track_type, data_sources = input_dataset.datatype.get_track_type()
# Convert to datasource that provides 'data' because we need to
# extract the original data.
data_source = data_sources[ 'data' ]
msg = self._convert_dataset( trans, input_dataset, data_source )
if msg is not None:
messages_list.append( msg )
if run_on_region:
for jida in original_job.input_datasets:
input_dataset = jida.dataset
# TODO: put together more robust way to determine if a dataset can be indexed.
if hasattr( input_dataset, 'get_track_type' ):
# Can index dataset.
track_type, data_sources = input_dataset.datatype.get_track_type()
# Convert to datasource that provides 'data' because we need to
# extract the original data.
data_source = data_sources[ 'data' ]
msg = self._convert_dataset( trans, input_dataset, data_source )
if msg is not None:
messages_list.append( msg )
# Return any messages generated during conversions.
return_message = _get_highest_priority_msg( messages_list )
@@ -706,41 +703,40 @@ class TracksController( BaseController, UsesVisualization, UsesHistoryDatasetAss
return return_message
#
# Set input datasets for tool. Input datasets are subsets of full
# datasets and are based on chrom, low, high.
# Set target history (the history that tool will use for inputs/outputs).
# If user owns dataset, put new data in original dataset's history; if
# user does not own dataset (and hence is accessing dataset via sharing),
# put new data in user's current history.
#
# If user is rerunning own tool, put new data in original dataset's
# history. If another user is running tool, put new data in current
# history.
if original_dataset.history.user == trans.user:
working_history = original_dataset.history
target_history = original_dataset.history
else:
working_history = trans.get_history( create=True )
hda_permissions = trans.app.security_agent.history_get_default_permissions( working_history )
messages_list = []
target_history = trans.get_history( create=True )
hda_permissions = trans.app.security_agent.history_get_default_permissions( target_history )
#
# Set input datasets for tool. If running on region, extract and use subset
# when possible.
#
for jida in original_job.input_datasets:
input_dataset = jida.dataset
if hasattr( input_dataset.datatype, 'get_track_type' ):
#
# Dataset can be indexed and hence a subset can be extracted.
#
if run_on_region and hasattr( input_dataset.datatype, 'get_track_type' ):
# Dataset is indexed and hence a subset can be extracted and used
# as input.
track_type, data_sources = input_dataset.datatype.get_track_type()
data_source = data_sources[ 'data' ]
converted_dataset = input_dataset.get_converted_dataset( trans, data_source )
deps = input_dataset.get_converted_dataset_deps( trans, data_source )
#
# Create new HDA for input dataset's subset.
#
new_dataset = trans.app.model.HistoryDatasetAssociation( extension=input_dataset.ext, \
dbkey=input_dataset.dbkey, \
create_dataset=True, \
sa_session=trans.sa_session,
name="Subset [%s:%i-%i] of data %i" % \
( chrom, low, high, input_dataset.hid ),
visible=False )
working_history.add_dataset( new_dataset )
dbkey=input_dataset.dbkey, \
create_dataset=True, \
sa_session=trans.sa_session,
name="Subset [%s:%i-%i] of data %i" % \
( chrom, low, high, input_dataset.hid ),
visible=False )
target_history.add_dataset( new_dataset )
trans.sa_session.add( new_dataset )
trans.app.security_agent.set_all_dataset_permissions( new_dataset.dataset, hda_permissions )
@@ -751,7 +747,7 @@ class TracksController( BaseController, UsesVisualization, UsesHistoryDatasetAss
dependencies=deps )
data_provider.write_data_to_file( chrom, low, high, new_dataset.file_name )
# TODO: size not working.
# TODO: (a) size not working; (b) need to set peek.
new_dataset.set_size()
new_dataset.info = "Data subset for trackster"
new_dataset.set_dataset_state( trans.app.model.Dataset.states.OK )
@@ -761,18 +757,21 @@ class TracksController( BaseController, UsesVisualization, UsesHistoryDatasetAss
tool_params[ jida.name ] = new_dataset
#
# Start tool and handle outputs.
# Execute tool and handle outputs.
#
try:
subset_job, subset_job_outputs = tool.execute( trans, incoming=tool_params, history=working_history )
subset_job, subset_job_outputs = tool.execute( trans, incoming=tool_params, history=target_history )
except Exception, e:
# Lots of things can go wrong when trying to execute tool.
return to_json_string( { "error" : True, "message" : e.__class__.__name__ + ": " + str(e) } )
for output in subset_job_outputs.values():
output.visible = False
trans.sa_session.flush()
if run_on_region:
for output in subset_job_outputs.values():
output.visible = False
trans.sa_session.flush()
#
# Return new track that corresponds to the original dataset.
#
output_name = None
for joda in original_job.output_datasets:
if joda.dataset == original_dataset:
@@ -784,9 +783,9 @@ class TracksController( BaseController, UsesVisualization, UsesHistoryDatasetAss
return self.add_track_async( trans, output_dataset.id )
#
# -----------------
# Helper methods.
#
# -----------------
def _check_dataset_state( self, trans, dataset ):
"""
File diff suppressed because one or more lines are too long
+62 -24
View File
@@ -885,11 +885,15 @@ var Tool = function(track, tool_dict) {
this.parent_div.find("input").click(function() { $(this).select() });
// Add 'Go' button.
var run_tool_row = $("<div>").addClass("slider-row").appendTo(this.parent_div);
var run_tool_button = $("<input type='submit'>").attr("value", "Run").appendTo(run_tool_row);
var run_tool_row = $("<div>").addClass("param-row").appendTo(this.parent_div);
var run_on_dataset_button = $("<input type='submit'>").attr("value", "Run on complete dataset").appendTo(run_tool_row);
var run_on_region_button = $("<input type='submit'>").attr("value", "Run on visible region").css("margin-left", "3em").appendTo(run_tool_row);
var tool = this;
run_tool_button.click( function() {
tool.run();
run_on_region_button.click( function() {
tool.run_on_region();
});
run_on_dataset_button.click( function() {
tool.run_on_dataset();
});
};
extend(Tool.prototype, {
@@ -920,51 +924,87 @@ extend(Tool.prototype, {
return param_values;
},
/**
* Run tool. This creates a new child track, runs tool, and places tool's output in the new track.
* Run tool on dataset. Output is placed in dataset's history and no changes to viz are made.
*/
run: function() {
// Put together params for running tool.
var url_params = {
dataset_id: this.track.original_dataset_id,
chrom: this.track.view.chrom,
low: this.track.view.low,
high: this.track.view.high,
tool_id: this.name
};
$.extend(url_params, this.get_param_values_dict());
run_on_dataset: function() {
var tool = this;
tool.run(
// URL params.
{
dataset_id: this.track.original_dataset_id,
tool_id: tool.name
},
// Success callback.
function(track_data) {
show_modal(tool.name + " is Running",
tool.name + " is running on the complete dataset. Tool outputs are in dataset's history.",
{ "Close" : hide_modal } );
}
);
},
/**
* Run dataset on visible region. This creates a new track and sets the track's contents
* to the tool's output.
*/
run_on_region: function() {
//
// Create track for tool's output immediately to provide user feedback.
//
var
url_params =
{
dataset_id: this.track.original_dataset_id,
chrom: this.track.view.chrom,
low: this.track.view.low,
high: this.track.view.high,
tool_id: this.name
},
current_track = this.track,
// Set name of track to include tool name, parameters, and region used.
track_name = url_params.tool_id +
current_track.tool_region_and_parameters_str(url_params.chrom, url_params.low, url_params.high),
new_track;
// Create and add track.
// TODO: add support for other kinds of tool data tracks.
if (current_track.track_type === 'FeatureTrack') {
new_track = new ToolDataFeatureTrack(track_name, view, current_track.hda_ldda, undefined, {}, {}, current_track);
}
this.track.add_track(new_track);
new_track.content_div.text("Starting job.");
// Run tool.
this.run(url_params,
// Success callback.
function(track_data) {
new_track.dataset_id = track_data.dataset_id;
new_track.content_div.text("Running job.");
new_track.init();
}
);
},
/**
* Run tool using a set of URL params and a success callback.
*/
run: function(url_params, success_callback) {
// Add tool params to URL params.
$.extend(url_params, this.get_param_values_dict());
// Run tool.
var json_run_tool = function() {
$.getJSON(run_tool_url, url_params, function(track_data) {
if (track_data === "no converter") {
$.getJSON(run_tool_url, url_params, function(response) {
if (response === "no converter") {
// No converter available for input datasets, so cannot run tool.
new_track.container_div.addClass("error");
new_track.content_div.text(DATA_NOCONVERTER);
}
else if (track_data.error) {
else if (response.error) {
// General error.
new_track.container_div.addClass("error");
new_track.content_div.text(DATA_CANNOT_RUN_TOOL + track_data.message);
new_track.content_div.text(DATA_CANNOT_RUN_TOOL + response.message);
}
else if (track_data === "pending") {
else if (response === "pending") {
// Converting/indexing input datasets; show message and try again.
new_track.container_div.addClass("pending");
new_track.content_div.text("Converting input data so that it can be easily reused.");
@@ -972,9 +1012,7 @@ extend(Tool.prototype, {
}
else {
// Job submitted and running.
new_track.dataset_id = track_data.dataset_id;
new_track.content_div.text("Running job.");
new_track.init();
success_callback(response);
}
});
};