I have around 1000 SMILES entries in Excel and I have to generate .sdf
file for all. Is there any way to automate this whole process, preferably with an offline tool?
3 Answers
Working with this many SMILES you should consider to have a look at Open Babel, both, because it may transcribe many chemistry relevant formats as well as extract and filter information from them. This being said, you have at least two options:
One time use, preferentially with shorter lists to convert: Use Open Babel's GUI which equally is freely available. On the left hand side, select the input format as
.smi
and that you would like to paste the SMILES, rather than to read them from a file. Select on the right hand column the export format and enter the directory where your permanent.sdf
shall be written. Helpful for a human is to add the option (center column) "Append output index to title" as a counter, and highly recommended for future work with the.sdf
to activate "Generate 3D coordinates" a bit lower in this column, too.Depending on the operational system at your disposition, Open Babel has multiple interfaces to languages like Python. Let us assume you saved your data in the
.xlsx
format (e.g., Excel, LibreOffice Calc or gnumeric) in the second column of your spreadsheet:Even without entering into the inner tools of Open Babel, you then may already benefit from a module like
openpyxl
to access the SMILES directly, relaying them to Open Babel, e.g.# name: reader.py import openpyxl import subprocess as sub import sys try: source_file = sys.argv[1] workbook = openpyxl.load_workbook(source_file) sheet = workbook['Sheet1'] except: print("Call the script on the CLI by 'python reader.py [my_data.xlsx]'.") sys.exit() def reading(): """ retrieve the SMILES from the .xlsx """ global smiles_collector smiles_collector = "" for cell in sheet['B']: smiles_collector += str('-:"') + str(cell.value) + str('" ') def writing(): """ provide a container .sdf """ reading() conversion = str("obabel {} -osdf > output.sdf --gen3d".format(smiles_collector)) sub.call(conversion, shell=True) reading() writing() sys.exit()
Datawarrior lets you do it. Export a csv sheet with two columns: The name of the compound and its SMILES code. Be sure to use a comma as a delimiter. Your output file, opened with a text editor, should look like this:
Name,SMILES
Hexazine,n1nnnnn1
Furazan,c1nonc1
Benzisoxazole,c1noc2c1cccc2
From DataWarrior, File>Open and open your file. Structures are automatically generated from SMILES codes.
Then, File>Save Special>SD-File, and you are done.
I think there are two common ways to complete this task which are OpenBabel and RDKit.
You can use this scripts to convert multiple smiles from csv file (a format is saved as in Excel).
import subprocess
import pandas as pd
from rdkit import Chem
def convert_with_openbabel(smiles, output_file):
"""Convert SMILES to SDF using OpenBabel."""
try:
# Use subprocess to call OpenBabel
command = f'echo "{smiles}" | obabel -ismi -O {output_file}'
subprocess.run(command, shell=True, check=True)
print(f"Successfully converted using OpenBabel. Output saved to {output_file}")
except subprocess.CalledProcessError:
print("Error occurred while converting with OpenBabel.")
def convert_with_rdkit(smiles, output_file):
"""Convert SMILES to SDF using RDKit."""
try:
mol = Chem.MolFromSmiles(smiles)
if mol:
with Chem.SDWriter(output_file) as writer:
writer.write(mol)
print(f"Successfully converted using RDKit. Output saved to {output_file}")
else:
print(f"Invalid SMILES string provided: {smiles}")
except Exception as e:
print(f"Error occurred while converting with RDKit: {e}")
def main():
# Get the CSV file name from user input
csv_file = input("Enter the CSV file name (e.g., smiles.csv): ")
output_directory = input("Enter the output SDF file name prefix (e.g., output_): ")
# Read SMILES from the CSV file
try:
df = pd.read_csv(csv_file)
except Exception as e:
print(f"Error reading CSV file: {e}")
return
# Check if the necessary column with SMILES exists
if 'SMILES' not in df.columns:
print("CSV file must contain a 'SMILES' column.")
return
print("Choose the conversion method:")
print("1. OpenBabel")
print("2. RDKit")
choice = input("Enter 1 or 2: ")
for index, row in df.iterrows():
smiles = row['SMILES']
output_file = f"{output_directory}{index}.sdf" # Use index for unique output files
if choice == '1':
convert_with_openbabel(smiles, output_file)
elif choice == '2':
convert_with_rdkit(smiles, output_file)
else:
print("Invalid choice. Please select 1 or 2.")
break
if __name__ == "__main__":
main()
Instructions
Install Dependencies:
Make sure you have OpenBabel and RDKit installed. You can install OpenBabel via conda or from the OpenBabel website. Install pybel if you haven't already
pip install pybel
Install RDKit using conda:
conda install -c conda-forge rdkit
Prepare Your CSV File:
Create a CSV file with a column named SMILES. For example:
SMILES
C1=CC=CC=C1
CC(=O)Oc1ccccc1C(=O)O
C1CCCCC1
Run the Script:
Save the script to a file, e.g., convert_smiles_from_csv.py. Run the script in your terminal:
python convert_smiles_from_csv.py