Dermatological Safety: Acute Phototoxicity (Erythema Risk) Dashboard

DrugBank database
MolPort database
Python script number 117 to build the frequency distribution graph of the Phototoxicity_Photoirritation parameter on DrugBank molecules.
import matplotlib.pyplot as plt
import matplotlib.colors as mcolors
from matplotlib.patches import Patch
import numpy as np
from scipy.interpolate import PchipInterpolator

# 1. PASTE YOUR DATA HERE (Phototoxicity_Photoirritation)
datos_crudos = """Bin Center	% Frequency
0.1	0.212314225053079
0.15	3.69426751592357
0.2	10.0212314225053
0.25	15.1167728237792
0.3	14.0552016985138
0.35	14.47983014862
0.4	12.9087048832272
0.45	9.08704883227176
0.5	6.96390658174098
0.55	5.30785562632696
0.6	3.5244161358811
0.65	1.86836518046709
0.7	1.23142250530786
0.75	1.01910828025478
0.8	0.424628450106157
0.85	0.0849256900212314
0.9	0
0.95	0
1	0"""

# 2. AUTOMATIC PROCESSING
lineas = datos_crudos.strip().split('\n')[1:] 
bins_array = []
freq_array = []

for linea in lineas:
    b, f = linea.strip().split() 
    bins_array.append(float(b))
    freq_array.append(float(f))

bins = np.array(bins_array)
freq = np.array(freq_array)
mean_val = np.average(bins, weights=freq)

interpolator = PchipInterpolator(bins, freq)
x_fit = np.linspace(min(bins), max(bins), 500)
y_fit = interpolator(x_fit)
y_fit = np.clip(y_fit, 0, None)

def get_colors(b_array):
    return ['#008000' if b < 0.4 else '#FFD700' if b <= 0.7 else '#B22222' for b in b_array]

colors_hex = get_colors(bins)
face_colors = [mcolors.to_rgba(c, alpha=0.60) for c in colors_hex]
edge_colors = [mcolors.to_rgba(c, alpha=0.90) for c in colors_hex]

# 3. CREATION OF THE GRAPH
plt.figure(figsize=(7, 6))

plt.bar(bins, freq, width=0.04, color=face_colors, edgecolor=edge_colors, linewidth=1.5, zorder=2)

# Gaussian Curve (ADMETsar Excellent Fit)
amplitude = 15.12
mean = 0.3703
sd = 0.1401
gauss_y = amplitude * np.exp(-((x_fit - mean)**2) / (2 * sd**2))
plt.plot(x_fit, gauss_y, color='orange', linewidth=2.5, linestyle='-', alpha=0.7, zorder=4)

# 4. LABELS AND TITLES
# ==============================================================================
plt.xlabel('Photoirritation / Phototoxicity Probability (PIV)', fontsize=12)
plt.ylabel('% Frequency', fontsize=12)
plt.title('Dermatological Safety: Acute Phototoxicity (Erythema Risk)', fontsize=14)

legend_elements = [
    Patch(facecolor=mcolors.to_rgba('#008000', 0.6), edgecolor='#008000', label='Safe / Non-Irritant (< 0.4)'),
    Patch(facecolor=mcolors.to_rgba('#FFD700', 0.6), edgecolor='#FFD700', label='Moderate Risk (0.4 - 0.7)'),
    Patch(facecolor=mcolors.to_rgba('#B22222', 0.6), edgecolor='#B22222', label='High PIV Risk (> 0.7)'),
    plt.Line2D([0], [0], color='orange', lw=2.5, linestyle='-', alpha=0.7, label=f'Fit (Mean={mean}, SD={sd})')
]
plt.legend(handles=legend_elements, loc='upper right', framealpha=0.95, fontsize=10)

plt.grid(axis='y', linestyle=':', alpha=0.7, zorder=0)
plt.xlim(0, 1.05)
plt.ylim(0, max(max(freq), max(gauss_y)) * 1.15) 
plt.tight_layout()

plt.show()