Skip to content

Commit

Permalink
Merge pull request #120 from zakandrewking/convert-map-in-js
Browse files Browse the repository at this point in the history
Convert map in js
  • Loading branch information
zakandrewking committed Aug 18, 2015
2 parents 2e118e9 + c4046e0 commit dedff52
Show file tree
Hide file tree
Showing 22 changed files with 835 additions and 465 deletions.
4 changes: 2 additions & 2 deletions docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,9 +51,9 @@
# built documents.
#
# The short X.Y version.
version = '1.2.0'
version = '1.2.1'
# The full version, including alpha/beta/rc tags.
release = '1.2.0'
release = '1.2.1'

# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
Expand Down
17 changes: 12 additions & 5 deletions docs/contribute_maps.rst
Original file line number Diff line number Diff line change
Expand Up @@ -63,11 +63,18 @@ Building from an existing map for a similar organism
Follow the instruction above, except, rather than starting from scratch, load an
existing Escher map for a different organism.

In the Settings menu, activate the **Highlight reactions not in model**
option. Reactions that do not match your loaded COBRA model turn red, and you
can delete these and replace them with appropriate reactions from the new model.

You can repeat this for as many subsystems as you like.
Once you have the new model loaded, use the **Update names and gene reaction
rules using model** button in the Model menu to convert all descriptive names
and gene reaction rules in the model to those in the map. Reactions that do not
match the model will be highlighted in red. (This can be turned off again in the
settings menu by deselecting *Highlight reactions not in model*.)

Now, visit each highlighted reaction and see if you can replace it with an
equivalent biochemical pathway from the model. If not, then delete the reaction
and move on.

Finally, when there are no highlighted reactions left, you can repeat this for
other subsystems.

Submitting maps to the Escher website
-------------------------------------
Expand Down
10 changes: 10 additions & 0 deletions docs/getting_started.rst
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,16 @@ Choose **Load COBRA model JSON** to open a COBRA model. Read more about COBRA
models in :doc:`escher_and_cobrapy`. Once you have COBRApy v0.3.0 or later
installed, then you can generate a JSON model by following this `example code`_.

Once you have loaded a COBRA model, there may be inconsistencies between the
content in the map and the model (e.g. reaction IDs, descriptive names and gene
reaction rules). You click **Update names and gene reaction rules using model**
to find matching reactions and metabolites between the map and the model (based
on their IDs) and then apply the names and gene reaction rules from the model to
the map. The reactions that do not match will be highlighted in red. (This can
be turned off again in the settings menu by deselecting *Highlight reactions not
in model*.) More advice on building maps is available in
:doc:`contribute_maps`.

Click **Clear Model** to clear the current model.

.. _loading-reaction-gene-and-metabolite-data:
Expand Down
6 changes: 3 additions & 3 deletions docs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -18,17 +18,17 @@ Escher in 3 minutes

<iframe width="100%" height="315" src="https://www.youtube.com/embed/qUipX-xzZjQ" frameborder="0" allowfullscreen></iframe><br/><br/>

Help! I just upgraded to v1.3 and my map and model caches are empty!
Help! I just upgraded to v1.2 and my map and model caches are empty!
--------------------------------------------------------------------

Starting with Escher v1.3, the maps and models available from the Escher website
Starting with Escher v1.2, the maps and models available from the Escher website
are versioned. Each time you upgrade Escher, you will have access to the new
versions of the Escher maps and models. Any maps and models you were using
before are still saved in the Escher cache in case you need them. For more
details on finding, managing, and clearing the cache, see :ref:`the Python cache
functions<cache>`.

Also starting with Escher v1.3, the maps and models in Escher are the same as
Also starting with Escher v1.2, the maps and models in Escher are the same as
those in the `BiGG Database`_.

Features
Expand Down
49 changes: 26 additions & 23 deletions escher/convert_map.py
Original file line number Diff line number Diff line change
Expand Up @@ -420,34 +420,37 @@ def old_map_to_new_schema(the_map, map_name=None, map_description=None):
"""

def add_default_header(body, name, description):
"""Return a map with header and body."""

def check_for(var, name):
"""Print a warning if var is None."""
if var is None:
logging.warn('No {} for map'.format(name))
return ''
return var

new_id = hashlib.md5(json.dumps(body).encode('utf-8')).hexdigest()
default_header = {
"schema": "https://escher.github.io/escher/jsonschema/1-0-0#",
"homepage": "https://escher.github.io",
"map_name": check_for(name, 'name'),
"map_id": new_id,
"map_description": check_for(description, 'description')
}
logging.info('Map has the ID {}'.format(new_id))
return make_map(default_header, body)

def add_header_if_missing(a_map):
"""Check for new, 2-level maps, and add the header."""

def add_default_header(body):
"""Return a map with header and body."""

def check_for(var, name):
"""Print a warning if var is None."""
if var is None:
logging.warn('No {} for map'.format(name))
return ''
return var

new_id = hashlib.md5(json.dumps(body).encode('utf-8')).hexdigest()
default_header = {
"schema": "https://escher.github.io/escher/jsonschema/1-0-0#",
"homepage": "https://escher.github.io",
"map_name": check_for(map_name, 'name'),
"map_id": new_id,
"map_description": check_for(map_description, 'description')
}
logging.info('Map has the ID {}'.format(new_id))
return make_map(default_header, body)

if has_header_and_body(a_map):
return a_map
use_name = (get_header(a_map)['map_name'] if map_name is None else map_name)
use_description = (get_header(a_map)['map_description']
if map_description is None else map_description)
return add_default_header(get_body(a_map), use_name, use_description)
elif is_valid_body(a_map):
return add_default_header(a_map)
return add_default_header(a_map, map_name, map_description)
else:
raise Exception('The map provided cannot be converted. It is not a valid Escher map.')

Expand Down
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ svg.escher-svg .gene-label {
font-size: 18px;
fill: rgb(32, 32, 120);
text-rendering: optimizelegibility;
cursor: default;
}
svg.escher-svg .text-label .label {
font-size: 50px;
Expand Down
68 changes: 37 additions & 31 deletions escher/js/src/Builder.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
define(['utils', 'BuildInput', 'ZoomContainer', 'Map', 'CobraModel', 'Brush', 'CallbackManager', 'ui', 'SearchBar', 'Settings', 'SettingsMenu', 'TextEditInput', 'QuickJump', 'data_styles'], function(utils, BuildInput, ZoomContainer, Map, CobraModel, Brush, CallbackManager, ui, SearchBar, Settings, SettingsMenu, TextEditInput, QuickJump, data_styles) {
/** For documentation of this class, see docs/javascript_api.rst
/** For documentation of this class, see docs/javascript_api.rst
*/
*/
var Builder = utils.make_class();
Builder.prototype = { init: init,
load_map: load_map,
Expand Down Expand Up @@ -41,7 +41,7 @@ define(['utils', 'BuildInput', 'ZoomContainer', 'Map', 'CobraModel', 'Brush', 'C
this.model_data = model_data;
this.embedded_css = embedded_css;
this.selection = selection;

// apply this object as data for the selection
this.selection.datum(this);

Expand Down Expand Up @@ -118,7 +118,7 @@ define(['utils', 'BuildInput', 'ZoomContainer', 'Map', 'CobraModel', 'Brush', 'C
}.bind(this),
// the options that are erased when the settings menu is canceled
conditional_options = ['hide_secondary_metabolites', 'show_gene_reaction_rules',
'hide_all_labels', 'scroll_behavior', 'reaction_styles',
'hide_all_labels', 'scroll_behavior', 'reaction_styles',
'reaction_compare_style', 'reaction_scale',
'reaction_no_data_color', 'reaction_no_data_size',
'and_method_in_gene_reaction_rule', 'metabolite_styles',
Expand Down Expand Up @@ -188,7 +188,7 @@ define(['utils', 'BuildInput', 'ZoomContainer', 'Map', 'CobraModel', 'Brush', 'C
this.cobra_model = null;
else
this.cobra_model = CobraModel.from_cobra_json(model_data);

if (this.map) {
this.map.cobra_model = this.cobra_model;
if (should_update_data)
Expand All @@ -201,7 +201,7 @@ define(['utils', 'BuildInput', 'ZoomContainer', 'Map', 'CobraModel', 'Brush', 'C
}

function load_map(map_data, should_update_data) {
/** For documentation of this function, see docs/javascript_api.rst
/** For documentation of this function, see docs/javascript_api.rst
*/

Expand Down Expand Up @@ -406,47 +406,47 @@ define(['utils', 'BuildInput', 'ZoomContainer', 'Map', 'CobraModel', 'Brush', 'C
this.map.deselect_text_labels();
this.map.draw_everything();
}

function view_mode() {
/** For documentation of this function, see docs/javascript_api.rst.
*/
this.callback_manager.run('view_mode');
this._set_mode('view');
}

function build_mode() {
/** For documentation of this function, see docs/javascript_api.rst.
*/
this.callback_manager.run('build_mode');
this._set_mode('build');
}

function brush_mode() {
/** For documentation of this function, see docs/javascript_api.rst.
*/
this.callback_manager.run('brush_mode');
this._set_mode('brush');
}

function zoom_mode() {
/** For documentation of this function, see docs/javascript_api.rst.
*/
this.callback_manager.run('zoom_mode');
this._set_mode('zoom');
}

function rotate_mode() {
/** For documentation of this function, see docs/javascript_api.rst.
*/
this.callback_manager.run('rotate_mode');
this._set_mode('rotate');
}

function text_mode() {
/** For documentation of this function, see docs/javascript_api.rst.
Expand All @@ -463,7 +463,7 @@ define(['utils', 'BuildInput', 'ZoomContainer', 'Map', 'CobraModel', 'Brush', 'C
this._update_data(true, true, 'reaction');
this.map.set_status('');
}

function set_gene_data(data, clear_gene_reaction_rules) {
/** For documentation of this function, see docs/javascript_api.rst.
Expand All @@ -474,7 +474,7 @@ define(['utils', 'BuildInput', 'ZoomContainer', 'Map', 'CobraModel', 'Brush', 'C
this._update_data(true, true, 'reaction');
this.map.set_status('');
}

function set_metabolite_data(data) {
/** For documentation of this function, see docs/javascript_api.rst.
Expand Down Expand Up @@ -513,14 +513,14 @@ define(['utils', 'BuildInput', 'ZoomContainer', 'Map', 'CobraModel', 'Brush', 'C
met_data_object,
reaction_data_object,
gene_data_object;

// -------------------
// First map, and draw

// metabolite data
if (update_metabolite_data && update_map && this.map !== null) {
met_data_object = data_styles.import_and_check(this.options.metabolite_data,
'metabolite_data');
'metabolite_data');
this.map.apply_metabolite_data_to_map(met_data_object);
if (should_draw)
this.map.draw_all_nodes(false);
Expand All @@ -536,7 +536,7 @@ define(['utils', 'BuildInput', 'ZoomContainer', 'Map', 'CobraModel', 'Brush', 'C
this.map.draw_all_reactions(false, false);
} else if (this.options.gene_data !== null && update_map && this.map !== null) {
gene_data_object = make_gene_data_object(this.options.gene_data,
this.cobra_model, this.map);
this.cobra_model, this.map);
this.map.apply_gene_data_to_map(gene_data_object);
if (should_draw)
this.map.draw_all_reactions(false, false);
Expand All @@ -548,15 +548,15 @@ define(['utils', 'BuildInput', 'ZoomContainer', 'Map', 'CobraModel', 'Brush', 'C
}
}

// ----------------------------------------------------------------
// ----------------------------------------------------------------
// Then the model, after drawing. Delay by 5ms so the the map draws
// first.

// if this function runs again, cancel the previous model update
if (this.update_model_timer)
window.clearTimeout(this.update_model_timer);

var delay = 5;
var delay = 5;
this.update_model_timer = window.setTimeout(function() {

// metabolite_data
Expand All @@ -569,7 +569,7 @@ define(['utils', 'BuildInput', 'ZoomContainer', 'Map', 'CobraModel', 'Brush', 'C
this.options.metabolite_styles,
this.options.metabolite_compare_style);
}

// reaction data
if (update_reaction_data) {
if (this.options.reaction_data !== null && update_model && this.cobra_model !== null) {
Expand All @@ -583,7 +583,7 @@ define(['utils', 'BuildInput', 'ZoomContainer', 'Map', 'CobraModel', 'Brush', 'C
} else if (this.options.gene_data !== null && update_model && this.cobra_model !== null) {
if (!gene_data_object)
gene_data_object = make_gene_data_object(this.options.gene_data,
this.cobra_model, this.map);
this.cobra_model, this.map);
this.cobra_model.apply_gene_data(gene_data_object,
this.options.reaction_styles,
this.options.identifiers_on_map,
Expand All @@ -601,7 +601,7 @@ define(['utils', 'BuildInput', 'ZoomContainer', 'Map', 'CobraModel', 'Brush', 'C
this.callback_manager.run('update_data', null, update_model, update_map, kind, should_draw);

}.bind(this), delay);

// definitions
function make_gene_data_object(gene_data, cobra_model, map) {
var all_reactions = {};
Expand Down Expand Up @@ -657,20 +657,25 @@ define(['utils', 'BuildInput', 'ZoomContainer', 'Map', 'CobraModel', 'Brush', 'C
map.set_status('');
} }
})
.button({ key: keys.clear_model,
.button({ id: 'convert_map',
key: keys.convert_map,
text: 'Update names and gene reaction rules using model' })
.button({ id: 'clear_model',
key: keys.clear_model,
text: 'Clear model' });
// disable the clear button
var disable_model_clear = function() {
// disable the clear and convert buttons
var disable_model_clear_convert = function() {
model_menu.dropdown.selectAll('li')
.classed('escher-disabled', function(d) {
if (d.text == 'Clear model' && this.cobra_model === null)
if ((d.id == 'clear_model' || d.id == 'convert_map') &&
this.cobra_model === null)
return true;
return null;
}.bind(this));
}.bind(this);
disable_model_clear();
this.callback_manager.set('load_model', disable_model_clear);
disable_model_clear_convert();
this.callback_manager.set('load_model', disable_model_clear_convert);

// data dropdown
var data_menu = ui.dropdown_menu(menu, 'Data')
.button({ input: { assign: key_manager.assigned_keys.load_reaction_data,
Expand Down Expand Up @@ -700,7 +705,7 @@ define(['utils', 'BuildInput', 'ZoomContainer', 'Map', 'CobraModel', 'Brush', 'C
text: 'Clear gene data' })
.divider()
.button({ input: { fn: load_metabolite_data_for_file.bind(this),
accept_csv: true,
accept_csv: true,
pre_fn: function() {
map.set_status('Loading metabolite data ...');
},
Expand Down Expand Up @@ -1074,7 +1079,7 @@ define(['utils', 'BuildInput', 'ZoomContainer', 'Map', 'CobraModel', 'Brush', 'C
this.map.set_status('');
}.bind(this));
}.bind(this);

// make the quick jump object
this.quick_jump = QuickJump(selection, load_fn);
}
Expand Down Expand Up @@ -1111,6 +1116,7 @@ define(['utils', 'BuildInput', 'ZoomContainer', 'Map', 'CobraModel', 'Brush', 'C
fn: map.save_svg },
load: { key: 79, modifiers: { control: true }, // ctrl-o
fn: null }, // defined by button
convert_map: { fn: this.map.convert_map.bind(this.map) },
clear_map: { fn: this.map.clear_map.bind(this.map) },
load_model: { key: 77, modifiers: { control: true }, // ctrl-m
fn: null }, // defined by button
Expand Down
Loading

0 comments on commit dedff52

Please sign in to comment.