Package: smallworld-api
Python_SmallWorld_APIAn unofficial Python3 module to query a SmallWorld chemical space search server.DisclaimerThis is Unofficial So please do not abuse it or use it when you cannot legally use the site!SmallWorld is a search engine for chemical space developed by John Mayfield and Roger Sayle atNextMove Software.
John Irwin and Brian Shoichet at UCSF (the creators and maintainers of theZINCdatabase),
host a version of it atsw.docking.orgalong with another NextMove Software product,Arthor.OverviewSmallWorld allows one to search for similar compounds
to a giveSMILESin one of many databases —a very complex feat.A copy is hosted atsw.docking.orgby John Irwin, Brian Shoichet and co.
This is a free service, but it is not intended for heavy use.
To change the endpoint, one can change the class attributeSmallWorld.base_urlto a different URL.
The folk at NextMove Software deploy instances of it for paying customers —and with full support.The API points of the site are described inwiki.docking.org/index.php/How_to_use_SmallWorld_API.This Python3 module allows one to search it.For searches in Arthor, Zinc and EnamineStore see elsewhere.Installpip install -q smallworld-apiUsageThe following searches for Aspirin in Enamine's make-on-demand space, Enamine REAL, which does not contain it
as the latter is filtered by Lipinski's rule of five (Aspirin is actuallya terrible placeholder drug)fromrdkitimportChemfromrdkit.ChemimportPandasToolsimportpandasaspd# for typehinting belowfromsmallworld_apiimportSmallWorldprint(SmallWorld.base_url)# 'https://sw.docking.org'aspirin='O=C(C)Oc1ccccc1C(=O)O'sw=SmallWorld()results:pd.DataFrame=sw.search(aspirin,dist=5,db=sw.REAL_dataset)fromIPython.displayimportdisplaydisplay(results)The first two import lines are optional as the code works without rdkit. If pandas gets imported before PandasTools
and Chem imported not inmainthen display issues happen,
which can be fixed with afrom rdkit.Chem.Draw import IPythonConsole.So it's up to you to remember to run:PandasTools.AddMoleculeColumnToFrame(results,'smiles','molecule',includeFingerprints=True)The argumentdbfor.searchis a string and is the name of the database. These do seem to change,
so they get updated during initialisation or with the call:dbs:pd.DataFrame=SmallWorld.retrieve_databases()#: pd.DataFrame (.db_choices gets updated too)The dynamic properties.REAL_datasetand.ZINC_datasetsimply return the best value from the presets, which may have
become out of date (unless updated).Query termsThe first argument passed to.searchcan be:astr(SMILES)aChem.Mol(rdkit is an optional requirement though)a list-like (sequence) or a dict-like (mapping) of the above, where the index or key becomes the name in the output
table.See the class attribute dictionarySmallWorld.default_submissionfor what the defaults are set to, which ought to be:{'dist': 8,
'tdn': 6,
'rdn': 6,
'rup': 2,
'ldn': 2,
'lup': 2,
'maj': 6,
'min': 6,
'sub': 6,
'sdist': 12,
'tup': 6,
'scores': 'Atom Alignment,ECFP4,Daylight'}If one is sure that the correct dataset is being used and any raisedNoMatchErroris due to the SMILES, then once can
add for the last case the argumenttolerate_tolerate_NoMatchError=True, which makes them ignored bar for a warning.DebugThe instantiation is set up so for debugging, namely it has two attributes of interest:sw.last_reply, arequests.Responseinstancesw.hit_list_idan integer representing the search (AKA.hlidin the server responses)The errors raised are generally eitherrequests.HTTPErrororsmallworld.NoMatchError. The former is raised by arequests.Response.raise_for_statuscall and means there is a
status code that isn't 200, the latter is raised by one of the various checks insw.get_results().For the former errors, i.e. those by a serverside-declared HTML-formatting error (eg. status code 404), if one is in a
Jupyter notebook one can dosw.show_reply_as_html(). Generally if you get status code 500, it is best to try again
tomorrow as the server is having a hard time and is probably not okay on the web.For the latter, the result in.last_replyshould be a JSON string, therefore should give something like this:reply_data:dict=sw.last_reply.json()A common issue is the change in database names, therefore do do and pick a different one
(ATM, the index of the dataframe is the name to use, but in 2021 it was thename)fromIPython.displayimportdisplayfromsmallworld_apiimportSmallWorlddb_table:pd.DataFrame=SmallWorld.retrieve_databases()display(db_table)There will be a "ground control to major Tom" warning in the first query. This weird reply means that the stream has
finished, but not closed or something. Ignore it.Also, as a shorthand,mol: Chem.Mol = SmallWorld.check_smiles(aspirin)can be called to check if the molecules is fine.For extreme debugging, open Chrome and go tosw.docking.organd open the developer tools (F12). Then go to the Network tab and do a search, eg. withCC2=CC=C(CNC(=O)C1CCC1)C=N2,
this will be populated by all the figure requests, but/search/submitwill be the first one to look at
if the issue is with the submit method in the trace,/search/viewif it's with theget_resultsmethod.
Then simply copy the url query off the request and use it as parameters or compare them etc. For example:importurllib.parsefromsmallworld_apiimportSmallWorldurl_query='👾=👾&👾=👾'expected=dict(urllib.parse.parse_qsl(url_query))classDebug(SmallWorld):defsubmit_query(self,params):# override the method to check the parametersprint('Going to use:',params)print('Missing:',set(expected).difference(params))returnsuper().submit_query(expected)d=Debug()d.search('CCO',db=d.REAL_dataset)If it's a field that change, raise an issue and I'll update the class or do a pull request :pray:.ChoicesThe database choices can seen with the preset listSmallWorld.db_choices. But also this can be recached via the
classmethodSmallWorld.retrieve_databases().Two databases,REAL_Space_21Q3_2B(public)andREAL_DB_20Q2, are Enamine REAL databases
(aka. Enamine will make the compound on request). Previously, the
repository,enamine-real-searchwas good for this, but unfortunately
Enamine changed their endpoints. So I wrote this to take its place!
Despite the smaller number of entries,REAL_DB_20Q2gives the most hits and is less likely to "Major Tom out".Likewise, the attributeSmallWorld.sf_choices(type list) and
the classmethodSmallWorld.retrieve_scorefun_options()do the same.
The values are less and are:['Atom Alignment', 'SMARTS Alignment', 'ECFP4', 'Daylight'], but these
are activated by default and will be visible as columns in the resulting dataframe from a search call.Here is the full list of databases:importpandasaspdchoices:pd.DataFrame=SmallWorld.retrieve_databases()display(choices)Which will return (as of writing on the 9th Dec 2021):namenumEntriesnumMappednumUnmappednumSkippedstatusREAL_Space_21Q3_All_2B_public.smi.anonREAL_Space_21Q3_2B(public)19503560981935062471152936270AvailableZINC-All-2020Q2-1.46B.anonZINC-All-20Q2-1.46B146855463814670309471523691231AvailableZINC-For-Sale-2020Q2-1.46B.anonZINC-For-Sale-20Q2-1.46B14649491461463519428142971822AvailableZINC20-ForSale-21Q3.smi.anonZINC20-ForSale-21Q3-1.4B147928491914407847653850015429AvailableEnamine_REAL_Public_July_2020_Q1-2_1.36B.anonREAL_DB_20Q213611984681350462346107361220AvailableWait-OK-2020Q2-1.2B.anonWait-OK-20Q2-1.2B1174063221117278519012780311AvailableWuXi-20Q4.smi.anonWuXi-20Q4-600M23535828756007625811752820294284AvailableMculeUltimate-20Q2.smi.anonMculeUltimate_20Q2_126M12647152312647152300AvailableWuXi-2020Q2-120M.anonWuXi-20Q2-120M3391323611204005702187317910Availablemcule_ultimate_200407_c8bxI4.anonMcule_ultimate_20Q2-126M12647152345589462808820610AvailableBB-All-2020Q2-26.7M.anonBB-All-20Q2-26.7M26787985267072418074416AvailableIn-Stock-2020Q2-13.8M.anonIn-Stock-20Q2-13.8M1384248513829086133991AvailableZINC20-InStock-21Q3.smi.anonZINC20-InStock-21Q3-11M1112244511103910185355AvailableBBall.smi.anonBB-All-21Q4-3.3M331996033197052556AvailableBBnow.smi.anonBB-Now-21Q4-2M207663920764641756AvailableBB-Now-2020Q2-1.6M.anonBB-Now-20Q2-1.6M164978916493864034AvailableBB_50.smi.anonBB-50-21Q4-1.5M148355114834341172AvailableBB_10.smi.anonBB-10-21Q4-1.2M12433211243241800AvailableBB_40.smi.anonBB-40-21Q4-590K589959589911484Availableinteresting.smi.anonZINC-Interesting-20Q2-320K320845320773721AvailableZINC-Interesting-2020Q2-300K.anonZINC-Interesting-20Q2-300K30785430076570891AvailableTCNMP-2020Q2-31912.anonTCNMP-20Q2-31912374383191255260AvailableBB_30.smi.anonBB-30-21Q4-3K31293119100AvailableWorldDrugs-2020Q2-3004.anonWorldDrugs-20Q2-30043004300310AvailableHMDB-2020Q2-584.anonHMDB-20Q2-58458558410AvailableNamesThere is a Python module calledsmallworld,
which implements the small world algorithm.
This is not an API to thesw.docking.orgsite.The blog of thesw.docking.orgsite mentions a pysmallworld.
There is no mention of this in Google so I am guessing it is for a future feature?
I however need to use this now as
I need it as a publicly usable example workflow ofFragmenstein.Also, there is a great and wacky boardgame calledSmall World,
with a curious/agonising dynamic which forces you to not be a collector.