It is clear from many publications that a number of physicochemical properties influence central nervous system (CNS) penetration and it is often possible to play off one property against another in an effort to improve CNS penetration. An interesting paper from Wagner et al Moving beyond Rules: The Development of a Central Nervous System Multiparameter Optimization (CNS MPO) Approach To Enable Alignment of Druglike Properties describes an algorithm to score compounds with respect to CNS penetration.
The CNS MPO score was built based on six fundamental physicochemical properties: ClogP, ClogD, MW, TPSA, HBD, and pKa each weighted from 0 to 1.0 and most desirable and least desirable ranges for each physicochemical property is displayed in the table below.
Property | Transformation (T0) | Weight | More desirable range (T0 = 1.0) | Less desirable range (T0 = 0.0) |
---|---|---|---|---|
ClogP | monotonic decreasing | 1.0 | ClogP <= 3 | ClogP > 5 |
ClogD | monotonic decreasing | 1.0 | ClogD <= 2 | ClogD > 4 |
MW | monotonic decreasing | 1.0 | MW <= 360 | MW> 500 |
TPSA | hump function | 1.0 | 40 < TPSA <= 90 | TPSA <= 20; TPSA > 120 |
HBD | monotonic decreasing | 1.0 | HBD <= 0.5 | HBD > 3.5 |
pKa | monotonic decreasing | 1.0 | pKa <= 8 | pKa > 10 |
The calculated physicochemical properties used in the paper were obtained using a selection commercial packages: Biobyte for ClogP calculations, ACD/Laboratories for ClogD at pH 7.4, and ACD/Laboratories for pKa. TPSA was calculated using a sum of fragment-based contributions methodology described by in J. Med. Chem. 43, 3714–3717..
It is important to note that changing the package used to calculate the physicochemical properties will render the subsequent calculations unreliable.
The script relies on workspace containing the correctly calculated properties in columns entitled MW, cLogP, TPSA, cLogD, HBD, PKA, the script first creates new columns for calculated to be inserted into.
1 2 3 4 5 |
# Create columns collogPscore = vtable.findColumnWithName("LogPScore", 1, 1) collogDscore = vtable.findColumnWithName("LogDScore", 1, 1) |
It then calculates the individual scores for each property using the logic described in the paper, shown below for cLogP,
1 2 3 4 5 6 7 8 9 10 11 12 13 |
col = vtable.findColumnWithName('cLogP', 0) rows = vtable.getRealRowCount() for r in range(0, int(rows)): taskID = col.getValue(r) if taskID <3: TheScore = 1 elif taskID < 5: TheScore = 1-(taskID-3)/2 elif taskID > 5: TheScore = 0 column = vtable.findColumnWithName('LogPScore', 0) column.setDouble(r, TheScore) |
Finally the composite score is calculated and the worksheet updated as shown in the image below.
Updated to include colour formatting columns
One of the popular features in Vortex is to colour code columns, this is done automatically but sometimes you want to customise the colouring. For example in one set of values smaller values might be better, in another column (perhaps an off-target activity) larger numbers might be better. Chatting to Sune Askjær, the author of the Unichem Script, it seemed that this might be a nice addition to this script.
Setting the colouring scheme is done on each individual column. You have 3 options: ColoringMode 0 = the default heat map (min value green high value red) ColoringMode 1 = Custom colour in simple mode, the one you get on the first pane in the Configure.. menu when you right click a column and select ‘Coloring’. ColoringMode 2 = Custom color in advanced mode, the second pane in Coloring > Configure menu. This one you need to by hand in the GUI and then export as a large string that you then have in you code.
If you whant the advanced scheme it is probably best of setting it by hand and then getting the full coloring scheme string for that column and store it as a string that you can then apply to the column in your script. See the screen shot below.
Once you have a colour scheme you like you can then get the code by typing in the Vortex terminal,
1 2 3 4 5 |
color = c3.getColorScheme() color color ='minExpression=-0.01;maxExpression=0.5;minColor=0xff0000;maxColor=0xffff00;log=false|minExpression=0.5;maxExpression=1;minColor=0xffff00;maxColor=0x00ff00;log=false| minExpression=;maxExpression=;minColor=0x00ff00;maxColor=0x00ff00;log=false|minExpression=;maxExpression=;minColor=0x00ff00;maxColor=0x00ff00;log=false| minExpression=;maxExpression=;minColor=0x00ff00;maxColor=0x00ff00;log=false|minExpression=;maxExpression=;minColor=0x00ff00;maxColor=0x00ff00;log=false| minExpression=;maxExpression=;minColor=0x00ff00;maxColor=0x00ff00;log=false|minExpression=;maxExpression=;minColor=0x00ff00;maxColor=0x00ff00;log=false| minExpression=;maxExpression=;minColor=0x00ff00;maxColor=0x00ff00;log=false|minExpression=;maxExpression=;minColor=0x00ff00;maxColor=0x00ff00;log=false| minExpression=;maxExpression=;minColor=0x00ff00;maxColor=0x00ff00;log=false|minExpression=;maxExpression=;minColor=0x00ff00;maxColor=0x00ff00;log=false| minExpression=;maxExpression=;minColor=0x00ff00;maxColor=0x00ff00;log=false|minExpression=;maxExpression=;minColor=0x00ff00;maxColor=0x00ff00;log=false| minExpression=;maxExpression=;minColor=0x00ff00;maxColor=0x00ff00;log=false|minExpression=;maxExpression=;minColor=0x00ff00;maxColor=0x00ff00;log=false| minExpression=;maxExpression=;minColor=0x00ff00;maxColor=0x00ff00;log=false|minExpression=;maxExpression=;minColor=0x00ff00;maxColor=0x00ff00;log=false' |
You can then set the colour scheme in the script.
1 2 3 |
column.setColoringMode(2) column.setColorScheme(color) |
This screenshot shows the original colour scheme
The screenshot below shows the same worksheet with the new colour scheme applied.
I’ve calculated the CNSscore for the 119 drugs described in the publication and the plot below shows the comparison with the CNS MPO results from the publication, the minor differences appear to be due to differences in rounding results.
Whilst there are several algorithms for predicting brain penetration one nice feature of this implementation is that it is possible to see how each of the six different physicochemical properties contribute to the overall score.
The Vortex Script
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 |
# Created by Chris Swain http://www.macinchem.org # Based on # Moving beyond Rules: The Development of a Central Nervous System Multiparameter Optimization (CNS MPO) Approach To Enable Alignment of Druglike Properties # DOI: 10.1021/cn100008c |ACS Chem. Neurosci. (2010), 1, 435449 import sys sys.path.append(vortex.getVortexFolder() + '/modules/jythonlib') import subprocess # Create columns collogPscore = vtable.findColumnWithName("LogPScore", 1, 1) collogDscore = vtable.findColumnWithName("LogDScore", 1, 1) colMwtscore = vtable.findColumnWithName("MWtScore", 1, 1) colTPSAscore = vtable.findColumnWithName("TPSAScore", 1, 1) colHBDscore = vtable.findColumnWithName("HBDScore", 1, 1) colPKascore = vtable.findColumnWithName("PkaScore", 1, 1) colPCNSscore = vtable.findColumnWithName("CNSScore", 1, 1) # Colourscheme for formatting color ='minExpression=-0.01;maxExpression=0.5;minColor=0xff0000;maxColor=0xffff00;log=false|minExpression=0.5;maxExpression=1;minColor=0xffff00;maxColor=0x00ff00;log=false| minExpression=;maxExpression=;minColor=0x00ff00;maxColor=0x00ff00;log=false|minExpression=;maxExpression=;minColor=0x00ff00;maxColor=0x00ff00;log=false| minExpression=;maxExpression=;minColor=0x00ff00;maxColor=0x00ff00;log=false|minExpression=;maxExpression=;minColor=0x00ff00;maxColor=0x00ff00;log=false| minExpression=;maxExpression=;minColor=0x00ff00;maxColor=0x00ff00;log=false|minExpression=;maxExpression=;minColor=0x00ff00;maxColor=0x00ff00;log=false| minExpression=;maxExpression=;minColor=0x00ff00;maxColor=0x00ff00;log=false|minExpression=;maxExpression=;minColor=0x00ff00;maxColor=0x00ff00;log=false| minExpression=;maxExpression=;minColor=0x00ff00;maxColor=0x00ff00;log=false|minExpression=;maxExpression=;minColor=0x00ff00;maxColor=0x00ff00;log=false| minExpression=;maxExpression=;minColor=0x00ff00;maxColor=0x00ff00;log=false|minExpression=;maxExpression=;minColor=0x00ff00;maxColor=0x00ff00;log=false| minExpression=;maxExpression=;minColor=0x00ff00;maxColor=0x00ff00;log=false|minExpression=;maxExpression=;minColor=0x00ff00;maxColor=0x00ff00;log=false| minExpression=;maxExpression=;minColor=0x00ff00;maxColor=0x00ff00;log=false|minExpression=;maxExpression=;minColor=0x00ff00;maxColor=0x00ff00;log=false' # Colourscheme for TotalScore colorTot ='minExpression=0;maxExpression=3;minColor=0xff0000;maxColor=0xffff00;log=false|minExpression=3;maxExpression=6;minColor=0xffff00;maxColor=0x00ff00;log=false| minExpression=;maxExpression=;minColor=0x00ff00;maxColor=0x00ff00;log=false|minExpression=;maxExpression=;minColor=0x00ff00;maxColor=0x00ff00;log=false| minExpression=;maxExpression=;minColor=0x00ff00;maxColor=0x00ff00;log=false|minExpression=;maxExpression=;minColor=0x00ff00;maxColor=0x00ff00;log=false| minExpression=;maxExpression=;minColor=0x00ff00;maxColor=0x00ff00;log=false|minExpression=;maxExpression=;minColor=0x00ff00;maxColor=0x00ff00;log=false| minExpression=;maxExpression=;minColor=0x00ff00;maxColor=0x00ff00;log=false|minExpression=;maxExpression=;minColor=0x00ff00;maxColor=0x00ff00;log=false| minExpression=;maxExpression=;minColor=0x00ff00;maxColor=0x00ff00;log=false|minExpression=;maxExpression=;minColor=0x00ff00;maxColor=0x00ff00;log=false| minExpression=;maxExpression=;minColor=0x00ff00;maxColor=0x00ff00;log=false|minExpression=;maxExpression=;minColor=0x00ff00;maxColor=0x00ff00;log=false| minExpression=;maxExpression=;minColor=0x00ff00;maxColor=0x00ff00;log=false|minExpression=;maxExpression=;minColor=0x00ff00;maxColor=0x00ff00;log=false| minExpression=;maxExpression=;minColor=0x00ff00;maxColor=0x00ff00;log=false|minExpression=;maxExpression=;minColor=0x00ff00;maxColor=0x00ff00;log=false' # Calculate scores # if(logP 3,1,if(logP >5,0,1((logP3)/2))) col = vtable.findColumnWithName('cLogP', 0) rows = vtable.getRealRowCount() for r in range(0, int(rows)): taskID = col.getValue(r) if taskID <3: TheScore = 1 elif taskID < 5: TheScore = 1-(taskID-3)/2 elif taskID > 5: TheScore = 0 column = vtable.findColumnWithName('LogPScore', 0) column.setDouble(r, TheScore) column.setColoringMode(2) column.setColorScheme(color) # IF(C11<2,1,IF(C11>4,0,1((C11-2)/2))) col = vtable.findColumnWithName('cLogD', 0) rows = vtable.getRealRowCount() for r in range(0, int(rows)): taskID = col.getValue(r) if taskID <2: TheScore = 1 elif taskID < 4: TheScore = 1-(taskID-2)/2 elif taskID > 4: TheScore = 0 column = vtable.findColumnWithName('LogDScore', 0) column.setDouble(r, TheScore) column.setColoringMode(2) column.setColorScheme(color) # MWtScore=if_else(${Mass}<360,1,if_else(${Mass}>500,0,1-((${Mass}-360)/140))) col = vtable.findColumnWithName('MW', 0) rows = vtable.getRealRowCount() for r in range(0, int(rows)): taskID = col.getValue(r) if taskID <360: TheScore = 1 elif taskID < 500: TheScore = 1-(taskID-360)/140 elif taskID > 500: TheScore = 0 column = vtable.findColumnWithName('MWtScore', 0) column.setDouble(r, TheScore) column.setColoringMode(2) column.setColorScheme(color) # IF(E11<20,0,IF(E11<40,((E1120)20),IF(E1190,1,IF(E11120,(1(E1190)30),0)))) col = vtable.findColumnWithName('TPSA', 0) rows = vtable.getRealRowCount() for r in range(0, int(rows)): taskID = col.getValue(r) if taskID <20: TheScore = 0 elif taskID < 40: TheScore = (taskID-20)/20 elif taskID < 90: TheScore = 1 elif taskID < 120: TheScore = 1 -(taskID -90)/30 elif taskID >120: TheScore = 0 column = vtable.findColumnWithName('TPSAScore', 0) column.setDouble(r, TheScore) column.setColoringMode(2) column.setColorScheme(color) # IF(F110.5,1,IF(F11>3.5,0,1((F110.5)3))) col = vtable.findColumnWithName('HBD', 0) rows = vtable.getRealRowCount() for r in range(0, int(rows)): taskID = col.getValue(r) if taskID <0.5: TheScore = 1 elif taskID < 3.5: TheScore = 1-(taskID-0.5)/3 elif taskID > 3.5: TheScore = 0 column = vtable.findColumnWithName('HBDScore', 0) column.setDouble(r, TheScore) column.setColoringMode(2) column.setColorScheme(color) # IF(G118,1,IF(G11>10,0,1((G118)2))) col = vtable.findColumnWithName('PKA', 0) rows = vtable.getRealRowCount() for r in range(0, int(rows)): taskID = col.getValue(r) if taskID <8: TheScore = 1 elif taskID <= 10: TheScore = 1-(taskID-8)/2 elif taskID > 10: TheScore = 0 column = vtable.findColumnWithName('PkaScore', 0) column.setDouble(r, TheScore) column.setColoringMode(2) column.setColorScheme(color) # Calc total score rows = vtable.getRealRowCount() for r in range(0, int(rows)): col = vtable.findColumnWithName('LogPScore', 0) logPscore = col.getValue(r) col = vtable.findColumnWithName('LogDScore', 0) logDscore = col.getValue(r) col = vtable.findColumnWithName('MWtScore', 0) Mwtscore = col.getValue(r) col = vtable.findColumnWithName('TPSAScore', 0) tpsascore = col.getValue(r) col = vtable.findColumnWithName('HBDScore', 0) hbdscore = col.getValue(r) col = vtable.findColumnWithName('PkaScore', 0) pkascore = col.getValue(r) TotalScore = logPscore + logDscore + Mwtscore + tpsascore + hbdscore +pkascore column = vtable.findColumnWithName('CNSScore', 0) column.setDouble(r, TotalScore) column.setColoringMode(2) column.setColorScheme(colorTot) vtable.fireTableStructureChanged() |
The script can be downloaded from here
Page Updated 9 June 2014
One thought on “Implementing a CNS penetration algorithm in Vortex”
Comments are closed.