bokehmol
Version:
Handle molecules with bokeh
451 lines (450 loc) • 20.1 kB
JavaScript
;
/*!
* Copyright (c) Anaconda, Inc., and Bokeh Contributors
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* Neither the name of Anaconda nor the names of any contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
(function(root, factory) {
factory(root["Bokeh"], undefined);
})(this, function(Bokeh, version) {
let define;
return (function(modules, entry, aliases, externals) {
const bokeh = typeof Bokeh !== "undefined" ? (version != null ? Bokeh[version] : Bokeh) : null;
if (bokeh != null) {
return bokeh.register_plugin(modules, entry, aliases);
} else {
throw new Error("Cannot find Bokeh" + (version != null ? " " + version : "") + ". You have to load it prior to loading plugins.");
}
})
({
"c27055c896": /* index.js */ function _(require, module, exports, __esModule, __esExport) {
__esModule();
const tslib_1 = require("tslib");
const bokehmol = tslib_1.__importStar(require("2fbbcedd89") /* ./models */);
exports.bokehmol = bokehmol;
const base_1 = require("@bokehjs/base");
(0, base_1.register_models)(bokehmol);
},
"2fbbcedd89": /* models/index.js */ function _(require, module, exports, __esModule, __esExport) {
__esModule();
var base_formatter_1 = require("bdbba644e6") /* ./base_formatter */;
__esExport("BaseFormatter", base_formatter_1.BaseFormatter);
var base_hover_1 = require("b3aabca0fa") /* ./base_hover */;
__esExport("BaseHover", base_hover_1.BaseHover);
var rdkit_formatter_1 = require("66b72b8836") /* ./rdkit_formatter */;
__esExport("RDKitFormatter", rdkit_formatter_1.RDKitFormatter);
var rdkit_hover_1 = require("db381e1cc8") /* ./rdkit_hover */;
__esExport("RDKitHover", rdkit_hover_1.RDKitHover);
var smilesdrawer_formatter_1 = require("be6f45e05e") /* ./smilesdrawer_formatter */;
__esExport("SmilesDrawerFormatter", smilesdrawer_formatter_1.SmilesDrawerFormatter);
var smilesdrawer_hover_1 = require("6c967671db") /* ./smilesdrawer_hover */;
__esExport("SmilesDrawerHover", smilesdrawer_hover_1.SmilesDrawerHover);
},
"bdbba644e6": /* models/base_formatter.js */ function _(require, module, exports, __esModule, __esExport) {
var _a;
__esModule();
const customjs_hover_1 = require("@bokehjs/models/tools/inspectors/customjs_hover");
const combinesvg_1 = require("01840ae548") /* ./combinesvg */;
class BaseFormatter extends customjs_hover_1.CustomJSHover {
constructor(attrs) {
super(attrs);
}
makeSVGElement() {
const svg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
svg.setAttribute("xmlns", "http://www.w3.org/2000/svg");
svg.setAttribute("xmlns:xlink", "http://www.w3.org/1999/xlink");
svg.setAttributeNS(null, "width", "" + this.width);
svg.setAttributeNS(null, "height", "" + this.height);
return svg;
}
draw_grid(smiles_array) {
const images = [];
smiles_array.forEach((smiles) => {
let svg = this.draw_svg(smiles);
images.push(svg);
});
return (0, combinesvg_1.combineSVGs)(images, this.width, this.height, this.mols_per_row);
}
// @ts-expect-error
draw_svg(smiles) {
const el = this.makeSVGElement();
const svg = el.outerHTML;
el.remove();
return svg;
}
format(value, format, special_vars) {
format;
special_vars;
return Array.isArray(value) ? this.draw_grid(value) : this.draw_svg(value);
}
}
exports.BaseFormatter = BaseFormatter;
_a = BaseFormatter;
BaseFormatter.__name__ = "BaseFormatter";
BaseFormatter.__module__ = "bokehmol.models.base_formatter";
(() => {
_a.define(({ Int }) => ({
width: [Int, 160],
height: [Int, 120],
mols_per_row: [Int, 5],
}));
})();
},
"01840ae548": /* models/combinesvg.js */ function _(require, module, exports, __esModule, __esExport) {
__esModule();
exports.combineSVGs = combineSVGs;
function combineSVGs(images, width, height, maxMolsRow) {
let grid = [];
let maxWidth = width;
let maxHeight = height;
const parser = new DOMParser();
for (let i = 0; i < images.length; i++) {
let svg = images[i];
let imgWidth = width;
let imgHeight = height;
// handle RDKit's edge case when width or height is set to -1
if ((width < 0) || (height < 0)) {
// parse directly from SVG element
let el = parser.parseFromString(svg, 'image/svg+xml').firstChild;
if (width < 0) {
// @ts-expect-error
imgWidth = el.width.baseVal.value;
if (imgWidth > maxWidth) {
maxWidth = imgWidth;
}
else {
imgWidth = maxWidth;
}
}
if (height < 0)
// @ts-expect-error
imgHeight = el.height.baseVal.value;
if (imgHeight > maxHeight) {
maxHeight = imgHeight;
}
else {
imgHeight = maxHeight;
}
}
let x = imgWidth * (i % maxMolsRow);
let y = imgHeight * Math.floor(i / maxMolsRow);
let b64dump = btoa(svg);
grid.push(`<image id="molecule-${i}" transform="translate(${x},${y})" href='data:image/svg+xml;base64,${b64dump}'></image>`);
}
const parentWidth = maxWidth * Math.min(maxMolsRow, images.length);
const parentHeight = maxHeight * Math.ceil(images.length / maxMolsRow);
return `<svg width="${parentWidth}" height="${parentHeight}">${grid.join("\n")}</svg>`;
}
},
"b3aabca0fa": /* models/base_hover.js */ function _(require, module, exports, __esModule, __esExport) {
var _a;
__esModule();
const dom_1 = require("@bokehjs/core/dom");
const templating_1 = require("@bokehjs/core/util/templating");
const types_1 = require("@bokehjs/core/util/types");
const hover_tool_1 = require("@bokehjs/models/tools/inspectors/hover_tool");
const icons_css_1 = require("@bokehjs/styles/icons.css");
class BaseHoverView extends hover_tool_1.HoverToolView {
_render_tooltips(ds, vars) {
const { tooltips, smiles_column } = this.model;
const i = vars.index;
let user_tooltip = tooltips;
if (user_tooltip === null) {
user_tooltip = "";
}
if (!(0, types_1.isString)(user_tooltip)) {
const template = this._template_el ?? (
// @ts-ignore
this._template_el = this._create_template(user_tooltip));
// @ts-ignore
user_tooltip = this._render_template(template, user_tooltip, ds, vars).outerHTML;
}
const mol_tooltip = "<div>@" + smiles_column + "{custom}</div>" + user_tooltip;
const content = (0, templating_1.replace_placeholders)({ html: mol_tooltip }, ds, i, this.model.formatters, vars);
return (0, dom_1.div)(content);
}
}
exports.BaseHoverView = BaseHoverView;
BaseHoverView.__name__ = "BaseHoverView";
class BaseHover extends hover_tool_1.HoverTool {
get computed_icon() {
return "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABYAAAAWCAMAAADzapwJAAAAt1BMVEUAAAAAAAArKyskJCQcHBwrKyscHBwmJiYjIyMhISEgICAfHx8dHR0kJCQiIiIhISEhISEgICAkJCQkJCQjIyMiIiIiIiIhISEkJCQjIyMiIiIiIiIjIyMjIyMkJCQjIyMiIiIkJCQhISEjIyMiIiIiIiIiIiIkJCQjIyMiIiIiIiIiIiIiIiIhISEjIyMjIyMiIiIiIiIjIyMiIiIiIiIhISEiIiIiIiIiIiIiIiIhISEjIyP///9o30WSAAAAPHRSTlMAAQYHCQwSFBYXGBkaKy0uLzAxMjM0NTY5UVJTV1hdYHJyc3V3eHmBk5SVlpeZmpucnaqtrrCytLa7wMBTv07WAAAAAWJLR0Q8p2phzwAAAKRJREFUGBmtwQkagUAAgNF/ZAtZo2yRIrusofvfi+ab0gG8xx85gS8FDjlabJuS/db4WQ1RRksy+p3ZRZpxbZA6t8gYJxRzTc7WQhKPCjnlSJDwXEIdRQ9xPRKeS+eAcurjeiTEo8JhgNTdU44EUm9D9SlIRDV2FkrYZjHhazrHOJLS7xReRSi+CtzqZJYjmiUoNRn7/GixbUr2WyPHCXwpcPifD0UBD3u/QqniAAAAAElFTkSuQmCC";
}
constructor(attrs) {
super(attrs);
this.tool_icon = icons_css_1.tool_icon_hover;
}
}
exports.BaseHover = BaseHover;
_a = BaseHover;
BaseHover.__name__ = "BaseHover";
BaseHover.__module__ = "bokehmol.models.base_hover";
(() => {
_a.prototype.default_view = BaseHoverView;
_a.define(({ Str, Int }) => ({
smiles_column: [Str, "SMILES"],
width: [Int, 160],
height: [Int, 120],
mols_per_row: [Int, 3],
}));
_a.override({
tooltips: [],
});
})();
},
"66b72b8836": /* models/rdkit_formatter.js */ function _(require, module, exports, __esModule, __esExport) {
var _a;
__esModule();
const base_formatter_1 = require("bdbba644e6") /* ./base_formatter */;
class RDKitFormatter extends base_formatter_1.BaseFormatter {
constructor(attrs) {
super(attrs);
}
initialize() {
super.initialize();
this.onRDKitReady(true, false, () => {
// @ts-expect-error
initRDKitModule().then((RDKitModule) => {
this.RDKitModule = RDKitModule;
console.log("RDKit version: " + RDKitModule.version());
});
});
}
onRDKitReady(init, lib, callback) {
this.hasLoadedRDKit(init, lib) ? callback() : setTimeout(() => {
this.onRDKitReady(init, lib, callback);
}, 100);
}
hasLoadedRDKit(init, lib) {
// @ts-expect-error
return (init ? typeof initRDKitModule !== "undefined" : true)
&& (lib ? typeof this.RDKitModule !== "undefined" : true);
}
setupRDKitOptions() {
this.onRDKitReady(true, true, () => {
this.RDKitModule.prefer_coordgen(this.prefer_coordgen);
});
this.json_mol_opts = JSON.stringify({
removeHs: this.remove_hs,
sanitize: this.sanitize,
kekulize: this.kekulize,
});
this.json_draw_opts = JSON.stringify({
width: this.width,
height: this.height,
...this.draw_options,
});
return this.json_draw_opts;
}
draw_svg(smiles) {
const draw_opts = this.json_draw_opts ?? this.setupRDKitOptions();
var mol;
this.onRDKitReady(true, true, () => {
mol = this.RDKitModule.get_mol(smiles, this.json_mol_opts);
});
// @ts-expect-error
if (typeof mol === "undefined") {
console.log("Attempting to display structures before RDKit has been loaded.");
}
else if (mol !== null && mol.is_valid()) {
const svg = mol.get_svg_with_highlights(draw_opts);
mol.delete();
return svg;
}
return super.draw_svg(smiles);
}
}
exports.RDKitFormatter = RDKitFormatter;
_a = RDKitFormatter;
RDKitFormatter.__name__ = "RDKitFormatter";
RDKitFormatter.__module__ = "bokehmol.models.rdkit_formatter";
(() => {
_a.define(({ Bool, Dict, Unknown }) => ({
prefer_coordgen: [Bool, true],
remove_hs: [Bool, true],
sanitize: [Bool, true],
kekulize: [Bool, true],
draw_options: [Dict(Unknown), {}],
}));
})();
},
"db381e1cc8": /* models/rdkit_hover.js */ function _(require, module, exports, __esModule, __esExport) {
var _a;
__esModule();
const base_hover_1 = require("b3aabca0fa") /* ./base_hover */;
const rdkit_formatter_1 = require("66b72b8836") /* ./rdkit_formatter */;
class RDKitHoverView extends base_hover_1.BaseHoverView {
initialize() {
super.initialize();
const { formatters, smiles_column, width, height, mols_per_row, prefer_coordgen, remove_hs, sanitize, kekulize, draw_options } = this.model;
// @ts-expect-error
formatters["@" + smiles_column] = new rdkit_formatter_1.RDKitFormatter({
width: width,
height: height,
mols_per_row: mols_per_row,
prefer_coordgen: prefer_coordgen,
remove_hs: remove_hs,
sanitize: sanitize,
kekulize: kekulize,
draw_options: draw_options,
});
}
}
exports.RDKitHoverView = RDKitHoverView;
RDKitHoverView.__name__ = "RDKitHoverView";
class RDKitHover extends base_hover_1.BaseHover {
get computed_icon() {
return "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQBAMAAADt3eJSAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAAFVBMVEXc3NwUFP8UPP9kZP+MjP+0tP////9ZXZotAAAAAXRSTlMAQObYZgAAAAFiS0dEBmFmuH0AAAAHdElNRQfmAwsPGi+MyC9RAAAAQElEQVQI12NgQABGQUEBMENISUkRLKBsbGwEEhIyBgJFsICLC0iIUdnExcUZwnANQWfApKCK4doRBsKtQFgKAQC5Ww1JEHSEkAAAACV0RVh0ZGF0ZTpjcmVhdGUAMjAyMi0wMy0xMVQxNToyNjo0NyswMDowMDzr2J4AAAAldEVYdGRhdGU6bW9kaWZ5ADIwMjItMDMtMTFUMTU6MjY6NDcrMDA6MDBNtmAiAAAAAElFTkSuQmCC";
}
constructor(attrs) {
super(attrs);
this.tool_name = "RDKit Hover";
}
}
exports.RDKitHover = RDKitHover;
_a = RDKitHover;
RDKitHover.__name__ = "RDKitHover";
RDKitHover.__module__ = "bokehmol.models.rdkit_hover";
(() => {
_a.prototype.default_view = RDKitHoverView;
_a.define(({ Bool, Dict, Unknown }) => ({
prefer_coordgen: [Bool, true],
remove_hs: [Bool, true],
sanitize: [Bool, true],
kekulize: [Bool, true],
draw_options: [Dict(Unknown), {}],
}));
_a.register_alias("rdkit_hover", () => new _a());
})();
},
"be6f45e05e": /* models/smilesdrawer_formatter.js */ function _(require, module, exports, __esModule, __esExport) {
var _a;
__esModule();
const base_formatter_1 = require("bdbba644e6") /* ./base_formatter */;
class SmilesDrawerFormatter extends base_formatter_1.BaseFormatter {
constructor(attrs) {
super(attrs);
}
initialize() {
super.initialize();
this.onSmiDrawerReady(true, false, () => {
// @ts-expect-error
this.SmiDrawer = SmiDrawer;
});
}
onSmiDrawerReady(init, lib, callback) {
this.hasLoadedSmiDrawer(init, lib) ? callback() : setTimeout(() => {
this.onSmiDrawerReady(init, lib, callback);
}, 100);
}
hasLoadedSmiDrawer(init, lib) {
// @ts-expect-error
return (init ? typeof SmiDrawer !== "undefined" : true)
&& (lib ? typeof this.SmiDrawer !== "undefined" : true);
}
makeSVGElement() {
const el = super.makeSVGElement();
el.style.backgroundColor = this.background_colour;
return el;
}
setupDrawer() {
this.onSmiDrawerReady(true, true, () => {
this.drawer = new this.SmiDrawer(this.mol_options, this.reaction_options);
});
return this.drawer;
}
draw_svg(smiles) {
const el = this.makeSVGElement();
this.onSmiDrawerReady(true, true, () => {
const sd = this.drawer ?? this.setupDrawer();
sd.draw(smiles, el, this.theme);
});
const svg = el.outerHTML;
el.remove();
return svg;
}
}
exports.SmilesDrawerFormatter = SmilesDrawerFormatter;
_a = SmilesDrawerFormatter;
SmilesDrawerFormatter.__name__ = "SmilesDrawerFormatter";
SmilesDrawerFormatter.__module__ = "bokehmol.models.smilesdrawer_formatter";
(() => {
_a.define(({ Str, Dict, Unknown }) => ({
theme: [Str, "light"],
background_colour: [Str, "transparent"],
mol_options: [Dict(Unknown), {}],
reaction_options: [Dict(Unknown), {}],
}));
})();
},
"6c967671db": /* models/smilesdrawer_hover.js */ function _(require, module, exports, __esModule, __esExport) {
var _a;
__esModule();
const base_hover_1 = require("b3aabca0fa") /* ./base_hover */;
const smilesdrawer_formatter_1 = require("be6f45e05e") /* ./smilesdrawer_formatter */;
class SmilesDrawerHoverView extends base_hover_1.BaseHoverView {
initialize() {
super.initialize();
const { formatters, smiles_column, width, height, mols_per_row, theme, background_colour, mol_options, reaction_options, } = this.model;
// @ts-expect-error
formatters["@" + smiles_column] = new smilesdrawer_formatter_1.SmilesDrawerFormatter({
width: width,
height: height,
mols_per_row: mols_per_row,
theme: theme,
background_colour: background_colour,
mol_options: mol_options,
reaction_options: reaction_options,
});
}
}
exports.SmilesDrawerHoverView = SmilesDrawerHoverView;
SmilesDrawerHoverView.__name__ = "SmilesDrawerHoverView";
class SmilesDrawerHover extends base_hover_1.BaseHover {
constructor(attrs) {
super(attrs);
this.tool_name = "SmilesDrawer Hover";
}
}
exports.SmilesDrawerHover = SmilesDrawerHover;
_a = SmilesDrawerHover;
SmilesDrawerHover.__name__ = "SmilesDrawerHover";
SmilesDrawerHover.__module__ = "bokehmol.models.smilesdrawer_hover";
(() => {
_a.prototype.default_view = SmilesDrawerHoverView;
_a.define(({ Str, Dict, Unknown }) => ({
theme: [Str, "light"],
background_colour: [Str, "transparent"],
mol_options: [Dict(Unknown), {}],
reaction_options: [Dict(Unknown), {}],
}));
_a.register_alias("smiles_hover", () => new _a());
})();
},
}, "c27055c896", {"index":"c27055c896","models/index":"2fbbcedd89","models/base_formatter":"bdbba644e6","models/combinesvg":"01840ae548","models/base_hover":"b3aabca0fa","models/rdkit_formatter":"66b72b8836","models/rdkit_hover":"db381e1cc8","models/smilesdrawer_formatter":"be6f45e05e","models/smilesdrawer_hover":"6c967671db"}, {});});
//# sourceMappingURL=bokehmol.js.map