Ya hemos desarrollado un 'bot' para calculos con ADMETlab 3.0, a continuación se muestra un 'bot' para calculos con ADMETsar 3.0. Hemos aplicado ambos scripts sobre la base de datos Drugbank approved (puedes descargar una copia con estructuras 3D). Puedes descargar una copia de los cálculos de ADMET en este fichero Excel con macros.

Los colores de fondo en las celdas del fichero Excel de la figura anterior se consiguen con un script de Visual Basic para Aplicaciones (VBA) que puedes ver justo debajo.
¿Cómo se aplicar sobre un fichero Excel?
admetlab30-DRUGBank-approved.xlsm.ALT + F11 para abrir el editor de VBA.ALT + F8, selecciona ADMET_Final_Numeric_87_Corregido y pulsa Ejecutar.Sub ADMET_Final_Numeric_87_Corregido()
Dim ws As Worksheet: Set ws = ActiveSheet
Dim lastRow As Long: lastRow = ws.Cells(ws.Rows.Count, "A").End(xlUp).Row
Dim lastCol As Long: lastCol = ws.Cells(1, ws.Columns.Count).End(xlToLeft).Column
Dim r As Long, c As Long
Dim h As String, v As Variant
' Columnas de soporte para cálculos
Dim colMW As Long, colLogP As Long, colLogD As Long
Dim colNHA As Long, colNHD As Long, colTPSA As Long
Dim vCount As Integer
' Definición de colores
Dim cGreen As Long: cGreen = RGB(198, 239, 206)
Dim cYellow As Long: cYellow = RGB(255, 235, 156)
Dim cRed As Long: cRed = RGB(255, 199, 206)
Application.ScreenUpdating = False
' 1. Mapeo de columnas de datos base
For c = 1 To lastCol
Select Case UCase(Trim(ws.Cells(1, c).Value))
Case "MW": colMW = c
Case "LOGP": colLogP = c
Case "LOGD": colLogD = c
Case "NHA": colNHA = c
Case "NHD": colNHD = c
Case "TPSA": colTPSA = c
End Select
Next c
' 2. Procesar toda la tabla
For c = 1 To lastCol
h = UCase(Trim(ws.Cells(1, c).Value))
For r = 2 To lastRow
v = ws.Cells(r, c).Value
Select Case h
' --- REGLAS INDUSTRIALES CON RESULTADO NUMÉRICO ---
Case "LIPINSKI"
vCount = 0
If ws.Cells(r, colMW).Value > 500 Then vCount = vCount + 1
If ws.Cells(r, colLogP).Value > 5 Then vCount = vCount + 1
If ws.Cells(r, colNHA).Value > 10 Then vCount = vCount + 1
If ws.Cells(r, colNHD).Value > 5 Then vCount = vCount + 1
ws.Cells(r, c).Value = vCount ' Guardamos el nro de violaciones (0-4)
' Verde si cumple (0-1 violaciones), Rojo si falla (>=2)
If vCount < 2 Then ws.Cells(r, c).Interior.Color = cGreen Else ws.Cells(r, c).Interior.Color = cRed
Case "PFIZER"
' logP > 3 y TPSA < 75 = 0 (Pobre), de lo contrario 1 (Excelente)
If ws.Cells(r, colLogP).Value > 3 And ws.Cells(r, colTPSA).Value < 75 Then
ws.Cells(r, c).Value = 0: ws.Cells(r, c).Interior.Color = cRed
Else
ws.Cells(r, c).Value = 1: ws.Cells(r, c).Interior.Color = cGreen
End If
Case "GSK"
' MW <= 400 y logP <= 4 = 1 (Excelente)
If ws.Cells(r, colMW).Value <= 400 And ws.Cells(r, colLogP).Value <= 4 Then
ws.Cells(r, c).Value = 1: ws.Cells(r, c).Interior.Color = cGreen
Else
ws.Cells(r, c).Value = 0: ws.Cells(r, c).Interior.Color = cRed
End If
Case "GOLDENTRIANGLE"
' 200 <= MW <= 500 y -2 <= logD <= 5 = 1 (Excelente)
If (ws.Cells(r, colMW).Value >= 200 And ws.Cells(r, colMW).Value <= 500) And _
(ws.Cells(r, colLogD).Value >= -2 And ws.Cells(r, colLogD).Value <= 5) Then
ws.Cells(r, c).Value = 1: ws.Cells(r, c).Interior.Color = cGreen
Else
ws.Cells(r, c).Value = 0: ws.Cells(r, c).Interior.Color = cRed
End If
' --- COLOREADO DE LOS 83 PARÁMETROS RESTANTES ---
Case Else
If IsNumeric(v) And v <> "" Then
Select Case h
' Rangos Óptimos
Case "MW": If v >= 100 And v <= 600 Then ws.Cells(r, c).Interior.Color = cGreen Else ws.Cells(r, c).Interior.Color = cRed
Case "NHA": If v >= 0 And v <= 12 Then ws.Cells(r, c).Interior.Color = cGreen Else ws.Cells(r, c).Interior.Color = cRed
Case "NHD": If v >= 0 And v <= 7 Then ws.Cells(r, c).Interior.Color = cGreen Else ws.Cells(r, c).Interior.Color = cRed
Case "TPSA": If v >= 0 And v <= 140 Then ws.Cells(r, c).Interior.Color = cGreen Else ws.Cells(r, c).Interior.Color = cRed
Case "NROT": If v >= 0 And v <= 11 Then ws.Cells(r, c).Interior.Color = cGreen Else ws.Cells(r, c).Interior.Color = cRed
Case "NRING": If v >= 0 And v <= 6 Then ws.Cells(r, c).Interior.Color = cGreen Else ws.Cells(r, c).Interior.Color = cRed
Case "MAXRING": If v >= 0 And v <= 18 Then ws.Cells(r, c).Interior.Color = cGreen Else ws.Cells(r, c).Interior.Color = cRed
Case "NHET": If v >= 1 And v <= 15 Then ws.Cells(r, c).Interior.Color = cGreen Else ws.Cells(r, c).Interior.Color = cRed
Case "FCHAR": If v >= -4 And v <= 4 Then ws.Cells(r, c).Interior.Color = cGreen Else ws.Cells(r, c).Interior.Color = cRed
Case "NRIG": If v >= 0 And v <= 30 Then ws.Cells(r, c).Interior.Color = cGreen Else ws.Cells(r, c).Interior.Color = cRed
Case "NSTEREO": If v <= 2 Then ws.Cells(r, c).Interior.Color = cGreen Else ws.Cells(r, c).Interior.Color = cRed
' Índices y Logs
Case "QED", "FSP3": If v > 0.67 Then ws.Cells(r, c).Interior.Color = cGreen Else ws.Cells(r, c).Interior.Color = cRed
Case "MCE-18": If v >= 45 Then ws.Cells(r, c).Interior.Color = cGreen Else ws.Cells(r, c).Interior.Color = cRed
Case "LOGS": If v >= -4 And v <= 0.5 Then ws.Cells(r, c).Interior.Color = cGreen Else ws.Cells(r, c).Interior.Color = cRed
Case "LOGD", "LOGP": If v >= 1 And v <= 3 Then ws.Cells(r, c).Interior.Color = cGreen Else ws.Cells(r, c).Interior.Color = cRed
Case "LOGVDSS": If v >= 0.04 And v <= 20 Then ws.Cells(r, c).Interior.Color = cGreen Else ws.Cells(r, c).Interior.Color = cRed
' Permeabilidad y Transporte
Case "CACO2", "PAMPA": If v > -5.15 Then ws.Cells(r, c).Interior.Color = cGreen Else ws.Cells(r, c).Interior.Color = cRed
Case "MDCK": If v > 0.000002 Then ws.Cells(r, c).Interior.Color = cGreen Else ws.Cells(r, c).Interior.Color = cRed
Case "PPB": If v <= 90 Then ws.Cells(r, c).Interior.Color = cGreen Else ws.Cells(r, c).Interior.Color = cRed
Case "FU": If v >= 5 Then ws.Cells(r, c).Interior.Color = cGreen Else ws.Cells(r, c).Interior.Color = cRed
' Farmacocinética y Toxicidad (Probabilidades 0-1)
' Verdes si < 0.3 (Inhibidores, Tox, etc)
Case "PGP_INH", "PGP_SUB", "HIA", "F20", "F30", "F50", "OATP1B1", "OATP1B3", "MRP1", _
"CYP1A2-INH", "CYP2C19-INH", "CYP2C9-INH", "CYP2D6-INH", "CYP3A4-INH", "CYP2B6-INH", "CYP2C8-INH", _
"HERG", "HERG-10UM", "DILI", "AMES", "ROA", "FDAMDD", "SKINSEN", "CARCINOGENICITY", "EC", "EI", _
"RESPIRATORY", "NEUROTOXICITY-DI", "OTOTOXICITY", "HEMATOTOXICITY", "NEPHROTOXICITY-DI", "GENOTOXICITY", _
"NR-AHR", "NR-AR", "NR-AR-LBD", "NR-AROMATASE", "NR-ER", "NR-ER-LBD", "NR-PPAR-GAMMA", "SR-ARE", _
"SR-ATAD5", "SR-HSE", "SR-MMP", "SR-P53", "SKIN_SENSITIZATION":
If v <= 0.3 Then ws.Cells(r, c).Interior.Color = cGreen Else _
If v <= 0.7 Then ws.Cells(r, c).Interior.Color = cYellow Else ws.Cells(r, c).Interior.Color = cRed
' Invertidos (Verde si > 0.7, como los sustratos CYP que queremos que se metabolicen o BBB)
Case "BCRP", "BSEP", "BBB", "CYP1A2-SUB", "CYP2C19-SUB", "CYP2C9-SUB", "CYP2D6-SUB", "CYP3A4-SUB", "CYP2B6-SUB", "LM-HUMAN":
If v >= 0.7 Then ws.Cells(r, c).Interior.Color = cGreen Else _
If v >= 0.3 Then ws.Cells(r, c).Interior.Color = cYellow Else ws.Cells(r, c).Interior.Color = cRed
' Clearance y Vida Media
Case "CL-PLASMA":
If v <= 5 Then ws.Cells(r, c).Interior.Color = cGreen Else _
If v <= 15 Then ws.Cells(r, c).Interior.Color = cYellow Else ws.Cells(r, c).Interior.Color = cRed
Case "T0.5":
If v > 8 Then ws.Cells(r, c).Interior.Color = cGreen Else _
If v >= 1 Then ws.Cells(r, c).Interior.Color = cYellow Else ws.Cells(r, c).Interior.Color = cRed
End Select
End If
End Select
Next r
Next c
Application.ScreenUpdating = True
MsgBox "Análisis de Frecuencias (1/0) y Violaciones de Lipinski (0-4) completado.", vbInformation
End Sub
'bot' de Python...
import os
import time
import glob
import pandas as pd
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.chrome.service import Service
from webdriver_manager.chrome import ChromeDriverManager
from selenium.common.exceptions import TimeoutException
# --- CONFIGURACIÓN DE RUTAS ---
INPUT_FILE = r'D:\admetsar3\todos_mis_smiles.txt'
DOWNLOAD_DIR = r'D:\admetsar3\descargas'
TEMP_FILE = r'D:\admetsar3\temp_50.txt'
FINAL_OUTPUT = r'D:\admetsar3\resultados_combinados_admetsar.txt'
TAMANO_BLOQUE = 50
# --- XPATHS ---
URL_WEB = "https://lmmd.ecust.edu.cn/admetsar3/predict.php"
PESTANA_ADMET_XPATH = '//*[@id="myTab"]/li[2]/a'
INPUT_FILE_XPATH = '//*[@id="smiles_file"]'
BOTON_SUBMIT_XPATH = '//*[@id="ios"]/div/div[2]/div[2]/a/button'
ENLACE_JOB_XPATH = '/html/body/div/div[1]/div[2]/ul/li[1]/a'
BOTON_TXT_XPATH = '/html/body/div/div/div[3]/div[2]/div[1]/a/button'
# --- NUEVO: Función para limpiar la carpeta antes de empezar ---
def limpiar_descargas_anteriores():
if not os.path.exists(DOWNLOAD_DIR):
os.makedirs(DOWNLOAD_DIR)
return
archivos_viejos = glob.glob(os.path.join(DOWNLOAD_DIR, '*.*'))
if archivos_viejos:
print(f"Limpiando {len(archivos_viejos)} archivos de ejecuciones anteriores...")
for f in archivos_viejos:
try:
os.remove(f)
except Exception as e:
print(f"No se pudo borrar {os.path.basename(f)}: {e}")
print("Carpeta de descargas limpia y lista.\n")
def divide_list(lst, n):
for i in range(0, len(lst), n):
yield lst[i:i + n]
def esperar_descarga(directorio, timeout=120):
segundos = 0
while segundos < timeout:
time.sleep(1)
if not glob.glob(os.path.join(directorio, '*.crdownload')):
return True
segundos += 1
return False
def configurar_navegador():
opciones = webdriver.ChromeOptions()
opciones.add_argument('--ignore-certificate-errors')
opciones.add_argument('--ignore-ssl-errors')
prefs = {
"download.default_directory": DOWNLOAD_DIR,
"download.prompt_for_download": False,
"directory_upgrade": True,
"safebrowsing.enabled": True
}
opciones.add_experimental_option("prefs", prefs)
return webdriver.Chrome(service=Service(ChromeDriverManager().install()), options=opciones)
def unir_resultados_txt():
archivos_txt = glob.glob(os.path.join(DOWNLOAD_DIR, '*.txt'))
if not archivos_txt:
print("No hay archivos para unir.")
return
archivos_txt.sort(key=os.path.getctime)
print(f"\nUniendo {len(archivos_txt)} archivos...")
lista_df = []
for f in archivos_txt:
try:
df = pd.read_csv(f, sep='\t')
lista_df.append(df)
except Exception as e:
try:
df = pd.read_csv(f, sep=',')
lista_df.append(df)
except Exception as e2:
print(f"Error al leer {os.path.basename(f)}: {e2}")
if lista_df:
df_final = pd.concat(lista_df, ignore_index=True)
df_final.to_csv(FINAL_OUTPUT, index=False, sep='\t')
print("="*50)
print(f"¡ÉXITO! Archivo final generado: {FINAL_OUTPUT}")
print(f"Total de moléculas procesadas: {len(df_final)}")
print("="*50)
if __name__ == '__main__':
# 0. Limpiamos la basura de ayer
limpiar_descargas_anteriores()
try:
with open(INPUT_FILE, 'r') as f:
smiles_list = [line.strip() for line in f if line.strip()]
except FileNotFoundError:
print(f"Error: No se encontró el archivo {INPUT_FILE}")
exit(1)
total_bloques = (len(smiles_list) // TAMANO_BLOQUE) + (1 if len(smiles_list) % TAMANO_BLOQUE != 0 else 0)
print(f"Iniciando ADMETsar 3: {len(smiles_list)} moléculas en {total_bloques} bloques de {TAMANO_BLOQUE}.")
driver = configurar_navegador()
try:
for i, bloque in enumerate(divide_list(smiles_list, TAMANO_BLOQUE)):
print(f"\n--- Procesando bloque {i+1} de {total_bloques} ---")
with open(TEMP_FILE, 'w') as f_temp:
f_temp.write("\n".join(bloque))
driver.get(URL_WEB)
time.sleep(2)
pestana = WebDriverWait(driver, 20).until(EC.element_to_be_clickable((By.XPATH, PESTANA_ADMET_XPATH)))
driver.execute_script("arguments[0].click();", pestana)
time.sleep(1)
input_file = WebDriverWait(driver, 20).until(EC.presence_of_element_located((By.XPATH, INPUT_FILE_XPATH)))
input_file.send_keys(TEMP_FILE)
time.sleep(1)
btn_submit = WebDriverWait(driver, 20).until(EC.element_to_be_clickable((By.XPATH, BOTON_SUBMIT_XPATH)))
driver.execute_script("arguments[0].click();", btn_submit)
enlace_elemento = WebDriverWait(driver, 60).until(EC.presence_of_element_located((By.XPATH, ENLACE_JOB_XPATH)))
url_resultado = enlace_elemento.get_attribute("href")
print(f"Job generado! Navegando a: {url_resultado}")
driver.get(url_resultado)
print("Esperando cálculos...")
archivos_antes = len(glob.glob(os.path.join(DOWNLOAD_DIR, '*.txt')))
boton_txt = None
intentos = 0
max_intentos = 10
while intentos < max_intentos:
try:
boton_txt = WebDriverWait(driver, 60).until(EC.element_to_be_clickable((By.XPATH, BOTON_TXT_XPATH)))
break
except TimeoutException:
intentos += 1
print(f" -> El botón TXT no aparece. Recargando web (Intento {intentos}/{max_intentos})...")
driver.refresh()
time.sleep(3)
if boton_txt:
print("¡Resultados listos! Descargando TXT...")
driver.execute_script("arguments[0].click();", boton_txt)
esperar_descarga(DOWNLOAD_DIR)
if len(glob.glob(os.path.join(DOWNLOAD_DIR, '*.txt'))) > archivos_antes:
print(f"-> Bloque {i+1} completado con éxito.")
else:
print("-> ADVERTENCIA: No se detectó la descarga del archivo.")
else:
print(f"-> ERROR GRAVE: El botón TXT no apareció tras {max_intentos} recargas. Saltando al siguiente bloque.")
time.sleep(3)
except Exception as e:
print(f"\nSe detuvo por un error: {e}")
finally:
driver.quit()
if os.path.exists(TEMP_FILE):
os.remove(TEMP_FILE)
print("\nNavegador cerrado.")
unir_resultados_txt()

Sub ColorearADMETsar()
Dim ws As Worksheet
Dim lastRow As Long, lastCol As Long
Dim c As Long, r As Long
Dim header As String
Dim cell As Range
Dim v As Variant
Dim hexC As String
' Colores principales por defecto
Const R_Col As String = "#C14E4E"
Const Y_Col As String = "#FFDF33"
Const G_Col As String = "#63C28D"
On Error Resume Next
Set ws = ThisWorkbook.Sheets("ADMETsar30")
On Error GoTo 0
If ws Is Nothing Then
MsgBox "No se encontró la hoja 'ADMETsar30'. Comprueba el nombre.", vbExclamation
Exit Sub
End If
' Optimizamos el rendimiento apagando el refresco de pantalla
Application.ScreenUpdating = False
Application.Calculation = xlCalculationManual
lastCol = ws.Cells(1, ws.Columns.Count).End(xlToLeft).Column
lastRow = ws.Cells(ws.Rows.Count, 1).End(xlUp).Row
For c = 1 To lastCol
header = Trim(ws.Cells(1, c).Value)
For r = 2 To lastRow
Set cell = ws.Cells(r, c)
v = cell.Value
hexC = ""
' Validar que la celda no esté vacía
If Not IsEmpty(v) And Trim(CStr(v)) <> "" Then
' 1. Reglas Categóricas (Texto)
If header = "Lipinski_rule" Or header = "Pfizer_rule" Or header = "GSK_rule" Then
If LCase(CStr(v)) = "accept" Then
hexC = G_Col
ElseIf LCase(CStr(v)) = "not accept" Then
hexC = R_Col
End If
' 2. Reglas Numéricas
ElseIf IsNumeric(v) Then
v = CDbl(v)
Select Case header
' --- RANGOS PERSONALIZADOS DISCONTINUOS ---
Case "MW"
If v < 100 Or v > 600 Then
hexC = R_Col
ElseIf (v >= 100 And v <= 200) Or (v >= 500 And v <= 600) Then
hexC = Y_Col
ElseIf v > 200 And v < 500 Then
hexC = G_Col
End If
Case "nAtom"
If v < 5 Or v > 50 Then
hexC = R_Col
ElseIf (v >= 5 And v <= 15) Or (v >= 35 And v <= 50) Then
hexC = Y_Col
ElseIf v > 15 And v < 35 Then
hexC = G_Col
End If
Case "nHet"
If v = 0 Or v > 15 Then
hexC = R_Col
ElseIf v = 1 Or (v >= 10 And v <= 15) Then
hexC = Y_Col
ElseIf v >= 2 And v <= 9 Then
hexC = G_Col
End If
Case "nRing"
If v > 6 Then
hexC = R_Col
ElseIf v = 0 Or (v >= 5 And v <= 6) Then
hexC = Y_Col
ElseIf v >= 1 And v <= 4 Then
hexC = G_Col
End If
Case "nRot"
If v > 15 Then
hexC = R_Col
ElseIf v >= 10 And v <= 15 Then
hexC = Y_Col
ElseIf v >= 0 And v <= 9 Then
hexC = G_Col
End If
Case "HBA"
If v > 12 Then
hexC = R_Col
ElseIf v = 0 Or (v >= 11 And v <= 12) Then
hexC = Y_Col
ElseIf v >= 1 And v <= 10 Then
hexC = G_Col
End If
Case "HBD"
If v > 5 Then
hexC = R_Col
ElseIf v >= 4 And v <= 5 Then
hexC = Y_Col
ElseIf v >= 0 And v <= 3 Then
hexC = G_Col
End If
Case "TPSA"
If v > 160 Then
hexC = R_Col
ElseIf (v >= 0 And v <= 20) Or (v >= 140 And v <= 160) Then
hexC = Y_Col
ElseIf v > 20 And v < 140 Then
hexC = G_Col
End If
Case "SlogP"
If v < 0 Or v > 5# Then
hexC = R_Col
ElseIf (v >= 0 And v <= 1#) Or (v >= 3.5 And v <= 5#) Then
hexC = Y_Col
ElseIf v > 1# And v < 3.5 Then
hexC = G_Col
End If
Case "logS"
If v < -6 Or v > 1 Then
hexC = R_Col
ElseIf (v >= -6 And v <= -4) Or (v >= 0.5 And v <= 1) Then
hexC = Y_Col
ElseIf v > -4 And v < 0.5 Then
hexC = G_Col
End If
Case "QED"
If v < 0.35 Then
hexC = R_Col
ElseIf v >= 0.35 And v < 0.6 Then
hexC = Y_Col
ElseIf v >= 0.6 Then
hexC = G_Col
End If
Case "logP"
If v < 0 Or v > 5 Then
hexC = R_Col
ElseIf (v >= 0 And v < 2) Or (v >= 4 And v <= 5) Then
hexC = Y_Col
ElseIf v >= 2 And v <= 4 Then
hexC = G_Col
End If
Case "pKa"
If v < 0 Or v > 11 Then
hexC = R_Col
ElseIf (v >= 0 And v <= 3) Or (v >= 8 And v <= 11) Then
hexC = Y_Col
ElseIf v > 3 And v < 8 Then
hexC = G_Col
End If
Case "MATE1_inhibitor"
If v <= 0.5 Then
hexC = G_Col
Else
hexC = R_Col
End If
Case "CLr"
If v < 0.5 Then
hexC = "#FFE24C"
Else
hexC = "#7DA7CA"
End If
' --- BLOQUES AGRUPADOS POR RANGOS ESTÁNDAR ---
Case "Caco_2_c", "HIA", "F50", "F30", "F20": hexC = GetRangeCol(v, 0.3, 0.7, R_Col, Y_Col, G_Col)
Case "Caco_2": hexC = GetRangeCol(v, -6#, -5.15, R_Col, Y_Col, G_Col)
Case "MDCK": hexC = GetRangeCol(v, 0.4, 0.6, R_Col, Y_Col, G_Col)
Case "BBB", "Eye_irritation", "Skin_corrosion", "Skin_sensitisation": hexC = GetRangeCol(v, 0.3, 0.8, R_Col, Y_Col, G_Col)
Case "OATP1B1_inhibitor": hexC = GetRangeCol(v, 0.5, 0.8, "#DBDBDB", "#FFB733", R_Col)
Case "OATP1B3_inhibitor": hexC = GetRangeCol(v, 0.6, 0.85, "#DBDBDB", "#FF926A", R_Col, True)
Case "OATP2B1_inhibitor": hexC = GetRangeCol(v, 0.3, 0.5, G_Col, Y_Col, R_Col)
Case "OCT1_inhibitor": hexC = GetRangeCol(v, 0.3, 0.6, G_Col, Y_Col, R_Col)
Case "OCT2_inhibitor": hexC = GetRangeCol(v, 0.2, 0.5, G_Col, Y_Col, R_Col)
Case "BCRP_inhibitor", "CYP2B6_inhibitor": hexC = GetRangeCol(v, 0.25, 0.6, G_Col, Y_Col, R_Col)
Case "BSEP_inhibitor": hexC = GetRangeCol(v, 0.25, 0.7, G_Col, Y_Col, R_Col)
Case "Pgp_inhibitor", "CYP1A2_inhibitor": hexC = GetRangeCol(v, 0.2, 0.6, G_Col, Y_Col, R_Col)
Case "Pgp_substrate": hexC = GetRangeCol(v, 0.3, 0.7, G_Col, Y_Col, R_Col)
Case "PPB": hexC = GetRangeCol(v, 0.2, 0.7, R_Col, Y_Col, G_Col)
Case "VDss": hexC = GetRangeCol(v, -0.6, 0.5, "#C96464", "#FFE24C", "#7995E9", True)
Case "CYP3A4_inhibitor", "CYP2C9_inhibitor", "CYP2C19_inhibitor": hexC = GetRangeCol(v, 0.15, 0.5, G_Col, Y_Col, R_Col)
Case "CYP2D6_inhibitor": hexC = GetRangeCol(v, 0.15, 0.8, G_Col, Y_Col, R_Col)
Case "CYP1A2_substrate": hexC = GetRangeCol(v, 0.2, 0.6, "#9FD7EF", "#DBDBDB", "#6787E7")
Case "CYP3A4_substrate": hexC = GetRangeCol(v, 0.3, 0.65, "#9FD7EF", "#DBDBDB", "#FFA333")
Case "CYP2B6_substrate": hexC = GetRangeCol(v, 0.2, 0.8, "#9FD7EF", "#DFCBDF", "#845CAD")
Case "CYP2C9_substrate": hexC = GetRangeCol(v, 0.2, 0.6, "#9FD7EF", "#7FB1B3", "#F39999")
Case "CYP2C19_substrate": hexC = GetRangeCol(v, 0.25, 0.75, "#9FD7EF", "#DBDBDB", "#EDAB94")
Case "CYP2D6_substrate": hexC = GetRangeCol(v, 0.2, 0.75, "#9FD7EF", "#DBDBDB", "#C777DB")
Case "HLM", "RLM", "CLp_c", "DILI", "Nephrotoxicity", "Ames", "Skin_irritation": hexC = GetRangeCol(v, 0.3, 0.7, G_Col, Y_Col, R_Col)
Case "UGT_substrate": hexC = GetRangeCol(v, 0.3, 0.7, R_Col, Y_Col, G_Col, True)
Case "T50": hexC = GetRangeCol(v, -1#, 0, "#C96464", "#76C99B", "#7DA7CA")
Case "MRT": hexC = GetRangeCol(v, -1.2, 0, "#C96464", "#76C99B", "#7DA7CA")
Case "Neurotoxicity": hexC = GetRangeCol(v, -2, -1.5, G_Col, Y_Col, R_Col)
Case "hERG_1uM": hexC = GetRangeCol(v, 0.15, 0.4, G_Col, Y_Col, R_Col)
Case "hERG_10uM": hexC = GetRangeCol(v, 0.25, 0.75, G_Col, Y_Col, R_Col)
Case "hERG_30uM": hexC = GetRangeCol(v, 0.25, 0.8, G_Col, "#FFE9C3", "#F39999")
Case "Respiratory_toxicity": hexC = GetRangeCol(v, 0.4, 0.8, "#33FF98", "#F3EBA3", "#D79D65")
Case "Eye_corrosion": hexC = GetRangeCol(v, 0.2, 0.8, G_Col, Y_Col, R_Col)
Case "ADT", "Mouse_carcinogenicity_c": hexC = GetRangeCol(v, 0.4, 0.7, G_Col, Y_Col, R_Col)
Case "Mouse_carcinogenicity": hexC = GetRangeCol(v, 1, 3, G_Col, Y_Col, R_Col)
End Select
End If
End If
' Aplicar color (si coincide con alguna regla) o limpiar el fondo si no
If hexC <> "" Then
cell.Interior.Color = HexToRGB(hexC)
' === NUEVA REGLA DE FORMATO DE TEXTO ===
' Si el color asignado es exactamente el rojo principal (#C14E4E)
If UCase(hexC) = UCase(R_Col) Then
cell.Font.Color = vbWhite ' Letra blanca
cell.Font.Bold = True ' Negrita
Else
cell.Font.ColorIndex = xlAutomatic ' Letra por defecto (negra)
cell.Font.Bold = False ' Quitar negrita
End If
' =======================================
Else
cell.Interior.ColorIndex = xlNone
cell.Font.ColorIndex = xlAutomatic ' Restaurar letra si no hay fondo
cell.Font.Bold = False
End If
Next r
Next c
' Restaurar ajustes de Excel
Application.ScreenUpdating = True
Application.Calculation = xlCalculationAutomatic
MsgBox "¡Análisis ADMET completado y celdas coloreadas!", vbInformation
End Sub
' Función auxiliar para evaluar rangos simples contínuos (CORREGIDA CON ByVal)
Function GetRangeCol(ByVal v As Double, ByVal t1 As Double, ByVal t2 As Double, ByVal cLow As String, ByVal cMid As String, ByVal cHigh As String, Optional ByVal incLow As Boolean = False) As String
Dim inLow As Boolean
If incLow Then inLow = (v <= t1) Else inLow = (v < t1)
If inLow Then
GetRangeCol = cLow
ElseIf v <= t2 Then
GetRangeCol = cMid
Else
GetRangeCol = cHigh
End If
End Function
' Función auxiliar para convertir HEX (ej. #C14E4E) a color Long de VBA (CORREGIDA CON ByVal)
Function HexToRGB(ByVal hexStr As String) As Long
hexStr = Replace(hexStr, "#", "")
HexToRGB = RGB(Val("&H" & Mid(hexStr, 1, 2)), Val("&H" & Mid(hexStr, 3, 2)), Val("&H" & Mid(hexStr, 5, 2)))
End Function