Topological Polar Surface Area (TPSA) Distribution Dashboard

DrugBank database
MolPort database
Python script number 9 to build the frequency distribution graph of the TPSA parameter on DrugBank molecules.
import matplotlib.pyplot as plt
from matplotlib.patches import Patch
from matplotlib.lines import Line2D
import numpy as np

# 1. TPSA data
bin_centers = [0, 20, 40, 60, 80, 100, 120, 140, 160, 180, 200, 220, 240]
frequencies = [
    7.295, 9.956, 15.719, 16.243, 14.873, 13.301, 8.182, 4.595, 3.104, 
    2.781, 2.297, 1.169, 0.484
]

# 2. Gaussian Fit Parameters
amplitude = 16.16
mean = 64.34
sd = 51.18

# Generate smooth X data for the curve
x_smooth = np.linspace(-20, 260, 300)

# Calculate Y using the Gaussian equation
y_smooth = amplitude * np.exp(-0.5 * ((x_smooth - mean) / sd)**2)

# 3. Define colors (TPSA Traffic Light)
colors = []
for x in bin_centers:
    # Optimal Range: 20 to 140 (Veber's Rule for oral absorption)
    if 20 <= x <= 140:
        colors.append('green')
    # Caution Range: Very nonpolar (<20) or High limit (140-160)
    elif (x < 20) or (140 < x <= 160):
        colors.append('gold')
    # Risk Range: > 160 (Poor permeability)
    else:
        colors.append('firebrick')

# 4. Create the chart
plt.figure(figsize=(7, 6))

# A. Draw Bars (Width 16 to leave space between bins of 20)
plt.bar(bin_centers, frequencies, width=16, color=colors, edgecolor='black', alpha=0.7, label='Data Frequency')

# B. Draw Trend Line
plt.plot(x_smooth, y_smooth, color='darkorange', linewidth=2, label='Gaussian Fit')

# 5. Tags and Titles
plt.xlabel('Topological Polar Surface Area (TPSA) [Ų]', fontsize=12)
plt.ylabel('% Frequency', fontsize=12)
plt.title('TPSA Distribution', fontsize=14)

# Adjust X axis
plt.xticks(np.arange(0, 260, 20)) 
plt.xlim(-10, 250)

# 6. Custom Legend
legend_elements = [
    Line2D([0], [0], color='darkorange', lw=2, label=f'Fit (Mean={mean}, SD={sd})'),
    Patch(facecolor='green', edgecolor='black', alpha=0.7, label='Good Oral Absorption (20 - 140 Ų)'),
    Patch(facecolor='gold', edgecolor='black', alpha=0.7, label='Caution (<20 or 140-160 Ų)'),
    Patch(facecolor='firebrick', edgecolor='black', alpha=0.7, label='Poor Permeability (> 160 Ų)')
]

plt.legend(handles=legend_elements, loc='upper right')
plt.grid(axis='y', linestyle='--', alpha=0.5)
plt.tight_layout()

plt.show()