Skip to content

Instantly share code, notes, and snippets.

@PatWalters
Created April 3, 2024 23:15
Show Gist options
  • Save PatWalters/4bab1d78f3c85b39f956e6717ee221f0 to your computer and use it in GitHub Desktop.
Save PatWalters/4bab1d78f3c85b39f956e6717ee221f0 to your computer and use it in GitHub Desktop.
Display the source blob
Display the rendered blob
Raw
{
"cells": [
{
"cell_type": "markdown",
"id": "fb4a727b",
"metadata": {},
"source": [
"#### Dependencies\n",
"<pre>\n",
"!pip install pandas useful_rdkit_utils rdkit mols2grid\n",
"</pre>"
]
},
{
"cell_type": "code",
"execution_count": 1,
"id": "6618b152",
"metadata": {},
"outputs": [],
"source": [
"import pandas as pd\n",
"import useful_rdkit_utils as uru\n",
"from rdkit import Chem\n",
"import mols2grid"
]
},
{
"cell_type": "markdown",
"id": "77938ea8",
"metadata": {},
"source": [
"Read a set of 487 molecules generated by REINVENT 4"
]
},
{
"cell_type": "code",
"execution_count": 2,
"id": "496068a2",
"metadata": {},
"outputs": [],
"source": [
"df = pd.read_csv(\"https://raw.githubusercontent.com/PatWalters/datafiles/main/generative/reinvent_sampling.csv\")"
]
},
{
"cell_type": "code",
"execution_count": 3,
"id": "9811c16e",
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"<div>\n",
"<style scoped>\n",
" .dataframe tbody tr th:only-of-type {\n",
" vertical-align: middle;\n",
" }\n",
"\n",
" .dataframe tbody tr th {\n",
" vertical-align: top;\n",
" }\n",
"\n",
" .dataframe thead th {\n",
" text-align: right;\n",
" }\n",
"</style>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th>SMILES</th>\n",
" <th>NLL</th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>0</th>\n",
" <td>O=C(c1cccc2ccccc12)N1CCC(N2CCCC2)CC1</td>\n",
" <td>21.627243</td>\n",
" </tr>\n",
" <tr>\n",
" <th>1</th>\n",
" <td>O=C(N=c1[nH]c2ccc(C(=O)NCCCCCNC(=O)c3ccc4c(c3)...</td>\n",
" <td>36.927090</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2</th>\n",
" <td>O=C(CCC#Cc1ccc2c(c1)N(Cc1cc(=O)c(O)cn1O)c1ccc(...</td>\n",
" <td>52.575752</td>\n",
" </tr>\n",
" <tr>\n",
" <th>3</th>\n",
" <td>COc1cc(C(=O)c2cc3ccc(OCc4cccc(F)c4)cc3oc2=O)cc...</td>\n",
" <td>23.845703</td>\n",
" </tr>\n",
" <tr>\n",
" <th>4</th>\n",
" <td>CCOC(=O)C(CSCCC(=O)NCCCOc1no[n+]([O-])c1S(=O)(...</td>\n",
" <td>42.056152</td>\n",
" </tr>\n",
" <tr>\n",
" <th>...</th>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" </tr>\n",
" <tr>\n",
" <th>483</th>\n",
" <td>COc1ccc2[nH]c3c(c2c1)C(COC(=O)NC(C)C)C1C(=O)NC...</td>\n",
" <td>52.920334</td>\n",
" </tr>\n",
" <tr>\n",
" <th>484</th>\n",
" <td>COCCN(CCOC)c1c(SC)cccc1S(=O)(=O)Nc1ccc(Oc2cccc...</td>\n",
" <td>38.612385</td>\n",
" </tr>\n",
" <tr>\n",
" <th>485</th>\n",
" <td>COc1cc(CN=c2[nH]cnc3c(C(N)=O)cc(F)cc23)cc(NC(=...</td>\n",
" <td>30.847250</td>\n",
" </tr>\n",
" <tr>\n",
" <th>486</th>\n",
" <td>O=[N+]([O-])c1ccccc1-n1nnnc1COc1ccc(C2CC(c3ccc...</td>\n",
" <td>38.157059</td>\n",
" </tr>\n",
" <tr>\n",
" <th>487</th>\n",
" <td>COc1ccc(-c2cc(Oc3ccc(F)c(Cl)c3)c3c(=N)[nH]cnc3...</td>\n",
" <td>27.198133</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"<p>488 rows × 2 columns</p>\n",
"</div>"
],
"text/plain": [
" SMILES NLL\n",
"0 O=C(c1cccc2ccccc12)N1CCC(N2CCCC2)CC1 21.627243\n",
"1 O=C(N=c1[nH]c2ccc(C(=O)NCCCCCNC(=O)c3ccc4c(c3)... 36.927090\n",
"2 O=C(CCC#Cc1ccc2c(c1)N(Cc1cc(=O)c(O)cn1O)c1ccc(... 52.575752\n",
"3 COc1cc(C(=O)c2cc3ccc(OCc4cccc(F)c4)cc3oc2=O)cc... 23.845703\n",
"4 CCOC(=O)C(CSCCC(=O)NCCCOc1no[n+]([O-])c1S(=O)(... 42.056152\n",
".. ... ...\n",
"483 COc1ccc2[nH]c3c(c2c1)C(COC(=O)NC(C)C)C1C(=O)NC... 52.920334\n",
"484 COCCN(CCOC)c1c(SC)cccc1S(=O)(=O)Nc1ccc(Oc2cccc... 38.612385\n",
"485 COc1cc(CN=c2[nH]cnc3c(C(N)=O)cc(F)cc23)cc(NC(=... 30.847250\n",
"486 O=[N+]([O-])c1ccccc1-n1nnnc1COc1ccc(C2CC(c3ccc... 38.157059\n",
"487 COc1ccc(-c2cc(Oc3ccc(F)c(Cl)c3)c3c(=N)[nH]cnc3... 27.198133\n",
"\n",
"[488 rows x 2 columns]"
]
},
"execution_count": 3,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"df"
]
},
{
"cell_type": "markdown",
"id": "20a2d3ae",
"metadata": {},
"source": [
"Instantiate a RingSystemLookup object. This extracts ring systems from a molecule and reports the number of times that ring system occurs in the ChEMBL database. "
]
},
{
"cell_type": "code",
"execution_count": 4,
"id": "84033b0c",
"metadata": {},
"outputs": [],
"source": [
"ring_system_lookup = uru.RingSystemLookup.default()"
]
},
{
"cell_type": "markdown",
"id": "19bf9b8c",
"metadata": {},
"source": [
"Find the ring systems in all the molecules. "
]
},
{
"cell_type": "code",
"execution_count": 5,
"id": "518acd1a",
"metadata": {},
"outputs": [],
"source": [
"df['ring_systems'] = df.SMILES.apply(ring_system_lookup.process_smiles)"
]
},
{
"cell_type": "markdown",
"id": "4366b74e",
"metadata": {},
"source": [
"A simple function to process the ring system output and return the frequency for the least frequently occuring ring system. "
]
},
{
"cell_type": "code",
"execution_count": 6,
"id": "cb592383",
"metadata": {},
"outputs": [],
"source": [
"def get_min_freq(ring_system_list):\n",
" freq_list = [x[1] for x in ring_system_list]\n",
" ring_min = -1\n",
" if len(freq_list):\n",
" ring_min = min(freq_list)\n",
" return ring_min "
]
},
{
"cell_type": "code",
"execution_count": 7,
"id": "ba3cd523",
"metadata": {},
"outputs": [],
"source": [
"df['min_freq'] = df.ring_systems.apply(get_min_freq)"
]
},
{
"cell_type": "code",
"execution_count": 8,
"id": "0f3334fc",
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"<div>\n",
"<style scoped>\n",
" .dataframe tbody tr th:only-of-type {\n",
" vertical-align: middle;\n",
" }\n",
"\n",
" .dataframe tbody tr th {\n",
" vertical-align: top;\n",
" }\n",
"\n",
" .dataframe thead th {\n",
" text-align: right;\n",
" }\n",
"</style>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th>SMILES</th>\n",
" <th>NLL</th>\n",
" <th>ring_systems</th>\n",
" <th>min_freq</th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>303</th>\n",
" <td>CC(=O)NC(CCCN=C(N)N)C(=O)NC(C)C(=O)NC(CC(C)C)C...</td>\n",
" <td>35.943214</td>\n",
" <td>[]</td>\n",
" <td>-1</td>\n",
" </tr>\n",
" <tr>\n",
" <th>427</th>\n",
" <td>CCCC(C)(CC)OOC(C)=O</td>\n",
" <td>26.387020</td>\n",
" <td>[]</td>\n",
" <td>-1</td>\n",
" </tr>\n",
" <tr>\n",
" <th>423</th>\n",
" <td>CN(c1ccccc1)c1nc(CCl)nc2cc3c(cc12)CC1(CCCCN1)C3</td>\n",
" <td>35.511784</td>\n",
" <td>[(c1ccccc1, 2260082), (c1ncc2cc3c(cc2n1)CC1(CC...</td>\n",
" <td>0</td>\n",
" </tr>\n",
" <tr>\n",
" <th>148</th>\n",
" <td>O=C1CC2c3ccccc3C1c1c2c(O)n(-c2ccc(F)c(F)c2)c1O</td>\n",
" <td>25.324789</td>\n",
" <td>[(O=C1CC2c3ccccc3C1c1c[nH]cc12, 0), (c1ccccc1,...</td>\n",
" <td>0</td>\n",
" </tr>\n",
" <tr>\n",
" <th>407</th>\n",
" <td>Cc1cccc(C2C(Oc3cc(C)n(C)n3)CC3C4CCCN(CC4)C32)c1</td>\n",
" <td>45.677868</td>\n",
" <td>[(c1ccccc1, 2260082), (C1CC2C3CCCN(CC3)C2C1, 0...</td>\n",
" <td>0</td>\n",
" </tr>\n",
" <tr>\n",
" <th>...</th>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" <td>...</td>\n",
" </tr>\n",
" <tr>\n",
" <th>462</th>\n",
" <td>COc1ccc(NS(=O)(=O)c2cccc(C(=O)N(C)CC(=O)Nc3cc(...</td>\n",
" <td>33.911350</td>\n",
" <td>[(c1ccccc1, 2260082), (c1ccccc1, 2260082), (c1...</td>\n",
" <td>2260082</td>\n",
" </tr>\n",
" <tr>\n",
" <th>397</th>\n",
" <td>CN(C)CC(c1ccccc1)c1cccc(CNS(=O)(=O)N(C)C)c1</td>\n",
" <td>30.529419</td>\n",
" <td>[(c1ccccc1, 2260082), (c1ccccc1, 2260082)]</td>\n",
" <td>2260082</td>\n",
" </tr>\n",
" <tr>\n",
" <th>55</th>\n",
" <td>CCOc1ccc(CCc2ccc(OC)cc2OCC(=O)O)cc1O</td>\n",
" <td>32.903862</td>\n",
" <td>[(c1ccccc1, 2260082), (c1ccccc1, 2260082)]</td>\n",
" <td>2260082</td>\n",
" </tr>\n",
" <tr>\n",
" <th>389</th>\n",
" <td>FC(F)(F)c1cc(CNCCc2ccccc2Cl)cc(C(F)(F)F)c1</td>\n",
" <td>24.897690</td>\n",
" <td>[(c1ccccc1, 2260082), (c1ccccc1, 2260082)]</td>\n",
" <td>2260082</td>\n",
" </tr>\n",
" <tr>\n",
" <th>193</th>\n",
" <td>CCCCCC=CCCCCCCCCCCCc1cc(O)ccc1O</td>\n",
" <td>23.098900</td>\n",
" <td>[(c1ccccc1, 2260082)]</td>\n",
" <td>2260082</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"<p>488 rows × 4 columns</p>\n",
"</div>"
],
"text/plain": [
" SMILES NLL \\\n",
"303 CC(=O)NC(CCCN=C(N)N)C(=O)NC(C)C(=O)NC(CC(C)C)C... 35.943214 \n",
"427 CCCC(C)(CC)OOC(C)=O 26.387020 \n",
"423 CN(c1ccccc1)c1nc(CCl)nc2cc3c(cc12)CC1(CCCCN1)C3 35.511784 \n",
"148 O=C1CC2c3ccccc3C1c1c2c(O)n(-c2ccc(F)c(F)c2)c1O 25.324789 \n",
"407 Cc1cccc(C2C(Oc3cc(C)n(C)n3)CC3C4CCCN(CC4)C32)c1 45.677868 \n",
".. ... ... \n",
"462 COc1ccc(NS(=O)(=O)c2cccc(C(=O)N(C)CC(=O)Nc3cc(... 33.911350 \n",
"397 CN(C)CC(c1ccccc1)c1cccc(CNS(=O)(=O)N(C)C)c1 30.529419 \n",
"55 CCOc1ccc(CCc2ccc(OC)cc2OCC(=O)O)cc1O 32.903862 \n",
"389 FC(F)(F)c1cc(CNCCc2ccccc2Cl)cc(C(F)(F)F)c1 24.897690 \n",
"193 CCCCCC=CCCCCCCCCCCCc1cc(O)ccc1O 23.098900 \n",
"\n",
" ring_systems min_freq \n",
"303 [] -1 \n",
"427 [] -1 \n",
"423 [(c1ccccc1, 2260082), (c1ncc2cc3c(cc2n1)CC1(CC... 0 \n",
"148 [(O=C1CC2c3ccccc3C1c1c[nH]cc12, 0), (c1ccccc1,... 0 \n",
"407 [(c1ccccc1, 2260082), (C1CC2C3CCCN(CC3)C2C1, 0... 0 \n",
".. ... ... \n",
"462 [(c1ccccc1, 2260082), (c1ccccc1, 2260082), (c1... 2260082 \n",
"397 [(c1ccccc1, 2260082), (c1ccccc1, 2260082)] 2260082 \n",
"55 [(c1ccccc1, 2260082), (c1ccccc1, 2260082)] 2260082 \n",
"389 [(c1ccccc1, 2260082), (c1ccccc1, 2260082)] 2260082 \n",
"193 [(c1ccccc1, 2260082)] 2260082 \n",
"\n",
"[488 rows x 4 columns]"
]
},
"execution_count": 8,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"df.sort_values('min_freq')"
]
},
{
"cell_type": "markdown",
"id": "2fa57105",
"metadata": {},
"source": [
"View the odd molecules. The value below the structure is the number of times a the least frequent ring system occurs in ChEMBL. "
]
},
{
"cell_type": "code",
"execution_count": 9,
"id": "95165b8c",
"metadata": {},
"outputs": [
{
"data": {
"application/vnd.jupyter.widget-view+json": {
"model_id": "d309a81781134edeaa38c11de34a020a",
"version_major": 2,
"version_minor": 0
},
"text/plain": [
"MolGridWidget()"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/html": [
"<style>\n",
" /* Some CSS to integrate with Jupyter more cleanly */\n",
" div.output_subarea {\n",
" /* Undo an unfortunate max-width parameter\n",
" that causes the output area to be too narrow\n",
" on smaller screens. */\n",
" max-width: none;\n",
"\n",
" /* Align the table with the content */\n",
" padding: 0;\n",
"\n",
" /* Let it breathe */\n",
" margin-top: 20px;\n",
" }\n",
"</style>\n",
"\n",
"<iframe class=\"mols2grid-iframe\" frameborder=\"0\" width=\"100%\"\n",
" \n",
" \n",
" allow=\"clipboard-write\"\n",
" \n",
" \n",
" sandbox=\"allow-scripts allow-same-origin allow-downloads allow-popups allow-modals\"\n",
" \n",
" srcdoc=\"\n",
"\n",
"\n",
"\n",
"&lt;html lang=&quot;en&quot;&gt;\n",
" &lt;head&gt;\n",
" &lt;meta charset=&quot;UTF-8&quot; /&gt;\n",
" &lt;meta http-equiv=&quot;X-UA-Compatible&quot; content=&quot;IE=edge&quot; /&gt;\n",
" &lt;meta name=&quot;viewport&quot; content=&quot;width=device-width, initial-scale=1.0&quot; /&gt;\n",
" &lt;title&gt;Document!&lt;/title&gt;\n",
"\n",
"\n",
"\n",
" &lt;style&gt;\n",
" /**\n",
" * General styling\n",
" */\n",
"body {\n",
" font-family: &#x27;DejaVu&#x27;, sans-serif;\n",
"}\n",
"h1,h2,h3,h4 {\n",
" margin: 0 0 10px 0;\n",
"}\n",
"h1 {\n",
" font-size: 26px;\n",
"}\n",
"h2 {\n",
" font-size: 20px;\n",
" font-weight: 400;\n",
"}\n",
"h3 {\n",
"\tfont-size: 16px;\n",
"}\n",
"p {\n",
" margin: 0 0 10px 0;\n",
"}\n",
"\n",
"\n",
"/* Remove body margin inside iframe */\n",
"body.m2g-inside-iframe {\n",
" margin: 0;\n",
"}\n",
"\n",
"/* In-cell text */\n",
"#mols2grid .data:not(.data-img) {\n",
" height: 16px;\n",
" line-height: 16px;\n",
"}\n",
"/* Text truncation */\n",
"#mols2grid .data {\n",
" /* Break text into multiple lines (default for static)... */\n",
" word-wrap: normal;\n",
"\n",
" /* ...or truncate it (default for interactive). */\n",
" overflow: hidden;\n",
" white-space: nowrap;\n",
" text-overflow: ellipsis;\n",
"}\n",
"\n",
"\n",
"/**\n",
" * Popover\n",
" * - - -\n",
" * Note: this is a bootstrap variable which is not namespaced.\n",
" * To avoid any contamination, we only style it when the\n",
" * x-placement parameter is set.\n",
" */\n",
".popover[x-placement] {\n",
" font-family: &#x27;DejaVu&#x27;, sans-serif;\n",
" background: white;\n",
" border: solid 1px rgba(0,0,0,.2);\n",
" font-size: 12px;\n",
" padding: 10px;\n",
" border-radius: 5px;\n",
" box-shadow: 0 0 20px rgba(0,0,0,.15);\n",
" user-select: none;\n",
"}\n",
".popover[x-placement] h3 {\n",
" margin: 0;\n",
"}\n",
".popover[x-placement] .arrow {\n",
" width: 10px;\n",
" height: 10px;\n",
" background: #fff;\n",
" border: solid 1px rgba(0,0,0,.2);\n",
" box-sizing: border-box;\n",
" position: absolute;\n",
" transform-origin: 5px 5px;\n",
" clip-path: polygon(0 0, 100% 0, 100% 100%);\n",
"}\n",
".popover[x-placement=&#x27;left&#x27;] .arrow {\n",
" transform: rotate(45deg);\n",
" top: 50%;\n",
" right: -5px;\n",
"}\n",
".popover[x-placement=&#x27;right&#x27;] .arrow {\n",
" transform: rotate(-135deg);\n",
" top: 50%;\n",
" left: -5px;\n",
"}\n",
".popover[x-placement=&#x27;top&#x27;] .arrow {\n",
" transform: rotate(135deg);\n",
" left: 50%;\n",
" bottom: -5px;\n",
"}\n",
".popover[x-placement=&#x27;bottom&#x27;] .arrow {\n",
" transform: rotate(-45deg);\n",
" left: 50%;\n",
" top: -5px;\n",
"}\n",
" body {\n",
" /* Colors */\n",
" --m2g-black: rgba(0,0,0,.75);\n",
" --m2g-black-soft: rgba(0,0,0,.35);\n",
" --m2g-black-10: rgba(0,0,0,.1);\n",
" --m2g-bg: #f6f6f6;\n",
" --m2g-border: solid 1px rgba(0,0,0,0.2);\n",
" --m2g-hl: #555; /* Highlight color */\n",
" --m2g-hl-shadow: inset 0 0 0 1px var(--m2g-hl); /* Inset 1px shadow to make border thicker */\n",
" --m2g-blue: #0f62fe;\n",
" --m2g-blue-soft: rgba(15,98,254,.2);\n",
"\n",
" /* Icons */\n",
" --m2g-icn-triangle: url(&#x27;data:image/svg+xml;utf8,&lt;svg width=&quot;20&quot; fill=&quot;rgba(0,0,0,.75)&quot; height=&quot;20&quot; viewBox=&quot;0 0 20 20&quot; xmlns=&quot;http://www.w3.org/2000/svg&quot;&gt;&lt;path d=&quot;M9.5713 13.285L6.2543 7.757C6.0543 7.424 6.2953 7 6.6823 7L13.3173 7C13.7053 7 13.9463 7.424 13.7453 7.757L10.4283 13.285C10.2343 13.609 9.7653 13.609 9.5713 13.285Z&quot;/&gt;&lt;/svg&gt;&#x27;);\n",
" --m2g-icn-triangle-white: url(&#x27;data:image/svg+xml;utf8,&lt;svg width=&quot;20&quot; fill=&quot;white&quot; height=&quot;20&quot; viewBox=&quot;0 0 20 20&quot; xmlns=&quot;http://www.w3.org/2000/svg&quot;&gt;&lt;path d=&quot;M9.5713 13.285L6.2543 7.757C6.0543 7.424 6.2953 7 6.6823 7L13.3173 7C13.7053 7 13.9463 7.424 13.7453 7.757L10.4283 13.285C10.2343 13.609 9.7653 13.609 9.5713 13.285Z&quot;/&gt;&lt;/svg&gt;&#x27;);\n",
" --m2g-icn-cb-white: url(&#x27;data:image/svg+xml;utf8,&lt;svg width=&quot;16&quot; height=&quot;16&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;none&quot; stroke=&quot;white&quot; stroke-width=&quot;2.5&quot; stroke-linecap=&quot;round&quot; xmlns=&quot;http://www.w3.org/2000/svg&quot;&gt;&lt;path d=&quot;M4 7.65686L7 10.6569L12.6569 5.00001&quot;/&gt;&lt;/svg&gt;&#x27;);\n",
" \n",
" /* Border radius */\n",
" --m2g-br: 3px;\n",
" --m2g-br-l: var(--m2g-br) 0 0 var(--m2g-br); /* Left-only */\n",
" --m2g-br-r: 0 var(--m2g-br) var(--m2g-br) 0; /* Right-only */\n",
"\n",
" /* Text */\n",
" --m2g-fs: 14px; /* UI font-size */\n",
" --m2g-fs-cell: 12px; /* Cell font-size */\n",
"\n",
" /* Transition speeds */\n",
" --m2g-trans: 150ms;\n",
"\n",
" /* Layout */\n",
" --m2g-h: 40px; /* Form element height */\n",
"}\n",
"\n",
"/* Styling */\n",
"#mols2grid {\n",
" font-family: &#x27;DejaVu&#x27;, sans-serif;\n",
" font-size: var(--m2g-fs);\n",
"}\n",
"\n",
"/* Fixes */\n",
"#mols2grid *,\n",
"#mols2grid *::before,\n",
"#mols2grid *::after {\n",
" box-sizing: border-box;\n",
" outline: none;\n",
"}\n",
"\n",
"\n",
"\n",
"/**\n",
" * Functions section\n",
" */\n",
"\n",
"#mols2grid .m2g-functions {\n",
" display: flex;\n",
"}\n",
"#mols2grid .m2g-functions .m2g-row {\n",
" flex: 0;\n",
" display: flex;\n",
"}\n",
"\n",
"/* Individual elements don&#x27;t scale */\n",
"#mols2grid .m2g-functions .m2g-row &gt; * {\n",
" flex: 0 0;\n",
" margin-right: 10px;\n",
"}\n",
"#mols2grid .m2g-functions .m2g-row:last-child &gt; *:last-child {\n",
" margin-right: 0;\n",
"}\n",
"\n",
"/* Row 1: pagination + gap + sort */\n",
"#mols2grid .m2g-functions .m2g-row:first-child {\n",
" flex: 1; /* Scale */\n",
"}\n",
"#mols2grid .m2g-functions .m2g-gap {\n",
" /* The gap in between will scale, so the pagination\n",
" stays on the left, while the rest moves to the right */\n",
" flex: 1;\n",
" margin-right: 0;\n",
"}\n",
"\n",
"\n",
"\n",
"/*\n",
" * Pagination\n",
" */\n",
"\n",
"#mols2grid ul.m2g-pagination {\n",
" /* Unset defaults */\n",
" list-style-type: none;\n",
" margin-block-start: 0;\n",
" margin-block-end: 0;\n",
" margin-inline-start: 0;\n",
" margin-inline-end: 0;\n",
" padding-inline-start: 0;\n",
"\n",
" /* Custom */\n",
" display: flex;\n",
"}\n",
"#mols2grid ul.m2g-pagination li {\n",
" background: var(--m2g-bg) ;\n",
" border: var(--m2g-border);\n",
" height: var(--m2g-h);\n",
" min-width: calc(var(--m2g-h) + 1px);\n",
" position: relative;\n",
" user-select: none;\n",
" \n",
" /* Compensate for double border */\n",
" margin-right: -1px;\n",
" \n",
" /* Center text */\n",
" display: flex;\n",
" align-items: center;\n",
" justify-content: center;\n",
"}\n",
"#mols2grid ul.m2g-pagination li:last-child {\n",
" min-width: var(--m2g-h);\n",
"}\n",
"#mols2grid ul.m2g-pagination li a {\n",
" text-decoration: none;\n",
" color: var(--m2g-black);\n",
" padding: 0 10px;\n",
" width: 100%;\n",
" height: var(--m2g-h);\n",
" line-height: var(--m2g-h);\n",
" text-align: center;\n",
" /* Compensate for border so there&#x27;s no gap between click areas */\n",
" margin: 0 -1px;\n",
"}\n",
"\n",
"/* Corner shape */\n",
"#mols2grid ul.m2g-pagination li:first-child {\n",
" border-radius: var(--m2g-br-l);\n",
"}\n",
"#mols2grid ul.m2g-pagination li:last-child {\n",
" border-radius: var(--m2g-br-r);\n",
" margin-right: 0;\n",
"}\n",
"\n",
"/* Focus state */\n",
"#mols2grid ul.m2g-pagination li:focus-within {\n",
" border-color: var(--m2g-hl);\n",
" box-shadow: var(--m2g-hl-shadow);\n",
" z-index: 1;\n",
"}\n",
"\n",
"/* Active state */\n",
"#mols2grid ul.m2g-pagination li.active {\n",
" background: var(--m2g-hl);\n",
" z-index: 1;\n",
"}\n",
"#mols2grid ul.m2g-pagination li.active a {\n",
" cursor: default;\n",
" color: #fff;\n",
"}\n",
"\n",
"/* Disabled sate */\n",
"#mols2grid ul.m2g-pagination li.disabled a {\n",
" cursor: default;\n",
" color: rgba(0,0,0,.25);\n",
" pointer-events: none;\n",
"}\n",
"\n",
"\n",
"\n",
"/*\n",
" * Dropdowns\n",
" */\n",
"\n",
"#mols2grid ::placeholder {\n",
" color: var(--m2g-black-soft);\n",
"}\n",
"#mols2grid .m2g-dropdown {\n",
" height: var(--m2g-h);\n",
" background: var(--m2g-bg);\n",
" border: var(--m2g-border);\n",
" border-radius: var(--m2g-br);\n",
" position: relative;\n",
"}\n",
"#mols2grid .m2g-dropdown select {\n",
" -webkit-appearance: none;\n",
" -moz-appearance: none;\n",
" -ms-appearance: none;\n",
" appearance: none;\n",
" background: transparent;\n",
" border: none;\n",
" height: 100%;\n",
" padding: 0 13px;\n",
" min-width: 0;\n",
" max-width: 250px;\n",
" color: var(--m2g-black);\n",
" cursor: pointer;\n",
"}\n",
"\n",
"/* Icon */\n",
"#mols2grid .m2g-dropdown .m2g-icon {\n",
" width: 30px;\n",
" height: var(--m2g-h);\n",
" display: flex;\n",
" align-items: center;\n",
" justify-content: center;\n",
" position: absolute;\n",
" top: 0;\n",
" right: 0;\n",
" pointer-events: none;\n",
"}\n",
"#mols2grid .m2g-dropdown .m2g-icon svg:not(.m2g-stroke) {\n",
" fill: var(--m2g-black);\n",
"}\n",
"#mols2grid .m2g-dropdown .m2g-icon svg.m2g-stroke {\n",
" stroke: var(--m2g-black);\n",
"}\n",
"\n",
"/* Display */\n",
"/* We hide the native select element because\n",
" * it is limited in styling. Instead, we display\n",
" * the selected value in a div. */\n",
"#mols2grid .m2g-dropdown .m2g-display {\n",
" position: absolute;\n",
" left: 0;\n",
" right: 0;\n",
" top: 0;\n",
" bottom: 0;\n",
" pointer-events: none;\n",
" color: var(--m2g-black);\n",
" line-height: var(--m2g-h);\n",
" padding: 0 25px 0 13px;\n",
"\n",
" /* Truncate dropdown text */\n",
" white-space: nowrap;\n",
"\ttext-overflow: ellipsis;\n",
"\toverflow: hidden;\n",
"}\n",
"\n",
"/* Focus state */\n",
"#mols2grid .m2g-dropdown:focus-within {\n",
" border-color: var(--m2g-hl);\n",
" box-shadow: var(--m2g-hl-shadow);\n",
"}\n",
"\n",
"\n",
"\n",
"/**\n",
" * Action dropdown\n",
" */\n",
"\n",
"#mols2grid .m2g-dropdown.m2g-actions {\n",
" width: var(--m2g-h);\n",
" padding: 0;\n",
"}\n",
"#mols2grid .m2g-dropdown.m2g-actions select {\n",
" opacity: 0;\n",
" width: var(--m2g-h);\n",
"}\n",
"#mols2grid .m2g-dropdown.m2g-actions .m2g-icon {\n",
" width: var(--m2g-h);\n",
"}\n",
"\n",
"\n",
"\n",
"/*\n",
" * Sort dropdown\n",
" */\n",
"\n",
"#mols2grid .m2g-dropdown.m2g-sort {\n",
" flex: 0 0 200px;\n",
" width: 200px; /* Needed in addition to flex-basis for small sizes! */\n",
" border-radius: var(--m2g-br);\n",
" background: var(--m2g-bg);\n",
" display: flex;\n",
"}\n",
"\n",
"/* Dropdown */\n",
"#mols2grid .m2g-dropdown.m2g-sort select {\n",
" flex: 1 1;\n",
" opacity: 0;\n",
" /* padding-right: 70px; Space for &quot;Sort:&quot; */\n",
" box-sizing: border-box;\n",
"}\n",
"\n",
"/* Sort order */\n",
"#mols2grid .m2g-dropdown.m2g-sort .m2g-order {\n",
" background: var(--m2g-bg) var(--m2g-icn-triangle) no-repeat center;\n",
" flex: 0 0 30px;\n",
" height: 100%;\n",
" border-left: var(--m2g-border);\n",
" cursor: pointer;\n",
"}\n",
"#mols2grid .m2g-dropdown.m2g-sort.m2d-arrow-desc .m2g-order {\n",
" transform: rotate(180deg);\n",
" border-left: none;\n",
" border-right: var(--m2g-border);\n",
"}\n",
"\n",
"/* Display */\n",
"#mols2grid .m2g-dropdown.m2g-sort .m2g-display {\n",
" right: 31px;\n",
" padding-right: 13px;\n",
"}\n",
"#mols2grid .m2g-dropdown.m2g-sort .m2g-display::before {\n",
" content: &#x27;Sort: &#x27;;\n",
"}\n",
"\n",
"/* Focus state */\n",
"#mols2grid .m2g-dropdown.m2g-sort:focus-within .m2g-display,\n",
"#mols2grid .m2g-dropdown.m2g-sort:focus-within .m2g-order {\n",
" background-color: transparent;\n",
"}\n",
"\n",
"\n",
"\n",
"/*\n",
" * Search bar\n",
" */\n",
"\n",
"#mols2grid .m2g-search-wrap {\n",
" height: var(--m2g-h);\n",
" display: flex;\n",
" align-items: center;\n",
" justify-content: flex-end;\n",
" background: var(--m2g-bg);\n",
" border: var(--m2g-border);\n",
" border-radius: var(--m2g-br);\n",
"}\n",
"#mols2grid .m2g-searchbar {\n",
" width: 170px;\n",
" height: var(--m2g-h);\n",
" padding: 0 13px;\n",
" border: none;\n",
" color: var(--m2g-black);\n",
" cursor: text;\n",
" background: transparent;\n",
"}\n",
"\n",
"/* Focus state */\n",
"#mols2grid .m2g-search-wrap:focus-within {\n",
" border-color: var(--m2g-hl);\n",
" box-shadow: var(--m2g-hl-shadow);\n",
"}\n",
"\n",
"/* Option buttons */\n",
"#mols2grid .m2g-search-options {\n",
" font-size: 12px;\n",
" display: flex;\n",
" height: calc(1.5em + .75rem);\n",
" line-height: calc(1.5em + .75rem);\n",
" margin-right: 5px;\n",
" border-radius: var(--m2g-br);\n",
" color: var(--m2g-black);\n",
"}\n",
"#mols2grid .m2g-search-options .m2g-option {\n",
" background: var(--m2g-black-10);\n",
" padding: 0 13px;\n",
" cursor: default;\n",
" user-select: none;\n",
"}\n",
"#mols2grid .m2g-search-options .m2g-option:not(.sel) {\n",
" cursor: pointer;\n",
"}\n",
"#mols2grid .m2g-search-options .m2g-option:first-child {\n",
" border-radius: 2px 0 0 2px;\n",
"}\n",
"#mols2grid .m2g-search-options .m2g-option:last-child {\n",
" border-radius: 0 2px 2px 0;\n",
"}\n",
"#mols2grid .m2g-search-options .m2g-option.sel {\n",
" background: var(--m2g-hl);\n",
" color: #fff;\n",
"}\n",
"\n",
"\n",
"\n",
"/**\n",
" * Grid\n",
" */\n",
"\n",
"/* Container */\n",
"#mols2grid .m2g-list {\n",
" display: flex;\n",
" flex-wrap: wrap;\n",
" align-items: flex-start;\n",
" justify-content: flex-start;\n",
" padding: 1px; /* Compensate for negative padding on cell */\n",
" user-select: none;\n",
" margin: 0px;\n",
" margin-top: 20px;\n",
" font-family: &#x27;DejaVu&#x27;, sans-serif;\n",
" \n",
"}\n",
"\n",
"/* Cell */\n",
"#mols2grid .m2g-cell {\n",
" border: 1px solid #cccccc;\n",
" text-align: center;\n",
" vertical-align: top;\n",
" font-family: var(--font-family);\n",
" padding: 10px;\n",
" padding-top: max(10px, 20px);\n",
" margin: -1px -1px 0 0;\n",
" flex: 1 0 130px;\n",
" position: relative;\n",
" font-size: var(--m2g-fs-cell);\n",
" cursor: pointer;\n",
" color: var(--m2g-black);\n",
" overflow: hidden;\n",
" box-sizing: border-box;\n",
" background-color: white;\n",
"}\n",
"#mols2grid .m2g-cell:focus {\n",
" z-index: 1;\n",
" border-color: var(--m2g-hl);\n",
" box-shadow: var(--m2g-hl-shadow);\n",
"}\n",
"\n",
"/* Phantom cells to maintain grid structure with less results */\n",
"#mols2grid .m2g-cell.m2g-phantom {\n",
" border: none;\n",
" pointer-events: none;\n",
" height: 0;\n",
" padding: 0;\n",
"}\n",
"\n",
"/* Checkbox &amp; ID */\n",
"#mols2grid .m2g-cb-wrap {\n",
" position: absolute;\n",
" top: 3px;\n",
" left: 3px;\n",
" display: flex;\n",
" border-radius: 2px;\n",
" font-size: 0;\n",
" line-height: 0;\n",
" padding: 3px;\n",
" padding-right: 0;\n",
"}\n",
"#mols2grid .m2g-cb-wrap input[type=checkbox] {\n",
" display: none;\n",
"}\n",
"#mols2grid .m2g-cb-wrap input[type=checkbox] + .m2g-cb {\n",
"\twidth: 16px;\n",
"\theight: 16px;\n",
"\tbox-sizing: border-box;\n",
"\tbackground: #fff;\n",
"\tborder: var(--m2g-border);\n",
"\tborder-radius: 2px;\n",
" margin-right: 5px;\n",
"}\n",
"#mols2grid .m2g-cb-wrap input[type=checkbox]:checked + .m2g-cb {\n",
" border: none;\n",
" background-color: var(--m2g-blue);\n",
" background-image: var(--m2g-icn-cb-white);\n",
"}\n",
"#mols2grid .m2g-tooltip {\n",
" /* This is a div spanning full cell size where the\n",
" tooltip is rendered around, because you can&#x27;t attach\n",
" it to the parent due to list.js limitation. */\n",
" width: 100%;\n",
" height: 100%;\n",
" position: absolute;\n",
" left: 0;\n",
" top: 0;\n",
" z-index: -1;\n",
" pointer-events: none;\n",
" opacity: 0;\n",
"}\n",
"#mols2grid .m2g-cell:has(:checked) {\n",
" background: #ffd !important; /* Overrides user-set background color */\n",
"}\n",
"#mols2grid .data-mols2grid-id-display {\n",
" font-size: var(--m2g-fs-cell);\n",
" line-height: 16px;\n",
"}\n",
"#mols2grid .m2g-cb-wrap input[type=checkbox] + .data-mols2grid-id-display {\n",
" padding: 0 5px 0 5px;\n",
"}\n",
"#mols2grid .m2g-cb-wrap .data-name-display {\n",
" font-size: var(--m2g-fs);\n",
" line-height: 16px;\n",
"}\n",
"\n",
"/* Info + callback button wrap (28px high) */\n",
"#mols2grid .m2g-cell-actions {\n",
" position: absolute;\n",
" top: 0;\n",
" right: 0;\n",
" display: flex;\n",
" flex-direction: row;\n",
" font-size: 0;\n",
" line-height: 0;\n",
" \n",
" /* background: yellow; */\n",
"}\n",
"\n",
"/* Info button */\n",
"#mols2grid .m2g-info {\n",
" width: 28px;\n",
" height: 28px;\n",
" border-radius: 2px;\n",
" line-height: 28px;\n",
" font-size: min(14px, 12px);\n",
" font-family: Georgia, serif;\n",
" font-style: italic;\n",
" padding: 0;\n",
" text-align: center;\n",
"}\n",
"#mols2grid .m2g-keep-tooltip .m2g-info {\n",
" color: #fff;\n",
"}\n",
"#mols2grid .m2g-keep-tooltip .m2g-info::before {\n",
" content: &#x27;i&#x27;;\n",
" width: 18px;\n",
" height: 18px;\n",
" line-height: 18px;\n",
" background: var(--m2g-hl);\n",
" position: absolute;\n",
" left: 5px;\n",
" top: 5px;\n",
" border-radius: 9px;\n",
"}\n",
"\n",
"/* Callback button */\n",
"#mols2grid .m2g-callback {\n",
" width: 28px;\n",
" height: 28px;\n",
" cursor: pointer;\n",
"}\n",
"#mols2grid .m2g-callback::after {\n",
" content: &#x27;&#x27;;\n",
" display: block;\n",
" width: 16px;\n",
" height: 16px;\n",
" margin: 6px;\n",
" border: var(--m2g-border);\n",
" border-radius: 2px;\n",
" background: var(--m2g-bg) var(--m2g-icn-triangle) no-repeat center;\n",
" transform: rotate(-90deg);\n",
"}\n",
"\n",
"/* Image */\n",
"#mols2grid .m2g-cell .data-img {\n",
" padding: 0;\n",
"}\n",
"#mols2grid .m2g-cell img,\n",
"#mols2grid .m2g-cell svg {\n",
" max-width: 100%;\n",
" height: auto;\n",
" padding: 0;\n",
"}\n",
"#mols2grid .m2g-cell svg &gt; rect:first-child {\n",
" /* Remove the SVG background */\n",
" fill: transparent !important;\n",
"}\n",
"\n",
"/* Text below image */\n",
".m2g-copy-blink {\n",
" animation: m2g-blink var(--m2g-trans) 3;\n",
"}\n",
"@keyframes m2g-blink {\n",
" 0% {\n",
" opacity: 1;\n",
" }\n",
" 49% {\n",
" opacity: 1;\n",
" }\n",
" 50% {\n",
" opacity: 0;\n",
" }\n",
" 100% {\n",
" opacity: 0;\n",
" }\n",
"}\n",
"\n",
"/* Copyable text */\n",
".copy-me {\n",
" position: relative;\n",
" cursor: pointer;\n",
"}\n",
"\n",
"\n",
"\n",
"/**\n",
" * Modal popup\n",
" * - - -\n",
" * Triggered by make_popup_callback()\n",
" * See https://mols2grid.readthedocs.io/en/latest/notebooks/callbacks.html#Display-a-popup-containing-descriptors\n",
" */\n",
"\n",
"/* Container */\n",
"#m2g-modal-container {\n",
" display: flex;\n",
" align-items: center;\n",
" justify-content: center;\n",
" background: var(--m2g-black-10);\n",
" position: fixed;\n",
" top: 0;\n",
" left: 0;\n",
" z-index: 1;\n",
" width: 100%;\n",
" height: 100%;\n",
" \n",
" /* Transition */\n",
" opacity: 0;\n",
" transition: opacity var(--m2g-trans) linear;\n",
"}\n",
"\n",
"/* Modal */\n",
"#m2g-modal {\n",
" background: #fff;\n",
" border-radius: var(--m2g-br);\n",
" box-shadow: 0 0 30px var(--m2g-black-10);\n",
" padding: 20px;\n",
" position: relative;\n",
" max-width: calc(100% - 80px);\n",
" max-height: calc(100% - 80px);\n",
" display: flex;\n",
" flex-direction: column;\n",
" min-width: 26px;\n",
"\n",
" /* Transition */\n",
" opacity: 0;\n",
" transform: translate(0, 5px);\n",
" transition: transform var(--m2g-trans) ease-in-out, opacity var(--m2g-trans) linear;\n",
"}\n",
"#m2g-modal .m2g-modal-header {\n",
" flex: 0 0 26px;\n",
" margin-bottom: 10px;\n",
"}\n",
"#m2g-modal .m2g-modal-header h2 {\n",
" margin-bottom: 0;\n",
"}\n",
"#m2g-modal .m2g-modal-header h2 + p {\n",
" font-size: 15px;\n",
"}\n",
"#m2g-modal .m2g-modal-body {\n",
" flex: 1;\n",
" position: relative;\n",
"}\n",
"\n",
"/* Transition */\n",
"#m2g-modal-container.show {\n",
" opacity: 1;\n",
"}\n",
"#m2g-modal-container.show #m2g-modal {\n",
" opacity: 1;\n",
" transform: translate(0, 0);\n",
"}\n",
"\n",
"/* Header + close btn */\n",
"#m2g-modal h2 {\n",
" line-height: 26px;\n",
" padding-right: 40px;\n",
" text-transform: capitalize;\n",
"}\n",
"#m2g-modal h3 {\n",
" \n",
"}\n",
"#m2g-modal button.close {\n",
" background: transparent;\n",
" padding: 0;\n",
" color: var(--m2g-black);\n",
" font-size: 1.5rem;\n",
" width: 40px;\n",
" height: 40px;\n",
" position: absolute;\n",
" top: 13px;\n",
" right: 13px;\n",
" border: none;\n",
"}\n",
"\n",
"/* Image */\n",
"#m2g-modal .svg-wrap svg {\n",
" max-width: 100%;\n",
" margin-bottom: 20px;\n",
"}\n",
"\n",
"/* Separator */\n",
"hr {\n",
" width: 100%;\n",
" height: 1px;\n",
" background: #ddd;\n",
" margin: 15px 0;\n",
" border: none;\n",
"}\n",
"\n",
"\n",
"\n",
"/**\n",
" * Hover states\n",
" */\n",
"@media (hover:hover) {\n",
" /* Pagination */\n",
" #mols2grid ul.m2g-pagination li:not(.active):not(.disabled):hover {\n",
" background: #f0f0f0;\n",
" z-index: 1;\n",
" }\n",
" #mols2grid ul.m2g-pagination li.active + li:hover {\n",
" /* Keeping the hover border consiistent */\n",
" margin-left: 1px;\n",
" border-left: none;\n",
" min-width: 40px;\n",
" }\n",
"\n",
" /* Dropdowns &amp; search */\n",
" #mols2grid .m2g-dropdown:not(:focus-within):hover,\n",
" #mols2grid .m2g-search-wrap:not(:focus-within):hover,\n",
" #mols2grid .m2g-sort:not(:focus-within) .m2g-order:hover {\n",
" background-color: #f0f0f0;\n",
" }\n",
" #mols2grid .m2g-search-wrap:not(:focus-within):hover {\n",
" background: #fff;\n",
" border-color: rgba(0,0,0,.3);\n",
" }\n",
" /* Hocus pocus to have separate hover states for dropdown and arrow */\n",
" #mols2grid .m2g-dropdown.m2g-sort:not(:focus-within):hover .m2g-order:not(:hover) + .m2g-display {\n",
" background-color: transparent;\n",
" }\n",
"\n",
" /* Search options */\n",
" #mols2grid .m2g-search-options .m2g-option:not(.sel):hover {\n",
" background: rgba(0,0,0,.15);\n",
" }\n",
"\n",
" /* Grid */\n",
" /* Note: this is in an ::after pseudo element, so the transparent\n",
" hover color plays nice with the cell background color. */\n",
" #mols2grid .m2g-cell:hover::after {\n",
" content: &#x27;&#x27;;\n",
" width: 100%;\n",
" height: 100%;\n",
" position: absolute;\n",
" top: 0;\n",
" left: 0;\n",
" background-color: rgba(0,0,0,0.05);\n",
" pointer-events: none;\n",
" }\n",
"\n",
" /* info button */\n",
" #mols2grid .m2g-info:hover::before {\n",
" content: &#x27;i&#x27;;\n",
" color: #fff;\n",
" width: 18px;\n",
" height: 18px;\n",
" line-height: 18px;\n",
" background: var(--m2g-hl);\n",
" position: absolute;\n",
" left: 5px;\n",
" top: 5px;\n",
" border-radius: 9px;\n",
" }\n",
" \n",
" /* Callback button */\n",
" #mols2grid .m2g-callback:hover::after {\n",
" background-color: var(--m2g-black);\n",
" background-image: var(--m2g-icn-triangle-white);\n",
" border-color: transparent;\n",
" }\n",
"\n",
" /* Copyable text */\n",
" .copy-me:hover {\n",
" text-decoration: underline;\n",
" text-decoration-color: var(--m2g-blue);\n",
" }\n",
"}\n",
"\n",
"\n",
"\n",
"/**\n",
" * Responsive behavior.\n",
" * - - -\n",
" * Note: container queries won&#x27;t work in older browsers,\n",
" * but this is purely aesthetical behavior so that&#x27;s ok.\n",
" * https://caniuse.com/css-container-queries\n",
" */\n",
"\n",
"/* This sets the msg-list div as reference container */\n",
"#mols2grid {\n",
" container-type: inline-size;\n",
"}\n",
"\n",
"\n",
"\n",
"/**\n",
" * Functions section\n",
" */\n",
"\n",
"/* When there&#x27;s not enough space to put everything in one row, we break it into two.\n",
" * - - -\n",
" * 870px = pagination 280 + sort 200 + search 300 + menu 40 + (3*10 gap) = 850 + 20 buffer.\n",
" * Buffer required because the button width inside the search depends on the font.\n",
" */\n",
"@container (max-width: 870px) {\n",
" #mols2grid .m2g-functions {\n",
" flex-direction: column-reverse;\n",
" gap: 10px;\n",
" }\n",
" #mols2grid .m2g-functions .m2g-row:last-child {\n",
" justify-content: flex-end;\n",
" }\n",
" #mols2grid .m2g-functions .m2g-row:first-child *:last-child {\n",
" margin-right: 0;\n",
" }\n",
"}\n",
"\n",
"/* When there&#x27;s not enough room for pagination + sort on one row,\n",
" * we reduce the sort drodpwon width.\n",
" */\n",
"@container (max-width: 500px) {\n",
" #mols2grid .m2g-functions .m2g-sort {\n",
" width: 80px;\n",
" flex-basis: 80px;\n",
" }\n",
" #mols2grid .m2g-functions .m2g-sort .m2g-display {\n",
" font-size: 0;\n",
" line-height: 0;\n",
" padding-right: 0;\n",
" }\n",
" #mols2grid .m2g-functions .m2g-sort .m2g-display::before {\n",
" content: &#x27;Sort&#x27;;\n",
" font-size: var(--m2g-fs);\n",
" line-height: var(--m2g-h);\n",
" }\n",
"}\n",
"\n",
"/* When there&#x27;s not enough room for pagination + reduced sort on one row,\n",
" * we reduce the pagination width.\n",
" */\n",
"@container (max-width: 500px) {\n",
" /* We&#x27;re overriding min-width from different\n",
" locations, including responsive rules */\n",
" #mols2grid ul.m2g-pagination li,\n",
" #mols2grid ul.m2g-pagination li:last-child,\n",
" #mols2grid ul.m2g-pagination li.active + li:hover {\n",
" min-width: 0;\n",
" }\n",
"}\n",
"\n",
"/* When there&#x27;s not enough room for searchbar + menu\n",
" * we scale down the searchbar to fit the container.\n",
" */\n",
"@container (max-width: 370px) {\n",
" #mols2grid .m2g-functions .m2g-row .m2g-search-wrap {\n",
" flex: 1;\n",
" }\n",
" #mols2grid .m2g-searchbar {\n",
" width: calc(100% - 50px);\n",
" }\n",
" #mols2grid .m2g-search-options {\n",
" width: 50px;\n",
" }\n",
"\n",
" /* Collapse options in T/M buttons */\n",
" #mols2grid .m2g-search-options .m2g-option {\n",
" width: 25px;\n",
" text-align: center;\n",
" padding: 0;\n",
" overflow: hidden;\n",
" }\n",
" #mols2grid .m2g-search-options .m2g-option:first-child::before {\n",
" content: &#x27;T\\A&#x27;\n",
" }\n",
" #mols2grid .m2g-search-options .m2g-option:last-child::before {\n",
" content: &#x27;S\\A&#x27;\n",
" }\n",
"}\n",
"\n",
"\n",
"\n",
"/**\n",
" * Grid\n",
" */\n",
"\n",
"/* When there&#x27;s room for 5 columns, fall back to 4 */\n",
"@container (min-width: 519px) and (max-width: 779px) {\n",
" #mols2grid .m2g-cell {\n",
" flex-basis: calc(100% / 4);\n",
" }\n",
"}\n",
"\n",
"/* When there&#x27;s room for 7-11 columns, fall back to 6 */\n",
"@container (min-width: 779px) and (max-width: 1559px) {\n",
" #mols2grid .m2g-cell {\n",
" flex-basis: calc(100% / 6);\n",
" }\n",
"}\n",
"\n",
"/* When there&#x27;s room for 13+ columns, fall back to 12 */\n",
"@container (min-width: 1559px) {\n",
" #mols2grid .m2g-cell {\n",
" flex-basis: calc(100% / 12);\n",
" }\n",
"}\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;script src=&quot;https://code.jquery.com/jquery-3.6.0.min.js&quot; integrity=&quot;sha256-/xUj+3OJU5yExlq6GSYGSHk7tPXikynS7ogEvDej/m4=&quot; crossorigin=&quot;anonymous&quot;&gt;&lt;/script&gt;\n",
"&lt;script src=&quot;https://unpkg.com/@rdkit/rdkit@2022.3.1/Code/MinimalLib/dist/RDKit_minimal.js&quot;&gt;&lt;/script&gt;\n",
" &lt;script&gt;\n",
" // Set iframe height to fit content.\n",
" function fitIframe(iframe) {\n",
" // Ignore when there&#x27;s no iframe\n",
" if (!iframe) return\n",
"\n",
" // Only fit height when no specific height was given.\n",
" if (iframe.getAttribute(&#x27;height&#x27;)) return;\n",
"\n",
" // Initial fit + refit whenever the window width changes.\n",
" _fit()\n",
" $(window).on(&#x27;resize&#x27;, function() {\n",
" if (window.innerWidth != window.prevInnerWidth) {\n",
" window.prevInnerWidth = window.innerWidth\n",
" _fit();\n",
" }\n",
" })\n",
"\n",
" // Fit iframe height to content height.\n",
" function _fit() {\n",
" var height = iframe.contentDocument.body.scrollHeight + 18 + &#x27;px&#x27;;\n",
" iframe.style.height = height;\n",
" }\n",
" }\n",
"&lt;/script&gt;\n",
"\n",
"&lt;!-- prettier-ignore --&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",
" \n",
" &lt;!-- Custom header --&gt;\n",
" \n",
"\n",
"\n",
"\n",
"\n",
" &lt;/head&gt;\n",
" &lt;body class=&quot;m2g-inside-iframe&quot;&gt;\n",
"\n",
"\n",
"\n",
" &lt;div id=&quot;mols2grid&quot; class=&quot;grid-default&quot;&gt;\n",
" &lt;!-- Pagination &amp; search --&gt;\n",
" &lt;div class=&quot;m2g-functions&quot;&gt;\n",
" \n",
" &lt;div class=&quot;m2g-row&quot;&gt;\n",
" &lt;!-- Pagination --&gt;\n",
" &lt;ul class=&quot;m2g-pagination&quot; class=&quot;d-flex&quot;&gt;&lt;/ul&gt;\n",
" &lt;div class=&quot;m2g-gap&quot;&gt;&lt;/div&gt;\n",
"\n",
" &lt;!-- Sort dropdown --&gt;\n",
" &lt;div class=&quot;m2g-dropdown m2g-sort&quot;&gt;\n",
" &lt;select&gt;\n",
" \n",
" \n",
" \n",
" \n",
" \n",
" &lt;option value=&quot;mols2grid-id&quot; selected&gt;Index&lt;/option&gt;\n",
" \n",
" \n",
" \n",
" \n",
" \n",
" &lt;option value=&quot;data-min_freq&quot;&gt;min_freq&lt;/option&gt;\n",
" \n",
" \n",
" \n",
" &lt;option value=&quot;checkbox&quot;&gt;Selected&lt;/option&gt;\n",
" \n",
" &lt;/select&gt;\n",
" &lt;div class=&quot;m2g-order&quot;&gt;&lt;/div&gt;\n",
" &lt;div class=&quot;m2g-display&quot;&gt;\n",
" Index\n",
" &lt;/div&gt;\n",
" &lt;/div&gt;\n",
" &lt;/div&gt;\n",
" &lt;div class=&quot;m2g-row&quot;&gt;\n",
" &lt;!-- Search bar --&gt;\n",
" &lt;div class=&quot;m2g-search-wrap&quot;&gt;\n",
" &lt;input\n",
" type=&quot;text&quot;\n",
" class=&quot;m2g-searchbar form-control&quot;\n",
" placeholder=&quot;Search&quot;\n",
" aria-label=&quot;Search&quot;\n",
" aria-describedby=&quot;basic-addon1&quot;\n",
" /&gt;\n",
" &lt;div class=&quot;m2g-search-options&quot;&gt;\n",
" &lt;div class=&quot;m2g-option m2g-search-text sel&quot;&gt;Text&lt;/div&gt;\n",
" &lt;div class=&quot;m2g-option m2g-search-smarts&quot;&gt;SMARTS&lt;/div&gt;\n",
" &lt;/div&gt;\n",
" &lt;/div&gt;\n",
"\n",
" &lt;!-- Action dropdown --&gt;\n",
" &lt;div class=&quot;m2g-dropdown m2g-actions&quot;&gt;\n",
" &lt;select&gt;\n",
" &lt;option hidden&gt;-&lt;/option&gt;\n",
" &lt;option value=&quot;select-all&quot;&gt;Select all&lt;/option&gt;\n",
" &lt;option value=&quot;select-matching&quot;&gt;Select matching&lt;/option&gt;\n",
" &lt;option value=&quot;unselect-all&quot;&gt;Unselect all&lt;/option&gt;\n",
" &lt;option value=&quot;invert&quot;&gt;Invert&lt;/option&gt;\n",
" &lt;option value=&quot;copy&quot;&gt;Copy to clipboard&lt;/option&gt;\n",
" &lt;option value=&quot;save-smiles&quot;&gt;Save SMILES&lt;/option&gt;\n",
" &lt;option value=&quot;save-csv&quot;&gt;Save CSV&lt;/option&gt;\n",
" &lt;/select&gt;\n",
" &lt;div class=&quot;m2g-icon&quot;&gt;\n",
" &lt;svg width=&quot;20&quot; height=&quot;20&quot; viewBox=&quot;0 0 20 20&quot; xmlns=&quot;http://www.w3.org/2000/svg&quot;&gt;\n",
" &lt;path d=&quot;M11.5 4C11.5 4.82843 10.8284 5.5 10 5.5C9.17157 5.5 8.5 4.82843 8.5 4C8.5 3.17157 9.17157 2.5 10 2.5C10.8284 2.5 11.5 3.17157 11.5 4ZM11.5 10C11.5 10.8284 10.8284 11.5 10 11.5C9.17157 11.5 8.5 10.8284 8.5 10C8.5 9.17157 9.17157 8.5 10 8.5C10.8284 8.5 11.5 9.17157 11.5 10ZM10 17.5C10.8284 17.5 11.5 16.8284 11.5 16C11.5 15.1716 10.8284 14.5 10 14.5C9.17157 14.5 8.5 15.1716 8.5 16C8.5 16.8284 9.17157 17.5 10 17.5Z&quot;/&gt;\n",
" &lt;/svg&gt;\n",
" &lt;/div&gt;\n",
" &lt;/div&gt;\n",
" &lt;/div&gt;\n",
" &lt;/div&gt;\n",
"\n",
" &lt;!-- Grid --&gt;\n",
" \n",
" &lt;div class=&quot;m2g-list&quot;&gt;&lt;div class=&quot;m2g-cell&quot; data-mols2grid-id=&quot;0&quot; tabindex=&quot;0&quot;&gt;&lt;div class=&quot;m2g-cb-wrap&quot;&gt;&lt;input type=&quot;checkbox&quot; tabindex=&quot;-1&quot; class=&quot;position-relative float-left cached_checkbox&quot;&gt;&lt;div class=&quot;m2g-cb&quot;&gt;&lt;/div&gt;&lt;div class=&quot;data-mols2grid-id-display&quot;&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;m2g-cell-actions&quot;&gt;&lt;/div&gt;&lt;div class=&quot;data data-img copy-me&quot;&gt;&lt;/div&gt;&lt;div class=&quot;data data-min_freq copy-me&quot;&gt;&lt;/div&gt;&lt;div class=&quot;data data-SMILES copy-me&quot; style=&quot;display: none;&quot;&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;\n",
" &lt;/div&gt;\n",
" &lt;script&gt;\n",
" // list.js\n",
"var listObj = new List(&#x27;mols2grid&#x27;, {\n",
" listClass: &#x27;m2g-list&#x27;,\n",
" valueNames: [{data: [&#x27;mols2grid-id&#x27;]}, &#x27;data-mols2grid-id&#x27;, &#x27;data-min_freq&#x27;, &#x27;data-SMILES&#x27;, &#x27;data-img&#x27;, &#x27;data-mols2grid-id-display&#x27;],\n",
" item: &#x27;&lt;div class=&quot;m2g-cell&quot; data-mols2grid-id=&quot;0&quot; tabindex=&quot;0&quot;&gt;&lt;div class=&quot;m2g-cb-wrap&quot;&gt;&lt;input type=&quot;checkbox&quot; tabindex=&quot;-1&quot; class=&quot;position-relative float-left cached_checkbox&quot;&gt;&lt;div class=&quot;m2g-cb&quot;&gt;&lt;/div&gt;&lt;div class=&quot;data-mols2grid-id-display&quot;&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;m2g-cell-actions&quot;&gt;&lt;/div&gt;&lt;div class=&quot;data data-img copy-me&quot;&gt;&lt;/div&gt;&lt;div class=&quot;data data-min_freq copy-me&quot;&gt;&lt;/div&gt;&lt;div class=&quot;data data-SMILES copy-me&quot; style=&quot;display: none;&quot;&gt;&lt;/div&gt;&lt;/div&gt;&#x27;,\n",
" page: 24,\n",
" pagination: {\n",
" paginationClass: &quot;m2g-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;mols2grid-id&quot;: 0, &quot;data-min_freq&quot;: 0, &quot;data-SMILES&quot;: &quot;CC(=O)OC(CC12CCCCN1C(=O)C(=CCO)C2O)=C(C)C&quot;, &quot;data-img&quot;: null, &quot;data-mols2grid-id-display&quot;: 0}, {&quot;mols2grid-id&quot;: 1, &quot;data-min_freq&quot;: 0, &quot;data-SMILES&quot;: &quot;C=CCOC(=O)N1CCc2c(C(=O)OC)ncn2-c2ccc(Cl)cc2C1=O&quot;, &quot;data-img&quot;: null, &quot;data-mols2grid-id-display&quot;: 1}, {&quot;mols2grid-id&quot;: 2, &quot;data-min_freq&quot;: 0, &quot;data-SMILES&quot;: &quot;COc1ccc(-c2nc3cc(-c4ccc(C)cc4)[nH]c(=NC(=O)Cc4cccc5ccccc45)n3n2)cc1&quot;, &quot;data-img&quot;: null, &quot;data-mols2grid-id-display&quot;: 2}, {&quot;mols2grid-id&quot;: 3, &quot;data-min_freq&quot;: 0, &quot;data-SMILES&quot;: &quot;CC1=CC2C(=O)C(C)(C)CCC2(C(=O)CN2CCCN(Cc3ccccc3)CC2)C2C(C)CCC12&quot;, &quot;data-img&quot;: null, &quot;data-mols2grid-id-display&quot;: 3}, {&quot;mols2grid-id&quot;: 4, &quot;data-min_freq&quot;: 0, &quot;data-SMILES&quot;: &quot;COc1cccc(CC(=O)N=c2c3c([nH]n2-c2ccc(C)c(C)c2)C[S+]([O-])C3)c1OC&quot;, &quot;data-img&quot;: null, &quot;data-mols2grid-id-display&quot;: 4}, {&quot;mols2grid-id&quot;: 5, &quot;data-min_freq&quot;: 0, &quot;data-SMILES&quot;: &quot;C=C(C)C1CCC2(COC(C)=O)CCC3(C)C(CCC4C5(C)CCC(OC(C)=O)C(C)(C)C5CCC43C)C12&quot;, &quot;data-img&quot;: null, &quot;data-mols2grid-id-display&quot;: 5}, {&quot;mols2grid-id&quot;: 6, &quot;data-min_freq&quot;: 0, &quot;data-SMILES&quot;: &quot;CC(=O)NC(C)Cc1cc(C)ccc1N=c1cc[nH]c2cc(-c3cnn(C4CCN(C)CC4)c3)cnc12&quot;, &quot;data-img&quot;: null, &quot;data-mols2grid-id-display&quot;: 6}, {&quot;mols2grid-id&quot;: 7, &quot;data-min_freq&quot;: 0, &quot;data-SMILES&quot;: &quot;COc1cc2cc(-c3ccc(Cl)cc3)c[n+](CCC3NC4(C(=O)N5C(C)=CC=CC5=[N+]4C)C(C)(C)N3O)c2cc1OC&quot;, &quot;data-img&quot;: null, &quot;data-mols2grid-id-display&quot;: 7}, {&quot;mols2grid-id&quot;: 8, &quot;data-min_freq&quot;: 0, &quot;data-SMILES&quot;: &quot;COc1ccc2[nH]c3c(c2c1)C(COC(=O)NC(C)C)C1C(=O)NCC1C3CC(=O)Oc1ccccc1&quot;, &quot;data-img&quot;: null, &quot;data-mols2grid-id-display&quot;: 8}, {&quot;mols2grid-id&quot;: 9, &quot;data-min_freq&quot;: 0, &quot;data-SMILES&quot;: &quot;CON=C(CC1=NC(C(=O)OC)C(c2ccc(F)c(Cl)c2)C12C(=O)Nc1cc(Cl)ccc12)c1ccc(-n2ccnc2C)cc1&quot;, &quot;data-img&quot;: null, &quot;data-mols2grid-id-display&quot;: 9}, {&quot;mols2grid-id&quot;: 10, &quot;data-min_freq&quot;: 0, &quot;data-SMILES&quot;: &quot;CCC=CCC1C=Cc2c(C=CC=C(O)C(=O)NCC3CCCC3)oc3cc(OC)cc1c23&quot;, &quot;data-img&quot;: null, &quot;data-mols2grid-id-display&quot;: 10}, {&quot;mols2grid-id&quot;: 11, &quot;data-min_freq&quot;: 0, &quot;data-SMILES&quot;: &quot;COc1ccccc1C(=O)N=c1[nH]n(CC2OC(CO)C(O)C2O)c2ccc([N+](=O)[O-])cc12&quot;, &quot;data-img&quot;: null, &quot;data-mols2grid-id-display&quot;: 11}, {&quot;mols2grid-id&quot;: 12, &quot;data-min_freq&quot;: 0, &quot;data-SMILES&quot;: &quot;CN(c1ccccc1)c1nc(CCl)nc2cc3c(cc12)CC1(CCCCN1)C3&quot;, &quot;data-img&quot;: null, &quot;data-mols2grid-id-display&quot;: 12}, {&quot;mols2grid-id&quot;: 13, &quot;data-min_freq&quot;: 0, &quot;data-SMILES&quot;: &quot;COc1cccc2c1C(=O)c1ccc3sccc3c1C2=O&quot;, &quot;data-img&quot;: null, &quot;data-mols2grid-id-display&quot;: 13}, {&quot;mols2grid-id&quot;: 14, &quot;data-min_freq&quot;: 0, &quot;data-SMILES&quot;: &quot;N=c1nc2scc(-c3ccccc3Cl)n2[nH]1&quot;, &quot;data-img&quot;: null, &quot;data-mols2grid-id-display&quot;: 14}, {&quot;mols2grid-id&quot;: 15, &quot;data-min_freq&quot;: 0, &quot;data-SMILES&quot;: &quot;COc1cc(C=C2CC(=O)C(C(C)=O)C2=O)cc2c1OCO2&quot;, &quot;data-img&quot;: null, &quot;data-mols2grid-id-display&quot;: 15}, {&quot;mols2grid-id&quot;: 16, &quot;data-min_freq&quot;: 0, &quot;data-SMILES&quot;: &quot;O=C(O)CCC(=O)NC1CC=C(c2[nH]c3nccc4c3c2CCNC4=O)CC1&quot;, &quot;data-img&quot;: null, &quot;data-mols2grid-id-display&quot;: 16}, {&quot;mols2grid-id&quot;: 17, &quot;data-min_freq&quot;: 0, &quot;data-SMILES&quot;: &quot;Cc1cccc(C2C(Oc3cc(C)n(C)n3)CC3C4CCCN(CC4)C32)c1&quot;, &quot;data-img&quot;: null, &quot;data-mols2grid-id-display&quot;: 17}, {&quot;mols2grid-id&quot;: 18, &quot;data-min_freq&quot;: 0, &quot;data-SMILES&quot;: &quot;N=c1[nH]ccn2c(C3CCC(C(=O)NCc4ccccc4F)CC3)nc(-c3ccc(Oc4ccccc4)cc3F)c12&quot;, &quot;data-img&quot;: null, &quot;data-mols2grid-id-display&quot;: 18}, {&quot;mols2grid-id&quot;: 19, &quot;data-min_freq&quot;: 0, &quot;data-SMILES&quot;: &quot;CCNCc1c[nH]c2c(=Nc3ccc(N=c4nccc[nH]4)cc3)nc[nH]c12&quot;, &quot;data-img&quot;: null, &quot;data-mols2grid-id-display&quot;: 19}, {&quot;mols2grid-id&quot;: 20, &quot;data-min_freq&quot;: 0, &quot;data-SMILES&quot;: &quot;Cc1cccc(CCC(=O)N=c2c3c([nH]n2-c2ccccc2)CS(=O)(=O)C3)c1&quot;, &quot;data-img&quot;: null, &quot;data-mols2grid-id-display&quot;: 20}, {&quot;mols2grid-id&quot;: 21, &quot;data-min_freq&quot;: 0, &quot;data-SMILES&quot;: &quot;NCCCCNCCCCNCCCNCCCN=C1CC(=O)c2cccc3cccc1c23&quot;, &quot;data-img&quot;: null, &quot;data-mols2grid-id-display&quot;: 21}, {&quot;mols2grid-id&quot;: 22, &quot;data-min_freq&quot;: 0, &quot;data-SMILES&quot;: &quot;CCOc1cccc2c(C3c4c([nH]c(SC)nc4=O)N=C4CCCCC43)coc12&quot;, &quot;data-img&quot;: null, &quot;data-mols2grid-id-display&quot;: 22}, {&quot;mols2grid-id&quot;: 23, &quot;data-min_freq&quot;: 0, &quot;data-SMILES&quot;: &quot;O=c1ccc(=O)c2[nH]c(=O)n(O)c2[nH]1&quot;, &quot;data-img&quot;: null, &quot;data-mols2grid-id-display&quot;: 23}, {&quot;mols2grid-id&quot;: 24, &quot;data-min_freq&quot;: 0, &quot;data-SMILES&quot;: &quot;CC1(C)CCCC2(C(=O)O)CC=C3C(=CC(O)C4C3(C)CCC(O)C4(C)C)C12&quot;, &quot;data-img&quot;: null, &quot;data-mols2grid-id-display&quot;: 24}, {&quot;mols2grid-id&quot;: 25, &quot;data-min_freq&quot;: 0, &quot;data-SMILES&quot;: &quot;CN(C)CC(N=c1c2ccccc2[nH]c2scc(-c3ccccc3)c12)C(=O)NCC(=O)O&quot;, &quot;data-img&quot;: null, &quot;data-mols2grid-id-display&quot;: 25}, {&quot;mols2grid-id&quot;: 26, &quot;data-min_freq&quot;: 0, &quot;data-SMILES&quot;: &quot;Cn1c2c(c3ccccc31)C(c1ccc(Cl)cc1Cl)N(O)C(=O)C2&quot;, &quot;data-img&quot;: null, &quot;data-mols2grid-id-display&quot;: 26}, {&quot;mols2grid-id&quot;: 27, &quot;data-min_freq&quot;: 0, &quot;data-SMILES&quot;: &quot;CC1=C2CC3(C4CCCCC4)CCC4(C)C5=C(CC(=O)C5C)C(C)(C)C(=O)C(C#N)CC4C3CC2OC1=O&quot;, &quot;data-img&quot;: null, &quot;data-mols2grid-id-display&quot;: 27}, {&quot;mols2grid-id&quot;: 28, &quot;data-min_freq&quot;: 0, &quot;data-SMILES&quot;: &quot;CC(C)N=c1[nH]c(-c2ccc(C3(O)CCSCC3)cc2)cc2ncn(C)c(=O)c12&quot;, &quot;data-img&quot;: null, &quot;data-mols2grid-id-display&quot;: 28}, {&quot;mols2grid-id&quot;: 29, &quot;data-min_freq&quot;: 0, &quot;data-SMILES&quot;: &quot;COC1C(=O)C(n2cnc3c(=N)[nH]cnc32)CN2CSCC12&quot;, &quot;data-img&quot;: null, &quot;data-mols2grid-id-display&quot;: 29}, {&quot;mols2grid-id&quot;: 30, &quot;data-min_freq&quot;: 0, &quot;data-SMILES&quot;: &quot;Cc1ccc2ccccc2c1NC(=O)C1CN2CCCCC2S1(=O)=O&quot;, &quot;data-img&quot;: null, &quot;data-mols2grid-id-display&quot;: 30}, {&quot;mols2grid-id&quot;: 31, &quot;data-min_freq&quot;: 0, &quot;data-SMILES&quot;: &quot;Cc1n[nH]c2c1C1(C(=O)Nc3ccc(F)cc31)C(C#N)C(=N)O2&quot;, &quot;data-img&quot;: null, &quot;data-mols2grid-id-display&quot;: 31}, {&quot;mols2grid-id&quot;: 32, &quot;data-min_freq&quot;: 0, &quot;data-SMILES&quot;: &quot;Oc1cc2c3c(c1)C(C2)N(CCc1ccccc1)CC3&quot;, &quot;data-img&quot;: null, &quot;data-mols2grid-id-display&quot;: 32}, {&quot;mols2grid-id&quot;: 33, &quot;data-min_freq&quot;: 0, &quot;data-SMILES&quot;: &quot;CCN1c2ccc(Br)cc2CC2C1c1cncc(C(N)=O)c1OC2(C)C&quot;, &quot;data-img&quot;: null, &quot;data-mols2grid-id-display&quot;: 33}, {&quot;mols2grid-id&quot;: 34, &quot;data-min_freq&quot;: 0, &quot;data-SMILES&quot;: &quot;C=C1CC2C(=O)c3ccccc3C1c1ccccc12&quot;, &quot;data-img&quot;: null, &quot;data-mols2grid-id-display&quot;: 34}, {&quot;mols2grid-id&quot;: 35, &quot;data-min_freq&quot;: 0, &quot;data-SMILES&quot;: &quot;CCc1cc2c(=O)cc(-c3ccccc3)oc2c2c1OCN(Cc1cccc(OCc3ccccc3)c1)C2&quot;, &quot;data-img&quot;: null, &quot;data-mols2grid-id-display&quot;: 35}, {&quot;mols2grid-id&quot;: 36, &quot;data-min_freq&quot;: 0, &quot;data-SMILES&quot;: &quot;Cc1cccc(C2c3ccccc3-n3c2c(CC(=O)NS(=O)(=O)O)c2c(Cl)cccc23)c1&quot;, &quot;data-img&quot;: null, &quot;data-mols2grid-id-display&quot;: 36}, {&quot;mols2grid-id&quot;: 37, &quot;data-min_freq&quot;: 0, &quot;data-SMILES&quot;: &quot;COC(=O)C1=c2c(O)c(C)c(C)c(O)c2=NC2C1C(=O)C(C(C)=O)C(=O)C2N1CC1&quot;, &quot;data-img&quot;: null, &quot;data-mols2grid-id-display&quot;: 37}, {&quot;mols2grid-id&quot;: 38, &quot;data-min_freq&quot;: 0, &quot;data-SMILES&quot;: &quot;CN1CCN(c2nc3[nH]c(=N)[nH]c(=N)c3c(=Nc3ccc(Cl)cc3)[nH]2)CC1&quot;, &quot;data-img&quot;: null, &quot;data-mols2grid-id-display&quot;: 38}, {&quot;mols2grid-id&quot;: 39, &quot;data-min_freq&quot;: 0, &quot;data-SMILES&quot;: &quot;CC(=NNC(=O)c1nnn(-c2no[nH]c2=N)c1CN1CCC(C)CC1)c1ccccc1&quot;, &quot;data-img&quot;: null, &quot;data-mols2grid-id-display&quot;: 39}, {&quot;mols2grid-id&quot;: 40, &quot;data-min_freq&quot;: 0, &quot;data-SMILES&quot;: &quot;Cc1ccc2nc3c(cc2c1)N=CN(Cc1ccccc1)S3&quot;, &quot;data-img&quot;: null, &quot;data-mols2grid-id-display&quot;: 40}, {&quot;mols2grid-id&quot;: 41, &quot;data-min_freq&quot;: 0, &quot;data-SMILES&quot;: &quot;CCc1c(Cc2cccc(Br)c2)n2c(nc1=O)N(c1ccc(Cl)cc1)CC2&quot;, &quot;data-img&quot;: null, &quot;data-mols2grid-id-display&quot;: 41}, {&quot;mols2grid-id&quot;: 42, &quot;data-min_freq&quot;: 0, &quot;data-SMILES&quot;: &quot;O=C(O)c1cccc(Cn2cc3[nH]c4ccccc4c3cc2=O)c1&quot;, &quot;data-img&quot;: null, &quot;data-mols2grid-id-display&quot;: 42}, {&quot;mols2grid-id&quot;: 43, &quot;data-min_freq&quot;: 0, &quot;data-SMILES&quot;: &quot;Cc1occc1C1CC2OC23C2CCC(=O)OC2C2CC13CC(=O)C2C&quot;, &quot;data-img&quot;: null, &quot;data-mols2grid-id-display&quot;: 43}, {&quot;mols2grid-id&quot;: 44, &quot;data-min_freq&quot;: 0, &quot;data-SMILES&quot;: &quot;C=C(C)C1CCC2(C(=O)OCCC)CCC3(C)C(C(O)C(O)C4C5(C)CCC(=O)C(C)(C)C5CCC43C)C12&quot;, &quot;data-img&quot;: null, &quot;data-mols2grid-id-display&quot;: 44}, {&quot;mols2grid-id&quot;: 45, &quot;data-min_freq&quot;: 0, &quot;data-SMILES&quot;: &quot;COC1=CN(C)c2c(c3ccccc3n2CC(=O)Nc2cccc(F)c2)C1&quot;, &quot;data-img&quot;: null, &quot;data-mols2grid-id-display&quot;: 45}, {&quot;mols2grid-id&quot;: 46, &quot;data-min_freq&quot;: 0, &quot;data-SMILES&quot;: &quot;COc1cc(N=c2[nH]c(=NC3CCCc4ccccc43)c3cc[nH]c3[nH]2)cc(OC)c1OC&quot;, &quot;data-img&quot;: null, &quot;data-mols2grid-id-display&quot;: 46}, {&quot;mols2grid-id&quot;: 47, &quot;data-min_freq&quot;: 0, &quot;data-SMILES&quot;: &quot;CCCc1c(O)n2c(=NN=Cc3cccs3)[nH]nc(-c3ccco3)n2c1=O&quot;, &quot;data-img&quot;: null, &quot;data-mols2grid-id-display&quot;: 47}, {&quot;mols2grid-id&quot;: 48, &quot;data-min_freq&quot;: 0, &quot;data-SMILES&quot;: &quot;CN1C(=O)c2ccc(NS(=O)(=O)c3cc(Cl)ccc3Cl)cc2OCC2OC(CC(=O)NCCN3CCCC3)CCC21&quot;, &quot;data-img&quot;: null, &quot;data-mols2grid-id-display&quot;: 48}, {&quot;mols2grid-id&quot;: 49, &quot;data-min_freq&quot;: 0, &quot;data-SMILES&quot;: &quot;Cn1c2c(c(=O)n(C)c1=O)-c1ccccc1N(CCCCO)C=N2&quot;, &quot;data-img&quot;: null, &quot;data-mols2grid-id-display&quot;: 49}, {&quot;mols2grid-id&quot;: 50, &quot;data-min_freq&quot;: 0, &quot;data-SMILES&quot;: &quot;N=c1[nH]c(-n2cccc2OCCN)nc2c(-c3cccc([N+](=O)[O-])c3)nn(-c3ccccc3)c12&quot;, &quot;data-img&quot;: null, &quot;data-mols2grid-id-display&quot;: 50}, {&quot;mols2grid-id&quot;: 51, &quot;data-min_freq&quot;: 0, &quot;data-SMILES&quot;: &quot;O=C1CC2c3ccccc3C1c1c2c(O)n(-c2ccc(F)c(F)c2)c1O&quot;, &quot;data-img&quot;: null, &quot;data-mols2grid-id-display&quot;: 51}, {&quot;mols2grid-id&quot;: 52, &quot;data-min_freq&quot;: 0, &quot;data-SMILES&quot;: &quot;O=C(C=Cc1ccc(Cl)c(C(F)(F)F)c1)NC1CCC(CN2CCc3nc4ncsc4cc3C2)CC1&quot;, &quot;data-img&quot;: null, &quot;data-mols2grid-id-display&quot;: 52}, {&quot;mols2grid-id&quot;: 53, &quot;data-min_freq&quot;: 0, &quot;data-SMILES&quot;: &quot;COc1ccc(C(=O)N2CCc3c2ccc2nc(-c4ccco4)c(C)nc32)c(OC)c1&quot;, &quot;data-img&quot;: null, &quot;data-mols2grid-id-display&quot;: 53}, {&quot;mols2grid-id&quot;: 54, &quot;data-min_freq&quot;: 0, &quot;data-SMILES&quot;: &quot;CCCN(C(CC)c1ccc(N2CCc3c[nH]c(=O)nc3C2)nc1)S(N)(=O)=O&quot;, &quot;data-img&quot;: null, &quot;data-mols2grid-id-display&quot;: 54}, {&quot;mols2grid-id&quot;: 55, &quot;data-min_freq&quot;: 0, &quot;data-SMILES&quot;: &quot;Oc1ccc2c3c1OC1c4ncccc4CC4(O)C(C2)N(CC2CC2)CCC314&quot;, &quot;data-img&quot;: null, &quot;data-mols2grid-id-display&quot;: 55}, {&quot;mols2grid-id&quot;: 56, &quot;data-min_freq&quot;: 1, &quot;data-SMILES&quot;: &quot;CCOC(=O)C(CSCCC(=O)NCCCOc1no[n+]([O-])c1S(=O)(=O)c1ccccc1)NC(=O)c1c(N)[nH]c(=N)[nH]c1=N&quot;, &quot;data-img&quot;: null, &quot;data-mols2grid-id-display&quot;: 56}, {&quot;mols2grid-id&quot;: 57, &quot;data-min_freq&quot;: 1, &quot;data-SMILES&quot;: &quot;OC1CCN(CCN=c2c3c([nH]c4ccccc24)CCCC3)CC1&quot;, &quot;data-img&quot;: null, &quot;data-mols2grid-id-display&quot;: 57}, {&quot;mols2grid-id&quot;: 58, &quot;data-min_freq&quot;: 1, &quot;data-SMILES&quot;: &quot;O=c1cc2n(c(=S)n1-c1ccccc1)CCC2&quot;, &quot;data-img&quot;: null, &quot;data-mols2grid-id-display&quot;: 58}, {&quot;mols2grid-id&quot;: 59, &quot;data-min_freq&quot;: 1, &quot;data-SMILES&quot;: &quot;COc1ccc(Cn2c(Br)nc3cc(Cc4c[nH]c(=N)[nH]c4=N)ccc32)cc1&quot;, &quot;data-img&quot;: null, &quot;data-mols2grid-id-display&quot;: 59}, {&quot;mols2grid-id&quot;: 60, &quot;data-min_freq&quot;: 1, &quot;data-SMILES&quot;: &quot;C[N+](C)(C)CCCCCC[N+]1(C)CCS(=O)(=O)CC1&quot;, &quot;data-img&quot;: null, &quot;data-mols2grid-id-display&quot;: 60}, {&quot;mols2grid-id&quot;: 61, &quot;data-min_freq&quot;: 2, &quot;data-SMILES&quot;: &quot;Cc1o[nH]c(=NS(=O)(=O)c2c(Cl)cc(-c3ccc(Cl)cc3)cc2Cc2nc(-c3ccsc3)cs2)c1C&quot;, &quot;data-img&quot;: null, &quot;data-mols2grid-id-display&quot;: 61}, {&quot;mols2grid-id&quot;: 62, &quot;data-min_freq&quot;: 2, &quot;data-SMILES&quot;: &quot;CCCN(CCC)C1=C(Cl)c2ccc(Cl)c3cccc(c23)C1&quot;, &quot;data-img&quot;: null, &quot;data-mols2grid-id-display&quot;: 62}, {&quot;mols2grid-id&quot;: 63, &quot;data-min_freq&quot;: 2, &quot;data-SMILES&quot;: &quot;O=[N+]([O-])c1ccc(N=c2nc(OCC3CCCCC3)c3[nH]cnc3[nH]2)cc1Cl&quot;, &quot;data-img&quot;: null, &quot;data-mols2grid-id-display&quot;: 63}, {&quot;mols2grid-id&quot;: 64, &quot;data-min_freq&quot;: 2, &quot;data-SMILES&quot;: &quot;COc1cnc2ncn(-c3ccc(F)c(C(=O)N=c4cc(C(C)(C)C)o[nH]4)c3)c2c1&quot;, &quot;data-img&quot;: null, &quot;data-mols2grid-id-display&quot;: 64}, {&quot;mols2grid-id&quot;: 65, &quot;data-min_freq&quot;: 2, &quot;data-SMILES&quot;: &quot;COc1ccc(-c2cc(Oc3ccc(F)c(Cl)c3)c3c(=N)[nH]cnc3n2)cc1&quot;, &quot;data-img&quot;: null, &quot;data-mols2grid-id-display&quot;: 65}, {&quot;mols2grid-id&quot;: 66, &quot;data-min_freq&quot;: 2, &quot;data-SMILES&quot;: &quot;COc1cccc(-c2nc3ccc(C(=O)O)cc3nc2Cc2nn(C)c(=N)[nH]2)c1&quot;, &quot;data-img&quot;: null, &quot;data-mols2grid-id-display&quot;: 66}, {&quot;mols2grid-id&quot;: 67, &quot;data-min_freq&quot;: 2, &quot;data-SMILES&quot;: &quot;N#Cc1c[nH]c(=NC(=O)Nc2ccc(Cl)cc2)cn1&quot;, &quot;data-img&quot;: null, &quot;data-mols2grid-id-display&quot;: 67}, {&quot;mols2grid-id&quot;: 68, &quot;data-min_freq&quot;: 2, &quot;data-SMILES&quot;: &quot;C=C(C)C1(O)CCC2(C)C(CC=C3C4(C)CCC(C(CC=C(C)C)(CCC=C(C)C(=O)O)OC)C4CCC32C)C1(C)C&quot;, &quot;data-img&quot;: null, &quot;data-mols2grid-id-display&quot;: 68}, {&quot;mols2grid-id&quot;: 69, &quot;data-min_freq&quot;: 2, &quot;data-SMILES&quot;: &quot;C#CC1(O)CCC2C3CC(C)(O)C4CC(=NOCCN)CCC4(C)C3CCC21C&quot;, &quot;data-img&quot;: null, &quot;data-mols2grid-id-display&quot;: 69}, {&quot;mols2grid-id&quot;: 70, &quot;data-min_freq&quot;: 3, &quot;data-SMILES&quot;: &quot;Cc1cccc2[nH]c(=NCn3cncn3)oc12&quot;, &quot;data-img&quot;: null, &quot;data-mols2grid-id-display&quot;: 70}, {&quot;mols2grid-id&quot;: 71, &quot;data-min_freq&quot;: 3, &quot;data-SMILES&quot;: &quot;CC(=O)N=c1[nH]nc(SCC(=O)Nc2ccc(Cl)cc2)o1&quot;, &quot;data-img&quot;: null, &quot;data-mols2grid-id-display&quot;: 71}, {&quot;mols2grid-id&quot;: 72, &quot;data-min_freq&quot;: 4, &quot;data-SMILES&quot;: &quot;CC1(C)C(=O)Nc2cc3onc(-c4ccc(Cl)cc4)c3cc21&quot;, &quot;data-img&quot;: null, &quot;data-mols2grid-id-display&quot;: 72}, {&quot;mols2grid-id&quot;: 73, &quot;data-min_freq&quot;: 4, &quot;data-SMILES&quot;: &quot;CSc1ccc(CN2CCC3(CC2)OC(=O)Cc2ccccc23)cc1&quot;, &quot;data-img&quot;: null, &quot;data-mols2grid-id-display&quot;: 73}, {&quot;mols2grid-id&quot;: 74, &quot;data-min_freq&quot;: 4, &quot;data-SMILES&quot;: &quot;c1ccc(COC2CCC3C2OCCN3C2CCOC2)cc1&quot;, &quot;data-img&quot;: null, &quot;data-mols2grid-id-display&quot;: 74}]);\n",
"\n",
"\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 = &#x27;{&#x27;\n",
" for (let [key, value] of this) {\n",
" content += key + &#x27;:&#x27; + JSON.stringify(value) + &#x27;,&#x27;\n",
" }\n",
" content = content.length &gt; 1 ? content.slice(0, -1) : content\n",
" content += &#x27;}&#x27;\n",
" return content\n",
" }\n",
" to_keys() {\n",
" var content = []\n",
" for (let [key] of this) {\n",
" content.push(key)\n",
" }\n",
" return content\n",
" }\n",
" download_smi(fileName, allItems) {\n",
" var content = &#x27;&#x27;\n",
"\n",
" if (allItems) {\n",
" // Gather all smiles\n",
" for (var item of allItems) {\n",
" var smiles = item.values()[&#x27;data-SMILES&#x27;]\n",
" var id = item.values()[&#x27;mols2grid-id&#x27;]\n",
" content += smiles + &#x27; &#x27; + id + &#x27;\\n&#x27;\n",
" }\n",
" } else {\n",
" // Gather selected smiles\n",
" for (let [key, value] of this) {\n",
" content += value + &#x27; &#x27; + key + &#x27;\\n&#x27;\n",
" }\n",
" }\n",
"\n",
" var a = document.createElement(&#x27;a&#x27;)\n",
" var file = new Blob([content], { type: &#x27;text/plain&#x27; })\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",
"function add_selection(grid_id, _id, smiles) {\n",
" SELECTION.multi_set(_id, smiles);\n",
" let model = window.parent[&quot;_MOLS2GRID_&quot; + grid_id];\n",
" if (model) {\n",
" model.set(&quot;selection&quot;, SELECTION.to_dict());\n",
" model.save_changes();\n",
" }\n",
"}\n",
"function del_selection(grid_id, _id) {\n",
" SELECTION.multi_del(_id);\n",
" let model = window.parent[&quot;_MOLS2GRID_&quot; + grid_id];\n",
" if (model) {\n",
" model.set(&quot;selection&quot;, SELECTION.to_dict());\n",
" model.save_changes();\n",
" }\n",
"}\n",
"if (window.parent.IPython !== undefined) {\n",
" // Jupyter notebook\n",
" var kernel_env = &quot;jupyter&quot;;\n",
"} else if (window.parent.google !== undefined) {\n",
" // Google colab\n",
" var kernel_env = &quot;colab&quot;;\n",
"} else {\n",
" var kernel_env = null;\n",
"}\n",
"\n",
"\n",
"\n",
"\n",
"// sort\n",
"var sortField = &#x27;mols2grid-id&#x27;\n",
"var sortOrder = &#x27;asc&#x27;\n",
"\n",
"// Sort dropdown\n",
"$(&#x27;#mols2grid .m2g-sort select&#x27;).change(sort)\n",
"\n",
"// Sort order\n",
"$(&#x27;#mols2grid .m2g-order&#x27;).click(flipSort)\n",
"\n",
"function sort(e) {\n",
" if (e) {\n",
" sortField = e.target.value\n",
" var selectedOption = e.target.options[e.target.selectedIndex]\n",
" var sortFieldDisplay = selectedOption.text\n",
" }\n",
"\n",
" // Sort\n",
" if (sortField == &#x27;checkbox&#x27;) {\n",
" listObj.sort(&#x27;mols2grid-id&#x27;, {order: sortOrder, sortFunction: checkboxSort})\n",
" } else {\n",
" listObj.sort(sortField, {order: sortOrder, sortFunction: mols2gridSortFunction})\n",
" }\n",
"\n",
" // Update UI.\n",
" $(this).parent().find(&#x27;.m2g-display&#x27;).text(sortFieldDisplay)\n",
"}\n",
"\n",
"// prettier-ignore\n",
"function flipSort() {\n",
" $(this).parent().removeClass(&#x27;m2d-arrow-&#x27; + sortOrder)\n",
" sortOrder = sortOrder === &#x27;desc&#x27; ? &#x27;asc&#x27; : &#x27;desc&#x27;\n",
" $(this).parent().addClass(&#x27;m2d-arrow-&#x27; + sortOrder)\n",
" sort()\n",
"}\n",
"\n",
"function mols2gridSortFunction(itemA, itemB, options) {\n",
" var x = itemA.values()[options.valueName]\n",
" var y = itemB.values()[options.valueName]\n",
" if (typeof x === &#x27;number&#x27;) {\n",
" if (isFinite(x - y)) {\n",
" return x - y\n",
" } else {\n",
" return isFinite(x) ? -1 : 1\n",
" }\n",
" } else {\n",
" x = x ? x.toLowerCase() : x\n",
" y = y ? y.toLowerCase() : y\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.querySelector(&#x27;input[type=checkbox]&#x27;).checked\n",
" if (itemB.elm !== undefined) {\n",
" var checkedB = itemB.elm.querySelector(&#x27;input[type=checkbox]&#x27;).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",
"\n",
"\n",
"\n",
"\n",
"\n",
"// grid interactions (select, click, tooltip, key events)\n",
"// Check if selection UI is supported.\n",
"var supportSelection = eval(&#x27;True&#x27;.toLowerCase());\n",
"\n",
"listObj.on(&quot;updated&quot;, initInteraction);\n",
"\n",
"// (Re)initialiuze all grid interaction every time the grid changes.\n",
"function initInteraction(list) {\n",
" initCellClick()\n",
" initToolTip()\n",
" initKeyboard()\n",
" if (supportSelection) initCheckbox()\n",
"\n",
"\n",
" // Hide pagination if there is only one page.\n",
" if (listObj.matchingItems.length &lt;= listObj.page) {\n",
" $(&#x27;#mols2grid .m2g-pagination&#x27;).hide()\n",
" } else {\n",
" $(&#x27;#mols2grid .m2g-pagination&#x27;).show()\n",
" }\n",
"\n",
" // Add a bunch of phantom cells.\n",
" // These are used as filler to make sure that\n",
" // no grid cells need to be resized when there&#x27;s\n",
" // not enough results to fill the row.\n",
" $(&#x27;#mols2grid .m2g-list&#x27;).append(&#x27;&lt;div class=&quot;m2g-cell m2g-phantom&quot;&gt;&lt;/div&gt;&#x27;.repeat(11));\n",
"}\n",
"\n",
"// Cell click handler.\n",
"function initCellClick() {\n",
" $(&#x27;#mols2grid .m2g-cell&#x27;).off(&#x27;click&#x27;).click(function(e) {\n",
" if ($(e.target).hasClass(&#x27;m2g-info&#x27;) || $(e.target).is(&#x27;:checkbox&#x27;)) {\n",
" // Info button / Checkbox --&gt; do nothing.\n",
" } else if ($(e.target).is(&#x27;div&#x27;) &amp;&amp; $(e.target).hasClass(&#x27;data&#x27;)) {\n",
" // Data string --&gt; copy text.\n",
" copyOnClick(e.target)\n",
" } else if ($(e.target).hasClass(&#x27;m2g-callback&#x27;)) {\n",
" // Callback button.\n",
" onCallbackButtonClick(e.target)\n",
" } else {\n",
" // Outside checkbox --&gt; toggle the checkbox.\n",
" if (supportSelection) {\n",
" var chkbox = $(this).find(&#x27;input:checkbox&#x27;)[0]\n",
" chkbox.checked = !chkbox.checked\n",
" $(chkbox).trigger(&#x27;change&#x27;)\n",
" }\n",
" }\n",
" })\n",
"}\n",
"\n",
"// Store an element&#x27;s text content in the clipboard.\n",
"function copyOnClick(target) {\n",
" var text = $(target).text()\n",
" navigator.clipboard.writeText(text)\n",
"\n",
" // Blink the cell to indicate that the text was copied.\n",
" $(target).addClass(&#x27;m2g-copy-blink&#x27;)\n",
" setTimeout(function() {\n",
" $(target).removeClass(&#x27;m2g-copy-blink&#x27;)\n",
" }, 450)\n",
"}\n",
"\n",
"// Keyboard actions.\n",
"function initKeyboard() {\n",
" // Disable scroll when pressing UP/DOWN arrows\n",
" $(&#x27;#mols2grid .m2g-cell&#x27;).off(&#x27;keydown&#x27;).keydown(function(e) {\n",
" if (e.which == 38 || e.which == 40) {\n",
" e.preventDefault()\n",
" }\n",
" })\n",
"\n",
" $(&#x27;#mols2grid .m2g-cell&#x27;).off(&#x27;keyup&#x27;).keyup(function(e) {\n",
" var chkbox = $(this).find(&#x27;input:checkbox&#x27;)[0]\n",
" if (e.which == 13) {\n",
" // ENTER: toggle\n",
" chkbox.checked = !chkbox.checked\n",
" $(chkbox).trigger(&#x27;change&#x27;)\n",
" } else if (e.which == 27 || e.which == 8) {\n",
" // ESC/BACKSPACE: unselect\n",
" chkbox.checked = false\n",
" $(chkbox).trigger(&#x27;change&#x27;)\n",
" } else if (e.which == 37) {\n",
" // LEFT\n",
" $(this).prev().focus()\n",
" } else if (e.which == 39) {\n",
" // RIGHT\n",
" $(this).next().focus()\n",
" } else if (e.which == 38 || e.which == 40) {\n",
" var containerWidth = $(this).parent().outerWidth()\n",
" var cellWidth = $(this).outerWidth() + parseInt($(this).css(&#x27;marginLeft&#x27;)) * 2\n",
" var columns = Math.round(containerWidth / cellWidth)\n",
" var index = $(this).index()\n",
" if (e.which == 38) {\n",
" // UP\n",
" var indexAbove = Math.max(index - columns, 0)\n",
" $(this).parent().children().eq(indexAbove).focus()\n",
" } else if (e.which == 40) {\n",
" // DOWN \n",
" var total = $(this).parent().children().length\n",
" var indexBelow = Math.min(index + columns, total)\n",
" $(this).parent().children().eq(indexBelow).focus()\n",
" }\n",
" }\n",
" })\n",
"}\n",
"\n",
"// Show tooltip when hovering the info icon.\n",
"function initToolTip() {\n",
" $(&#x27;#mols2grid .m2g-info&#x27;).off(&#x27;mouseenter&#x27;).off(&#x27;mouseleave&#x27;).off(&#x27;click&#x27;).mouseenter(function() {\n",
" // Show on enter\n",
" $(this).closest(&#x27;.m2g-cell&#x27;).find(&#x27;.m2g-tooltip[data-toggle=&quot;popover&quot;]&#x27;).popover(&#x27;show&#x27;)\n",
" $(&#x27;body &gt; .popover&#x27;).click(function(e) {\n",
" if ($(e.target).hasClass(&#x27;copy-me&#x27;)) {\n",
" copyOnClick(e.target)\n",
" } else if ($(e.target).is(&#x27;button&#x27;)) {\n",
" \n",
" }\n",
" })\n",
" }).mouseleave(function() {\n",
" // Hide on leave, unless sticky.\n",
" if (!$(this).closest(&#x27;.m2g-cell&#x27;).hasClass(&#x27;m2g-keep-tooltip&#x27;)) {\n",
" $(this).closest(&#x27;.m2g-cell&#x27;).find(&#x27;.m2g-tooltip[data-toggle=&quot;popover&quot;]&#x27;).popover(&#x27;hide&#x27;)\n",
" }\n",
" }).click(function() {\n",
" // Toggle sticky on click.\n",
" $(this).closest(&#x27;.m2g-cell&#x27;).toggleClass(&#x27;m2g-keep-tooltip&#x27;)\n",
"\n",
" // Hide tooltip when sticky was turned off.\n",
" if ($(this).closest(&#x27;.m2g-cell&#x27;).hasClass(&#x27;m2g-keep-tooltip&#x27;)) {\n",
" $(this).closest(&#x27;.m2g-cell&#x27;).find(&#x27;.m2g-tooltip[data-toggle=&quot;popover&quot;]&#x27;).popover(&#x27;show&#x27;)\n",
" } else if (!$(this).closest(&#x27;.m2g-cell&#x27;).hasClass(&#x27;m2g-keep-tooltip&#x27;)) {\n",
" $(this).closest(&#x27;.m2g-cell&#x27;).find(&#x27;.m2g-tooltip[data-toggle=&quot;popover&quot;]&#x27;).popover(&#x27;hide&#x27;)\n",
" }\n",
" })\n",
"}\n",
"\n",
"// Update selection on checkbox click.\n",
"function initCheckbox() {\n",
" $(&quot;input:checkbox&quot;).off(&#x27;change&#x27;).change(function() {\n",
" var _id = parseInt($(this).closest(&quot;.m2g-cell&quot;).attr(&quot;data-mols2grid-id&quot;));\n",
" if (this.checked) {\n",
" var _smiles = $($(this).closest(&quot;.m2g-cell&quot;).children(&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",
"// Callback button\n",
"function onCallbackButtonClick(target) {\n",
" var data = {}\n",
" data[&quot;mols2grid-id&quot;] = parseInt($(target).closest(&quot;.m2g-cell&quot;)\n",
" .attr(&quot;data-mols2grid-id&quot;));\n",
" data[&quot;img&quot;] = $(target).parent().siblings(&quot;.data-img&quot;).eq(0).get(0).innerHTML;\n",
" $(target).parent().siblings(&quot;.data&quot;).not(&quot;.data-img&quot;).each(function() {\n",
" let name = this.className.split(&quot; &quot;)\n",
" .filter(cls =&gt; cls.startsWith(&quot;data-&quot;))[0]\n",
" .substring(5);\n",
" data[name] = this.innerHTML;\n",
" });\n",
"\n",
" \n",
" // Call custom js callback.\n",
" None\n",
" \n",
"}\n",
"\n",
"\n",
"\n",
"/**\n",
" * Actions\n",
" */\n",
"\n",
"// Listen to action dropdown.\n",
"$(&#x27;#mols2grid .m2g-actions select&#x27;).change(function(e) {\n",
" var val = e.target.value\n",
" switch(val) {\n",
" case &#x27;select-all&#x27;:\n",
" selectAll()\n",
" break\n",
" case &#x27;select-matching&#x27;:\n",
" selectMatching()\n",
" break\n",
" case &#x27;unselect-all&#x27;:\n",
" unselectAll()\n",
" break\n",
" case &#x27;invert&#x27;:\n",
" invertSelection()\n",
" break\n",
" case &#x27;copy&#x27;:\n",
" copy()\n",
" break\n",
" case &#x27;save-smiles&#x27;:\n",
" saveSmiles()\n",
" break\n",
" case &#x27;save-csv&#x27;:\n",
" saveCSV()\n",
" break\n",
" }\n",
" $(this).val(&#x27;&#x27;) // Reset dropdown\n",
"})\n",
"\n",
"// Check all.\n",
"function selectAll(e) {\n",
" var _id = [];\n",
" var _smiles = [];\n",
" listObj.items.forEach(function (item) {\n",
" if (item.elm) {\n",
" item.elm.getElementsByTagName(&quot;input&quot;)[0].checked = true;\n",
" } else {\n",
" item.show()\n",
" item.elm.getElementsByTagName(&quot;input&quot;)[0].checked = true;\n",
" item.hide()\n",
" }\n",
" _id.push(item.values()[&quot;mols2grid-id&quot;]);\n",
" _smiles.push(item.values()[&quot;data-SMILES&quot;]);\n",
" });\n",
" add_selection(&quot;default&quot;, _id, _smiles);\n",
"};\n",
"\n",
"\n",
"// Check matching.\n",
"function selectMatching(e) {\n",
" var _id = [];\n",
" var _smiles = [];\n",
" listObj.matchingItems.forEach(function (item) {\n",
" if (item.elm) {\n",
" item.elm.getElementsByTagName(&quot;input&quot;)[0].checked = true;\n",
" } else {\n",
" item.show()\n",
" item.elm.getElementsByTagName(&quot;input&quot;)[0].checked = true;\n",
" item.hide()\n",
" }\n",
" _id.push(item.values()[&quot;mols2grid-id&quot;]);\n",
" _smiles.push(item.values()[&quot;data-SMILES&quot;]);\n",
" });\n",
" add_selection(&quot;default&quot;, _id, _smiles);\n",
"};\n",
"\n",
"// Uncheck all.\n",
"function unselectAll(e) {\n",
" var _id = [];\n",
" listObj.items.forEach(function (item) {\n",
" if (item.elm) {\n",
" item.elm.getElementsByTagName(&quot;input&quot;)[0].checked = false;\n",
" } else {\n",
" item.show()\n",
" item.elm.getElementsByTagName(&quot;input&quot;)[0].checked = false;\n",
" item.hide()\n",
" }\n",
" _id.push(item.values()[&quot;mols2grid-id&quot;]);\n",
" });\n",
" del_selection(&quot;default&quot;, _id);\n",
"};\n",
"\n",
"// Invert selection.\n",
"function invertSelection(e) {\n",
" var _id_add = [];\n",
" var _id_del = [];\n",
" var _smiles = [];\n",
" listObj.items.forEach(function (item) {\n",
" if (item.elm) {\n",
" var chkbox = item.elm.getElementsByTagName(&quot;input&quot;)[0]\n",
" chkbox.checked = !chkbox.checked;\n",
" } else {\n",
" item.show()\n",
" var chkbox = item.elm.getElementsByTagName(&quot;input&quot;)[0]\n",
" chkbox.checked = !chkbox.checked;\n",
" item.hide()\n",
" }\n",
" if (chkbox.checked) {\n",
" _id_add.push(item.values()[&quot;mols2grid-id&quot;]);\n",
" _smiles.push(item.values()[&quot;data-SMILES&quot;]);\n",
" } else {\n",
" _id_del.push(item.values()[&quot;mols2grid-id&quot;]);\n",
" }\n",
" });\n",
" del_selection(&quot;default&quot;, _id_del);\n",
" add_selection(&quot;default&quot;, _id_add, _smiles);\n",
"};\n",
"\n",
"// Copy to clipboard.\n",
"function copy(e) {\n",
" // navigator.clipboard.writeText(SELECTION.to_dict());\n",
" content = _renderCSV(&#x27;\\t&#x27;)\n",
" navigator.clipboard.writeText(content)\n",
"};\n",
"\n",
"// Export smiles.\n",
"function saveSmiles(e) {\n",
" var fileName = &quot;selection.smi&quot;\n",
" if (SELECTION.size) {\n",
" // Download selected smiles\n",
" SELECTION.download_smi(fileName);\n",
" } else {\n",
" // Download all smiles\n",
" SELECTION.download_smi(fileName, listObj.items);\n",
" }\n",
"};\n",
"\n",
"// Export CSV.\n",
"function saveCSV(e) {\n",
" content = _renderCSV(&#x27;;&#x27;)\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",
"\n",
"// Render CSV for export of clipboard.\n",
"function _renderCSV(sep) {\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",
" .filter(name =&gt; name !== &quot;data-img&quot;);\n",
" // Remove &#x27;data-&#x27; and img\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",
" listObj.items.forEach(function (item) {\n",
" let data = item.values();\n",
" let index = data[&quot;mols2grid-id&quot;];\n",
" if (SELECTION.has(index) || SELECTION.size === 0) {\n",
" content += index;\n",
" columns.forEach((key) =&gt; {\n",
" content += sep + data[key];\n",
" })\n",
" content += &quot;\\n&quot;;\n",
" }\n",
" });\n",
" return content\n",
"}\n",
"\n",
"\n",
"// generate images for the currently displayed molecules\n",
"var draw_opts = {&quot;width&quot;: 130, &quot;height&quot;: 90};\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",
" // Searchbar\n",
" function SmartsSearch(query, columns) {\n",
" var smiles_col = columns[0];\n",
" smarts_matches = {};\n",
" var query = $(&#x27;#mols2grid .m2g-searchbar&#x27;).val();\n",
" var qmol = RDKit.get_qmol(query);\n",
" if (qmol.is_valid()) {\n",
" listObj.items.forEach(function (item) {\n",
" var smiles = item.values()[smiles_col]\n",
" var mol = RDKit.get_mol(smiles, &#x27;{&quot;removeHs&quot;: false }&#x27;);\n",
" if (mol.is_valid()) {\n",
" var results = mol.get_substruct_matches(qmol);\n",
" if (results === &quot;\\{\\}&quot;) {\n",
" item.found = false;\n",
" } else {\n",
" item.found = true;\n",
" \n",
" results = JSON.parse(results);\n",
" \n",
" var highlights = {&quot;atoms&quot;: [], &quot;bonds&quot;: []};\n",
" results.forEach(function (match) {\n",
" highlights[&quot;atoms&quot;].push(...match.atoms)\n",
" highlights[&quot;bonds&quot;].push(...match.bonds)\n",
" });\n",
" \n",
" var index = item.values()[&quot;mols2grid-id&quot;];\n",
" smarts_matches[index] = highlights;\n",
" \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",
"// Temporary fix for regex characters being escaped by list.js\n",
"// This extends String.replace to ignore the regex pattern used by list.js and returns\n",
"// the string unmodified. Other calls should not be affected, unless they use the exact\n",
"// same pattern and replacement value.\n",
"// TODO: remove once the issue is fixed in list.js and released\n",
"String.prototype.replace = (function(_super) {\n",
" return function() {\n",
" if (\n",
" (arguments[0].toString() === &#x27;/[-[\\\\]{}()*+?.,\\\\\\\\^$|#]/g&#x27;)\n",
" &amp;&amp; (arguments[1] === &#x27;\\\\$&amp;&#x27;)\n",
" ) {\n",
" if (this.length === 0) {\n",
" return &#x27;&#x27;\n",
" }\n",
" return this\n",
" }\n",
" return _super.apply(this, arguments);\n",
" }; \n",
"})(String.prototype.replace);\n",
"\n",
"// Switch search type (Text or SMARTS)\n",
"$(&#x27;#mols2grid .m2g-search-options .m2g-option&#x27;).click(function() {\n",
" search_type = $(this).text();\n",
" $(&#x27;#mols2grid .m2g-search-options .m2g-option.sel&#x27;).removeClass(&quot;sel&quot;);\n",
" $(this).addClass(&quot;sel&quot;);\n",
"});\n",
"\n",
"// Searchbar update event handler\n",
"$(&#x27;#mols2grid .m2g-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-min_freq&#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, index, template_mol) {\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[index];\n",
" if (highlights) {\n",
" var details = Object.assign({}, draw_opts, highlights);\n",
" details = JSON.stringify(details);\n",
" mol.generate_aligned_coords(template_mol, true);\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;130&quot; height=&quot;90&quot; xmlns=&quot;http://www.w3.org/2000/svg&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 130 90&quot;&gt;&lt;/svg&gt;&#x27;;\n",
" }\n",
" return svg;\n",
"}\n",
"\n",
"// Update images when the list is updated.\n",
"listObj.on(&quot;updated&quot;, function (list) {\n",
" var query = $(&#x27;#mols2grid .m2g-searchbar&#x27;).val();\n",
" var template_mol;\n",
" if (query === &quot;&quot;) {\n",
" smarts_matches = {};\n",
" template_mol = null;\n",
" } else {\n",
" template_mol = RDKit.get_qmol(query);\n",
" template_mol.set_new_coords(true);\n",
" }\n",
" $(&#x27;#mols2grid .m2g-cell&#x27;).each(function() {\n",
" var $t = $(this);\n",
" var smiles = $t.children(&quot;.data-SMILES&quot;).first().text();\n",
" var index = parseInt(this.getAttribute(&quot;data-mols2grid-id&quot;));\n",
" var svg = draw_mol(smiles, index, template_mol);\n",
" $t.children(&quot;.data-img&quot;).html(svg);\n",
" });\n",
" if (template_mol) {\n",
" template_mol.delete();\n",
" }\n",
"});\n",
" \n",
"\n",
" // Trigger update to activate tooltips, draw images, setup callbacks...\n",
" listObj.update();\n",
" \n",
" // Set iframe height to fit content.\n",
" fitIframe(window.frameElement);\n",
"});\n",
" &lt;/script&gt;\n",
"\n",
"\n",
"\n",
"\n",
" &lt;/body&gt;\n",
"&lt;/html&gt;\n",
"\">\n",
"</iframe>"
],
"text/plain": [
"<IPython.core.display.HTML object>"
]
},
"execution_count": 9,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"df_odd = df.query('min_freq >= 0 and min_freq < 5')\n",
"mols2grid.display(df_odd.sort_values(\"min_freq\"),subset=[\"img\",\"min_freq\"])"
]
},
{
"cell_type": "code",
"execution_count": 10,
"id": "ab02b746",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"15.4% of molecules contain odd ring systems\n"
]
}
],
"source": [
"print(f\"{len(df_odd)/len(df)*100:.1f}% of molecules contain odd ring systems\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "21a3d699",
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3 (ipykernel)",
"language": "python",
"name": "python3"
},
"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.11.3"
}
},
"nbformat": 4,
"nbformat_minor": 5
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment