{"id":12212,"date":"2025-01-14T19:01:33","date_gmt":"2025-01-14T19:01:33","guid":{"rendered":"https:\/\/www.blopig.com\/blog\/?p=12212"},"modified":"2025-01-14T19:13:26","modified_gmt":"2025-01-14T19:13:26","slug":"molecule-networks-data-visualization-using-pyvis","status":"publish","type":"post","link":"https:\/\/www.blopig.com\/blog\/2025\/01\/molecule-networks-data-visualization-using-pyvis\/","title":{"rendered":"Molecule Networks: data visualization using PyVis"},"content":{"rendered":"\n<p class=\"wp-block-paragraph\">Over the past few years I have explored different data visualization strategies with the goal of rapidly communicating information to medicinal chemists. I have recently fallen in love with &#8220;molecule networks&#8221; as an intuitive and interactive data visualization strategy. This blog gives a brief tutorial on how to start generating your own molecule networks. <\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><a href=\"https:\/\/i0.wp.com\/www.blopig.com\/blog\/wp-content\/uploads\/2025\/01\/image-3.png?ssl=1\"><img data-recalc-dims=\"1\" decoding=\"async\" width=\"625\" height=\"295\" loading=\"lazy\" src=\"https:\/\/i0.wp.com\/www.blopig.com\/blog\/wp-content\/uploads\/2025\/01\/image-3.png?resize=625%2C295&#038;ssl=1\" alt=\"\" class=\"wp-image-12215\" srcset=\"https:\/\/i0.wp.com\/www.blopig.com\/blog\/wp-content\/uploads\/2025\/01\/image-3.png?resize=1024%2C484&amp;ssl=1 1024w, https:\/\/i0.wp.com\/www.blopig.com\/blog\/wp-content\/uploads\/2025\/01\/image-3.png?resize=300%2C142&amp;ssl=1 300w, https:\/\/i0.wp.com\/www.blopig.com\/blog\/wp-content\/uploads\/2025\/01\/image-3.png?resize=768%2C363&amp;ssl=1 768w, https:\/\/i0.wp.com\/www.blopig.com\/blog\/wp-content\/uploads\/2025\/01\/image-3.png?resize=1536%2C726&amp;ssl=1 1536w, https:\/\/i0.wp.com\/www.blopig.com\/blog\/wp-content\/uploads\/2025\/01\/image-3.png?resize=624%2C295&amp;ssl=1 624w, https:\/\/i0.wp.com\/www.blopig.com\/blog\/wp-content\/uploads\/2025\/01\/image-3.png?w=1623&amp;ssl=1 1623w, https:\/\/i0.wp.com\/www.blopig.com\/blog\/wp-content\/uploads\/2025\/01\/image-3.png?w=1250&amp;ssl=1 1250w\" sizes=\"auto, (max-width: 625px) 100vw, 625px\" \/><\/a><\/figure>\n\n\n\n<!--more-->\n\n\n\n<h2 class=\"wp-block-heading\">Visualizing one molecule<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">To generate the networks I use <a href=\"https:\/\/pyvis.readthedocs.io\/en\/latest\/documentation.html\">PyVis<\/a>. The package is simple to use, and they have a <a href=\"https:\/\/pyvis.readthedocs.io\/en\/latest\/tutorial.html\">great tutorial<\/a>. There&#8217;s only two steps to generating a network: add some nodes, then add some edges. <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">To add a node containing a molecule, use the code below. Here I have written the function <code><code data-enlighter-language=\"python\" class=\"EnlighterJSRAW\">generate_molecule_image()<\/code><\/code> which takes an RDKit molecule and creates an image. A node can then be defined using <code data-enlighter-language=\"python\" class=\"EnlighterJSRAW\">net.add_node(node_id,shape=\"circularImage\", image=image_path)<\/code>. Then just visualize the network using <code><code data-enlighter-language=\"python\" class=\"EnlighterJSRAW\">net.show()<\/code><\/code>. <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">There are multiple keyword arguments that can be passed in to change the appearance of nodes. We will see more in the rest of this post, but the first two I share are <code>label<\/code> (text displayed under the node), and <code>title<\/code> (text displayed when you hover your mouse over the node)<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><em>Note: Sometimes molecules are not visualized in Jupyter notebook. If you have a network in Jupyter which shows nodes but no molecules, try opening the .html in a browser. <\/em><\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"python\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">import pandas as pd\nimport numpy as np\nimport base64\nfrom PIL import Image\nfrom pyvis.network import Network\n\nfrom rdkit import Chem\nfrom rdkit.Chem.Draw import rdMolDraw2D\nfrom rdkit.Chem.rdRGroupDecomposition import RGroupDecompose\nfrom rdkit.Chem import rdRGroupDecomposition\nfrom rdkit import RDLogger\nRDLogger.DisableLog('rdApp.*')\n\n\n# Function to generate a molecule image as a base64 string\ndef generate_molecule_image(mol):\n    drawer = rdMolDraw2D.MolDraw2DCairo(300, 300)  # Image size (300x300)\n    rdMolDraw2D.PrepareAndDrawMolecule(drawer, mol)\n    drawer.FinishDrawing()\n    image_data = drawer.GetDrawingText()\n    return base64.b64encode(image_data).decode(\"utf-8\")\n\n# Create a PyVis network\nnet = Network(notebook=True)\n\n# Load RDKit molecule\nsmiles = \"CCCC1=NN(C2=C1N=C(NC2=O)C3=C(C=CC(=C3)S(=O)(=O)N4CCN(CC4)C)OCC)C\"\nmol = Chem.MolFromSmiles(smiles)\n\n# Generate image of molecule\nmol_image_base64 = generate_molecule_image(mol)\n\n# Add node to network\n# - Image is added using shape=\"circularImage\" or shape=\"image\"\nnet.add_node(1, \n             label=\"My molecule\", \n             title=\"More information\", \n             shape=\"circularImage\", \n             image=f\"data:image\/png;base64,{mol_image_base64}\")\n\n# Visualize the network\nnet.show(\"single_molecule_network.html\")<\/pre>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter is-resized\"><img data-recalc-dims=\"1\" decoding=\"async\" width=\"490\" height=\"460\" loading=\"lazy\" src=\"https:\/\/i0.wp.com\/www.blopig.com\/blog\/wp-content\/uploads\/2025\/01\/image-2.png?resize=490%2C460&#038;ssl=1\" alt=\"\" class=\"wp-image-12207\" style=\"width:230px;height:auto\" srcset=\"https:\/\/i0.wp.com\/www.blopig.com\/blog\/wp-content\/uploads\/2025\/01\/image-2.png?w=490&amp;ssl=1 490w, https:\/\/i0.wp.com\/www.blopig.com\/blog\/wp-content\/uploads\/2025\/01\/image-2.png?resize=300%2C282&amp;ssl=1 300w\" sizes=\"auto, (max-width: 490px) 100vw, 490px\" \/><\/figure>\n<\/div>\n\n\n<h1 class=\"wp-block-heading\">Adding an edge<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">An edge is defined between two nodes by using <code data-enlighter-language=\"python\" class=\"EnlighterJSRAW\">net.add_edge(from_node_id, to_node_id)<\/code>. In the example below I have created two nodes with indexes 1 and 2 respectively, and added an edge between them using <code data-enlighter-language=\"python\" class=\"EnlighterJSRAW\">net.add_edge(1, 2)<\/code>. <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Some more customization options: Nodes can be customized with <code>color<\/code> (set color of node), and <code>borderWidth<\/code> (border thickness of the node). Edges can be customized with <code>label<\/code> (text shown on edge), <code>title<\/code> (text shown when hovering), and <code>color<\/code> (color of edge). <\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><em>More customization options exist, please see <a href=\"https:\/\/pyvis.readthedocs.io\/en\/latest\/documentation.html\">PyVis documentation<\/a>.<\/em><\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"python\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\"># Create a PyVis network\nnet = Network(height=\"800px\", width=\"1200px\", notebook=True)\n\n# Load RDKit molecules\nsmiles1 = \"CCCC1=NN(C2=C1N=C(NC2=O)C3=C(C=CC(=C3)S(=O)(=O)N4CCN(CC4)C)OCC)C\"\nsmiles2 = \"CN1CC(=O)N2[C@@H](C1=O)CC3=C([C@H]2C4=CC5=C(C=C4)OCO5)NC6=CC=CC=C36\"\nmol1 = Chem.MolFromSmiles(smiles1)\nmol2 = Chem.MolFromSmiles(smiles2)\n\n# Generate images of molecules\nmol1_image_base64 = generate_molecule_image(mol1)\nmol2_image_base64 = generate_molecule_image(mol2)\n\n# Add molecules to network\n# - In this network molecules are indexed by indices 1 and 2. Index can also be a string.\nnet.add_node(1, \n             label=\"Sildenafil\", \n             title=\"Potency = XXX\", \n             shape=\"circularImage\", \n             image=f\"data:image\/png;base64,{mol1_image_base64}\", \n             color=\"red\", \n             borderWidth=3)\n\nnet.add_node(2, \n             label=\"Tadalafil\", \n             title=\"Potency = YYY\", \n             shape=\"circularImage\", \n             image=f\"data:image\/png;base64,{mol2_image_base64}\", \n             color=\"blue\", \n             borderWidth=3)\n\n# Make edge between molecules\n# - Edge is formed between nodes of index 1 and 2.\nnet.add_edge(1, 2, label=\"PDE5\", title=\"Protein target\", color=\"purple\")\n\n# Visualize the network\nnet.show(\"two_molecule_network.html\")<\/pre>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-large is-resized\"><a href=\"https:\/\/i0.wp.com\/www.blopig.com\/blog\/wp-content\/uploads\/2025\/01\/image-4.png?ssl=1\"><img data-recalc-dims=\"1\" decoding=\"async\" width=\"625\" height=\"291\" loading=\"lazy\" src=\"https:\/\/i0.wp.com\/www.blopig.com\/blog\/wp-content\/uploads\/2025\/01\/image-4.png?resize=625%2C291&#038;ssl=1\" alt=\"\" class=\"wp-image-12217\" style=\"width:458px;height:auto\" srcset=\"https:\/\/i0.wp.com\/www.blopig.com\/blog\/wp-content\/uploads\/2025\/01\/image-4.png?resize=1024%2C477&amp;ssl=1 1024w, https:\/\/i0.wp.com\/www.blopig.com\/blog\/wp-content\/uploads\/2025\/01\/image-4.png?resize=300%2C140&amp;ssl=1 300w, https:\/\/i0.wp.com\/www.blopig.com\/blog\/wp-content\/uploads\/2025\/01\/image-4.png?resize=768%2C358&amp;ssl=1 768w, https:\/\/i0.wp.com\/www.blopig.com\/blog\/wp-content\/uploads\/2025\/01\/image-4.png?resize=624%2C291&amp;ssl=1 624w, https:\/\/i0.wp.com\/www.blopig.com\/blog\/wp-content\/uploads\/2025\/01\/image-4.png?w=1033&amp;ssl=1 1033w\" sizes=\"auto, (max-width: 625px) 100vw, 625px\" \/><\/a><\/figure>\n<\/div>\n\n\n<h1 class=\"wp-block-heading\">Visualizing set of elaborations and color by score<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">Now that we can add nodes and edges, all that is left is to automatically generate some networks. In this example I have defined an arbitrary core smiles, a list of possible R group, and a list of random scores. <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">To generate the network I loop through each R group, add a node to the network, and add an edge to my core molecule. Here I introduce my simple function <code data-enlighter-language=\"python\" class=\"EnlighterJSRAW\">get_color() <\/code> which maps a value to a color according to a heat map. For each R group in my network I color code the node using this score. You can imagine this can be used for visualizing potency or other molecular properties. <\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"python\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">import random\nimport matplotlib.pyplot as plt\nimport matplotlib.colors as mcolors\n\n# Function to map a score to a heatmap color\ndef get_color(score, vmin=-1, vmax=1):\n    cmap = plt.cm.coolwarm  # Use a heatmap color map\n    norm = mcolors.Normalize(vmin=vmin, vmax=vmax)  # Normalize scores between 0 and 1\n    rgba = cmap(norm(score))\n    hex_color = mcolors.rgb2hex(rgba)  # Convert RGBA to hex color\n    return hex_color\n    \n\n# Molecule data\ncore_smiles = \"C1=NN(C2=C1N=C(NC2=O)C3=C(C=CC(=C3)[*:1]))C\"\nr_group_smiles = [\"*C\",\"*O\",\"*C(=O)N\",\"*c1nocc1\",\"*C(F)(F)F\",\"*c1ccncc1\",\"*OCC\",]\nscores = [random.uniform(-1, 1) for s in r_group_smiles]\n\n# Create a PyVis network and add the node with the molecule image\nnet = Network(height=\"700px\", width=\"1000px\", notebook=True)\n\n# Add Core molecule to network\ncore_mol = Chem.MolFromSmiles(core_smiles)\nmol_image_base64 = generate_molecule_image(core_mol)\nnet.add_node(\"Core\", label=\"Core\", title=\"Core\", shape=\"circularImage\", image=f\"data:image\/png;base64,{mol_image_base64}\")\n\n# --- Add R groups ---\nfor idx, (smiles, score) in enumerate(zip(r_group_smiles, scores)):\n    r_mol = Chem.MolFromSmiles(smiles)\n    color = get_color(score)\n    \n    mol_image_base64 = generate_molecule_image(r_mol)\n    net.add_node(smiles, label=\"\", title=smiles, shape=\"circularImage\", image=f\"data:image\/png;base64,{mol_image_base64}\", color=color, borderWidth=3)\n    net.add_edge(smiles, \"Core\", width=3)\n\n# Visualize the graph\nnet.show(\"elaboration_network.html\")<\/pre>\n\n\n\n<figure class=\"wp-block-image size-full\"><a href=\"https:\/\/i0.wp.com\/www.blopig.com\/blog\/wp-content\/uploads\/2025\/01\/image-8.png?ssl=1\"><img data-recalc-dims=\"1\" decoding=\"async\" width=\"625\" height=\"595\" loading=\"lazy\" src=\"https:\/\/i0.wp.com\/www.blopig.com\/blog\/wp-content\/uploads\/2025\/01\/image-8.png?resize=625%2C595&#038;ssl=1\" alt=\"\" class=\"wp-image-12222\" srcset=\"https:\/\/i0.wp.com\/www.blopig.com\/blog\/wp-content\/uploads\/2025\/01\/image-8.png?w=676&amp;ssl=1 676w, https:\/\/i0.wp.com\/www.blopig.com\/blog\/wp-content\/uploads\/2025\/01\/image-8.png?resize=300%2C286&amp;ssl=1 300w, https:\/\/i0.wp.com\/www.blopig.com\/blog\/wp-content\/uploads\/2025\/01\/image-8.png?resize=624%2C594&amp;ssl=1 624w\" sizes=\"auto, (max-width: 625px) 100vw, 625px\" \/><\/a><\/figure>\n\n\n\n<h1 class=\"wp-block-heading\">Visualizing Free Wilson coefficients<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">Finally, I want to show a more complex example to demonstrate a possible use case for this visualization. Here I run the beginning of a Free Wilson analysis (a classic cheminformatics analysis that everyone should know). I have taken the analysis code and example directly from <a href=\"https:\/\/github.com\/PatWalters\/practical_cheminformatics_tutorials\">Pat Walters&#8217; tutorial<\/a>. For those not familiar with this method, we take a set of ligands which all share a core, decompose all the R groups, then run a simple regression model to predict which combination of R group would lead to optimal properties. <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">In this case I have run only the first half of the analysis which runs the regressions and generates R groups along with their coefficients describing how positively they contribute to potency (a larger positive coefficient is better). <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">I use the molecule network to visualize all R groups explored in this analysis. I have added two layers to my network: the first isolates the vector on the core, and the second shows all R groups elaborated at this position. The R groups are color coded by their contribution to potency, with dark red being more favorable and dark blue being least favorable R groups. <\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><a href=\"https:\/\/i0.wp.com\/www.blopig.com\/blog\/wp-content\/uploads\/2025\/01\/image-7.png?ssl=1\"><img data-recalc-dims=\"1\" decoding=\"async\" width=\"450\" height=\"150\" loading=\"lazy\" src=\"https:\/\/i0.wp.com\/www.blopig.com\/blog\/wp-content\/uploads\/2025\/01\/image-7.png?resize=450%2C150&#038;ssl=1\" alt=\"\" class=\"wp-image-12220\" srcset=\"https:\/\/i0.wp.com\/www.blopig.com\/blog\/wp-content\/uploads\/2025\/01\/image-7.png?w=450&amp;ssl=1 450w, https:\/\/i0.wp.com\/www.blopig.com\/blog\/wp-content\/uploads\/2025\/01\/image-7.png?resize=300%2C100&amp;ssl=1 300w\" sizes=\"auto, (max-width: 450px) 100vw, 450px\" \/><\/a><\/figure>\n<\/div>\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"python\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">\n#------------ Do free wilson calculation --------------\n# I only run the first half of the calculation which obtained coefficients for each R group\n# The second part involves enumerating combinations of R group to identify promising combinations\n# This section of code is taken from Pat Walters' Free Wilson Analysis\n# https:\/\/practicalcheminformatics.blogspot.com\/2018\/05\/free-wilson-analysis.html\n# https:\/\/github.com\/PatWalters\/practical_cheminformatics_tutorials\n# https:\/\/colab.research.google.com\/github\/PatWalters\/practical_cheminformatics_tutorials\/blob\/main\/sar_analysis\/free_wilson.ipynb\n\nfrom sklearn.preprocessing import OneHotEncoder\nfrom sklearn.linear_model import Ridge\n\n# Get dataset from Pat Walters\ninput_filename = \"https:\/\/raw.githubusercontent.com\/PatWalters\/practical_cheminformatics_tutorials\/main\/data\/CHEMBL313_sel.smi\"\ndf = pd.read_csv(input_filename)\ndf['mol'] = df.SMILES.apply(Chem.MolFromSmiles)\n\n# Define core molecule\ncore_smiles = \"c1ccc(C2CC3CCC(C2)N3)cc1\"\ncore_mol = Chem.MolFromSmiles(core_smiles)\n\n# Run R group decomposition and construct DataFrame\nps = rdRGroupDecomposition.RGroupDecompositionParameters()\nps.allowMultipleRGroupsOnUnlabelled = True\nmatch, miss = RGroupDecompose(core_mol,df.mol.values,asSmiles=True, options=ps)\nrgroup_df = pd.DataFrame(match)\ncore_df = pd.DataFrame({\"mol\" : [Chem.MolFromSmiles(x) for x in rgroup_df.Core.unique()]})\n\n# Get unique R groups\nunique_list = []\nprint(\"Total unique R groups\")\nfor r in rgroup_df.columns[1:]:\n    num_rgroups = len(rgroup_df[r].unique())\n    print(f\" {r} {num_rgroups}\")\n    unique_list.append(rgroup_df[r].unique())\n\n# Featurise and run ridge regression\nenc = OneHotEncoder(categories=unique_list,sparse_output=False)\none_hot_mat = enc.fit_transform(rgroup_df.values[:,1:])\nridge = Ridge()\nridge.fit(one_hot_mat,df.pIC50)\n\n# Extract data from regression\nrg_df_dict = {}\nstart = 0\nrgroup_names = rgroup_df.columns[1:]\nfor rg,name in zip(enc.categories_,rgroup_names):\n    rg_mol_list = [Chem.MolFromSmiles(x) for x in rg]\n    coef_list = ridge.coef_[start:start+len(rg)]\n    start += len(rg)\n    rg_df = pd.DataFrame({\"smiles\":rg, \"mol\": rg_mol_list, \"coef\": coef_list})\n    rg_df.sort_values(\"coef\",inplace=True)\n    rg_df_dict[name] = rg_df\n\n\n# ----------- Visualising coefficients as Graph-------------------\n# Initalise network\nnet = Network(height=\"1000px\", width=\"1900px\", notebook=True)\n\n# Add core molecule node\ncore_image_base64 = generate_molecule_image(core_df.iloc[0][\"mol\"])\nnet.add_node(\"Core\", label=\"Core\", title=\"Core\", shape=\"circularImage\", image=f\"data:image\/png;base64,{core_image_base64}\", borderWidth=3, color=\"grey\")\n\nfor r in rg_df_dict:\n    net.add_node(r, label=r, title=r, color=\"grey\")\n    net.add_edge(\"Core\", r, width=3, color=\"grey\", label=r)  # Connect core to vector\n\n    for index, row in rg_df_dict[r].iterrows():       \n        node_id = f\"{row['smiles']}\"\n        score = row['coef']\n        score_string = str(round(score, 3))\n        color = get_color(score)\n        mol_image = generate_molecule_image(row[\"mol\"])\n        \n        net.add_node(node_id,\n                     label=score_string,\n                     title=node_id,\n                     shape=\"circularImage\",\n                     image=f\"data:image\/png;base64,{mol_image}\",\n                     borderWidth=3,\n                     color=color)\n\n        net.add_edge(r, node_id, width=3, color=color)  # Connect core to vector\n        \nnet.show(\"free_wilson_coefficient_network.html\")<\/pre>\n\n\n\n<figure class=\"wp-block-image size-full\"><a href=\"https:\/\/i0.wp.com\/www.blopig.com\/blog\/wp-content\/uploads\/2025\/01\/image-5.png?ssl=1\"><img data-recalc-dims=\"1\" decoding=\"async\" width=\"625\" height=\"531\" loading=\"lazy\" src=\"https:\/\/i0.wp.com\/www.blopig.com\/blog\/wp-content\/uploads\/2025\/01\/image-5.png?resize=625%2C531&#038;ssl=1\" alt=\"\" class=\"wp-image-12218\" srcset=\"https:\/\/i0.wp.com\/www.blopig.com\/blog\/wp-content\/uploads\/2025\/01\/image-5.png?w=996&amp;ssl=1 996w, https:\/\/i0.wp.com\/www.blopig.com\/blog\/wp-content\/uploads\/2025\/01\/image-5.png?resize=300%2C255&amp;ssl=1 300w, https:\/\/i0.wp.com\/www.blopig.com\/blog\/wp-content\/uploads\/2025\/01\/image-5.png?resize=768%2C652&amp;ssl=1 768w, https:\/\/i0.wp.com\/www.blopig.com\/blog\/wp-content\/uploads\/2025\/01\/image-5.png?resize=624%2C530&amp;ssl=1 624w\" sizes=\"auto, (max-width: 625px) 100vw, 625px\" \/><\/a><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">If you run this method yourself, the generated networks will be interactive. In this case I have moved around the nodes so that they are arranged by score. You can also quickly see that the most favorable group in the R3 position is the ester, and second most favorable is isoxazole. You can also see an interesting insight that adding any methyl groups to the isoxazole appears unfavorable.  <\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><a href=\"https:\/\/i0.wp.com\/www.blopig.com\/blog\/wp-content\/uploads\/2025\/01\/image-6.png?ssl=1\"><img data-recalc-dims=\"1\" decoding=\"async\" width=\"625\" height=\"547\" loading=\"lazy\" src=\"https:\/\/i0.wp.com\/www.blopig.com\/blog\/wp-content\/uploads\/2025\/01\/image-6.png?resize=625%2C547&#038;ssl=1\" alt=\"\" class=\"wp-image-12219\" srcset=\"https:\/\/i0.wp.com\/www.blopig.com\/blog\/wp-content\/uploads\/2025\/01\/image-6.png?resize=1024%2C896&amp;ssl=1 1024w, https:\/\/i0.wp.com\/www.blopig.com\/blog\/wp-content\/uploads\/2025\/01\/image-6.png?resize=300%2C262&amp;ssl=1 300w, https:\/\/i0.wp.com\/www.blopig.com\/blog\/wp-content\/uploads\/2025\/01\/image-6.png?resize=768%2C672&amp;ssl=1 768w, https:\/\/i0.wp.com\/www.blopig.com\/blog\/wp-content\/uploads\/2025\/01\/image-6.png?resize=624%2C546&amp;ssl=1 624w, https:\/\/i0.wp.com\/www.blopig.com\/blog\/wp-content\/uploads\/2025\/01\/image-6.png?w=1047&amp;ssl=1 1047w\" sizes=\"auto, (max-width: 625px) 100vw, 625px\" \/><\/a><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">This is only one small example of what this network visualization can do. I have used this method for making SAR visualization tools, and the paper <a href=\"https:\/\/pubs.acs.org\/doi\/10.1021\/acs.jcim.0c00296\">rdScaffoldNetwork: The Scaffold Network Implementation in RDKit<\/a> used PyVis for visualizing scaffold networks. <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Happy networking!<br>&#8211; Nicholas Runcie<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Over the past few years I have explored different data visualization strategies with the goal of rapidly communicating information to medicinal chemists. I have recently fallen in love with &#8220;molecule networks&#8221; as an intuitive and interactive data visualization strategy. This blog gives a brief tutorial on how to start generating your own molecule networks.<\/p>\n","protected":false},"author":133,"featured_media":0,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"nf_dc_page":"","wikipediapreview_detectlinks":true,"_monsterinsights_skip_tracking":false,"_monsterinsights_sitenote_active":false,"_monsterinsights_sitenote_note":"","_monsterinsights_sitenote_category":0,"ngg_post_thumbnail":0,"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_feature_clip_id":0,"_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_post_was_ever_published":false},"categories":[187,29,621,188,227,201],"tags":[130,129,134],"ppma_author":[830],"class_list":["post-12212","post","type-post","status-publish","format-standard","hentry","category-cheminformatics","category-code","category-data-visualization","category-networks","category-python-code","category-small-molecules","tag-cheminformatics","tag-rdkit","tag-small-molecules"],"jetpack_featured_media_url":"","jetpack_sharing_enabled":true,"authors":[{"term_id":830,"user_id":133,"is_guest":0,"slug":"nicholas","display_name":"Nicholas Runcie","avatar_url":"https:\/\/secure.gravatar.com\/avatar\/0e750509b2d35cd15a7d1a304722cab7dd4601643e63e604b835d0b3ea14a45a?s=96&d=mm&r=g","author_category":"","user_url":"","last_name":"Runcie","first_name":"Nicholas","job_title":"","description":""}],"_links":{"self":[{"href":"https:\/\/www.blopig.com\/blog\/wp-json\/wp\/v2\/posts\/12212","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.blopig.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.blopig.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.blopig.com\/blog\/wp-json\/wp\/v2\/users\/133"}],"replies":[{"embeddable":true,"href":"https:\/\/www.blopig.com\/blog\/wp-json\/wp\/v2\/comments?post=12212"}],"version-history":[{"count":5,"href":"https:\/\/www.blopig.com\/blog\/wp-json\/wp\/v2\/posts\/12212\/revisions"}],"predecessor-version":[{"id":12246,"href":"https:\/\/www.blopig.com\/blog\/wp-json\/wp\/v2\/posts\/12212\/revisions\/12246"}],"wp:attachment":[{"href":"https:\/\/www.blopig.com\/blog\/wp-json\/wp\/v2\/media?parent=12212"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.blopig.com\/blog\/wp-json\/wp\/v2\/categories?post=12212"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.blopig.com\/blog\/wp-json\/wp\/v2\/tags?post=12212"},{"taxonomy":"author","embeddable":true,"href":"https:\/\/www.blopig.com\/blog\/wp-json\/wp\/v2\/ppma_author?post=12212"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}