ChEBI, offline: ChebiSDF¶
ChEBI publishes its whole database as one SD file, about 190,000 compounds
with structures, names, synonyms, CAS numbers and links to other databases.
ChebiSDF reads that file through an index, so a lookup takes milliseconds
and needs no network.
The file is one of the datasets Search uses. Install it with
datasets.fetch("chebi") (955 MiB); see
Installing the offline databases. The first time
it is opened, the index is built and saved beside the file, which takes a few
seconds. After that, opening it is quick.
For what the file does not carry, such as the ontology, roles and citations, use the web service; see the ChEBI tutorial.
The outputs below were produced on 2026-09-23.
import os
os.environ["TQDM_DISABLE"] = "1" # no progress bars on this page
import pandas as pd
from provesid import ChebiSDF
pd.set_option("display.width", 200)
pd.set_option("display.max_colwidth", 60)
chebi = ChebiSDF()
chebi.get_database_stats()
{'total_compounds': 192479,
'compounds_with_inchikey': 179842,
'compounds_with_inchi': 179843,
'compounds_with_cas': 28914,
'unique_formulas': 61148,
'indexed_names': 192476,
'indexed_synonyms': 215580}
A record¶
A record is a dict of the SD file's fields, all as strings:
caffeine = chebi.get_compound_by_id("CHEBI:27732")
{key: caffeine[key] for key in ("ChEBI ID", "ChEBI NAME", "FORMULA", "MASS", "SMILES",
"INCHIKEY", "STAR", "CAS Registry Numbers")}
{'ChEBI ID': 'CHEBI:27732',
'ChEBI NAME': 'caffeine',
'FORMULA': 'C8H10N4O2',
'MASS': '194.194',
'SMILES': 'Cn1c(=O)c2c(ncn2C)n(C)c1=O',
'INCHIKEY': 'RYYVLZVUVIJVGH-UHFFFAOYSA-N',
'STAR': '3',
'CAS Registry Numbers': '58-08-2'}
Fields with several values, such as synonyms and database links, are joined
with ;:
caffeine["SYNONYM"].split(";")[:8]
['CAFFEINE', 'Thein', '7-methyltheophylline', 'cafeine', 'mateina', 'cafeina', '3,7-Dihydro-1,3,7-trimethyl-1H-purin-2,6-dion', 'caffeine']
links = {key: value for key, value in caffeine.items() if key.endswith("Database Links")}
print(len(links), "databases linked, for example:")
{key: links[key][:60] for key in ["PubChem Compound Database Links", "ChEMBL Database Links",
"CompTox Database Links", "DrugBank Database Links"]}
32 databases linked, for example:
{'PubChem Compound Database Links': '2519',
'ChEMBL Database Links': 'CHEMBL113',
'CompTox Database Links': 'DTXSID0020232',
'DrugBank Database Links': 'DB00201'}
Lookups¶
Every identifier the file carries has a lookup. The ones that can match several compounds return a list:
def show(records):
return [(r["ChEBI ID"], r["ChEBI NAME"]) for r in records]
print("CAS 58-08-2: ", show(chebi.search_by_cas("58-08-2")))
print("synonym 'aspirin': ", show(chebi.search_by_synonym("aspirin")))
print("formula H2O: ", show(chebi.search_by_formula("H2O")))
print("InChIKey: ", chebi.search_by_inchikey("RYYVLZVUVIJVGH-UHFFFAOYSA-N")["ChEBI NAME"])
CAS 58-08-2: [('CHEBI:27732', 'caffeine')]
synonym 'aspirin': [('CHEBI:15365', 'acetylsalicylic acid')]
formula H2O: [('CHEBI:15377', 'water'), ('CHEBI:29375', 'diprotium oxide')]
InChIKey: caffeine
Name and synonym searches ignore case. They match whole names by default, and
exact=False matches any name containing the text:
print("exact 'ethanol': ", show(chebi.search_by_name("ethanol")))
partial = chebi.search_by_name("caffeine", exact=False)
print(len(partial), "names contain 'caffeine', for example", show(partial[:4]))
exact 'ethanol': [('CHEBI:16236', 'ethanol')]
8 names contain 'caffeine', for example [('CHEBI:27732', 'caffeine'), ('CHEBI:31332', 'caffeine monohydrate'), ('CHEBI:32140', 'sodium caffeine benzoate'), ('CHEBI:53115', '8-(3-chlorostyryl)caffeine')]
What is not in the file¶
The SD file holds compounds with a structure. A ChEBI entry that is a class, with no single structure, is not in it. "Glucose" (CHEBI:17234) is one:
print(chebi.get_compound_by_id("CHEBI:17234"))
show(chebi.search_by_name("D-glucopyranose"))
None
[('CHEBI:4167', 'D-glucopyranose')]
Several compounds as a table¶
chebi.export_to_dataframe(["CHEBI:15377", "CHEBI:16236", "CHEBI:27732", "CHEBI:15365"],
fields=["ChEBI ID", "ChEBI NAME", "FORMULA", "MASS", "STAR",
"CAS Registry Numbers"])
| ChEBI ID | ChEBI NAME | FORMULA | MASS | STAR | CAS Registry Numbers | |
|---|---|---|---|---|---|---|
| 0 | CHEBI:15377 | water | H2O | 18.015 | 3 | 7732-18-5 |
| 1 | CHEBI:16236 | ethanol | C2H6O | 46.069 | 3 | 64-17-5 |
| 2 | CHEBI:27732 | caffeine | C8H10N4O2 | 194.194 | 3 | 58-08-2 |
| 3 | CHEBI:15365 | acetylsalicylic acid | C9H8O4 | 180.159 | 3 | 50-78-2 |
Filtering by quality¶
ChEBI rates each entry from one to three stars, three meaning checked by a
curator. filter_by_star_rating reads every record, so it takes a few
seconds:
three_star = chebi.filter_by_star_rating(min_stars=3)
print(len(three_star), "three-star compounds")
52903 three-star compounds
Through Search¶
Search uses ChebiSDF as one of its sources, together with the other
installed databases, and returns one table with the answer they agree on. For
resolving a list of identifiers that is usually the better entry point; see
the Search tutorial.