{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "static-wrestling",
   "metadata": {},
   "source": [
    "# Exploring molecular generative models checking out their latent spaces\n",
    "\n",
    "Here you can find some examples on how to explore the latent spaces of some of the molecular generative models hosted in GT4SD."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "natural-orbit",
   "metadata": {},
   "outputs": [],
   "source": [
    "import torch\n",
    "import mols2grid\n",
    "import seaborn as sns\n",
    "from tqdm import tqdm\n",
    "from rdkit import Chem\n",
    "from typing import Optional, List\n",
    "from matplotlib import pyplot as plt\n",
    "from sklearn.decomposition import PCA\n",
    "from paccmann_generator.drug_evaluators.scsore import SCScore\n",
    "\n",
    "\n",
    "def render_latent_points(latent_points: torch.Tensor, values: Optional[List]):\n",
    "    decomposed_points = PCA(n_components=2).fit_transform(latent_points)\n",
    "    sns.scatterplot(x=decomposed_points[:, 0], y=decomposed_points[:, 1], hue=values)\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "suspected-custom",
   "metadata": {},
   "source": [
    "## PolymerBlocks\n",
    "\n",
    "An algorithm for generating monomers and catalyst for polymer chemistry."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "significant-magic",
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "Using TensorFlow backend.\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "19:55:04   using as local cache path: /Users/tte/.gt4sd\n",
      "19:55:04   Better speed can be achieved with apex installed from https://www.github.com/nvidia/apex .\n",
      "19:55:05   runnning PolymerBlocks with configuration=PolymerBlocksGenerator(algorithm_version='v0', batch_size=32, generated_length=100)\n",
      "19:55:05   ensure artifacts for the application are present.\n",
      "19:55:05   starting syncing\n",
      "19:55:05   syncing complete\n"
     ]
    }
   ],
   "source": [
    "from gt4sd.algorithms.generation.polymer_blocks.core import PolymerBlocksGenerator, PolymerBlocks\n",
    "\n",
    "configuration = PolymerBlocksGenerator()\n",
    "algorithm = PolymerBlocks(configuration=configuration)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "administrative-scratch",
   "metadata": {},
   "source": [
    "Via the algorithm you can easily inspect the generated molecules interactively:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "still-anxiety",
   "metadata": {},
   "outputs": [],
   "source": [
    "molecules = list(algorithm.sample(15))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "competitive-updating",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<script>\n",
       "    function fit_height(obj) {\n",
       "        obj.style.height = 0;\n",
       "        var height = obj.contentDocument.body.scrollHeight + 18 + 'px';\n",
       "        obj.style.height = height;\n",
       "    }\n",
       "</script>\n",
       "<iframe class=\"mols2grid-iframe\" frameborder=\"0\" width=\"100%\"\n",
       "\n",
       "height=\"200\"\n",
       "\n",
       "\n",
       "allow=\"clipboard-write\"\n",
       "\n",
       "srcdoc=\"&lt;html&gt;\n",
       "  &lt;meta charset=&quot;utf-8&quot;&gt;\n",
       "  &lt;head&gt;\n",
       "    &lt;style&gt;\n",
       "    #mols2grid.gridcontainer {\n",
       "    display: block;\n",
       "    padding-left: 1em;\n",
       "    max-width: 820px;\n",
       "    width: 820px;\n",
       "}\n",
       "#mols2grid .cell {\n",
       "    border: 1px solid #cccccc;\n",
       "    text-align: center;\n",
       "    vertical-align: top;\n",
       "    max-width: 160px;\n",
       "    width: 160px;\n",
       "    font-family: &#x27;DejaVu&#x27;, sans-serif;\n",
       "    font-size: 12pt;\n",
       "    padding: 0;\n",
       "    margin: 0px;\n",
       "    float: left;\n",
       "}\n",
       "#mols2grid .cell:hover {\n",
       "    background-color: #e7e7e7 !important;\n",
       "}\n",
       "#mols2grid .cell .data-img {\n",
       "    padding: 0;\n",
       "    margin: 0;\n",
       "}\n",
       "#mols2grid .cell img, #mols2grid .cell svg {\n",
       "    max-width: 100%;\n",
       "    height: auto;\n",
       "    padding: 0;\n",
       "}\n",
       "#mols2grid .data {\n",
       "    overflow: hidden;\n",
       "    white-space: nowrap;\n",
       "    text-overflow: ellipsis;\n",
       "    display: block;\n",
       "}\n",
       "#mols2grid .arrow-asc:after {\n",
       "    content: &#x27;↑&#x27;;\n",
       "    text-align: right;\n",
       "    float:right;\n",
       "}\n",
       "#mols2grid .arrow-desc:after {\n",
       "    content: &#x27;↓&#x27;;\n",
       "    text-align: right;\n",
       "    float:right;\n",
       "}\n",
       "    /* custom CSS */\n",
       "    \n",
       "    &lt;/style&gt;\n",
       "    &lt;script src=&quot;https://cdnjs.cloudflare.com/ajax/libs/list.js/2.3.1/list.min.js&quot;&gt;&lt;/script&gt;\n",
       "&lt;link rel=&quot;stylesheet&quot; href=&quot;https://cdn.jsdelivr.net/npm/bootstrap@4.6.0/dist/css/bootstrap.min.css&quot; integrity=&quot;sha384-B0vP5xmATw1+K9KRQjQERJvTumQW0nPEzvF6L/Z6nronJ3oUOFUFpCjEUQouq2+l&quot; crossorigin=&quot;anonymous&quot;&gt;\n",
       "&lt;script src=&quot;https://code.jquery.com/jquery-3.5.1.slim.min.js&quot; integrity=&quot;sha384-DfXdz2htPH0lsSSs5nCTpuj/zy4C+OGpamoFVy38MVBnE+IbbVYUew+OrCXaRkfj&quot; crossorigin=&quot;anonymous&quot;&gt;&lt;/script&gt;\n",
       "&lt;script src=&quot;https://cdn.jsdelivr.net/npm/bootstrap@4.6.0/dist/js/bootstrap.bundle.min.js&quot; integrity=&quot;sha384-Piv4xVNRyMGpqkS2by6br4gNJ7DXjqk09RmUpJ8jgGtD7zP9yug3goQfGII0yAns&quot; crossorigin=&quot;anonymous&quot;&gt;&lt;/script&gt;\n",
       "&lt;script src=&quot;https://unpkg.com/@rdkit/rdkit@2021.9.4/Code/MinimalLib/dist/RDKit_minimal.js&quot;&gt;&lt;/script&gt;\n",
       "    &lt;!-- custom header --&gt;\n",
       "    \n",
       "  &lt;/head&gt;\n",
       "  &lt;body&gt;\n",
       "    &lt;div id=&quot;mols2grid&quot; class=&quot;gridcontainer grid-default&quot;&gt;\n",
       "      &lt;div class=&quot;row mb-3&quot;&gt;\n",
       "        &lt;div class=&quot;list&quot;&gt;&lt;div class=&quot;cell&quot; data-mols2grid-id=&quot;0&quot;&gt;&lt;input type=&quot;checkbox&quot; class=&quot;position-relative float-left cached_checkbox&quot;&gt;&lt;div class=&quot;data data-img&quot;&gt;&lt;/div&gt;&lt;div class=&quot;data data-mols2grid-id-copy&quot;&gt;&lt;/div&gt;&lt;div class=&quot;data data-SMILES&quot;&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;\n",
       "      &lt;/div&gt;\n",
       "      &lt;div class=&quot;d-inline&quot;&gt;\n",
       "        &lt;ul class=&quot;pagination float-left&quot;&gt;&lt;/ul&gt;\n",
       "        &lt;div id=&quot;controls&quot; class=&quot;d-flex flex-row float-right&quot;&gt;\n",
       "          \n",
       "          &lt;div id=&quot;chkbox-dropdown&quot; class=&quot;dropdown&quot;&gt;\n",
       "    &lt;button class=&quot;btn btn-light dropdown-toggle&quot; type=&quot;button&quot; id=&quot;chkboxDropdown&quot; data-toggle=&quot;dropdown&quot; aria-haspopup=&quot;true&quot; aria-expanded=&quot;false&quot;&gt;☑&lt;/button&gt;\n",
       "    &lt;div class=&quot;dropdown-menu&quot; aria-labelledby=&quot;checkboxDropdownMenu&quot;&gt;\n",
       "        &lt;button id=&quot;btn-chkbox-all&quot; class=&quot;dropdown-item&quot; type=&quot;button&quot;&gt;Check all&lt;/button&gt;\n",
       "        &lt;button id=&quot;btn-chkbox-none&quot; class=&quot;dropdown-item&quot; type=&quot;button&quot;&gt;Uncheck all&lt;/button&gt;\n",
       "        &lt;button id=&quot;btn-chkbox-invert&quot; class=&quot;dropdown-item&quot; type=&quot;button&quot;&gt;Invert&lt;/button&gt;\n",
       "        &lt;div class=&quot;dropdown-divider&quot;&gt;&lt;/div&gt;\n",
       "        &lt;button id=&quot;btn-chkbox-copy&quot; class=&quot;dropdown-item&quot; type=&quot;button&quot;&gt;Copy to clipboard&lt;/button&gt;\n",
       "        &lt;button id=&quot;btn-chkbox-dlsmi&quot; class=&quot;dropdown-item&quot; type=&quot;button&quot;&gt;Save SMILES&lt;/button&gt;\n",
       "        &lt;button id=&quot;btn-chkbox-dlcsv&quot; class=&quot;dropdown-item&quot; type=&quot;button&quot;&gt;Save CSV&lt;/button&gt;\n",
       "    &lt;/div&gt;\n",
       "&lt;/div&gt;\n",
       "          \n",
       "          &lt;div id=&quot;sort-dropdown&quot; class=&quot;dropdown pl-2&quot;&gt;\n",
       "            &lt;button class=&quot;btn btn-light dropdown-toggle&quot; type=&quot;button&quot; id=&quot;sortDropdown&quot; data-toggle=&quot;dropdown&quot; aria-haspopup=&quot;true&quot; aria-expanded=&quot;false&quot;&gt;\n",
       "              Sort by\n",
       "            &lt;/button&gt;\n",
       "            &lt;div class=&quot;dropdown-menu&quot; aria-labelledby=&quot;sortDropdownMenu&quot;&gt;\n",
       "              \n",
       "              \n",
       "              \n",
       "              \n",
       "              \n",
       "              &lt;button class=&quot;dropdown-item sort-btn arrow-asc active&quot; type=&quot;button&quot; data-name=&quot;mols2grid-id&quot;&gt;Index&lt;/button&gt;\n",
       "              \n",
       "              \n",
       "              \n",
       "              \n",
       "              \n",
       "              &lt;button class=&quot;dropdown-item sort-btn arrow-asc active&quot; type=&quot;button&quot; data-name=&quot;data-mols2grid-id&quot;&gt;mols2grid-id&lt;/button&gt;\n",
       "              \n",
       "              \n",
       "              \n",
       "              \n",
       "              \n",
       "              &lt;button class=&quot;dropdown-item sort-btn &quot; type=&quot;button&quot; data-name=&quot;data-SMILES&quot;&gt;SMILES&lt;/button&gt;\n",
       "              \n",
       "              \n",
       "              \n",
       "              &lt;button class=&quot;dropdown-item sort-btn&quot; type=&quot;button&quot; data-name=&quot;checkbox&quot;&gt;Selected&lt;/button&gt;\n",
       "              \n",
       "            &lt;/div&gt;\n",
       "          &lt;/div&gt;\n",
       "          &lt;div class=&quot;input-group row pl-4&quot;&gt;\n",
       "            &lt;input type=&quot;text&quot; id=&quot;searchbar&quot; class=&quot;form-control&quot; placeholder=&quot;Search&quot; aria-label=&quot;Search&quot; aria-describedby=&quot;basic-addon1&quot;&gt;\n",
       "            &lt;div class=&quot;input-group-append&quot;&gt;\n",
       "              &lt;button id=&quot;searchBtn&quot; class=&quot;btn btn-light dropdown-toggle&quot; type=&quot;button&quot; data-toggle=&quot;dropdown&quot; aria-haspopup=&quot;true&quot; aria-expanded=&quot;false&quot;&gt;🔎&lt;/button&gt;\n",
       "              &lt;div class=&quot;dropdown-menu dropdown-menu-right&quot;&gt;\n",
       "                &lt;button id=&quot;txtSearch&quot; class=&quot;search-btn dropdown-item active&quot;&gt;Text&lt;/button&gt;\n",
       "                &lt;button id=&quot;smartsSearch&quot; class=&quot;search-btn dropdown-item&quot;&gt;SMARTS&lt;/button&gt;\n",
       "              &lt;/div&gt;\n",
       "            &lt;/div&gt;\n",
       "          &lt;/div&gt;\n",
       "        &lt;/div&gt;\n",
       "      &lt;/div&gt;\n",
       "    &lt;/div&gt;\n",
       "    &lt;script&gt;\n",
       "    // list.js\n",
       "var listObj = new List(&#x27;mols2grid&#x27;, {\n",
       "    valueNames: [{data: [&#x27;mols2grid-id&#x27;]}, &#x27;data-img&#x27;, &#x27;data-mols2grid-id&#x27;, &#x27;data-SMILES&#x27;, &#x27;data-mols2grid-id-copy&#x27;],\n",
       "    item: &#x27;&lt;div class=&quot;cell&quot; data-mols2grid-id=&quot;0&quot;&gt;&lt;input type=&quot;checkbox&quot; class=&quot;position-relative float-left cached_checkbox&quot;&gt;&lt;div class=&quot;data data-img&quot;&gt;&lt;/div&gt;&lt;div class=&quot;data data-mols2grid-id-copy&quot;&gt;&lt;/div&gt;&lt;div class=&quot;data data-SMILES&quot;&gt;&lt;/div&gt;&lt;/div&gt;&#x27;,\n",
       "    page: 15,\n",
       "    pagination: {\n",
       "        name: &quot;pagination&quot;,\n",
       "        item: &#x27;&lt;li class=&quot;page-item&quot;&gt;&lt;a class=&quot;page page-link&quot; href=&quot;#&quot; onclick=&quot;event.preventDefault()&quot;&gt;&lt;/a&gt;&lt;/li&gt;&#x27;,\n",
       "        innerWindow: 1,\n",
       "        outerWindow: 1,\n",
       "    },\n",
       "});\n",
       "listObj.remove(&quot;mols2grid-id&quot;, &quot;0&quot;);\n",
       "listObj.add([{&quot;data-img&quot;: null, &quot;mols2grid-id&quot;: 0, &quot;data-SMILES&quot;: &quot;C=CC&quot;, &quot;data-mols2grid-id-copy&quot;: 0}, {&quot;data-img&quot;: null, &quot;mols2grid-id&quot;: 1, &quot;data-SMILES&quot;: &quot;CCN(C(=O)OCC1(C)COC(=O)OC1)c1ccccc1&quot;, &quot;data-mols2grid-id-copy&quot;: 1}, {&quot;data-img&quot;: null, &quot;mols2grid-id&quot;: 2, &quot;data-SMILES&quot;: &quot;CN(C1=CC=C=C[N+]=CCC1)C(OCC(CCO)(NCCO)OC(C)(C)C)C(=O)c1ccccc1&quot;, &quot;data-mols2grid-id-copy&quot;: 2}, {&quot;data-img&quot;: null, &quot;mols2grid-id&quot;: 3, &quot;data-SMILES&quot;: &quot;CCOC(=O)OCCC1(C)COC(=O)OC1&quot;, &quot;data-mols2grid-id-copy&quot;: 3}, {&quot;data-img&quot;: null, &quot;mols2grid-id&quot;: 4, &quot;data-SMILES&quot;: &quot;CC1(C(=O)OCC2=C(F)C(F)=C(F)C(F)C(F)=C2F)COC(=O)OC1&quot;, &quot;data-mols2grid-id-copy&quot;: 4}, {&quot;data-img&quot;: null, &quot;mols2grid-id&quot;: 5, &quot;data-SMILES&quot;: &quot;CC(C)(C)OC(=O)N=C(NCCCOC(=O)C1(C)COC(=O)OC1)NC(=O)OC(C)(C)C&quot;, &quot;data-mols2grid-id-copy&quot;: 5}, {&quot;data-img&quot;: null, &quot;mols2grid-id&quot;: 6, &quot;data-SMILES&quot;: &quot;CC1(C(=O)OCCN2C(=O)C3C4C=CC(O4)C3C2=O)COC(=O)OC1&quot;, &quot;data-mols2grid-id-copy&quot;: 6}, {&quot;data-img&quot;: null, &quot;mols2grid-id&quot;: 7, &quot;data-SMILES&quot;: &quot;CS(C1=CC=C(c2ccccc2)CC1=O)(C(F)(F)F)C(F)(F)F&quot;, &quot;data-mols2grid-id-copy&quot;: 7}, {&quot;data-img&quot;: null, &quot;mols2grid-id&quot;: 8, &quot;data-SMILES&quot;: &quot;CC1(COC(=O)Nc2ccc(C=O)cc2)COC(=O)OC1&quot;, &quot;data-mols2grid-id-copy&quot;: 8}, {&quot;data-img&quot;: null, &quot;mols2grid-id&quot;: 9, &quot;data-SMILES&quot;: &quot;CC1(C(=O)OCc2ccc(Cl)cc2)COC(=O)OC1&quot;, &quot;data-mols2grid-id-copy&quot;: 9}, {&quot;data-img&quot;: null, &quot;mols2grid-id&quot;: 10, &quot;data-SMILES&quot;: &quot;CC1(CCN2C(=O)OCC2C(=O)Nc2ccccc2)C=CC(=O)OC1&quot;, &quot;data-mols2grid-id-copy&quot;: 10}, {&quot;data-img&quot;: null, &quot;mols2grid-id&quot;: 11, &quot;data-SMILES&quot;: &quot;CC1(C(=O)OCCCc2ccccc2)COC(=O)OC1&quot;, &quot;data-mols2grid-id-copy&quot;: 11}, {&quot;data-img&quot;: null, &quot;mols2grid-id&quot;: 12, &quot;data-SMILES&quot;: &quot;CC(C)(C)C(=O)OCC(=O)c1cccn1CCCOC(=O)C1(C)COC(=O)OC1&quot;, &quot;data-mols2grid-id-copy&quot;: 12}, {&quot;data-img&quot;: null, &quot;mols2grid-id&quot;: 13, &quot;data-SMILES&quot;: &quot;CC1(C(=O)OCC(F)(F)F)COC(=O)OC1&quot;, &quot;data-mols2grid-id-copy&quot;: 13}, {&quot;data-img&quot;: null, &quot;mols2grid-id&quot;: 14, &quot;data-SMILES&quot;: &quot;Cc1cc(C)c(N2CCN(c3c(C)cc(C)cc3C)C2OC(C)(C)C)c(C)c1&quot;, &quot;data-mols2grid-id-copy&quot;: 14}]);\n",
       "// filter\n",
       "if (window.parent.mols2grid_lists === undefined) {\n",
       "    window.parent.mols2grid_lists = {};\n",
       "}\n",
       "window.parent.mols2grid_lists[&quot;default&quot;] = listObj;\n",
       "\n",
       "\n",
       "// selection\n",
       "class MolStorage extends Map {\n",
       "    multi_set(_id, _smiles) {\n",
       "        for (let i=0; i &lt; _id.length; i++) {\n",
       "            this.set(_id[i], _smiles[i]);\n",
       "        }\n",
       "    }\n",
       "    multi_del(_id) {\n",
       "        for (let i=0; i &lt; _id.length; i++) {\n",
       "            this.delete(_id[i]);\n",
       "        };\n",
       "    }\n",
       "    to_dict() {\n",
       "        var content = &quot;{&quot;;\n",
       "        for (let [key, value] of this) {\n",
       "            content += key + &quot;:&quot; + JSON.stringify(value) + &quot;,&quot;;\n",
       "        }\n",
       "        content = content.length &gt; 1 ? content.slice(0, -1) : content;\n",
       "        content += &quot;}&quot;;\n",
       "        return content\n",
       "    }\n",
       "    download_smi(fileName) {\n",
       "        var content = &quot;SMILES index\\n&quot;;\n",
       "        for (let [key, value] of this) {\n",
       "            content += value + &quot; &quot; + key + &quot;\\n&quot;;\n",
       "        }\n",
       "        var a = document.createElement(&quot;a&quot;);\n",
       "        var file = new Blob([content], {type: &quot;text/plain&quot;});\n",
       "        a.href = URL.createObjectURL(file);\n",
       "        a.download = fileName;\n",
       "        a.click();\n",
       "        a.remove();\n",
       "    }\n",
       "}\n",
       "var SELECTION = new MolStorage();\n",
       "\n",
       "\n",
       "\n",
       "// kernel\n",
       "var kernel_env = null;\n",
       "if (window.parent.IPython !== undefined) {\n",
       "    // Jupyter notebook\n",
       "    kernel_env = &quot;jupyter&quot;;\n",
       "    var kernel = window.parent.IPython.notebook.kernel;\n",
       "    kernel.execute(&#x27;from mols2grid.select import register as _m2g_reg&#x27;)\n",
       "    function add_selection(grid_id, _id, smiles) {\n",
       "        SELECTION.multi_set(_id, smiles);\n",
       "        kernel.execute(&quot;_m2g_reg.add_selection(&#x27;&quot;+grid_id+&quot;&#x27;, &quot;+JSON.stringify(_id)+&quot;,&quot;+JSON.stringify(smiles)+&quot;)&quot;);\n",
       "    }\n",
       "    function del_selection(grid_id, _id) {\n",
       "        SELECTION.multi_del(_id);\n",
       "        kernel.execute(&quot;_m2g_reg.del_selection(&#x27;&quot;+grid_id+&quot;&#x27;, &quot;+JSON.stringify(_id)+&quot;)&quot;);\n",
       "    }\n",
       "} else if (window.parent.google !== undefined) {\n",
       "    // Google colab\n",
       "    kernel_env = &quot;colab&quot;;\n",
       "    var kernel = window.parent.google.colab.kernel;\n",
       "    function add_selection(grid_id, _id, smiles) {\n",
       "        SELECTION.multi_set(_id, smiles);\n",
       "        (async function() {\n",
       "        const result = await kernel.invokeFunction(&#x27;_m2g_reg.add_selection&#x27;,\n",
       "                                                   [grid_id, _id, smiles], {});\n",
       "        })();\n",
       "    }\n",
       "    function del_selection(grid_id, _id) {\n",
       "        SELECTION.multi_del(_id);\n",
       "        (async function() {\n",
       "        const result = await kernel.invokeFunction(&#x27;_m2g_reg.del_selection&#x27;,\n",
       "                                                   [grid_id, _id], {});\n",
       "        })();\n",
       "    }\n",
       "} else {\n",
       "    function add_selection(grid_id, _id, smiles) {\n",
       "        SELECTION.multi_set(_id, smiles);\n",
       "    }\n",
       "    function del_selection(grid_id, _id) {\n",
       "        SELECTION.multi_del(_id);\n",
       "    }\n",
       "}\n",
       "\n",
       "\n",
       "\n",
       "\n",
       "// sort\n",
       "var sort_field = &quot;mols2grid-id&quot;;\n",
       "var sort_order = &quot;asc&quot;;\n",
       "function mols2gridSortFunction(itemA, itemB, options) {\n",
       "    var x = itemA.values()[options.valueName];\n",
       "    var y = itemB.values()[options.valueName];\n",
       "    if (typeof x === &quot;number&quot;) {\n",
       "        if (isFinite(x - y)) {\n",
       "            return x - y; \n",
       "        } else {\n",
       "            return isFinite(x) ? -1 : 1;\n",
       "        }\n",
       "    } else {\n",
       "        x = x.toLowerCase();\n",
       "        y = y.toLowerCase();\n",
       "        return (x &lt; y) ? -1: (x &gt; y) ? 1: 0;\n",
       "    }\n",
       "}\n",
       "function checkboxSort(itemA, itemB, options) {\n",
       "    if (itemA.elm !== undefined) {\n",
       "        var checkedA = itemA.elm.firstChild.checked;\n",
       "        if (itemB.elm !== undefined) {\n",
       "            var checkedB = itemB.elm.firstChild.checked;\n",
       "            if (checkedA &amp;&amp; !checkedB) {\n",
       "                return -1;\n",
       "            } else if (!checkedA &amp;&amp; checkedB) {\n",
       "                return 1;\n",
       "            } else {\n",
       "                return 0;\n",
       "            }\n",
       "        } else {\n",
       "            return -1;\n",
       "        }\n",
       "    } else if (itemB.elm !== undefined) {\n",
       "        return 1;\n",
       "    } else {\n",
       "        return 0;\n",
       "    }\n",
       "}\n",
       "$(&#x27;#mols2grid button.sort-btn&#x27;).click(function(e) {\n",
       "    var _field = $(this).attr(&quot;data-name&quot;);\n",
       "    if (_field == sort_field) {\n",
       "        $(this).removeClass(&quot;arrow-&quot; + sort_order)\n",
       "        sort_order = (sort_order === &quot;desc&quot;) ? &quot;asc&quot; : &quot;desc&quot;;\n",
       "    } else {\n",
       "        $(&#x27;#mols2grid button.sort-btn.active&#x27;).removeClass(&quot;active arrow-&quot; + sort_order);\n",
       "        sort_order = &quot;asc&quot;;\n",
       "        sort_field = _field;\n",
       "        $(this).addClass(&quot;active&quot;);\n",
       "    }\n",
       "    $(this).addClass(&quot;arrow-&quot; + sort_order)\n",
       "    if (sort_field == &quot;checkbox&quot;) {\n",
       "        listObj.sort(&quot;mols2grid-id&quot;, {order: sort_order, sortFunction: checkboxSort});\n",
       "    } else {\n",
       "        listObj.sort(_field, {order: sort_order, sortFunction: mols2gridSortFunction});\n",
       "    }\n",
       "});\n",
       "\n",
       "\n",
       "\n",
       "\n",
       "\n",
       "\n",
       "// selection modifyers and export options\n",
       "// check all\n",
       "$(&#x27;#btn-chkbox-all&#x27;).click(function (e) {\n",
       "    var current_page = parseInt($(&quot;li.page-item.active &gt; a&quot;).text());\n",
       "    var n_items = 15;\n",
       "    var last_page = parseInt($(&quot;li.page-item &gt; a&quot;).last().text());\n",
       "    var _id = [];\n",
       "    var _smiles = [];\n",
       "    for (let i = 0; i &lt; last_page; i++) {\n",
       "        listObj.show(i * n_items + 1, n_items);\n",
       "        $(&quot;input:checkbox&quot;).each(function() {\n",
       "            this.checked = true;\n",
       "            _id.push(parseInt($(this).closest(&quot;.cell&quot;).attr(&quot;data-mols2grid-id&quot;)));\n",
       "            _smiles.push($($(this).siblings(&quot;.data-SMILES&quot;)[0]).text());\n",
       "        });\n",
       "    }\n",
       "    listObj.show((current_page - 1) * n_items + 1, n_items);\n",
       "    add_selection(&quot;default&quot;, _id, _smiles);\n",
       "});\n",
       "// uncheck all\n",
       "$(&#x27;#btn-chkbox-none&#x27;).click(function (e) {\n",
       "    var current_page = parseInt($(&quot;li.page-item.active &gt; a&quot;).text());\n",
       "    var n_items = 15;\n",
       "    var last_page = parseInt($(&quot;li.page-item &gt; a&quot;).last().text());\n",
       "    var _id = [];\n",
       "    for (let i = 0; i &lt; last_page; i++) {\n",
       "        listObj.show(i * n_items + 1, n_items);\n",
       "        $(&quot;input:checkbox:checked&quot;).each(function() {\n",
       "            this.checked = false;\n",
       "            _id.push(parseInt($(this).closest(&quot;.cell&quot;).attr(&quot;data-mols2grid-id&quot;)));\n",
       "        });\n",
       "    }\n",
       "    listObj.show((current_page - 1) * n_items + 1, n_items);\n",
       "    del_selection(&quot;default&quot;, _id);\n",
       "});\n",
       "// invert\n",
       "$(&#x27;#btn-chkbox-invert&#x27;).click(function (e) {\n",
       "    var current_page = parseInt($(&quot;li.page-item.active &gt; a&quot;).text());\n",
       "    var n_items = 15;\n",
       "    var last_page = parseInt($(&quot;li.page-item &gt; a&quot;).last().text());\n",
       "    var _id_add = [];\n",
       "    var _id_del = [];\n",
       "    var _smiles = [];\n",
       "    for (let i = 0; i &lt; last_page; i++) {\n",
       "        listObj.show(i * n_items + 1, n_items);\n",
       "        $(&quot;input:checkbox&quot;).each(function() {\n",
       "            this.checked = !this.checked;\n",
       "            var _id = parseInt($(this).closest(&quot;.cell&quot;).attr(&quot;data-mols2grid-id&quot;));\n",
       "            if (this.checked) {\n",
       "                _id_add.push(_id);\n",
       "                _smiles.push($(this).siblings(&quot;.data-SMILES&quot;).first().text());\n",
       "            } else {\n",
       "                _id_del.push(_id);\n",
       "            }\n",
       "        });\n",
       "    }\n",
       "    listObj.show((current_page - 1) * n_items + 1, n_items);\n",
       "    del_selection(&quot;default&quot;, _id_del);\n",
       "    add_selection(&quot;default&quot;, _id_add, _smiles);\n",
       "});\n",
       "// copy to clipboard\n",
       "$(&quot;#btn-chkbox-copy&quot;).click(function(e) {\n",
       "    navigator.clipboard.writeText(SELECTION.to_dict());\n",
       "});\n",
       "// export smiles\n",
       "$(&quot;#btn-chkbox-dlsmi&quot;).click(function(e) {\n",
       "    SELECTION.download_smi(&quot;selection.smi&quot;);\n",
       "});\n",
       "// export CSV\n",
       "$(&quot;#btn-chkbox-dlcsv&quot;).click(function(e) {\n",
       "    var sep = &quot;\\t&quot;\n",
       "    // same order as subset + tooltip\n",
       "    var columns = Array.from(listObj.items[0].elm.querySelectorAll(&quot;div.data&quot;))\n",
       "                       .map(elm =&gt; elm.classList[1]);\n",
       "    // remove &#x27;data-&#x27;\n",
       "    var header = columns.map(name =&gt; name.slice(5));\n",
       "    // csv content\n",
       "    header = [&quot;index&quot;].concat(header).join(sep);\n",
       "    var content = header + &quot;\\n&quot;;\n",
       "    for (let [index, smiles] of SELECTION.entries()) {\n",
       "        var data = listObj.items[index].values();\n",
       "        content += index;\n",
       "        columns.forEach((key) =&gt; {\n",
       "            content += sep + data[key];\n",
       "        })\n",
       "        content += &quot;\\n&quot;;\n",
       "    }\n",
       "    var a = document.createElement(&quot;a&quot;);\n",
       "    var file = new Blob([content], {type: &quot;text/csv&quot;});\n",
       "    a.href = URL.createObjectURL(file);\n",
       "    a.download = &quot;selection.csv&quot;;\n",
       "    a.click();\n",
       "    a.remove();\n",
       "});\n",
       "// update selection on checkbox click\n",
       "listObj.on(&quot;updated&quot;, function (list) {\n",
       "    $(&quot;input:checkbox&quot;).change(function() {\n",
       "        var _id = parseInt($(this).closest(&quot;.cell&quot;).attr(&quot;data-mols2grid-id&quot;));\n",
       "        if (this.checked) {\n",
       "            var _smiles = $($(this).siblings(&quot;.data-SMILES&quot;)[0]).text();\n",
       "            add_selection(&quot;default&quot;, [_id], [_smiles]);\n",
       "        } else {\n",
       "            del_selection(&quot;default&quot;, [_id]);\n",
       "        }\n",
       "    }); \n",
       "});\n",
       "\n",
       "\n",
       "\n",
       "\n",
       "\n",
       "// generate images for the currently displayed molecules\n",
       "var draw_opts = {&quot;fixedBondLength&quot;: 200, &quot;width&quot;: 160, &quot;height&quot;: 120};\n",
       "var json_draw_opts = JSON.stringify(draw_opts);\n",
       "\n",
       "var smarts_matches = {};\n",
       "\n",
       "// Load RDKit\n",
       "window\n",
       ".initRDKitModule()\n",
       ".then(function(RDKit) {\n",
       "    console.log(&#x27;RDKit version: &#x27;, RDKit.version());\n",
       "    window.RDKit = RDKit;\n",
       "    window.RDKitModule = RDKit;\n",
       "\n",
       "    // search bar\n",
       "    function SmartsSearch(query, columns) {\n",
       "    var smiles_col = columns[0];\n",
       "    smarts_matches = {};\n",
       "    var query = $(&#x27;#mols2grid #searchbar&#x27;).val();\n",
       "    var qmol = RDKit.get_qmol(query);\n",
       "    if (qmol.is_valid()) {\n",
       "        for (var k = 0, kl = listObj.items.length; k &lt; kl; k++) {\n",
       "            var item = listObj.items[k];\n",
       "            var smiles = item.values()[smiles_col]\n",
       "            var mol = RDKit.get_mol(smiles);\n",
       "            if (mol.is_valid()) {\n",
       "                var results = JSON.parse(mol.get_substruct_match(qmol));\n",
       "                if (results.atoms) {\n",
       "                    item.found = true;\n",
       "                    \n",
       "                    smarts_matches[smiles] = results;\n",
       "                    \n",
       "                } else {\n",
       "                    item.found = false;\n",
       "                }\n",
       "            } else {\n",
       "                item.found = false;\n",
       "            }\n",
       "            mol.delete();\n",
       "        }\n",
       "    }\n",
       "    qmol.delete();\n",
       "}\n",
       "var search_type = &quot;Text&quot;;\n",
       "$(&#x27;#mols2grid .search-btn&#x27;).click(function() {\n",
       "    search_type = $(this).text();\n",
       "    $(&#x27;#mols2grid button.search-btn.active&#x27;).removeClass(&quot;active&quot;);\n",
       "    $(this).addClass(&quot;active&quot;);\n",
       "});\n",
       "$(&#x27;#mols2grid #searchbar&#x27;).on(&quot;keyup&quot;, function(e) {\n",
       "    var query = e.target.value;\n",
       "    if (search_type === &quot;Text&quot;) {\n",
       "        smarts_matches = {};\n",
       "        listObj.search(query, [&#x27;data-mols2grid-id&#x27;, &#x27;data-SMILES&#x27;]);\n",
       "    } else {\n",
       "        listObj.search(query, [&quot;data-SMILES&quot;], SmartsSearch);\n",
       "    }\n",
       "});\n",
       "\n",
       "    \n",
       "    // generate images for the currently displayed molecules\n",
       "RDKit.prefer_coordgen(true);\n",
       "function draw_mol(smiles) {\n",
       "    var mol = RDKit.get_mol(smiles, &#x27;{&quot;removeHs&quot;: false }&#x27;);\n",
       "    var svg = &quot;&quot;;\n",
       "    if (mol.is_valid()) {\n",
       "        var highlights = smarts_matches[smiles];\n",
       "        if (highlights) {\n",
       "            var details = Object.assign({}, draw_opts, highlights);\n",
       "            details = JSON.stringify(details);\n",
       "        } else {\n",
       "            var details = json_draw_opts;\n",
       "        }\n",
       "        svg = mol.get_svg_with_highlights(details);\n",
       "    }\n",
       "    mol.delete();\n",
       "    if (svg == &quot;&quot;) {\n",
       "        return &#x27;&lt;svg width=&quot;160&quot; height=&quot;120&quot; xmlns=&quot;http://www.w3.org/2000/svg&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 160 120&quot;&gt;&lt;/svg&gt;&#x27;;\n",
       "    }\n",
       "    return svg;\n",
       "}\n",
       "listObj.on(&quot;updated&quot;, function (list) {\n",
       "    var query = $(&#x27;#mols2grid #searchbar&#x27;).val();\n",
       "    if (query === &quot;&quot;) {\n",
       "        smarts_matches = {};\n",
       "    }\n",
       "    $(&#x27;#mols2grid .cell&#x27;).each(function() {\n",
       "        var $t = $(this);\n",
       "        var smiles = $t.children(&quot;.data-SMILES&quot;).first().text()\n",
       "        var svg = draw_mol(smiles);\n",
       "        $t.children(&quot;.data-img&quot;).html(svg);\n",
       "    });\n",
       "});\n",
       "    \n",
       "\n",
       "    // trigger update to activate tooltips, draw images, setup callbacks...\n",
       "    listObj.update();\n",
       "    // resize iframe to fit content\n",
       "    if (window.frameElement) {\n",
       "        window.parent.fit_height(window.frameElement);\n",
       "    }\n",
       "});\n",
       "    &lt;/script&gt;\n",
       "  &lt;/body&gt;\n",
       "&lt;/html&gt;\">\n",
       "</iframe>"
      ],
      "text/plain": [
       "<IPython.core.display.HTML object>"
      ]
     },
     "execution_count": 4,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "mols2grid.display([Chem.MolFromSmiles(molecule) for molecule in molecules], fixedBondLength=200)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "varying-emerald",
   "metadata": {},
   "source": [
    "To unpack the model and inspect its latent spaces we can simply conduct an exploration using a random point cloud"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "together-alarm",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "19:55:11   starting syncing\n",
      "19:55:11   syncing complete\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "100%|███████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 32/32 [00:22<00:00,  1.44it/s]\n"
     ]
    }
   ],
   "source": [
    "# get the actual generator\n",
    "generator = configuration.get_conditional_generator(configuration.ensure_artifacts())\n",
    "# generate randomly points in the latent space\n",
    "number_of_latent_points = 1024\n",
    "latent_points = torch.randn(\n",
    "    number_of_latent_points - (number_of_latent_points % generator.batch_size),  # making sure the points are chunked properly\n",
    "    generator.gru_decoder.latent_dim,\n",
    "    device=generator.device\n",
    ")\n",
    "# keep points related to valid molecules\n",
    "molecules = []\n",
    "for latent_points_batch in tqdm(torch.split(latent_points, generator.batch_size)):\n",
    "    indexes = generator.decode(latent_points_batch)\n",
    "    generated_molecules = [\n",
    "        Chem.MolFromSmiles(generator.smiles_language.token_indexes_to_smiles(index))\n",
    "        for index in indexes\n",
    "    ]\n",
    "    molecules.extend(generated_molecules)\n",
    "valid_indexes = [index for index, molecule in enumerate(molecules) if molecule is not None]\n",
    "molecules = [molecules[index] for index in valid_indexes]\n",
    "latent_points = latent_points[valid_indexes]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "massive-speaking",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "%matplotlib inline\n",
    "values = [Chem.Descriptors.MolWt(molecule) for molecule in molecules]\n",
    "_ = render_latent_points(latent_points, values=values)\n",
    "_ = plt.title(\"Rendering molecular weight in a 2D projection of the latent space\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "armed-radius",
   "metadata": {},
   "source": [
    "## PaccMannRL\n",
    "\n",
    "A family of algorithms for generating candidate hit-like molecules either targeting an omic profile [[1]](https://doi.org/10.1016/j.isci.2021.102269) or AA sequences [[2]](https://doi.org/10.1088/2632-2153/abe808).\n",
    "\n",
    "Let's explore the model for targeted ligand design given a protein sequence."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "british-cookie",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "19:55:34   runnning PaccMannRL with configuration=PaccMannRLProteinBasedGenerator(algorithm_version='v0', batch_size=32, temperature=1.4, generated_length=100)\n",
      "19:55:34   ensure artifacts for the application are present.\n",
      "19:55:34   starting syncing\n",
      "19:55:34   syncing complete\n",
      "19:55:36   loading configuration file https://s3.amazonaws.com/songlabdata/proteindata/pytorch-models/bert-base-config.json from cache at /Users/tte/.cache/torch/protein_models/fbb05edff0ffa844a729a04850272a1f8973bc002526f6615ad113a5f5aacd36.05edb4ed225e1907a3878f9d68b275d79e025b667555aa94a086e27cb5c591e0\n",
      "19:55:36   Model config {\n",
      "  \"attention_probs_dropout_prob\": 0.1,\n",
      "  \"base_model\": \"transformer\",\n",
      "  \"finetuning_task\": null,\n",
      "  \"hidden_act\": \"gelu\",\n",
      "  \"hidden_dropout_prob\": 0.1,\n",
      "  \"hidden_size\": 768,\n",
      "  \"initializer_range\": 0.02,\n",
      "  \"input_size\": 768,\n",
      "  \"intermediate_size\": 3072,\n",
      "  \"layer_norm_eps\": 1e-12,\n",
      "  \"max_position_embeddings\": 8192,\n",
      "  \"num_attention_heads\": 12,\n",
      "  \"num_hidden_layers\": 12,\n",
      "  \"num_labels\": -1,\n",
      "  \"output_attentions\": false,\n",
      "  \"output_hidden_states\": false,\n",
      "  \"output_size\": 768,\n",
      "  \"pruned_heads\": {},\n",
      "  \"torchscript\": false,\n",
      "  \"type_vocab_size\": 1,\n",
      "  \"vocab_size\": 30\n",
      "}\n",
      "\n",
      "19:55:36   loading weights file https://s3.amazonaws.com/songlabdata/proteindata/pytorch-models/bert-base-pytorch_model.bin from cache at /Users/tte/.cache/torch/protein_models/2ed84d28db0a61af4cd2dd3f2ccdd3ee45b1533547a8e1213840af895e2fa8d1.8206daaea9be2736b6ccde432df9dc3dbb8c3233b47f07688d6ff38d74258d22\n"
     ]
    }
   ],
   "source": [
    "from gt4sd.algorithms.conditional_generation.paccmann_rl.core import PaccMannRL, PaccMannRLProteinBasedGenerator\n",
    "\n",
    "# >sp|Q9BYF1|ACE2_HUMAN Angiotensin-converting enzyme 2 OS=Homo sapiens OX=9606 GN=ACE2 PE=1 SV=2\n",
    "target = \"\".join(filter(str.isalpha, (list(\"\"\"\n",
    "MSSSSWLLLSLVAVTAAQSTIEEQAKTFLDKFNHEAEDLFYQSSLASWNYNTNITEENVQ\n",
    "NMNNAGDKWSAFLKEQSTLAQMYPLQEIQNLTVKLQLQALQQNGSSVLSEDKSKRLNTIL\n",
    "NTMSTIYSTGKVCNPDNPQECLLLEPGLNEIMANSLDYNERLWAWESWRSEVGKQLRPLY\n",
    "EEYVVLKNEMARANHYEDYGDYWRGDYEVNGVDGYDYSRGQLIEDVEHTFEEIKPLYEHL\n",
    "HAYVRAKLMNAYPSYISPIGCLPAHLLGDMWGRFWTNLYSLTVPFGQKPNIDVTDAMVDQ\n",
    "AWDAQRIFKEAEKFFVSVGLPNMTQGFWENSMLTDPGNVQKAVCHPTAWDLGKGDFRILM\n",
    "CTKVTMDDFLTAHHEMGHIQYDMAYAAQPFLLRNGANEGFHEAVGEIMSLSAATPKHLKS\n",
    "IGLLSPDFQEDNETEINFLLKQALTIVGTLPFTYMLEKWRWMVFKGEIPKDQWMKKWWEM\n",
    "KREIVGVVEPVPHDETYCDPASLFHVSNDYSFIRYYTRTLYQFQFQEALCQAAKHEGPLH\n",
    "KCDISNSTEAGQKLFNMLRLGKSEPWTLALENVVGAKNMNVRPLLNYFEPLFTWLKDQNK\n",
    "NSFVGWSTDWSPYADQSIKVRISLKSALGDKAYEWNDNEMYLFRSSVAYAMRQYFLKVKN\n",
    "QMILFGEEDVRVANLKPRISFNFFVTAPKNVSDIIPRTEVEKAIRMSRSRINDAFRLNDN\n",
    "SLEFLGIQPTLGPPNQPPVSIWLIVFGVVMGVIVVGIVILIFTGIRDRKKKNKARSGENP\n",
    "YASIDISKGENNPGFQNTDDVQTSF\n",
    "\"\"\"))))\n",
    "configuration = PaccMannRLProteinBasedGenerator()\n",
    "algorithm = PaccMannRL(configuration=configuration, target=target)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "australian-ethics",
   "metadata": {},
   "source": [
    "Via the algorithm you can easily inspect the generated molecules interactively:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "id": "resistant-questionnaire",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "19:55:38   embedding condition and getting reparametrized latent samples\n",
      "19:55:41   starting generation of molecules\n",
      "19:55:42   embedding condition and getting reparametrized latent samples\n",
      "19:55:45   starting generation of molecules\n",
      "19:55:46   embedding condition and getting reparametrized latent samples\n",
      "19:55:49   starting generation of molecules\n"
     ]
    }
   ],
   "source": [
    "molecules = list(algorithm.sample(15))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "id": "psychological-picking",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<script>\n",
       "    function fit_height(obj) {\n",
       "        obj.style.height = 0;\n",
       "        var height = obj.contentDocument.body.scrollHeight + 18 + 'px';\n",
       "        obj.style.height = height;\n",
       "    }\n",
       "</script>\n",
       "<iframe class=\"mols2grid-iframe\" frameborder=\"0\" width=\"100%\"\n",
       "\n",
       "height=\"200\"\n",
       "\n",
       "\n",
       "allow=\"clipboard-write\"\n",
       "\n",
       "srcdoc=\"&lt;html&gt;\n",
       "  &lt;meta charset=&quot;utf-8&quot;&gt;\n",
       "  &lt;head&gt;\n",
       "    &lt;style&gt;\n",
       "    #mols2grid.gridcontainer {\n",
       "    display: block;\n",
       "    padding-left: 1em;\n",
       "    max-width: 820px;\n",
       "    width: 820px;\n",
       "}\n",
       "#mols2grid .cell {\n",
       "    border: 1px solid #cccccc;\n",
       "    text-align: center;\n",
       "    vertical-align: top;\n",
       "    max-width: 160px;\n",
       "    width: 160px;\n",
       "    font-family: &#x27;DejaVu&#x27;, sans-serif;\n",
       "    font-size: 12pt;\n",
       "    padding: 0;\n",
       "    margin: 0px;\n",
       "    float: left;\n",
       "}\n",
       "#mols2grid .cell:hover {\n",
       "    background-color: #e7e7e7 !important;\n",
       "}\n",
       "#mols2grid .cell .data-img {\n",
       "    padding: 0;\n",
       "    margin: 0;\n",
       "}\n",
       "#mols2grid .cell img, #mols2grid .cell svg {\n",
       "    max-width: 100%;\n",
       "    height: auto;\n",
       "    padding: 0;\n",
       "}\n",
       "#mols2grid .data {\n",
       "    overflow: hidden;\n",
       "    white-space: nowrap;\n",
       "    text-overflow: ellipsis;\n",
       "    display: block;\n",
       "}\n",
       "#mols2grid .arrow-asc:after {\n",
       "    content: &#x27;↑&#x27;;\n",
       "    text-align: right;\n",
       "    float:right;\n",
       "}\n",
       "#mols2grid .arrow-desc:after {\n",
       "    content: &#x27;↓&#x27;;\n",
       "    text-align: right;\n",
       "    float:right;\n",
       "}\n",
       "    /* custom CSS */\n",
       "    \n",
       "    &lt;/style&gt;\n",
       "    &lt;script src=&quot;https://cdnjs.cloudflare.com/ajax/libs/list.js/2.3.1/list.min.js&quot;&gt;&lt;/script&gt;\n",
       "&lt;link rel=&quot;stylesheet&quot; href=&quot;https://cdn.jsdelivr.net/npm/bootstrap@4.6.0/dist/css/bootstrap.min.css&quot; integrity=&quot;sha384-B0vP5xmATw1+K9KRQjQERJvTumQW0nPEzvF6L/Z6nronJ3oUOFUFpCjEUQouq2+l&quot; crossorigin=&quot;anonymous&quot;&gt;\n",
       "&lt;script src=&quot;https://code.jquery.com/jquery-3.5.1.slim.min.js&quot; integrity=&quot;sha384-DfXdz2htPH0lsSSs5nCTpuj/zy4C+OGpamoFVy38MVBnE+IbbVYUew+OrCXaRkfj&quot; crossorigin=&quot;anonymous&quot;&gt;&lt;/script&gt;\n",
       "&lt;script src=&quot;https://cdn.jsdelivr.net/npm/bootstrap@4.6.0/dist/js/bootstrap.bundle.min.js&quot; integrity=&quot;sha384-Piv4xVNRyMGpqkS2by6br4gNJ7DXjqk09RmUpJ8jgGtD7zP9yug3goQfGII0yAns&quot; crossorigin=&quot;anonymous&quot;&gt;&lt;/script&gt;\n",
       "&lt;script src=&quot;https://unpkg.com/@rdkit/rdkit@2021.9.4/Code/MinimalLib/dist/RDKit_minimal.js&quot;&gt;&lt;/script&gt;\n",
       "    &lt;!-- custom header --&gt;\n",
       "    \n",
       "  &lt;/head&gt;\n",
       "  &lt;body&gt;\n",
       "    &lt;div id=&quot;mols2grid&quot; class=&quot;gridcontainer grid-default&quot;&gt;\n",
       "      &lt;div class=&quot;row mb-3&quot;&gt;\n",
       "        &lt;div class=&quot;list&quot;&gt;&lt;div class=&quot;cell&quot; data-mols2grid-id=&quot;0&quot;&gt;&lt;input type=&quot;checkbox&quot; class=&quot;position-relative float-left cached_checkbox&quot;&gt;&lt;div class=&quot;data data-img&quot;&gt;&lt;/div&gt;&lt;div class=&quot;data data-mols2grid-id-copy&quot;&gt;&lt;/div&gt;&lt;div class=&quot;data data-SMILES&quot;&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;\n",
       "      &lt;/div&gt;\n",
       "      &lt;div class=&quot;d-inline&quot;&gt;\n",
       "        &lt;ul class=&quot;pagination float-left&quot;&gt;&lt;/ul&gt;\n",
       "        &lt;div id=&quot;controls&quot; class=&quot;d-flex flex-row float-right&quot;&gt;\n",
       "          \n",
       "          &lt;div id=&quot;chkbox-dropdown&quot; class=&quot;dropdown&quot;&gt;\n",
       "    &lt;button class=&quot;btn btn-light dropdown-toggle&quot; type=&quot;button&quot; id=&quot;chkboxDropdown&quot; data-toggle=&quot;dropdown&quot; aria-haspopup=&quot;true&quot; aria-expanded=&quot;false&quot;&gt;☑&lt;/button&gt;\n",
       "    &lt;div class=&quot;dropdown-menu&quot; aria-labelledby=&quot;checkboxDropdownMenu&quot;&gt;\n",
       "        &lt;button id=&quot;btn-chkbox-all&quot; class=&quot;dropdown-item&quot; type=&quot;button&quot;&gt;Check all&lt;/button&gt;\n",
       "        &lt;button id=&quot;btn-chkbox-none&quot; class=&quot;dropdown-item&quot; type=&quot;button&quot;&gt;Uncheck all&lt;/button&gt;\n",
       "        &lt;button id=&quot;btn-chkbox-invert&quot; class=&quot;dropdown-item&quot; type=&quot;button&quot;&gt;Invert&lt;/button&gt;\n",
       "        &lt;div class=&quot;dropdown-divider&quot;&gt;&lt;/div&gt;\n",
       "        &lt;button id=&quot;btn-chkbox-copy&quot; class=&quot;dropdown-item&quot; type=&quot;button&quot;&gt;Copy to clipboard&lt;/button&gt;\n",
       "        &lt;button id=&quot;btn-chkbox-dlsmi&quot; class=&quot;dropdown-item&quot; type=&quot;button&quot;&gt;Save SMILES&lt;/button&gt;\n",
       "        &lt;button id=&quot;btn-chkbox-dlcsv&quot; class=&quot;dropdown-item&quot; type=&quot;button&quot;&gt;Save CSV&lt;/button&gt;\n",
       "    &lt;/div&gt;\n",
       "&lt;/div&gt;\n",
       "          \n",
       "          &lt;div id=&quot;sort-dropdown&quot; class=&quot;dropdown pl-2&quot;&gt;\n",
       "            &lt;button class=&quot;btn btn-light dropdown-toggle&quot; type=&quot;button&quot; id=&quot;sortDropdown&quot; data-toggle=&quot;dropdown&quot; aria-haspopup=&quot;true&quot; aria-expanded=&quot;false&quot;&gt;\n",
       "              Sort by\n",
       "            &lt;/button&gt;\n",
       "            &lt;div class=&quot;dropdown-menu&quot; aria-labelledby=&quot;sortDropdownMenu&quot;&gt;\n",
       "              \n",
       "              \n",
       "              \n",
       "              \n",
       "              \n",
       "              &lt;button class=&quot;dropdown-item sort-btn arrow-asc active&quot; type=&quot;button&quot; data-name=&quot;mols2grid-id&quot;&gt;Index&lt;/button&gt;\n",
       "              \n",
       "              \n",
       "              \n",
       "              \n",
       "              \n",
       "              &lt;button class=&quot;dropdown-item sort-btn arrow-asc active&quot; type=&quot;button&quot; data-name=&quot;data-mols2grid-id&quot;&gt;mols2grid-id&lt;/button&gt;\n",
       "              \n",
       "              \n",
       "              \n",
       "              \n",
       "              \n",
       "              &lt;button class=&quot;dropdown-item sort-btn &quot; type=&quot;button&quot; data-name=&quot;data-SMILES&quot;&gt;SMILES&lt;/button&gt;\n",
       "              \n",
       "              \n",
       "              \n",
       "              &lt;button class=&quot;dropdown-item sort-btn&quot; type=&quot;button&quot; data-name=&quot;checkbox&quot;&gt;Selected&lt;/button&gt;\n",
       "              \n",
       "            &lt;/div&gt;\n",
       "          &lt;/div&gt;\n",
       "          &lt;div class=&quot;input-group row pl-4&quot;&gt;\n",
       "            &lt;input type=&quot;text&quot; id=&quot;searchbar&quot; class=&quot;form-control&quot; placeholder=&quot;Search&quot; aria-label=&quot;Search&quot; aria-describedby=&quot;basic-addon1&quot;&gt;\n",
       "            &lt;div class=&quot;input-group-append&quot;&gt;\n",
       "              &lt;button id=&quot;searchBtn&quot; class=&quot;btn btn-light dropdown-toggle&quot; type=&quot;button&quot; data-toggle=&quot;dropdown&quot; aria-haspopup=&quot;true&quot; aria-expanded=&quot;false&quot;&gt;🔎&lt;/button&gt;\n",
       "              &lt;div class=&quot;dropdown-menu dropdown-menu-right&quot;&gt;\n",
       "                &lt;button id=&quot;txtSearch&quot; class=&quot;search-btn dropdown-item active&quot;&gt;Text&lt;/button&gt;\n",
       "                &lt;button id=&quot;smartsSearch&quot; class=&quot;search-btn dropdown-item&quot;&gt;SMARTS&lt;/button&gt;\n",
       "              &lt;/div&gt;\n",
       "            &lt;/div&gt;\n",
       "          &lt;/div&gt;\n",
       "        &lt;/div&gt;\n",
       "      &lt;/div&gt;\n",
       "    &lt;/div&gt;\n",
       "    &lt;script&gt;\n",
       "    // list.js\n",
       "var listObj = new List(&#x27;mols2grid&#x27;, {\n",
       "    valueNames: [{data: [&#x27;mols2grid-id&#x27;]}, &#x27;data-img&#x27;, &#x27;data-mols2grid-id&#x27;, &#x27;data-SMILES&#x27;, &#x27;data-mols2grid-id-copy&#x27;],\n",
       "    item: &#x27;&lt;div class=&quot;cell&quot; data-mols2grid-id=&quot;0&quot;&gt;&lt;input type=&quot;checkbox&quot; class=&quot;position-relative float-left cached_checkbox&quot;&gt;&lt;div class=&quot;data data-img&quot;&gt;&lt;/div&gt;&lt;div class=&quot;data data-mols2grid-id-copy&quot;&gt;&lt;/div&gt;&lt;div class=&quot;data data-SMILES&quot;&gt;&lt;/div&gt;&lt;/div&gt;&#x27;,\n",
       "    page: 15,\n",
       "    pagination: {\n",
       "        name: &quot;pagination&quot;,\n",
       "        item: &#x27;&lt;li class=&quot;page-item&quot;&gt;&lt;a class=&quot;page page-link&quot; href=&quot;#&quot; onclick=&quot;event.preventDefault()&quot;&gt;&lt;/a&gt;&lt;/li&gt;&#x27;,\n",
       "        innerWindow: 1,\n",
       "        outerWindow: 1,\n",
       "    },\n",
       "});\n",
       "listObj.remove(&quot;mols2grid-id&quot;, &quot;0&quot;);\n",
       "listObj.add([{&quot;data-img&quot;: null, &quot;mols2grid-id&quot;: 0, &quot;data-SMILES&quot;: &quot;N=Nc1ccc(C#CSCOc2ccc(N(O)O)cc2)cc1&quot;, &quot;data-mols2grid-id-copy&quot;: 0}, {&quot;data-img&quot;: null, &quot;mols2grid-id&quot;: 1, &quot;data-SMILES&quot;: &quot;C1=Cc2ccnn2CC=CC(OCc2ccccc2)=C1&quot;, &quot;data-mols2grid-id-copy&quot;: 1}, {&quot;data-img&quot;: null, &quot;mols2grid-id&quot;: 2, &quot;data-SMILES&quot;: &quot;CC=NC1=CCOC(=O)O1&quot;, &quot;data-mols2grid-id-copy&quot;: 2}, {&quot;data-img&quot;: null, &quot;mols2grid-id&quot;: 3, &quot;data-SMILES&quot;: &quot;COC1=NC=CC=C[SH]=C2N=CNC2C1&quot;, &quot;data-mols2grid-id-copy&quot;: 3}, {&quot;data-img&quot;: null, &quot;mols2grid-id&quot;: 4, &quot;data-SMILES&quot;: &quot;CN1CCN(C)C(c2ccccn2)C1&quot;, &quot;data-mols2grid-id-copy&quot;: 4}, {&quot;data-img&quot;: null, &quot;mols2grid-id&quot;: 5, &quot;data-SMILES&quot;: &quot;ON(O)c1ccccc1F&quot;, &quot;data-mols2grid-id-copy&quot;: 5}, {&quot;data-img&quot;: null, &quot;mols2grid-id&quot;: 6, &quot;data-SMILES&quot;: &quot;CCN(C1C=CC1CBr)C1c2ccccc2N2CCC(CC2)NC1C=O&quot;, &quot;data-mols2grid-id-copy&quot;: 6}, {&quot;data-img&quot;: null, &quot;mols2grid-id&quot;: 7, &quot;data-SMILES&quot;: &quot;OC=NC1CCNC=CNN=CCSCN2CCCN12&quot;, &quot;data-mols2grid-id-copy&quot;: 7}, {&quot;data-img&quot;: null, &quot;mols2grid-id&quot;: 8, &quot;data-SMILES&quot;: &quot;CS(N)(=O)=O&quot;, &quot;data-mols2grid-id-copy&quot;: 8}, {&quot;data-img&quot;: null, &quot;mols2grid-id&quot;: 9, &quot;data-SMILES&quot;: &quot;Cc1cccc(N(O)O)n1&quot;, &quot;data-mols2grid-id-copy&quot;: 9}, {&quot;data-img&quot;: null, &quot;mols2grid-id&quot;: 10, &quot;data-SMILES&quot;: &quot;COc1[nH]cnc1C(=O)Nc1ccccc1Br&quot;, &quot;data-mols2grid-id-copy&quot;: 10}, {&quot;data-img&quot;: null, &quot;mols2grid-id&quot;: 11, &quot;data-SMILES&quot;: &quot;N#CNCNCC=O&quot;, &quot;data-mols2grid-id-copy&quot;: 11}, {&quot;data-img&quot;: null, &quot;mols2grid-id&quot;: 12, &quot;data-SMILES&quot;: &quot;C=[SH](N)=O&quot;, &quot;data-mols2grid-id-copy&quot;: 12}, {&quot;data-img&quot;: null, &quot;mols2grid-id&quot;: 13, &quot;data-SMILES&quot;: &quot;CC1(O)Nc2ccccc2C(O)=CC=CC2CCCC2CN2CCC1CC2&quot;, &quot;data-mols2grid-id-copy&quot;: 13}, {&quot;data-img&quot;: null, &quot;mols2grid-id&quot;: 14, &quot;data-SMILES&quot;: &quot;O=C1NCC=C1CCO&quot;, &quot;data-mols2grid-id-copy&quot;: 14}]);\n",
       "// filter\n",
       "if (window.parent.mols2grid_lists === undefined) {\n",
       "    window.parent.mols2grid_lists = {};\n",
       "}\n",
       "window.parent.mols2grid_lists[&quot;default&quot;] = listObj;\n",
       "\n",
       "\n",
       "// selection\n",
       "class MolStorage extends Map {\n",
       "    multi_set(_id, _smiles) {\n",
       "        for (let i=0; i &lt; _id.length; i++) {\n",
       "            this.set(_id[i], _smiles[i]);\n",
       "        }\n",
       "    }\n",
       "    multi_del(_id) {\n",
       "        for (let i=0; i &lt; _id.length; i++) {\n",
       "            this.delete(_id[i]);\n",
       "        };\n",
       "    }\n",
       "    to_dict() {\n",
       "        var content = &quot;{&quot;;\n",
       "        for (let [key, value] of this) {\n",
       "            content += key + &quot;:&quot; + JSON.stringify(value) + &quot;,&quot;;\n",
       "        }\n",
       "        content = content.length &gt; 1 ? content.slice(0, -1) : content;\n",
       "        content += &quot;}&quot;;\n",
       "        return content\n",
       "    }\n",
       "    download_smi(fileName) {\n",
       "        var content = &quot;SMILES index\\n&quot;;\n",
       "        for (let [key, value] of this) {\n",
       "            content += value + &quot; &quot; + key + &quot;\\n&quot;;\n",
       "        }\n",
       "        var a = document.createElement(&quot;a&quot;);\n",
       "        var file = new Blob([content], {type: &quot;text/plain&quot;});\n",
       "        a.href = URL.createObjectURL(file);\n",
       "        a.download = fileName;\n",
       "        a.click();\n",
       "        a.remove();\n",
       "    }\n",
       "}\n",
       "var SELECTION = new MolStorage();\n",
       "\n",
       "\n",
       "\n",
       "// kernel\n",
       "var kernel_env = null;\n",
       "if (window.parent.IPython !== undefined) {\n",
       "    // Jupyter notebook\n",
       "    kernel_env = &quot;jupyter&quot;;\n",
       "    var kernel = window.parent.IPython.notebook.kernel;\n",
       "    kernel.execute(&#x27;from mols2grid.select import register as _m2g_reg&#x27;)\n",
       "    function add_selection(grid_id, _id, smiles) {\n",
       "        SELECTION.multi_set(_id, smiles);\n",
       "        kernel.execute(&quot;_m2g_reg.add_selection(&#x27;&quot;+grid_id+&quot;&#x27;, &quot;+JSON.stringify(_id)+&quot;,&quot;+JSON.stringify(smiles)+&quot;)&quot;);\n",
       "    }\n",
       "    function del_selection(grid_id, _id) {\n",
       "        SELECTION.multi_del(_id);\n",
       "        kernel.execute(&quot;_m2g_reg.del_selection(&#x27;&quot;+grid_id+&quot;&#x27;, &quot;+JSON.stringify(_id)+&quot;)&quot;);\n",
       "    }\n",
       "} else if (window.parent.google !== undefined) {\n",
       "    // Google colab\n",
       "    kernel_env = &quot;colab&quot;;\n",
       "    var kernel = window.parent.google.colab.kernel;\n",
       "    function add_selection(grid_id, _id, smiles) {\n",
       "        SELECTION.multi_set(_id, smiles);\n",
       "        (async function() {\n",
       "        const result = await kernel.invokeFunction(&#x27;_m2g_reg.add_selection&#x27;,\n",
       "                                                   [grid_id, _id, smiles], {});\n",
       "        })();\n",
       "    }\n",
       "    function del_selection(grid_id, _id) {\n",
       "        SELECTION.multi_del(_id);\n",
       "        (async function() {\n",
       "        const result = await kernel.invokeFunction(&#x27;_m2g_reg.del_selection&#x27;,\n",
       "                                                   [grid_id, _id], {});\n",
       "        })();\n",
       "    }\n",
       "} else {\n",
       "    function add_selection(grid_id, _id, smiles) {\n",
       "        SELECTION.multi_set(_id, smiles);\n",
       "    }\n",
       "    function del_selection(grid_id, _id) {\n",
       "        SELECTION.multi_del(_id);\n",
       "    }\n",
       "}\n",
       "\n",
       "\n",
       "\n",
       "\n",
       "// sort\n",
       "var sort_field = &quot;mols2grid-id&quot;;\n",
       "var sort_order = &quot;asc&quot;;\n",
       "function mols2gridSortFunction(itemA, itemB, options) {\n",
       "    var x = itemA.values()[options.valueName];\n",
       "    var y = itemB.values()[options.valueName];\n",
       "    if (typeof x === &quot;number&quot;) {\n",
       "        if (isFinite(x - y)) {\n",
       "            return x - y; \n",
       "        } else {\n",
       "            return isFinite(x) ? -1 : 1;\n",
       "        }\n",
       "    } else {\n",
       "        x = x.toLowerCase();\n",
       "        y = y.toLowerCase();\n",
       "        return (x &lt; y) ? -1: (x &gt; y) ? 1: 0;\n",
       "    }\n",
       "}\n",
       "function checkboxSort(itemA, itemB, options) {\n",
       "    if (itemA.elm !== undefined) {\n",
       "        var checkedA = itemA.elm.firstChild.checked;\n",
       "        if (itemB.elm !== undefined) {\n",
       "            var checkedB = itemB.elm.firstChild.checked;\n",
       "            if (checkedA &amp;&amp; !checkedB) {\n",
       "                return -1;\n",
       "            } else if (!checkedA &amp;&amp; checkedB) {\n",
       "                return 1;\n",
       "            } else {\n",
       "                return 0;\n",
       "            }\n",
       "        } else {\n",
       "            return -1;\n",
       "        }\n",
       "    } else if (itemB.elm !== undefined) {\n",
       "        return 1;\n",
       "    } else {\n",
       "        return 0;\n",
       "    }\n",
       "}\n",
       "$(&#x27;#mols2grid button.sort-btn&#x27;).click(function(e) {\n",
       "    var _field = $(this).attr(&quot;data-name&quot;);\n",
       "    if (_field == sort_field) {\n",
       "        $(this).removeClass(&quot;arrow-&quot; + sort_order)\n",
       "        sort_order = (sort_order === &quot;desc&quot;) ? &quot;asc&quot; : &quot;desc&quot;;\n",
       "    } else {\n",
       "        $(&#x27;#mols2grid button.sort-btn.active&#x27;).removeClass(&quot;active arrow-&quot; + sort_order);\n",
       "        sort_order = &quot;asc&quot;;\n",
       "        sort_field = _field;\n",
       "        $(this).addClass(&quot;active&quot;);\n",
       "    }\n",
       "    $(this).addClass(&quot;arrow-&quot; + sort_order)\n",
       "    if (sort_field == &quot;checkbox&quot;) {\n",
       "        listObj.sort(&quot;mols2grid-id&quot;, {order: sort_order, sortFunction: checkboxSort});\n",
       "    } else {\n",
       "        listObj.sort(_field, {order: sort_order, sortFunction: mols2gridSortFunction});\n",
       "    }\n",
       "});\n",
       "\n",
       "\n",
       "\n",
       "\n",
       "\n",
       "\n",
       "// selection modifyers and export options\n",
       "// check all\n",
       "$(&#x27;#btn-chkbox-all&#x27;).click(function (e) {\n",
       "    var current_page = parseInt($(&quot;li.page-item.active &gt; a&quot;).text());\n",
       "    var n_items = 15;\n",
       "    var last_page = parseInt($(&quot;li.page-item &gt; a&quot;).last().text());\n",
       "    var _id = [];\n",
       "    var _smiles = [];\n",
       "    for (let i = 0; i &lt; last_page; i++) {\n",
       "        listObj.show(i * n_items + 1, n_items);\n",
       "        $(&quot;input:checkbox&quot;).each(function() {\n",
       "            this.checked = true;\n",
       "            _id.push(parseInt($(this).closest(&quot;.cell&quot;).attr(&quot;data-mols2grid-id&quot;)));\n",
       "            _smiles.push($($(this).siblings(&quot;.data-SMILES&quot;)[0]).text());\n",
       "        });\n",
       "    }\n",
       "    listObj.show((current_page - 1) * n_items + 1, n_items);\n",
       "    add_selection(&quot;default&quot;, _id, _smiles);\n",
       "});\n",
       "// uncheck all\n",
       "$(&#x27;#btn-chkbox-none&#x27;).click(function (e) {\n",
       "    var current_page = parseInt($(&quot;li.page-item.active &gt; a&quot;).text());\n",
       "    var n_items = 15;\n",
       "    var last_page = parseInt($(&quot;li.page-item &gt; a&quot;).last().text());\n",
       "    var _id = [];\n",
       "    for (let i = 0; i &lt; last_page; i++) {\n",
       "        listObj.show(i * n_items + 1, n_items);\n",
       "        $(&quot;input:checkbox:checked&quot;).each(function() {\n",
       "            this.checked = false;\n",
       "            _id.push(parseInt($(this).closest(&quot;.cell&quot;).attr(&quot;data-mols2grid-id&quot;)));\n",
       "        });\n",
       "    }\n",
       "    listObj.show((current_page - 1) * n_items + 1, n_items);\n",
       "    del_selection(&quot;default&quot;, _id);\n",
       "});\n",
       "// invert\n",
       "$(&#x27;#btn-chkbox-invert&#x27;).click(function (e) {\n",
       "    var current_page = parseInt($(&quot;li.page-item.active &gt; a&quot;).text());\n",
       "    var n_items = 15;\n",
       "    var last_page = parseInt($(&quot;li.page-item &gt; a&quot;).last().text());\n",
       "    var _id_add = [];\n",
       "    var _id_del = [];\n",
       "    var _smiles = [];\n",
       "    for (let i = 0; i &lt; last_page; i++) {\n",
       "        listObj.show(i * n_items + 1, n_items);\n",
       "        $(&quot;input:checkbox&quot;).each(function() {\n",
       "            this.checked = !this.checked;\n",
       "            var _id = parseInt($(this).closest(&quot;.cell&quot;).attr(&quot;data-mols2grid-id&quot;));\n",
       "            if (this.checked) {\n",
       "                _id_add.push(_id);\n",
       "                _smiles.push($(this).siblings(&quot;.data-SMILES&quot;).first().text());\n",
       "            } else {\n",
       "                _id_del.push(_id);\n",
       "            }\n",
       "        });\n",
       "    }\n",
       "    listObj.show((current_page - 1) * n_items + 1, n_items);\n",
       "    del_selection(&quot;default&quot;, _id_del);\n",
       "    add_selection(&quot;default&quot;, _id_add, _smiles);\n",
       "});\n",
       "// copy to clipboard\n",
       "$(&quot;#btn-chkbox-copy&quot;).click(function(e) {\n",
       "    navigator.clipboard.writeText(SELECTION.to_dict());\n",
       "});\n",
       "// export smiles\n",
       "$(&quot;#btn-chkbox-dlsmi&quot;).click(function(e) {\n",
       "    SELECTION.download_smi(&quot;selection.smi&quot;);\n",
       "});\n",
       "// export CSV\n",
       "$(&quot;#btn-chkbox-dlcsv&quot;).click(function(e) {\n",
       "    var sep = &quot;\\t&quot;\n",
       "    // same order as subset + tooltip\n",
       "    var columns = Array.from(listObj.items[0].elm.querySelectorAll(&quot;div.data&quot;))\n",
       "                       .map(elm =&gt; elm.classList[1]);\n",
       "    // remove &#x27;data-&#x27;\n",
       "    var header = columns.map(name =&gt; name.slice(5));\n",
       "    // csv content\n",
       "    header = [&quot;index&quot;].concat(header).join(sep);\n",
       "    var content = header + &quot;\\n&quot;;\n",
       "    for (let [index, smiles] of SELECTION.entries()) {\n",
       "        var data = listObj.items[index].values();\n",
       "        content += index;\n",
       "        columns.forEach((key) =&gt; {\n",
       "            content += sep + data[key];\n",
       "        })\n",
       "        content += &quot;\\n&quot;;\n",
       "    }\n",
       "    var a = document.createElement(&quot;a&quot;);\n",
       "    var file = new Blob([content], {type: &quot;text/csv&quot;});\n",
       "    a.href = URL.createObjectURL(file);\n",
       "    a.download = &quot;selection.csv&quot;;\n",
       "    a.click();\n",
       "    a.remove();\n",
       "});\n",
       "// update selection on checkbox click\n",
       "listObj.on(&quot;updated&quot;, function (list) {\n",
       "    $(&quot;input:checkbox&quot;).change(function() {\n",
       "        var _id = parseInt($(this).closest(&quot;.cell&quot;).attr(&quot;data-mols2grid-id&quot;));\n",
       "        if (this.checked) {\n",
       "            var _smiles = $($(this).siblings(&quot;.data-SMILES&quot;)[0]).text();\n",
       "            add_selection(&quot;default&quot;, [_id], [_smiles]);\n",
       "        } else {\n",
       "            del_selection(&quot;default&quot;, [_id]);\n",
       "        }\n",
       "    }); \n",
       "});\n",
       "\n",
       "\n",
       "\n",
       "\n",
       "\n",
       "// generate images for the currently displayed molecules\n",
       "var draw_opts = {&quot;fixedBondLength&quot;: 200, &quot;width&quot;: 160, &quot;height&quot;: 120};\n",
       "var json_draw_opts = JSON.stringify(draw_opts);\n",
       "\n",
       "var smarts_matches = {};\n",
       "\n",
       "// Load RDKit\n",
       "window\n",
       ".initRDKitModule()\n",
       ".then(function(RDKit) {\n",
       "    console.log(&#x27;RDKit version: &#x27;, RDKit.version());\n",
       "    window.RDKit = RDKit;\n",
       "    window.RDKitModule = RDKit;\n",
       "\n",
       "    // search bar\n",
       "    function SmartsSearch(query, columns) {\n",
       "    var smiles_col = columns[0];\n",
       "    smarts_matches = {};\n",
       "    var query = $(&#x27;#mols2grid #searchbar&#x27;).val();\n",
       "    var qmol = RDKit.get_qmol(query);\n",
       "    if (qmol.is_valid()) {\n",
       "        for (var k = 0, kl = listObj.items.length; k &lt; kl; k++) {\n",
       "            var item = listObj.items[k];\n",
       "            var smiles = item.values()[smiles_col]\n",
       "            var mol = RDKit.get_mol(smiles);\n",
       "            if (mol.is_valid()) {\n",
       "                var results = JSON.parse(mol.get_substruct_match(qmol));\n",
       "                if (results.atoms) {\n",
       "                    item.found = true;\n",
       "                    \n",
       "                    smarts_matches[smiles] = results;\n",
       "                    \n",
       "                } else {\n",
       "                    item.found = false;\n",
       "                }\n",
       "            } else {\n",
       "                item.found = false;\n",
       "            }\n",
       "            mol.delete();\n",
       "        }\n",
       "    }\n",
       "    qmol.delete();\n",
       "}\n",
       "var search_type = &quot;Text&quot;;\n",
       "$(&#x27;#mols2grid .search-btn&#x27;).click(function() {\n",
       "    search_type = $(this).text();\n",
       "    $(&#x27;#mols2grid button.search-btn.active&#x27;).removeClass(&quot;active&quot;);\n",
       "    $(this).addClass(&quot;active&quot;);\n",
       "});\n",
       "$(&#x27;#mols2grid #searchbar&#x27;).on(&quot;keyup&quot;, function(e) {\n",
       "    var query = e.target.value;\n",
       "    if (search_type === &quot;Text&quot;) {\n",
       "        smarts_matches = {};\n",
       "        listObj.search(query, [&#x27;data-mols2grid-id&#x27;, &#x27;data-SMILES&#x27;]);\n",
       "    } else {\n",
       "        listObj.search(query, [&quot;data-SMILES&quot;], SmartsSearch);\n",
       "    }\n",
       "});\n",
       "\n",
       "    \n",
       "    // generate images for the currently displayed molecules\n",
       "RDKit.prefer_coordgen(true);\n",
       "function draw_mol(smiles) {\n",
       "    var mol = RDKit.get_mol(smiles, &#x27;{&quot;removeHs&quot;: false }&#x27;);\n",
       "    var svg = &quot;&quot;;\n",
       "    if (mol.is_valid()) {\n",
       "        var highlights = smarts_matches[smiles];\n",
       "        if (highlights) {\n",
       "            var details = Object.assign({}, draw_opts, highlights);\n",
       "            details = JSON.stringify(details);\n",
       "        } else {\n",
       "            var details = json_draw_opts;\n",
       "        }\n",
       "        svg = mol.get_svg_with_highlights(details);\n",
       "    }\n",
       "    mol.delete();\n",
       "    if (svg == &quot;&quot;) {\n",
       "        return &#x27;&lt;svg width=&quot;160&quot; height=&quot;120&quot; xmlns=&quot;http://www.w3.org/2000/svg&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 160 120&quot;&gt;&lt;/svg&gt;&#x27;;\n",
       "    }\n",
       "    return svg;\n",
       "}\n",
       "listObj.on(&quot;updated&quot;, function (list) {\n",
       "    var query = $(&#x27;#mols2grid #searchbar&#x27;).val();\n",
       "    if (query === &quot;&quot;) {\n",
       "        smarts_matches = {};\n",
       "    }\n",
       "    $(&#x27;#mols2grid .cell&#x27;).each(function() {\n",
       "        var $t = $(this);\n",
       "        var smiles = $t.children(&quot;.data-SMILES&quot;).first().text()\n",
       "        var svg = draw_mol(smiles);\n",
       "        $t.children(&quot;.data-img&quot;).html(svg);\n",
       "    });\n",
       "});\n",
       "    \n",
       "\n",
       "    // trigger update to activate tooltips, draw images, setup callbacks...\n",
       "    listObj.update();\n",
       "    // resize iframe to fit content\n",
       "    if (window.frameElement) {\n",
       "        window.parent.fit_height(window.frameElement);\n",
       "    }\n",
       "});\n",
       "    &lt;/script&gt;\n",
       "  &lt;/body&gt;\n",
       "&lt;/html&gt;\">\n",
       "</iframe>"
      ],
      "text/plain": [
       "<IPython.core.display.HTML object>"
      ]
     },
     "execution_count": 9,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "mols2grid.display([Chem.MolFromSmiles(molecule) for molecule in molecules], fixedBondLength=200)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "maritime-supply",
   "metadata": {},
   "source": [
    "To unpack the model and inspect its latent spaces we can simply conduct an exploration using a random point cloud"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "id": "designed-portable",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "19:55:50   starting syncing\n",
      "19:55:51   syncing complete\n",
      "19:55:51   loading configuration file https://s3.amazonaws.com/songlabdata/proteindata/pytorch-models/bert-base-config.json from cache at /Users/tte/.cache/torch/protein_models/fbb05edff0ffa844a729a04850272a1f8973bc002526f6615ad113a5f5aacd36.05edb4ed225e1907a3878f9d68b275d79e025b667555aa94a086e27cb5c591e0\n",
      "19:55:51   Model config {\n",
      "  \"attention_probs_dropout_prob\": 0.1,\n",
      "  \"base_model\": \"transformer\",\n",
      "  \"finetuning_task\": null,\n",
      "  \"hidden_act\": \"gelu\",\n",
      "  \"hidden_dropout_prob\": 0.1,\n",
      "  \"hidden_size\": 768,\n",
      "  \"initializer_range\": 0.02,\n",
      "  \"input_size\": 768,\n",
      "  \"intermediate_size\": 3072,\n",
      "  \"layer_norm_eps\": 1e-12,\n",
      "  \"max_position_embeddings\": 8192,\n",
      "  \"num_attention_heads\": 12,\n",
      "  \"num_hidden_layers\": 12,\n",
      "  \"num_labels\": -1,\n",
      "  \"output_attentions\": false,\n",
      "  \"output_hidden_states\": false,\n",
      "  \"output_size\": 768,\n",
      "  \"pruned_heads\": {},\n",
      "  \"torchscript\": false,\n",
      "  \"type_vocab_size\": 1,\n",
      "  \"vocab_size\": 30\n",
      "}\n",
      "\n",
      "19:55:52   loading weights file https://s3.amazonaws.com/songlabdata/proteindata/pytorch-models/bert-base-pytorch_model.bin from cache at /Users/tte/.cache/torch/protein_models/2ed84d28db0a61af4cd2dd3f2ccdd3ee45b1533547a8e1213840af895e2fa8d1.8206daaea9be2736b6ccde432df9dc3dbb8c3233b47f07688d6ff38d74258d22\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "100%|█████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 512/512 [00:56<00:00,  9.01it/s]\n"
     ]
    }
   ],
   "source": [
    "# get the actual generator\n",
    "generator = configuration.get_conditional_generator(configuration.ensure_artifacts())\n",
    "# generate randomly points in the latent space\n",
    "number_of_latent_points = 512\n",
    "latent_points = torch.randn(\n",
    "    number_of_latent_points, generator.encoder_latent_size, device=generator.device\n",
    ")\n",
    "# keep points related to valid molecules\n",
    "molecules = []\n",
    "for latent_point in tqdm(torch.unsqueeze(latent_points, 1)):\n",
    "    smiles_list = generator.get_smiles_from_latent(latent_point)\n",
    "    generated_molecules = [\n",
    "        Chem.MolFromSmiles(smiles)\n",
    "        for smiles in smiles_list\n",
    "    ][:1]  # keeping only a molecule per point\n",
    "    molecules.extend(generated_molecules)\n",
    "valid_indexes = [index for index, molecule in enumerate(molecules) if molecule is not None]\n",
    "molecules = [molecules[index] for index in valid_indexes]\n",
    "latent_points = latent_points[valid_indexes]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "id": "elementary-albania",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "%matplotlib inline\n",
    "values=[]\n",
    "for molecule in molecules:\n",
    "    try:\n",
    "        values.append(Chem.QED.qed(molecule))\n",
    "    except:\n",
    "        values.append(0.0)\n",
    "_ = render_latent_points(latent_points, values=values)\n",
    "_ = plt.title(\"Rendering drug likeness in a 2D projection of the latent space\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "sorted-chair",
   "metadata": {},
   "source": [
    "## PaccMannGP\n",
    "\n",
    "An algorithm for generating molecules using controlled sampling based on Gaussian Processes [[3]](https://doi.org/10.1021/acs.jcim.1c00889)."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "id": "exclusive-crossing",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "19:56:51   runnning PaccMannGP with configuration=PaccMannGPGenerator(algorithm_version='v0', batch_size=32, temperature=1.4, generated_length=100, limit=5.0, acquisition_function='EI', number_of_steps=32, number_of_initial_points=16, initial_point_generator='random', seed=42, number_of_optimization_rounds=1, sampling_variance=0.1, samples_for_evaluation=4, maximum_number_of_sampling_steps=32)\n",
      "19:56:51   ensure artifacts for the application are present.\n",
      "19:56:51   starting syncing\n",
      "19:56:51   syncing complete\n"
     ]
    }
   ],
   "source": [
    "from gt4sd.algorithms.controlled_sampling.paccmann_gp.core import PaccMannGP, PaccMannGPGenerator\n",
    "\n",
    "# maximizing drug likeness and synthesizability\n",
    "target = {\"qed\": {\"weight\": 1.0}, \"sa\": {\"weight\": 1.0}}\n",
    "configuration = PaccMannGPGenerator()\n",
    "algorithm = PaccMannGP(configuration=configuration, target=target)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "critical-correspondence",
   "metadata": {},
   "source": [
    "Via the algorithm you can easily inspect the generated molecules interactively:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "id": "wanted-progressive",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "19:56:52   configuring optimization for target: {'qed': {'weight': 1.0}, 'sa': {'weight': 1.0}}\n",
      "19:56:53   running optimization with the following parameters: {'dimensions': [(-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0), (-5.0, 5.0)], 'acq_func': 'EI', 'n_calls': 32, 'n_initial_points': 16, 'initial_point_generator': 'random', 'random_state': 4112119562}\n",
      "19:56:53   running at most 1 optmization rounds\n",
      "19:56:53   starting round 1\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "2022-05-12 19:57:09.224 | WARNING  | paccmann_gp.sa_minimization:evaluate:47 - SA calculation failed.\n",
      "2022-05-12 19:57:29.235 | WARNING  | paccmann_gp.sa_minimization:evaluate:47 - SA calculation failed.\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "19:58:13   starting sampling for 1\n",
      "19:58:58   completing round 1\n",
      "19:58:58   generated 157 molecules in the current run\n"
     ]
    }
   ],
   "source": [
    "molecules = list(algorithm.sample(15))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "id": "instant-definition",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<script>\n",
       "    function fit_height(obj) {\n",
       "        obj.style.height = 0;\n",
       "        var height = obj.contentDocument.body.scrollHeight + 18 + 'px';\n",
       "        obj.style.height = height;\n",
       "    }\n",
       "</script>\n",
       "<iframe class=\"mols2grid-iframe\" frameborder=\"0\" width=\"100%\"\n",
       "\n",
       "height=\"200\"\n",
       "\n",
       "\n",
       "allow=\"clipboard-write\"\n",
       "\n",
       "srcdoc=\"&lt;html&gt;\n",
       "  &lt;meta charset=&quot;utf-8&quot;&gt;\n",
       "  &lt;head&gt;\n",
       "    &lt;style&gt;\n",
       "    #mols2grid.gridcontainer {\n",
       "    display: block;\n",
       "    padding-left: 1em;\n",
       "    max-width: 820px;\n",
       "    width: 820px;\n",
       "}\n",
       "#mols2grid .cell {\n",
       "    border: 1px solid #cccccc;\n",
       "    text-align: center;\n",
       "    vertical-align: top;\n",
       "    max-width: 160px;\n",
       "    width: 160px;\n",
       "    font-family: &#x27;DejaVu&#x27;, sans-serif;\n",
       "    font-size: 12pt;\n",
       "    padding: 0;\n",
       "    margin: 0px;\n",
       "    float: left;\n",
       "}\n",
       "#mols2grid .cell:hover {\n",
       "    background-color: #e7e7e7 !important;\n",
       "}\n",
       "#mols2grid .cell .data-img {\n",
       "    padding: 0;\n",
       "    margin: 0;\n",
       "}\n",
       "#mols2grid .cell img, #mols2grid .cell svg {\n",
       "    max-width: 100%;\n",
       "    height: auto;\n",
       "    padding: 0;\n",
       "}\n",
       "#mols2grid .data {\n",
       "    overflow: hidden;\n",
       "    white-space: nowrap;\n",
       "    text-overflow: ellipsis;\n",
       "    display: block;\n",
       "}\n",
       "#mols2grid .arrow-asc:after {\n",
       "    content: &#x27;↑&#x27;;\n",
       "    text-align: right;\n",
       "    float:right;\n",
       "}\n",
       "#mols2grid .arrow-desc:after {\n",
       "    content: &#x27;↓&#x27;;\n",
       "    text-align: right;\n",
       "    float:right;\n",
       "}\n",
       "    /* custom CSS */\n",
       "    \n",
       "    &lt;/style&gt;\n",
       "    &lt;script src=&quot;https://cdnjs.cloudflare.com/ajax/libs/list.js/2.3.1/list.min.js&quot;&gt;&lt;/script&gt;\n",
       "&lt;link rel=&quot;stylesheet&quot; href=&quot;https://cdn.jsdelivr.net/npm/bootstrap@4.6.0/dist/css/bootstrap.min.css&quot; integrity=&quot;sha384-B0vP5xmATw1+K9KRQjQERJvTumQW0nPEzvF6L/Z6nronJ3oUOFUFpCjEUQouq2+l&quot; crossorigin=&quot;anonymous&quot;&gt;\n",
       "&lt;script src=&quot;https://code.jquery.com/jquery-3.5.1.slim.min.js&quot; integrity=&quot;sha384-DfXdz2htPH0lsSSs5nCTpuj/zy4C+OGpamoFVy38MVBnE+IbbVYUew+OrCXaRkfj&quot; crossorigin=&quot;anonymous&quot;&gt;&lt;/script&gt;\n",
       "&lt;script src=&quot;https://cdn.jsdelivr.net/npm/bootstrap@4.6.0/dist/js/bootstrap.bundle.min.js&quot; integrity=&quot;sha384-Piv4xVNRyMGpqkS2by6br4gNJ7DXjqk09RmUpJ8jgGtD7zP9yug3goQfGII0yAns&quot; crossorigin=&quot;anonymous&quot;&gt;&lt;/script&gt;\n",
       "&lt;script src=&quot;https://unpkg.com/@rdkit/rdkit@2021.9.4/Code/MinimalLib/dist/RDKit_minimal.js&quot;&gt;&lt;/script&gt;\n",
       "    &lt;!-- custom header --&gt;\n",
       "    \n",
       "  &lt;/head&gt;\n",
       "  &lt;body&gt;\n",
       "    &lt;div id=&quot;mols2grid&quot; class=&quot;gridcontainer grid-default&quot;&gt;\n",
       "      &lt;div class=&quot;row mb-3&quot;&gt;\n",
       "        &lt;div class=&quot;list&quot;&gt;&lt;div class=&quot;cell&quot; data-mols2grid-id=&quot;0&quot;&gt;&lt;input type=&quot;checkbox&quot; class=&quot;position-relative float-left cached_checkbox&quot;&gt;&lt;div class=&quot;data data-img&quot;&gt;&lt;/div&gt;&lt;div class=&quot;data data-mols2grid-id-copy&quot;&gt;&lt;/div&gt;&lt;div class=&quot;data data-SMILES&quot;&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;\n",
       "      &lt;/div&gt;\n",
       "      &lt;div class=&quot;d-inline&quot;&gt;\n",
       "        &lt;ul class=&quot;pagination float-left&quot;&gt;&lt;/ul&gt;\n",
       "        &lt;div id=&quot;controls&quot; class=&quot;d-flex flex-row float-right&quot;&gt;\n",
       "          \n",
       "          &lt;div id=&quot;chkbox-dropdown&quot; class=&quot;dropdown&quot;&gt;\n",
       "    &lt;button class=&quot;btn btn-light dropdown-toggle&quot; type=&quot;button&quot; id=&quot;chkboxDropdown&quot; data-toggle=&quot;dropdown&quot; aria-haspopup=&quot;true&quot; aria-expanded=&quot;false&quot;&gt;☑&lt;/button&gt;\n",
       "    &lt;div class=&quot;dropdown-menu&quot; aria-labelledby=&quot;checkboxDropdownMenu&quot;&gt;\n",
       "        &lt;button id=&quot;btn-chkbox-all&quot; class=&quot;dropdown-item&quot; type=&quot;button&quot;&gt;Check all&lt;/button&gt;\n",
       "        &lt;button id=&quot;btn-chkbox-none&quot; class=&quot;dropdown-item&quot; type=&quot;button&quot;&gt;Uncheck all&lt;/button&gt;\n",
       "        &lt;button id=&quot;btn-chkbox-invert&quot; class=&quot;dropdown-item&quot; type=&quot;button&quot;&gt;Invert&lt;/button&gt;\n",
       "        &lt;div class=&quot;dropdown-divider&quot;&gt;&lt;/div&gt;\n",
       "        &lt;button id=&quot;btn-chkbox-copy&quot; class=&quot;dropdown-item&quot; type=&quot;button&quot;&gt;Copy to clipboard&lt;/button&gt;\n",
       "        &lt;button id=&quot;btn-chkbox-dlsmi&quot; class=&quot;dropdown-item&quot; type=&quot;button&quot;&gt;Save SMILES&lt;/button&gt;\n",
       "        &lt;button id=&quot;btn-chkbox-dlcsv&quot; class=&quot;dropdown-item&quot; type=&quot;button&quot;&gt;Save CSV&lt;/button&gt;\n",
       "    &lt;/div&gt;\n",
       "&lt;/div&gt;\n",
       "          \n",
       "          &lt;div id=&quot;sort-dropdown&quot; class=&quot;dropdown pl-2&quot;&gt;\n",
       "            &lt;button class=&quot;btn btn-light dropdown-toggle&quot; type=&quot;button&quot; id=&quot;sortDropdown&quot; data-toggle=&quot;dropdown&quot; aria-haspopup=&quot;true&quot; aria-expanded=&quot;false&quot;&gt;\n",
       "              Sort by\n",
       "            &lt;/button&gt;\n",
       "            &lt;div class=&quot;dropdown-menu&quot; aria-labelledby=&quot;sortDropdownMenu&quot;&gt;\n",
       "              \n",
       "              \n",
       "              \n",
       "              \n",
       "              \n",
       "              &lt;button class=&quot;dropdown-item sort-btn arrow-asc active&quot; type=&quot;button&quot; data-name=&quot;mols2grid-id&quot;&gt;Index&lt;/button&gt;\n",
       "              \n",
       "              \n",
       "              \n",
       "              \n",
       "              \n",
       "              &lt;button class=&quot;dropdown-item sort-btn arrow-asc active&quot; type=&quot;button&quot; data-name=&quot;data-mols2grid-id&quot;&gt;mols2grid-id&lt;/button&gt;\n",
       "              \n",
       "              \n",
       "              \n",
       "              \n",
       "              \n",
       "              &lt;button class=&quot;dropdown-item sort-btn &quot; type=&quot;button&quot; data-name=&quot;data-SMILES&quot;&gt;SMILES&lt;/button&gt;\n",
       "              \n",
       "              \n",
       "              \n",
       "              &lt;button class=&quot;dropdown-item sort-btn&quot; type=&quot;button&quot; data-name=&quot;checkbox&quot;&gt;Selected&lt;/button&gt;\n",
       "              \n",
       "            &lt;/div&gt;\n",
       "          &lt;/div&gt;\n",
       "          &lt;div class=&quot;input-group row pl-4&quot;&gt;\n",
       "            &lt;input type=&quot;text&quot; id=&quot;searchbar&quot; class=&quot;form-control&quot; placeholder=&quot;Search&quot; aria-label=&quot;Search&quot; aria-describedby=&quot;basic-addon1&quot;&gt;\n",
       "            &lt;div class=&quot;input-group-append&quot;&gt;\n",
       "              &lt;button id=&quot;searchBtn&quot; class=&quot;btn btn-light dropdown-toggle&quot; type=&quot;button&quot; data-toggle=&quot;dropdown&quot; aria-haspopup=&quot;true&quot; aria-expanded=&quot;false&quot;&gt;🔎&lt;/button&gt;\n",
       "              &lt;div class=&quot;dropdown-menu dropdown-menu-right&quot;&gt;\n",
       "                &lt;button id=&quot;txtSearch&quot; class=&quot;search-btn dropdown-item active&quot;&gt;Text&lt;/button&gt;\n",
       "                &lt;button id=&quot;smartsSearch&quot; class=&quot;search-btn dropdown-item&quot;&gt;SMARTS&lt;/button&gt;\n",
       "              &lt;/div&gt;\n",
       "            &lt;/div&gt;\n",
       "          &lt;/div&gt;\n",
       "        &lt;/div&gt;\n",
       "      &lt;/div&gt;\n",
       "    &lt;/div&gt;\n",
       "    &lt;script&gt;\n",
       "    // list.js\n",
       "var listObj = new List(&#x27;mols2grid&#x27;, {\n",
       "    valueNames: [{data: [&#x27;mols2grid-id&#x27;]}, &#x27;data-img&#x27;, &#x27;data-mols2grid-id&#x27;, &#x27;data-SMILES&#x27;, &#x27;data-mols2grid-id-copy&#x27;],\n",
       "    item: &#x27;&lt;div class=&quot;cell&quot; data-mols2grid-id=&quot;0&quot;&gt;&lt;input type=&quot;checkbox&quot; class=&quot;position-relative float-left cached_checkbox&quot;&gt;&lt;div class=&quot;data data-img&quot;&gt;&lt;/div&gt;&lt;div class=&quot;data data-mols2grid-id-copy&quot;&gt;&lt;/div&gt;&lt;div class=&quot;data data-SMILES&quot;&gt;&lt;/div&gt;&lt;/div&gt;&#x27;,\n",
       "    page: 15,\n",
       "    pagination: {\n",
       "        name: &quot;pagination&quot;,\n",
       "        item: &#x27;&lt;li class=&quot;page-item&quot;&gt;&lt;a class=&quot;page page-link&quot; href=&quot;#&quot; onclick=&quot;event.preventDefault()&quot;&gt;&lt;/a&gt;&lt;/li&gt;&#x27;,\n",
       "        innerWindow: 1,\n",
       "        outerWindow: 1,\n",
       "    },\n",
       "});\n",
       "listObj.remove(&quot;mols2grid-id&quot;, &quot;0&quot;);\n",
       "listObj.add([{&quot;data-img&quot;: null, &quot;mols2grid-id&quot;: 0, &quot;data-SMILES&quot;: &quot;O=P(O)(O)OCCO&quot;, &quot;data-mols2grid-id-copy&quot;: 0}, {&quot;data-img&quot;: null, &quot;mols2grid-id&quot;: 1, &quot;data-SMILES&quot;: &quot;CCCSC(O)OCO&quot;, &quot;data-mols2grid-id-copy&quot;: 1}, {&quot;data-img&quot;: null, &quot;mols2grid-id&quot;: 2, &quot;data-SMILES&quot;: &quot;CN(CCNCN=CN)CN1C=CC=C2C=C(N)C(=O)NC(=CC(=O)NC1)O2&quot;, &quot;data-mols2grid-id-copy&quot;: 2}, {&quot;data-img&quot;: null, &quot;mols2grid-id&quot;: 3, &quot;data-SMILES&quot;: &quot;BrC1=COC1&quot;, &quot;data-mols2grid-id-copy&quot;: 3}, {&quot;data-img&quot;: null, &quot;mols2grid-id&quot;: 4, &quot;data-SMILES&quot;: &quot;O=[SH](F)(Cn1cncn1)c1ccc(N[O-])cc1&quot;, &quot;data-mols2grid-id-copy&quot;: 4}, {&quot;data-img&quot;: null, &quot;mols2grid-id&quot;: 5, &quot;data-SMILES&quot;: &quot;NCC(O)=Cc1ccc2oc(=O)[nH]c2c1-c1nc2ccccc2[nH]1&quot;, &quot;data-mols2grid-id-copy&quot;: 5}, {&quot;data-img&quot;: null, &quot;mols2grid-id&quot;: 6, &quot;data-SMILES&quot;: &quot;CNCC(O)=CC=CN(C=CS(=O)(=O)c1c2cccc1C2)c1ccccn1&quot;, &quot;data-mols2grid-id-copy&quot;: 6}, {&quot;data-img&quot;: null, &quot;mols2grid-id&quot;: 7, &quot;data-SMILES&quot;: &quot;CC1CCC#CCOCCN1&quot;, &quot;data-mols2grid-id-copy&quot;: 7}, {&quot;data-img&quot;: null, &quot;mols2grid-id&quot;: 8, &quot;data-SMILES&quot;: &quot;CC#CCON(C)C(=O)OOCOC(CCOCN)NC(=O)Cc1ccccc1C(=O)OCCl&quot;, &quot;data-mols2grid-id-copy&quot;: 8}, {&quot;data-img&quot;: null, &quot;mols2grid-id&quot;: 9, &quot;data-SMILES&quot;: &quot;NO&quot;, &quot;data-mols2grid-id-copy&quot;: 9}, {&quot;data-img&quot;: null, &quot;mols2grid-id&quot;: 10, &quot;data-SMILES&quot;: &quot;CN1CC#CSOCC=COCCCN2CCC(CC2)NCC1&quot;, &quot;data-mols2grid-id-copy&quot;: 10}, {&quot;data-img&quot;: null, &quot;mols2grid-id&quot;: 11, &quot;data-SMILES&quot;: &quot;O=C1NCCCC1NN=CCCNS(=O)(=O)c1cccc([SH](=O)(O)NO)c1&quot;, &quot;data-mols2grid-id-copy&quot;: 11}, {&quot;data-img&quot;: null, &quot;mols2grid-id&quot;: 12, &quot;data-SMILES&quot;: &quot;O=CCC(O)CO&quot;, &quot;data-mols2grid-id-copy&quot;: 12}, {&quot;data-img&quot;: null, &quot;mols2grid-id&quot;: 13, &quot;data-SMILES&quot;: &quot;C[SH](O)c1ccccc1CNS(=O)(=O)c1ccc(C(O)C(=O)C23C=CN([SH]=O)CC2CCCC3)cc1&quot;, &quot;data-mols2grid-id-copy&quot;: 13}, {&quot;data-img&quot;: null, &quot;mols2grid-id&quot;: 14, &quot;data-SMILES&quot;: &quot;NCC=CCC[SH]1CC(NC(=O)c2ccccc2O)c2ccccc21&quot;, &quot;data-mols2grid-id-copy&quot;: 14}]);\n",
       "// filter\n",
       "if (window.parent.mols2grid_lists === undefined) {\n",
       "    window.parent.mols2grid_lists = {};\n",
       "}\n",
       "window.parent.mols2grid_lists[&quot;default&quot;] = listObj;\n",
       "\n",
       "\n",
       "// selection\n",
       "class MolStorage extends Map {\n",
       "    multi_set(_id, _smiles) {\n",
       "        for (let i=0; i &lt; _id.length; i++) {\n",
       "            this.set(_id[i], _smiles[i]);\n",
       "        }\n",
       "    }\n",
       "    multi_del(_id) {\n",
       "        for (let i=0; i &lt; _id.length; i++) {\n",
       "            this.delete(_id[i]);\n",
       "        };\n",
       "    }\n",
       "    to_dict() {\n",
       "        var content = &quot;{&quot;;\n",
       "        for (let [key, value] of this) {\n",
       "            content += key + &quot;:&quot; + JSON.stringify(value) + &quot;,&quot;;\n",
       "        }\n",
       "        content = content.length &gt; 1 ? content.slice(0, -1) : content;\n",
       "        content += &quot;}&quot;;\n",
       "        return content\n",
       "    }\n",
       "    download_smi(fileName) {\n",
       "        var content = &quot;SMILES index\\n&quot;;\n",
       "        for (let [key, value] of this) {\n",
       "            content += value + &quot; &quot; + key + &quot;\\n&quot;;\n",
       "        }\n",
       "        var a = document.createElement(&quot;a&quot;);\n",
       "        var file = new Blob([content], {type: &quot;text/plain&quot;});\n",
       "        a.href = URL.createObjectURL(file);\n",
       "        a.download = fileName;\n",
       "        a.click();\n",
       "        a.remove();\n",
       "    }\n",
       "}\n",
       "var SELECTION = new MolStorage();\n",
       "\n",
       "\n",
       "\n",
       "// kernel\n",
       "var kernel_env = null;\n",
       "if (window.parent.IPython !== undefined) {\n",
       "    // Jupyter notebook\n",
       "    kernel_env = &quot;jupyter&quot;;\n",
       "    var kernel = window.parent.IPython.notebook.kernel;\n",
       "    kernel.execute(&#x27;from mols2grid.select import register as _m2g_reg&#x27;)\n",
       "    function add_selection(grid_id, _id, smiles) {\n",
       "        SELECTION.multi_set(_id, smiles);\n",
       "        kernel.execute(&quot;_m2g_reg.add_selection(&#x27;&quot;+grid_id+&quot;&#x27;, &quot;+JSON.stringify(_id)+&quot;,&quot;+JSON.stringify(smiles)+&quot;)&quot;);\n",
       "    }\n",
       "    function del_selection(grid_id, _id) {\n",
       "        SELECTION.multi_del(_id);\n",
       "        kernel.execute(&quot;_m2g_reg.del_selection(&#x27;&quot;+grid_id+&quot;&#x27;, &quot;+JSON.stringify(_id)+&quot;)&quot;);\n",
       "    }\n",
       "} else if (window.parent.google !== undefined) {\n",
       "    // Google colab\n",
       "    kernel_env = &quot;colab&quot;;\n",
       "    var kernel = window.parent.google.colab.kernel;\n",
       "    function add_selection(grid_id, _id, smiles) {\n",
       "        SELECTION.multi_set(_id, smiles);\n",
       "        (async function() {\n",
       "        const result = await kernel.invokeFunction(&#x27;_m2g_reg.add_selection&#x27;,\n",
       "                                                   [grid_id, _id, smiles], {});\n",
       "        })();\n",
       "    }\n",
       "    function del_selection(grid_id, _id) {\n",
       "        SELECTION.multi_del(_id);\n",
       "        (async function() {\n",
       "        const result = await kernel.invokeFunction(&#x27;_m2g_reg.del_selection&#x27;,\n",
       "                                                   [grid_id, _id], {});\n",
       "        })();\n",
       "    }\n",
       "} else {\n",
       "    function add_selection(grid_id, _id, smiles) {\n",
       "        SELECTION.multi_set(_id, smiles);\n",
       "    }\n",
       "    function del_selection(grid_id, _id) {\n",
       "        SELECTION.multi_del(_id);\n",
       "    }\n",
       "}\n",
       "\n",
       "\n",
       "\n",
       "\n",
       "// sort\n",
       "var sort_field = &quot;mols2grid-id&quot;;\n",
       "var sort_order = &quot;asc&quot;;\n",
       "function mols2gridSortFunction(itemA, itemB, options) {\n",
       "    var x = itemA.values()[options.valueName];\n",
       "    var y = itemB.values()[options.valueName];\n",
       "    if (typeof x === &quot;number&quot;) {\n",
       "        if (isFinite(x - y)) {\n",
       "            return x - y; \n",
       "        } else {\n",
       "            return isFinite(x) ? -1 : 1;\n",
       "        }\n",
       "    } else {\n",
       "        x = x.toLowerCase();\n",
       "        y = y.toLowerCase();\n",
       "        return (x &lt; y) ? -1: (x &gt; y) ? 1: 0;\n",
       "    }\n",
       "}\n",
       "function checkboxSort(itemA, itemB, options) {\n",
       "    if (itemA.elm !== undefined) {\n",
       "        var checkedA = itemA.elm.firstChild.checked;\n",
       "        if (itemB.elm !== undefined) {\n",
       "            var checkedB = itemB.elm.firstChild.checked;\n",
       "            if (checkedA &amp;&amp; !checkedB) {\n",
       "                return -1;\n",
       "            } else if (!checkedA &amp;&amp; checkedB) {\n",
       "                return 1;\n",
       "            } else {\n",
       "                return 0;\n",
       "            }\n",
       "        } else {\n",
       "            return -1;\n",
       "        }\n",
       "    } else if (itemB.elm !== undefined) {\n",
       "        return 1;\n",
       "    } else {\n",
       "        return 0;\n",
       "    }\n",
       "}\n",
       "$(&#x27;#mols2grid button.sort-btn&#x27;).click(function(e) {\n",
       "    var _field = $(this).attr(&quot;data-name&quot;);\n",
       "    if (_field == sort_field) {\n",
       "        $(this).removeClass(&quot;arrow-&quot; + sort_order)\n",
       "        sort_order = (sort_order === &quot;desc&quot;) ? &quot;asc&quot; : &quot;desc&quot;;\n",
       "    } else {\n",
       "        $(&#x27;#mols2grid button.sort-btn.active&#x27;).removeClass(&quot;active arrow-&quot; + sort_order);\n",
       "        sort_order = &quot;asc&quot;;\n",
       "        sort_field = _field;\n",
       "        $(this).addClass(&quot;active&quot;);\n",
       "    }\n",
       "    $(this).addClass(&quot;arrow-&quot; + sort_order)\n",
       "    if (sort_field == &quot;checkbox&quot;) {\n",
       "        listObj.sort(&quot;mols2grid-id&quot;, {order: sort_order, sortFunction: checkboxSort});\n",
       "    } else {\n",
       "        listObj.sort(_field, {order: sort_order, sortFunction: mols2gridSortFunction});\n",
       "    }\n",
       "});\n",
       "\n",
       "\n",
       "\n",
       "\n",
       "\n",
       "\n",
       "// selection modifyers and export options\n",
       "// check all\n",
       "$(&#x27;#btn-chkbox-all&#x27;).click(function (e) {\n",
       "    var current_page = parseInt($(&quot;li.page-item.active &gt; a&quot;).text());\n",
       "    var n_items = 15;\n",
       "    var last_page = parseInt($(&quot;li.page-item &gt; a&quot;).last().text());\n",
       "    var _id = [];\n",
       "    var _smiles = [];\n",
       "    for (let i = 0; i &lt; last_page; i++) {\n",
       "        listObj.show(i * n_items + 1, n_items);\n",
       "        $(&quot;input:checkbox&quot;).each(function() {\n",
       "            this.checked = true;\n",
       "            _id.push(parseInt($(this).closest(&quot;.cell&quot;).attr(&quot;data-mols2grid-id&quot;)));\n",
       "            _smiles.push($($(this).siblings(&quot;.data-SMILES&quot;)[0]).text());\n",
       "        });\n",
       "    }\n",
       "    listObj.show((current_page - 1) * n_items + 1, n_items);\n",
       "    add_selection(&quot;default&quot;, _id, _smiles);\n",
       "});\n",
       "// uncheck all\n",
       "$(&#x27;#btn-chkbox-none&#x27;).click(function (e) {\n",
       "    var current_page = parseInt($(&quot;li.page-item.active &gt; a&quot;).text());\n",
       "    var n_items = 15;\n",
       "    var last_page = parseInt($(&quot;li.page-item &gt; a&quot;).last().text());\n",
       "    var _id = [];\n",
       "    for (let i = 0; i &lt; last_page; i++) {\n",
       "        listObj.show(i * n_items + 1, n_items);\n",
       "        $(&quot;input:checkbox:checked&quot;).each(function() {\n",
       "            this.checked = false;\n",
       "            _id.push(parseInt($(this).closest(&quot;.cell&quot;).attr(&quot;data-mols2grid-id&quot;)));\n",
       "        });\n",
       "    }\n",
       "    listObj.show((current_page - 1) * n_items + 1, n_items);\n",
       "    del_selection(&quot;default&quot;, _id);\n",
       "});\n",
       "// invert\n",
       "$(&#x27;#btn-chkbox-invert&#x27;).click(function (e) {\n",
       "    var current_page = parseInt($(&quot;li.page-item.active &gt; a&quot;).text());\n",
       "    var n_items = 15;\n",
       "    var last_page = parseInt($(&quot;li.page-item &gt; a&quot;).last().text());\n",
       "    var _id_add = [];\n",
       "    var _id_del = [];\n",
       "    var _smiles = [];\n",
       "    for (let i = 0; i &lt; last_page; i++) {\n",
       "        listObj.show(i * n_items + 1, n_items);\n",
       "        $(&quot;input:checkbox&quot;).each(function() {\n",
       "            this.checked = !this.checked;\n",
       "            var _id = parseInt($(this).closest(&quot;.cell&quot;).attr(&quot;data-mols2grid-id&quot;));\n",
       "            if (this.checked) {\n",
       "                _id_add.push(_id);\n",
       "                _smiles.push($(this).siblings(&quot;.data-SMILES&quot;).first().text());\n",
       "            } else {\n",
       "                _id_del.push(_id);\n",
       "            }\n",
       "        });\n",
       "    }\n",
       "    listObj.show((current_page - 1) * n_items + 1, n_items);\n",
       "    del_selection(&quot;default&quot;, _id_del);\n",
       "    add_selection(&quot;default&quot;, _id_add, _smiles);\n",
       "});\n",
       "// copy to clipboard\n",
       "$(&quot;#btn-chkbox-copy&quot;).click(function(e) {\n",
       "    navigator.clipboard.writeText(SELECTION.to_dict());\n",
       "});\n",
       "// export smiles\n",
       "$(&quot;#btn-chkbox-dlsmi&quot;).click(function(e) {\n",
       "    SELECTION.download_smi(&quot;selection.smi&quot;);\n",
       "});\n",
       "// export CSV\n",
       "$(&quot;#btn-chkbox-dlcsv&quot;).click(function(e) {\n",
       "    var sep = &quot;\\t&quot;\n",
       "    // same order as subset + tooltip\n",
       "    var columns = Array.from(listObj.items[0].elm.querySelectorAll(&quot;div.data&quot;))\n",
       "                       .map(elm =&gt; elm.classList[1]);\n",
       "    // remove &#x27;data-&#x27;\n",
       "    var header = columns.map(name =&gt; name.slice(5));\n",
       "    // csv content\n",
       "    header = [&quot;index&quot;].concat(header).join(sep);\n",
       "    var content = header + &quot;\\n&quot;;\n",
       "    for (let [index, smiles] of SELECTION.entries()) {\n",
       "        var data = listObj.items[index].values();\n",
       "        content += index;\n",
       "        columns.forEach((key) =&gt; {\n",
       "            content += sep + data[key];\n",
       "        })\n",
       "        content += &quot;\\n&quot;;\n",
       "    }\n",
       "    var a = document.createElement(&quot;a&quot;);\n",
       "    var file = new Blob([content], {type: &quot;text/csv&quot;});\n",
       "    a.href = URL.createObjectURL(file);\n",
       "    a.download = &quot;selection.csv&quot;;\n",
       "    a.click();\n",
       "    a.remove();\n",
       "});\n",
       "// update selection on checkbox click\n",
       "listObj.on(&quot;updated&quot;, function (list) {\n",
       "    $(&quot;input:checkbox&quot;).change(function() {\n",
       "        var _id = parseInt($(this).closest(&quot;.cell&quot;).attr(&quot;data-mols2grid-id&quot;));\n",
       "        if (this.checked) {\n",
       "            var _smiles = $($(this).siblings(&quot;.data-SMILES&quot;)[0]).text();\n",
       "            add_selection(&quot;default&quot;, [_id], [_smiles]);\n",
       "        } else {\n",
       "            del_selection(&quot;default&quot;, [_id]);\n",
       "        }\n",
       "    }); \n",
       "});\n",
       "\n",
       "\n",
       "\n",
       "\n",
       "\n",
       "// generate images for the currently displayed molecules\n",
       "var draw_opts = {&quot;fixedBondLength&quot;: 200, &quot;width&quot;: 160, &quot;height&quot;: 120};\n",
       "var json_draw_opts = JSON.stringify(draw_opts);\n",
       "\n",
       "var smarts_matches = {};\n",
       "\n",
       "// Load RDKit\n",
       "window\n",
       ".initRDKitModule()\n",
       ".then(function(RDKit) {\n",
       "    console.log(&#x27;RDKit version: &#x27;, RDKit.version());\n",
       "    window.RDKit = RDKit;\n",
       "    window.RDKitModule = RDKit;\n",
       "\n",
       "    // search bar\n",
       "    function SmartsSearch(query, columns) {\n",
       "    var smiles_col = columns[0];\n",
       "    smarts_matches = {};\n",
       "    var query = $(&#x27;#mols2grid #searchbar&#x27;).val();\n",
       "    var qmol = RDKit.get_qmol(query);\n",
       "    if (qmol.is_valid()) {\n",
       "        for (var k = 0, kl = listObj.items.length; k &lt; kl; k++) {\n",
       "            var item = listObj.items[k];\n",
       "            var smiles = item.values()[smiles_col]\n",
       "            var mol = RDKit.get_mol(smiles);\n",
       "            if (mol.is_valid()) {\n",
       "                var results = JSON.parse(mol.get_substruct_match(qmol));\n",
       "                if (results.atoms) {\n",
       "                    item.found = true;\n",
       "                    \n",
       "                    smarts_matches[smiles] = results;\n",
       "                    \n",
       "                } else {\n",
       "                    item.found = false;\n",
       "                }\n",
       "            } else {\n",
       "                item.found = false;\n",
       "            }\n",
       "            mol.delete();\n",
       "        }\n",
       "    }\n",
       "    qmol.delete();\n",
       "}\n",
       "var search_type = &quot;Text&quot;;\n",
       "$(&#x27;#mols2grid .search-btn&#x27;).click(function() {\n",
       "    search_type = $(this).text();\n",
       "    $(&#x27;#mols2grid button.search-btn.active&#x27;).removeClass(&quot;active&quot;);\n",
       "    $(this).addClass(&quot;active&quot;);\n",
       "});\n",
       "$(&#x27;#mols2grid #searchbar&#x27;).on(&quot;keyup&quot;, function(e) {\n",
       "    var query = e.target.value;\n",
       "    if (search_type === &quot;Text&quot;) {\n",
       "        smarts_matches = {};\n",
       "        listObj.search(query, [&#x27;data-mols2grid-id&#x27;, &#x27;data-SMILES&#x27;]);\n",
       "    } else {\n",
       "        listObj.search(query, [&quot;data-SMILES&quot;], SmartsSearch);\n",
       "    }\n",
       "});\n",
       "\n",
       "    \n",
       "    // generate images for the currently displayed molecules\n",
       "RDKit.prefer_coordgen(true);\n",
       "function draw_mol(smiles) {\n",
       "    var mol = RDKit.get_mol(smiles, &#x27;{&quot;removeHs&quot;: false }&#x27;);\n",
       "    var svg = &quot;&quot;;\n",
       "    if (mol.is_valid()) {\n",
       "        var highlights = smarts_matches[smiles];\n",
       "        if (highlights) {\n",
       "            var details = Object.assign({}, draw_opts, highlights);\n",
       "            details = JSON.stringify(details);\n",
       "        } else {\n",
       "            var details = json_draw_opts;\n",
       "        }\n",
       "        svg = mol.get_svg_with_highlights(details);\n",
       "    }\n",
       "    mol.delete();\n",
       "    if (svg == &quot;&quot;) {\n",
       "        return &#x27;&lt;svg width=&quot;160&quot; height=&quot;120&quot; xmlns=&quot;http://www.w3.org/2000/svg&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 160 120&quot;&gt;&lt;/svg&gt;&#x27;;\n",
       "    }\n",
       "    return svg;\n",
       "}\n",
       "listObj.on(&quot;updated&quot;, function (list) {\n",
       "    var query = $(&#x27;#mols2grid #searchbar&#x27;).val();\n",
       "    if (query === &quot;&quot;) {\n",
       "        smarts_matches = {};\n",
       "    }\n",
       "    $(&#x27;#mols2grid .cell&#x27;).each(function() {\n",
       "        var $t = $(this);\n",
       "        var smiles = $t.children(&quot;.data-SMILES&quot;).first().text()\n",
       "        var svg = draw_mol(smiles);\n",
       "        $t.children(&quot;.data-img&quot;).html(svg);\n",
       "    });\n",
       "});\n",
       "    \n",
       "\n",
       "    // trigger update to activate tooltips, draw images, setup callbacks...\n",
       "    listObj.update();\n",
       "    // resize iframe to fit content\n",
       "    if (window.frameElement) {\n",
       "        window.parent.fit_height(window.frameElement);\n",
       "    }\n",
       "});\n",
       "    &lt;/script&gt;\n",
       "  &lt;/body&gt;\n",
       "&lt;/html&gt;\">\n",
       "</iframe>"
      ],
      "text/plain": [
       "<IPython.core.display.HTML object>"
      ]
     },
     "execution_count": 14,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "mols2grid.display([Chem.MolFromSmiles(molecule) for molecule in molecules], fixedBondLength=200)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "powered-quarterly",
   "metadata": {},
   "source": [
    "To unpack the model and inspect its latent spaces we can simply conduct an exploration using a random point cloud"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "id": "tired-texas",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "19:58:58   starting syncing\n",
      "19:58:59   syncing complete\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "100%|███████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 32/32 [00:45<00:00,  1.43s/it]\n"
     ]
    }
   ],
   "source": [
    "# get the actual generator\n",
    "generator = configuration.get_conditional_generator(configuration.ensure_artifacts())\n",
    "# generate randomly points in the latent space\n",
    "number_of_latent_points = 1024\n",
    "latent_points = torch.randn(\n",
    "    number_of_latent_points - (number_of_latent_points % generator.batch_size),\n",
    "    generator.latent_dim, device=generator.device\n",
    ")\n",
    "# keep points related to valid molecules\n",
    "molecules = []\n",
    "for latent_points_batch in tqdm(torch.split(latent_points, generator.batch_size)):\n",
    "    smiles_list = generator.smiles_generator.generate_smiles(latent_points_batch.unsqueeze(0))\n",
    "    generated_molecules = [\n",
    "        Chem.MolFromSmiles(smiles)\n",
    "        for smiles in smiles_list\n",
    "    ]\n",
    "    molecules.extend(generated_molecules)\n",
    "valid_indexes = [index for index, molecule in enumerate(molecules) if molecule is not None]\n",
    "molecules = [molecules[index] for index in valid_indexes]\n",
    "latent_points = latent_points[valid_indexes]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "id": "premier-champion",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "%matplotlib inline\n",
    "values=[]\n",
    "for molecule in molecules:\n",
    "    try:\n",
    "        values.append(Chem.QED.qed(molecule))\n",
    "    except:\n",
    "        values.append(0.0)\n",
    "_ = render_latent_points(latent_points, values=values)\n",
    "_ = plt.title(\"Rendering drug likeness in a 2D projection of the latent space\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "optional-armenia",
   "metadata": {},
   "source": [
    "## AdvancedManufacturing\n",
    "\n",
    "A collection of algorithm for generating molecules using controlled sampling leveraging data-driven continuos representations of molecules [[4]](https://doi.org/10.1021/acscentsci.7b00572) extending the autoencoders architecture considered (e.g., VAE-RNNs, VAE-Transformers)."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "id": "earlier-hungarian",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "19:59:47   no parameters validation\n",
      "19:59:47   runnning AdvancedManufacturing with configuration=CatalystGenerator(algorithm_version='v0', number_of_points=32, number_of_steps=50, generated_length=100, primer_smiles='')\n",
      "19:59:47   ensure artifacts for the application are present.\n",
      "19:59:47   starting syncing\n",
      "19:59:48   syncing complete\n",
      "19:59:48   load vocab from: /Users/tte/.gt4sd/algorithms/controlled_sampling/AdvancedManufacturing/CatalystGenerator/v0/vocab_combined.csv\n",
      "19:59:48   load vocab from: /Users/tte/.gt4sd/algorithms/controlled_sampling/AdvancedManufacturing/CatalystGenerator/v0/vocab_combined.csv\n"
     ]
    }
   ],
   "source": [
    "from gt4sd.algorithms.controlled_sampling.advanced_manufacturing.core import AdvancedManufacturing, CatalystGenerator \n",
    "\n",
    "# generate catalysts with target binding energy\n",
    "target = 10.0\n",
    "configuration = CatalystGenerator()\n",
    "algorithm = AdvancedManufacturing(configuration=configuration, target=target)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "express-vector",
   "metadata": {},
   "source": [
    "Via the algorithm you can easily inspect the generated molecules interactively:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "id": "intelligent-inspiration",
   "metadata": {},
   "outputs": [],
   "source": [
    "molecules = list(algorithm.sample(15))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "id": "synthetic-saturn",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<script>\n",
       "    function fit_height(obj) {\n",
       "        obj.style.height = 0;\n",
       "        var height = obj.contentDocument.body.scrollHeight + 18 + 'px';\n",
       "        obj.style.height = height;\n",
       "    }\n",
       "</script>\n",
       "<iframe class=\"mols2grid-iframe\" frameborder=\"0\" width=\"100%\"\n",
       "\n",
       "height=\"200\"\n",
       "\n",
       "\n",
       "allow=\"clipboard-write\"\n",
       "\n",
       "srcdoc=\"&lt;html&gt;\n",
       "  &lt;meta charset=&quot;utf-8&quot;&gt;\n",
       "  &lt;head&gt;\n",
       "    &lt;style&gt;\n",
       "    #mols2grid.gridcontainer {\n",
       "    display: block;\n",
       "    padding-left: 1em;\n",
       "    max-width: 820px;\n",
       "    width: 820px;\n",
       "}\n",
       "#mols2grid .cell {\n",
       "    border: 1px solid #cccccc;\n",
       "    text-align: center;\n",
       "    vertical-align: top;\n",
       "    max-width: 160px;\n",
       "    width: 160px;\n",
       "    font-family: &#x27;DejaVu&#x27;, sans-serif;\n",
       "    font-size: 12pt;\n",
       "    padding: 0;\n",
       "    margin: 0px;\n",
       "    float: left;\n",
       "}\n",
       "#mols2grid .cell:hover {\n",
       "    background-color: #e7e7e7 !important;\n",
       "}\n",
       "#mols2grid .cell .data-img {\n",
       "    padding: 0;\n",
       "    margin: 0;\n",
       "}\n",
       "#mols2grid .cell img, #mols2grid .cell svg {\n",
       "    max-width: 100%;\n",
       "    height: auto;\n",
       "    padding: 0;\n",
       "}\n",
       "#mols2grid .data {\n",
       "    overflow: hidden;\n",
       "    white-space: nowrap;\n",
       "    text-overflow: ellipsis;\n",
       "    display: block;\n",
       "}\n",
       "#mols2grid .arrow-asc:after {\n",
       "    content: &#x27;↑&#x27;;\n",
       "    text-align: right;\n",
       "    float:right;\n",
       "}\n",
       "#mols2grid .arrow-desc:after {\n",
       "    content: &#x27;↓&#x27;;\n",
       "    text-align: right;\n",
       "    float:right;\n",
       "}\n",
       "    /* custom CSS */\n",
       "    \n",
       "    &lt;/style&gt;\n",
       "    &lt;script src=&quot;https://cdnjs.cloudflare.com/ajax/libs/list.js/2.3.1/list.min.js&quot;&gt;&lt;/script&gt;\n",
       "&lt;link rel=&quot;stylesheet&quot; href=&quot;https://cdn.jsdelivr.net/npm/bootstrap@4.6.0/dist/css/bootstrap.min.css&quot; integrity=&quot;sha384-B0vP5xmATw1+K9KRQjQERJvTumQW0nPEzvF6L/Z6nronJ3oUOFUFpCjEUQouq2+l&quot; crossorigin=&quot;anonymous&quot;&gt;\n",
       "&lt;script src=&quot;https://code.jquery.com/jquery-3.5.1.slim.min.js&quot; integrity=&quot;sha384-DfXdz2htPH0lsSSs5nCTpuj/zy4C+OGpamoFVy38MVBnE+IbbVYUew+OrCXaRkfj&quot; crossorigin=&quot;anonymous&quot;&gt;&lt;/script&gt;\n",
       "&lt;script src=&quot;https://cdn.jsdelivr.net/npm/bootstrap@4.6.0/dist/js/bootstrap.bundle.min.js&quot; integrity=&quot;sha384-Piv4xVNRyMGpqkS2by6br4gNJ7DXjqk09RmUpJ8jgGtD7zP9yug3goQfGII0yAns&quot; crossorigin=&quot;anonymous&quot;&gt;&lt;/script&gt;\n",
       "&lt;script src=&quot;https://unpkg.com/@rdkit/rdkit@2021.9.4/Code/MinimalLib/dist/RDKit_minimal.js&quot;&gt;&lt;/script&gt;\n",
       "    &lt;!-- custom header --&gt;\n",
       "    \n",
       "  &lt;/head&gt;\n",
       "  &lt;body&gt;\n",
       "    &lt;div id=&quot;mols2grid&quot; class=&quot;gridcontainer grid-default&quot;&gt;\n",
       "      &lt;div class=&quot;row mb-3&quot;&gt;\n",
       "        &lt;div class=&quot;list&quot;&gt;&lt;div class=&quot;cell&quot; data-mols2grid-id=&quot;0&quot;&gt;&lt;input type=&quot;checkbox&quot; class=&quot;position-relative float-left cached_checkbox&quot;&gt;&lt;div class=&quot;data data-img&quot;&gt;&lt;/div&gt;&lt;div class=&quot;data data-mols2grid-id-copy&quot;&gt;&lt;/div&gt;&lt;div class=&quot;data data-SMILES&quot;&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;\n",
       "      &lt;/div&gt;\n",
       "      &lt;div class=&quot;d-inline&quot;&gt;\n",
       "        &lt;ul class=&quot;pagination float-left&quot;&gt;&lt;/ul&gt;\n",
       "        &lt;div id=&quot;controls&quot; class=&quot;d-flex flex-row float-right&quot;&gt;\n",
       "          \n",
       "          &lt;div id=&quot;chkbox-dropdown&quot; class=&quot;dropdown&quot;&gt;\n",
       "    &lt;button class=&quot;btn btn-light dropdown-toggle&quot; type=&quot;button&quot; id=&quot;chkboxDropdown&quot; data-toggle=&quot;dropdown&quot; aria-haspopup=&quot;true&quot; aria-expanded=&quot;false&quot;&gt;☑&lt;/button&gt;\n",
       "    &lt;div class=&quot;dropdown-menu&quot; aria-labelledby=&quot;checkboxDropdownMenu&quot;&gt;\n",
       "        &lt;button id=&quot;btn-chkbox-all&quot; class=&quot;dropdown-item&quot; type=&quot;button&quot;&gt;Check all&lt;/button&gt;\n",
       "        &lt;button id=&quot;btn-chkbox-none&quot; class=&quot;dropdown-item&quot; type=&quot;button&quot;&gt;Uncheck all&lt;/button&gt;\n",
       "        &lt;button id=&quot;btn-chkbox-invert&quot; class=&quot;dropdown-item&quot; type=&quot;button&quot;&gt;Invert&lt;/button&gt;\n",
       "        &lt;div class=&quot;dropdown-divider&quot;&gt;&lt;/div&gt;\n",
       "        &lt;button id=&quot;btn-chkbox-copy&quot; class=&quot;dropdown-item&quot; type=&quot;button&quot;&gt;Copy to clipboard&lt;/button&gt;\n",
       "        &lt;button id=&quot;btn-chkbox-dlsmi&quot; class=&quot;dropdown-item&quot; type=&quot;button&quot;&gt;Save SMILES&lt;/button&gt;\n",
       "        &lt;button id=&quot;btn-chkbox-dlcsv&quot; class=&quot;dropdown-item&quot; type=&quot;button&quot;&gt;Save CSV&lt;/button&gt;\n",
       "    &lt;/div&gt;\n",
       "&lt;/div&gt;\n",
       "          \n",
       "          &lt;div id=&quot;sort-dropdown&quot; class=&quot;dropdown pl-2&quot;&gt;\n",
       "            &lt;button class=&quot;btn btn-light dropdown-toggle&quot; type=&quot;button&quot; id=&quot;sortDropdown&quot; data-toggle=&quot;dropdown&quot; aria-haspopup=&quot;true&quot; aria-expanded=&quot;false&quot;&gt;\n",
       "              Sort by\n",
       "            &lt;/button&gt;\n",
       "            &lt;div class=&quot;dropdown-menu&quot; aria-labelledby=&quot;sortDropdownMenu&quot;&gt;\n",
       "              \n",
       "              \n",
       "              \n",
       "              \n",
       "              \n",
       "              &lt;button class=&quot;dropdown-item sort-btn arrow-asc active&quot; type=&quot;button&quot; data-name=&quot;mols2grid-id&quot;&gt;Index&lt;/button&gt;\n",
       "              \n",
       "              \n",
       "              \n",
       "              \n",
       "              \n",
       "              &lt;button class=&quot;dropdown-item sort-btn arrow-asc active&quot; type=&quot;button&quot; data-name=&quot;data-mols2grid-id&quot;&gt;mols2grid-id&lt;/button&gt;\n",
       "              \n",
       "              \n",
       "              \n",
       "              \n",
       "              \n",
       "              &lt;button class=&quot;dropdown-item sort-btn &quot; type=&quot;button&quot; data-name=&quot;data-SMILES&quot;&gt;SMILES&lt;/button&gt;\n",
       "              \n",
       "              \n",
       "              \n",
       "              &lt;button class=&quot;dropdown-item sort-btn&quot; type=&quot;button&quot; data-name=&quot;checkbox&quot;&gt;Selected&lt;/button&gt;\n",
       "              \n",
       "            &lt;/div&gt;\n",
       "          &lt;/div&gt;\n",
       "          &lt;div class=&quot;input-group row pl-4&quot;&gt;\n",
       "            &lt;input type=&quot;text&quot; id=&quot;searchbar&quot; class=&quot;form-control&quot; placeholder=&quot;Search&quot; aria-label=&quot;Search&quot; aria-describedby=&quot;basic-addon1&quot;&gt;\n",
       "            &lt;div class=&quot;input-group-append&quot;&gt;\n",
       "              &lt;button id=&quot;searchBtn&quot; class=&quot;btn btn-light dropdown-toggle&quot; type=&quot;button&quot; data-toggle=&quot;dropdown&quot; aria-haspopup=&quot;true&quot; aria-expanded=&quot;false&quot;&gt;🔎&lt;/button&gt;\n",
       "              &lt;div class=&quot;dropdown-menu dropdown-menu-right&quot;&gt;\n",
       "                &lt;button id=&quot;txtSearch&quot; class=&quot;search-btn dropdown-item active&quot;&gt;Text&lt;/button&gt;\n",
       "                &lt;button id=&quot;smartsSearch&quot; class=&quot;search-btn dropdown-item&quot;&gt;SMARTS&lt;/button&gt;\n",
       "              &lt;/div&gt;\n",
       "            &lt;/div&gt;\n",
       "          &lt;/div&gt;\n",
       "        &lt;/div&gt;\n",
       "      &lt;/div&gt;\n",
       "    &lt;/div&gt;\n",
       "    &lt;script&gt;\n",
       "    // list.js\n",
       "var listObj = new List(&#x27;mols2grid&#x27;, {\n",
       "    valueNames: [{data: [&#x27;mols2grid-id&#x27;]}, &#x27;data-img&#x27;, &#x27;data-mols2grid-id&#x27;, &#x27;data-SMILES&#x27;, &#x27;data-mols2grid-id-copy&#x27;],\n",
       "    item: &#x27;&lt;div class=&quot;cell&quot; data-mols2grid-id=&quot;0&quot;&gt;&lt;input type=&quot;checkbox&quot; class=&quot;position-relative float-left cached_checkbox&quot;&gt;&lt;div class=&quot;data data-img&quot;&gt;&lt;/div&gt;&lt;div class=&quot;data data-mols2grid-id-copy&quot;&gt;&lt;/div&gt;&lt;div class=&quot;data data-SMILES&quot;&gt;&lt;/div&gt;&lt;/div&gt;&#x27;,\n",
       "    page: 15,\n",
       "    pagination: {\n",
       "        name: &quot;pagination&quot;,\n",
       "        item: &#x27;&lt;li class=&quot;page-item&quot;&gt;&lt;a class=&quot;page page-link&quot; href=&quot;#&quot; onclick=&quot;event.preventDefault()&quot;&gt;&lt;/a&gt;&lt;/li&gt;&#x27;,\n",
       "        innerWindow: 1,\n",
       "        outerWindow: 1,\n",
       "    },\n",
       "});\n",
       "listObj.remove(&quot;mols2grid-id&quot;, &quot;0&quot;);\n",
       "listObj.add([{&quot;data-img&quot;: null, &quot;mols2grid-id&quot;: 0, &quot;data-SMILES&quot;: &quot;CN(C)c1ccncc1.Cc1ccccn1.[Cu]&quot;, &quot;data-mols2grid-id-copy&quot;: 0}, {&quot;data-img&quot;: null, &quot;mols2grid-id&quot;: 1, &quot;data-SMILES&quot;: &quot;C&quot;, &quot;data-mols2grid-id-copy&quot;: 1}, {&quot;data-img&quot;: null, &quot;mols2grid-id&quot;: 2, &quot;data-SMILES&quot;: &quot;C=O.Fc1ccccn1.[Pd]&quot;, &quot;data-mols2grid-id-copy&quot;: 2}, {&quot;data-img&quot;: null, &quot;mols2grid-id&quot;: 3, &quot;data-SMILES&quot;: &quot;CC(C)(C)P(C(C)(C)C)C(C)(C)C.CP(C(C)(C)C)C(C)(C)C.[Pd]&quot;, &quot;data-mols2grid-id-copy&quot;: 3}, {&quot;data-img&quot;: null, &quot;mols2grid-id&quot;: 4, &quot;data-SMILES&quot;: &quot;CCN1[C]N(CC)C=C1.Clc1ccncc1.[Cu]&quot;, &quot;data-mols2grid-id-copy&quot;: 4}, {&quot;data-img&quot;: null, &quot;mols2grid-id&quot;: 5, &quot;data-SMILES&quot;: &quot;CC(C)N1CC2(C)CN(C(C)C)P1N(C(C)C)C2.ClP(Cl)Cl.[Pd]&quot;, &quot;data-mols2grid-id-copy&quot;: 5}, {&quot;data-img&quot;: null, &quot;mols2grid-id&quot;: 6, &quot;data-SMILES&quot;: &quot;Cc1cc(C)c(N2[C]N(c3c(C)cc(C)cc3C)C=C2)c(C)c1.Cc1ccccc1P(c1ccccc1)c1ccccc1.[Pd]&quot;, &quot;data-mols2grid-id-copy&quot;: 6}, {&quot;data-img&quot;: null, &quot;mols2grid-id&quot;: 7, &quot;data-SMILES&quot;: &quot;CN1[C]N(c2ccccc2)C=C1.[Au].c1ccncc1&quot;, &quot;data-mols2grid-id-copy&quot;: 7}, {&quot;data-img&quot;: null, &quot;mols2grid-id&quot;: 8, &quot;data-SMILES&quot;: &quot;ClC1=C(Cl)N[C]N1.[Au].c1ccc(P(c2ccccc2)C2CCCCC2)cc1&quot;, &quot;data-mols2grid-id-copy&quot;: 8}, {&quot;data-img&quot;: null, &quot;mols2grid-id&quot;: 9, &quot;data-SMILES&quot;: &quot;Cc1ccccc1P(c1ccccc1)c1ccccc1.[Pt].c1ccc(P(c2ccccc2)c2ccccc2)cc1&quot;, &quot;data-mols2grid-id-copy&quot;: 9}, {&quot;data-img&quot;: null, &quot;mols2grid-id&quot;: 10, &quot;data-SMILES&quot;: &quot;C1CCC(P(C2CCCCC2)C2CCCCC2)CC1.CC(C)N1CC2(C)CN(C(C)C)P1N(C(C)C)C2.[Ni]&quot;, &quot;data-mols2grid-id-copy&quot;: 10}, {&quot;data-img&quot;: null, &quot;mols2grid-id&quot;: 11, &quot;data-SMILES&quot;: &quot;C=O.C=O.[Cu]&quot;, &quot;data-mols2grid-id-copy&quot;: 11}, {&quot;data-img&quot;: null, &quot;mols2grid-id&quot;: 12, &quot;data-SMILES&quot;: &quot;CC(C)N1[C]N(C(C)CN)C=C1.Cc1cc(C)c(N2[C]N(c3c(C)cc(C)cc3C)C=C2)c(C)c1.[Au]&quot;, &quot;data-mols2grid-id-copy&quot;: 12}, {&quot;data-img&quot;: null, &quot;mols2grid-id&quot;: 13, &quot;data-SMILES&quot;: &quot;CC1=C(C)N(C)[C]N1C.[Cu].c1ccc(P(c2ccccc2)c2ccccc2)cc1&quot;, &quot;data-mols2grid-id-copy&quot;: 13}, {&quot;data-img&quot;: null, &quot;mols2grid-id&quot;: 14, &quot;data-SMILES&quot;: &quot;C=O.CCOP(OCC)OCC.[Pd]&quot;, &quot;data-mols2grid-id-copy&quot;: 14}]);\n",
       "// filter\n",
       "if (window.parent.mols2grid_lists === undefined) {\n",
       "    window.parent.mols2grid_lists = {};\n",
       "}\n",
       "window.parent.mols2grid_lists[&quot;default&quot;] = listObj;\n",
       "\n",
       "\n",
       "// selection\n",
       "class MolStorage extends Map {\n",
       "    multi_set(_id, _smiles) {\n",
       "        for (let i=0; i &lt; _id.length; i++) {\n",
       "            this.set(_id[i], _smiles[i]);\n",
       "        }\n",
       "    }\n",
       "    multi_del(_id) {\n",
       "        for (let i=0; i &lt; _id.length; i++) {\n",
       "            this.delete(_id[i]);\n",
       "        };\n",
       "    }\n",
       "    to_dict() {\n",
       "        var content = &quot;{&quot;;\n",
       "        for (let [key, value] of this) {\n",
       "            content += key + &quot;:&quot; + JSON.stringify(value) + &quot;,&quot;;\n",
       "        }\n",
       "        content = content.length &gt; 1 ? content.slice(0, -1) : content;\n",
       "        content += &quot;}&quot;;\n",
       "        return content\n",
       "    }\n",
       "    download_smi(fileName) {\n",
       "        var content = &quot;SMILES index\\n&quot;;\n",
       "        for (let [key, value] of this) {\n",
       "            content += value + &quot; &quot; + key + &quot;\\n&quot;;\n",
       "        }\n",
       "        var a = document.createElement(&quot;a&quot;);\n",
       "        var file = new Blob([content], {type: &quot;text/plain&quot;});\n",
       "        a.href = URL.createObjectURL(file);\n",
       "        a.download = fileName;\n",
       "        a.click();\n",
       "        a.remove();\n",
       "    }\n",
       "}\n",
       "var SELECTION = new MolStorage();\n",
       "\n",
       "\n",
       "\n",
       "// kernel\n",
       "var kernel_env = null;\n",
       "if (window.parent.IPython !== undefined) {\n",
       "    // Jupyter notebook\n",
       "    kernel_env = &quot;jupyter&quot;;\n",
       "    var kernel = window.parent.IPython.notebook.kernel;\n",
       "    kernel.execute(&#x27;from mols2grid.select import register as _m2g_reg&#x27;)\n",
       "    function add_selection(grid_id, _id, smiles) {\n",
       "        SELECTION.multi_set(_id, smiles);\n",
       "        kernel.execute(&quot;_m2g_reg.add_selection(&#x27;&quot;+grid_id+&quot;&#x27;, &quot;+JSON.stringify(_id)+&quot;,&quot;+JSON.stringify(smiles)+&quot;)&quot;);\n",
       "    }\n",
       "    function del_selection(grid_id, _id) {\n",
       "        SELECTION.multi_del(_id);\n",
       "        kernel.execute(&quot;_m2g_reg.del_selection(&#x27;&quot;+grid_id+&quot;&#x27;, &quot;+JSON.stringify(_id)+&quot;)&quot;);\n",
       "    }\n",
       "} else if (window.parent.google !== undefined) {\n",
       "    // Google colab\n",
       "    kernel_env = &quot;colab&quot;;\n",
       "    var kernel = window.parent.google.colab.kernel;\n",
       "    function add_selection(grid_id, _id, smiles) {\n",
       "        SELECTION.multi_set(_id, smiles);\n",
       "        (async function() {\n",
       "        const result = await kernel.invokeFunction(&#x27;_m2g_reg.add_selection&#x27;,\n",
       "                                                   [grid_id, _id, smiles], {});\n",
       "        })();\n",
       "    }\n",
       "    function del_selection(grid_id, _id) {\n",
       "        SELECTION.multi_del(_id);\n",
       "        (async function() {\n",
       "        const result = await kernel.invokeFunction(&#x27;_m2g_reg.del_selection&#x27;,\n",
       "                                                   [grid_id, _id], {});\n",
       "        })();\n",
       "    }\n",
       "} else {\n",
       "    function add_selection(grid_id, _id, smiles) {\n",
       "        SELECTION.multi_set(_id, smiles);\n",
       "    }\n",
       "    function del_selection(grid_id, _id) {\n",
       "        SELECTION.multi_del(_id);\n",
       "    }\n",
       "}\n",
       "\n",
       "\n",
       "\n",
       "\n",
       "// sort\n",
       "var sort_field = &quot;mols2grid-id&quot;;\n",
       "var sort_order = &quot;asc&quot;;\n",
       "function mols2gridSortFunction(itemA, itemB, options) {\n",
       "    var x = itemA.values()[options.valueName];\n",
       "    var y = itemB.values()[options.valueName];\n",
       "    if (typeof x === &quot;number&quot;) {\n",
       "        if (isFinite(x - y)) {\n",
       "            return x - y; \n",
       "        } else {\n",
       "            return isFinite(x) ? -1 : 1;\n",
       "        }\n",
       "    } else {\n",
       "        x = x.toLowerCase();\n",
       "        y = y.toLowerCase();\n",
       "        return (x &lt; y) ? -1: (x &gt; y) ? 1: 0;\n",
       "    }\n",
       "}\n",
       "function checkboxSort(itemA, itemB, options) {\n",
       "    if (itemA.elm !== undefined) {\n",
       "        var checkedA = itemA.elm.firstChild.checked;\n",
       "        if (itemB.elm !== undefined) {\n",
       "            var checkedB = itemB.elm.firstChild.checked;\n",
       "            if (checkedA &amp;&amp; !checkedB) {\n",
       "                return -1;\n",
       "            } else if (!checkedA &amp;&amp; checkedB) {\n",
       "                return 1;\n",
       "            } else {\n",
       "                return 0;\n",
       "            }\n",
       "        } else {\n",
       "            return -1;\n",
       "        }\n",
       "    } else if (itemB.elm !== undefined) {\n",
       "        return 1;\n",
       "    } else {\n",
       "        return 0;\n",
       "    }\n",
       "}\n",
       "$(&#x27;#mols2grid button.sort-btn&#x27;).click(function(e) {\n",
       "    var _field = $(this).attr(&quot;data-name&quot;);\n",
       "    if (_field == sort_field) {\n",
       "        $(this).removeClass(&quot;arrow-&quot; + sort_order)\n",
       "        sort_order = (sort_order === &quot;desc&quot;) ? &quot;asc&quot; : &quot;desc&quot;;\n",
       "    } else {\n",
       "        $(&#x27;#mols2grid button.sort-btn.active&#x27;).removeClass(&quot;active arrow-&quot; + sort_order);\n",
       "        sort_order = &quot;asc&quot;;\n",
       "        sort_field = _field;\n",
       "        $(this).addClass(&quot;active&quot;);\n",
       "    }\n",
       "    $(this).addClass(&quot;arrow-&quot; + sort_order)\n",
       "    if (sort_field == &quot;checkbox&quot;) {\n",
       "        listObj.sort(&quot;mols2grid-id&quot;, {order: sort_order, sortFunction: checkboxSort});\n",
       "    } else {\n",
       "        listObj.sort(_field, {order: sort_order, sortFunction: mols2gridSortFunction});\n",
       "    }\n",
       "});\n",
       "\n",
       "\n",
       "\n",
       "\n",
       "\n",
       "\n",
       "// selection modifyers and export options\n",
       "// check all\n",
       "$(&#x27;#btn-chkbox-all&#x27;).click(function (e) {\n",
       "    var current_page = parseInt($(&quot;li.page-item.active &gt; a&quot;).text());\n",
       "    var n_items = 15;\n",
       "    var last_page = parseInt($(&quot;li.page-item &gt; a&quot;).last().text());\n",
       "    var _id = [];\n",
       "    var _smiles = [];\n",
       "    for (let i = 0; i &lt; last_page; i++) {\n",
       "        listObj.show(i * n_items + 1, n_items);\n",
       "        $(&quot;input:checkbox&quot;).each(function() {\n",
       "            this.checked = true;\n",
       "            _id.push(parseInt($(this).closest(&quot;.cell&quot;).attr(&quot;data-mols2grid-id&quot;)));\n",
       "            _smiles.push($($(this).siblings(&quot;.data-SMILES&quot;)[0]).text());\n",
       "        });\n",
       "    }\n",
       "    listObj.show((current_page - 1) * n_items + 1, n_items);\n",
       "    add_selection(&quot;default&quot;, _id, _smiles);\n",
       "});\n",
       "// uncheck all\n",
       "$(&#x27;#btn-chkbox-none&#x27;).click(function (e) {\n",
       "    var current_page = parseInt($(&quot;li.page-item.active &gt; a&quot;).text());\n",
       "    var n_items = 15;\n",
       "    var last_page = parseInt($(&quot;li.page-item &gt; a&quot;).last().text());\n",
       "    var _id = [];\n",
       "    for (let i = 0; i &lt; last_page; i++) {\n",
       "        listObj.show(i * n_items + 1, n_items);\n",
       "        $(&quot;input:checkbox:checked&quot;).each(function() {\n",
       "            this.checked = false;\n",
       "            _id.push(parseInt($(this).closest(&quot;.cell&quot;).attr(&quot;data-mols2grid-id&quot;)));\n",
       "        });\n",
       "    }\n",
       "    listObj.show((current_page - 1) * n_items + 1, n_items);\n",
       "    del_selection(&quot;default&quot;, _id);\n",
       "});\n",
       "// invert\n",
       "$(&#x27;#btn-chkbox-invert&#x27;).click(function (e) {\n",
       "    var current_page = parseInt($(&quot;li.page-item.active &gt; a&quot;).text());\n",
       "    var n_items = 15;\n",
       "    var last_page = parseInt($(&quot;li.page-item &gt; a&quot;).last().text());\n",
       "    var _id_add = [];\n",
       "    var _id_del = [];\n",
       "    var _smiles = [];\n",
       "    for (let i = 0; i &lt; last_page; i++) {\n",
       "        listObj.show(i * n_items + 1, n_items);\n",
       "        $(&quot;input:checkbox&quot;).each(function() {\n",
       "            this.checked = !this.checked;\n",
       "            var _id = parseInt($(this).closest(&quot;.cell&quot;).attr(&quot;data-mols2grid-id&quot;));\n",
       "            if (this.checked) {\n",
       "                _id_add.push(_id);\n",
       "                _smiles.push($(this).siblings(&quot;.data-SMILES&quot;).first().text());\n",
       "            } else {\n",
       "                _id_del.push(_id);\n",
       "            }\n",
       "        });\n",
       "    }\n",
       "    listObj.show((current_page - 1) * n_items + 1, n_items);\n",
       "    del_selection(&quot;default&quot;, _id_del);\n",
       "    add_selection(&quot;default&quot;, _id_add, _smiles);\n",
       "});\n",
       "// copy to clipboard\n",
       "$(&quot;#btn-chkbox-copy&quot;).click(function(e) {\n",
       "    navigator.clipboard.writeText(SELECTION.to_dict());\n",
       "});\n",
       "// export smiles\n",
       "$(&quot;#btn-chkbox-dlsmi&quot;).click(function(e) {\n",
       "    SELECTION.download_smi(&quot;selection.smi&quot;);\n",
       "});\n",
       "// export CSV\n",
       "$(&quot;#btn-chkbox-dlcsv&quot;).click(function(e) {\n",
       "    var sep = &quot;\\t&quot;\n",
       "    // same order as subset + tooltip\n",
       "    var columns = Array.from(listObj.items[0].elm.querySelectorAll(&quot;div.data&quot;))\n",
       "                       .map(elm =&gt; elm.classList[1]);\n",
       "    // remove &#x27;data-&#x27;\n",
       "    var header = columns.map(name =&gt; name.slice(5));\n",
       "    // csv content\n",
       "    header = [&quot;index&quot;].concat(header).join(sep);\n",
       "    var content = header + &quot;\\n&quot;;\n",
       "    for (let [index, smiles] of SELECTION.entries()) {\n",
       "        var data = listObj.items[index].values();\n",
       "        content += index;\n",
       "        columns.forEach((key) =&gt; {\n",
       "            content += sep + data[key];\n",
       "        })\n",
       "        content += &quot;\\n&quot;;\n",
       "    }\n",
       "    var a = document.createElement(&quot;a&quot;);\n",
       "    var file = new Blob([content], {type: &quot;text/csv&quot;});\n",
       "    a.href = URL.createObjectURL(file);\n",
       "    a.download = &quot;selection.csv&quot;;\n",
       "    a.click();\n",
       "    a.remove();\n",
       "});\n",
       "// update selection on checkbox click\n",
       "listObj.on(&quot;updated&quot;, function (list) {\n",
       "    $(&quot;input:checkbox&quot;).change(function() {\n",
       "        var _id = parseInt($(this).closest(&quot;.cell&quot;).attr(&quot;data-mols2grid-id&quot;));\n",
       "        if (this.checked) {\n",
       "            var _smiles = $($(this).siblings(&quot;.data-SMILES&quot;)[0]).text();\n",
       "            add_selection(&quot;default&quot;, [_id], [_smiles]);\n",
       "        } else {\n",
       "            del_selection(&quot;default&quot;, [_id]);\n",
       "        }\n",
       "    }); \n",
       "});\n",
       "\n",
       "\n",
       "\n",
       "\n",
       "\n",
       "// generate images for the currently displayed molecules\n",
       "var draw_opts = {&quot;fixedBondLength&quot;: 200, &quot;width&quot;: 160, &quot;height&quot;: 120};\n",
       "var json_draw_opts = JSON.stringify(draw_opts);\n",
       "\n",
       "var smarts_matches = {};\n",
       "\n",
       "// Load RDKit\n",
       "window\n",
       ".initRDKitModule()\n",
       ".then(function(RDKit) {\n",
       "    console.log(&#x27;RDKit version: &#x27;, RDKit.version());\n",
       "    window.RDKit = RDKit;\n",
       "    window.RDKitModule = RDKit;\n",
       "\n",
       "    // search bar\n",
       "    function SmartsSearch(query, columns) {\n",
       "    var smiles_col = columns[0];\n",
       "    smarts_matches = {};\n",
       "    var query = $(&#x27;#mols2grid #searchbar&#x27;).val();\n",
       "    var qmol = RDKit.get_qmol(query);\n",
       "    if (qmol.is_valid()) {\n",
       "        for (var k = 0, kl = listObj.items.length; k &lt; kl; k++) {\n",
       "            var item = listObj.items[k];\n",
       "            var smiles = item.values()[smiles_col]\n",
       "            var mol = RDKit.get_mol(smiles);\n",
       "            if (mol.is_valid()) {\n",
       "                var results = JSON.parse(mol.get_substruct_match(qmol));\n",
       "                if (results.atoms) {\n",
       "                    item.found = true;\n",
       "                    \n",
       "                    smarts_matches[smiles] = results;\n",
       "                    \n",
       "                } else {\n",
       "                    item.found = false;\n",
       "                }\n",
       "            } else {\n",
       "                item.found = false;\n",
       "            }\n",
       "            mol.delete();\n",
       "        }\n",
       "    }\n",
       "    qmol.delete();\n",
       "}\n",
       "var search_type = &quot;Text&quot;;\n",
       "$(&#x27;#mols2grid .search-btn&#x27;).click(function() {\n",
       "    search_type = $(this).text();\n",
       "    $(&#x27;#mols2grid button.search-btn.active&#x27;).removeClass(&quot;active&quot;);\n",
       "    $(this).addClass(&quot;active&quot;);\n",
       "});\n",
       "$(&#x27;#mols2grid #searchbar&#x27;).on(&quot;keyup&quot;, function(e) {\n",
       "    var query = e.target.value;\n",
       "    if (search_type === &quot;Text&quot;) {\n",
       "        smarts_matches = {};\n",
       "        listObj.search(query, [&#x27;data-mols2grid-id&#x27;, &#x27;data-SMILES&#x27;]);\n",
       "    } else {\n",
       "        listObj.search(query, [&quot;data-SMILES&quot;], SmartsSearch);\n",
       "    }\n",
       "});\n",
       "\n",
       "    \n",
       "    // generate images for the currently displayed molecules\n",
       "RDKit.prefer_coordgen(true);\n",
       "function draw_mol(smiles) {\n",
       "    var mol = RDKit.get_mol(smiles, &#x27;{&quot;removeHs&quot;: false }&#x27;);\n",
       "    var svg = &quot;&quot;;\n",
       "    if (mol.is_valid()) {\n",
       "        var highlights = smarts_matches[smiles];\n",
       "        if (highlights) {\n",
       "            var details = Object.assign({}, draw_opts, highlights);\n",
       "            details = JSON.stringify(details);\n",
       "        } else {\n",
       "            var details = json_draw_opts;\n",
       "        }\n",
       "        svg = mol.get_svg_with_highlights(details);\n",
       "    }\n",
       "    mol.delete();\n",
       "    if (svg == &quot;&quot;) {\n",
       "        return &#x27;&lt;svg width=&quot;160&quot; height=&quot;120&quot; xmlns=&quot;http://www.w3.org/2000/svg&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 160 120&quot;&gt;&lt;/svg&gt;&#x27;;\n",
       "    }\n",
       "    return svg;\n",
       "}\n",
       "listObj.on(&quot;updated&quot;, function (list) {\n",
       "    var query = $(&#x27;#mols2grid #searchbar&#x27;).val();\n",
       "    if (query === &quot;&quot;) {\n",
       "        smarts_matches = {};\n",
       "    }\n",
       "    $(&#x27;#mols2grid .cell&#x27;).each(function() {\n",
       "        var $t = $(this);\n",
       "        var smiles = $t.children(&quot;.data-SMILES&quot;).first().text()\n",
       "        var svg = draw_mol(smiles);\n",
       "        $t.children(&quot;.data-img&quot;).html(svg);\n",
       "    });\n",
       "});\n",
       "    \n",
       "\n",
       "    // trigger update to activate tooltips, draw images, setup callbacks...\n",
       "    listObj.update();\n",
       "    // resize iframe to fit content\n",
       "    if (window.frameElement) {\n",
       "        window.parent.fit_height(window.frameElement);\n",
       "    }\n",
       "});\n",
       "    &lt;/script&gt;\n",
       "  &lt;/body&gt;\n",
       "&lt;/html&gt;\">\n",
       "</iframe>"
      ],
      "text/plain": [
       "<IPython.core.display.HTML object>"
      ]
     },
     "execution_count": 24,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "mols2grid.display([Chem.MolFromSmiles(molecule) for molecule in molecules], fixedBondLength=200)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "noble-classroom",
   "metadata": {},
   "source": [
    "To unpack the model and inspect its latent spaces we can simply conduct an exploration using a random point cloud"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "id": "comic-soundtrack",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "20:01:33   starting syncing\n",
      "20:01:33   syncing complete\n",
      "20:01:33   load vocab from: /Users/tte/.gt4sd/algorithms/controlled_sampling/AdvancedManufacturing/CatalystGenerator/v0/vocab_combined.csv\n",
      "20:01:34   load vocab from: /Users/tte/.gt4sd/algorithms/controlled_sampling/AdvancedManufacturing/CatalystGenerator/v0/vocab_combined.csv\n"
     ]
    }
   ],
   "source": [
    "generator = configuration.get_conditional_generator(configuration.ensure_artifacts())"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "id": "frozen-lithuania",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "20:01:34   starting syncing\n",
      "20:01:34   syncing complete\n",
      "20:01:34   load vocab from: /Users/tte/.gt4sd/algorithms/controlled_sampling/AdvancedManufacturing/CatalystGenerator/v0/vocab_combined.csv\n",
      "20:01:34   load vocab from: /Users/tte/.gt4sd/algorithms/controlled_sampling/AdvancedManufacturing/CatalystGenerator/v0/vocab_combined.csv\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "100%|█████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 256/256 [00:19<00:00, 12.87it/s]\n"
     ]
    }
   ],
   "source": [
    "# get the actual generator\n",
    "generator = configuration.get_conditional_generator(configuration.ensure_artifacts())\n",
    "# generate randomly points in the latent space\n",
    "number_of_latent_points = 256\n",
    "latent_points = torch.randn(number_of_latent_points, generator.vae.z_dimension)\n",
    "# keep points related to valid molecules\n",
    "molecules = []\n",
    "for latent_point in tqdm(latent_points):\n",
    "    molecules.append(Chem.MolFromSmiles(generator.vae.decode(latent_point)))\n",
    "valid_indexes = [index for index, molecule in enumerate(molecules) if molecule is not None]\n",
    "molecules = [molecules[index] for index in valid_indexes]\n",
    "latent_points = latent_points[valid_indexes]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "id": "legislative-grammar",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "%matplotlib inline\n",
    "scs_scorer = SCScore()\n",
    "values = [scs_scorer(molecule) for molecule in molecules]\n",
    "_ = render_latent_points(latent_points, values=values)\n",
    "_ = plt.title(\"Rendering SCS score in a 2D projection of the latent space\")"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "gt4sd",
   "language": "python",
   "name": "gt4sd"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.11"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}