"""Editable vector workflow and empty result-figure spaces.""" from pathlib import Path import numpy as np import matplotlib matplotlib.use('Agg') import matplotlib.pyplot as plt from matplotlib.font_manager import fontManager from matplotlib.patches import FancyArrowPatch, Circle, FancyBboxPatch, Rectangle from PIL import Image ROOT=Path(__file__).resolve().parents[1] for f in (ROOT/'assets/fonts').glob('*.ttf'):fontManager.addfont(str(f)) plt.rcParams.update({'font.family':'Ubuntu','font.size':13,'mathtext.fontset':'cm','pdf.fonttype':42,'svg.fonttype':'none'}) NAVY='#011F5B';PINK='#FBE8EF';ROSE='#B85C83';BLUE='#7C9DBC';GRAY='#617083' OUT=ROOT/'assets/figures';OUT.mkdir(parents=True,exist_ok=True) def text(ax,x,y,s,size=13,weight='normal',ha='center',color=NAVY,**kw): return ax.text(x,y,s,fontsize=size,fontweight=weight,ha=ha,va='center',color=color,**kw) def arrow(ax,a,b,rad=0,color=NAVY,lw=1.5): ax.add_patch(FancyArrowPatch(a,b,connectionstyle=f'arc3,rad={rad}',arrowstyle='-|>',mutation_scale=13,lw=lw,color=color)) def peptide(ax,x,y,width=.8,noncanonical=False): t=np.linspace(0,1,9);yy=y+.095*np.sin(t*3*np.pi) ax.plot(x+width*t,yy,c=ROSE,lw=2) for i,(xx,yyy) in enumerate(zip(x+width*t,yy)): ax.scatter([xx],[yyy],s=28,marker='D' if noncanonical and i in [2,6] else 'o',c=NAVY if noncanonical and i in [2,6] else PINK,edgecolors=ROSE,zorder=5) def protein(ax,x,y,scale=.40,phase=0): t=np.linspace(0,2*np.pi,180);r=1+.16*np.sin(5*t+phase)+.1*np.cos(3*t) ax.fill(x+scale*r*np.cos(t),y+scale*.8*r*np.sin(t),color=BLUE,alpha=.18) for j in range(3): q=np.linspace(0,1,100) ax.plot(x+scale*(1.55*q-.78),y+scale*(.45*np.sin(3*np.pi*q+j*.8)+.2*(j-1)),color=BLUE,lw=1.8) def save(fig,name): for ext in ['pdf','svg','png']:fig.savefig(OUT/(name+'.'+ext),dpi=200,bbox_inches='tight',facecolor='white',pad_inches=.07) plt.close(fig) fig,ax=plt.subplots(figsize=(13.6,9.5));ax.set(xlim=(0,13.6),ylim=(0,9.5));ax.axis('off') def box(x,y,w,h,title,number): ax.add_patch(FancyBboxPatch((x,y),w,h,boxstyle='round,pad=.03,rounding_size=.10',fc='white',ec=BLUE,lw=1)) ax.add_patch(FancyBboxPatch((x,y+h-.48),w,.48,boxstyle='round,pad=.03,rounding_size=.08',fc=PINK,ec='none')) text(ax,x+.17,y+h-.24,str(number),13,'bold',ha='left',color=ROSE) text(ax,x+.51,y+h-.24,title,13,'bold',ha='left') # Only the method name serves as the figure title. text(ax,.1,9.17,'PepPA',27,'bold',ha='left') for name,label,x,w in [('meta.png','Muse Glimmer-30B',7.0,.40),('ChatGPT-Logo.png','GPT-6 Astra Max',9.63,.43),('Claude_logo.png','Claude Opus Max',12.25,.30)]: im=Image.open(ROOT/'assets/logos'/name).convert('RGBA');h=min(.28,w*im.height/im.width) ax.imshow(im,extent=(x-w/2,x+w/2,9.15,9.15+h),aspect='auto',zorder=8) text(ax,x,8.93,label,10) box(.1,6.54,4.04,1.99,'Define the design goal',1) text(ax,.30,7.73,'Specify target and countertargets',11.8,ha='left') text(ax,.30,7.30,'Set chemistry and property thresholds',11.2,ha='left') text(ax,.30,6.86,'Choose human and preclinical contexts',11.1,ha='left') box(4.76,6.54,4.04,1.99,'Retrieve molecular evidence',2) text(ax,4.96,7.73,'Map sites, states and interactions',11.5,ha='left') text(ax,4.96,7.30,'Link each hypothesis to source passages',10.8,ha='left') text(ax,4.96,6.86,'Specify comparisons that test it',11.5,ha='left') box(9.42,6.54,4.04,1.99,'Fix the computational plan',3) text(ax,9.62,7.73,'Choose models and input requirements',10.9,ha='left') text(ax,9.62,7.30,'Set run order, seeds and compute limits',10.8,ha='left') text(ax,9.62,6.86,'Check that all required scores can be run',10.5,ha='left') arrow(ax,(4.2,7.48),(4.68,7.48));arrow(ax,(8.87,7.48),(9.34,7.48)) # The two computational stages have distinct inputs, operations and outputs. box(.1,2.83,6.29,3.13,'Generate and score peptides',4) box(7.13,2.83,6.33,3.13,'Verify the proposed peptides',5) ax.plot([11.42,11.42,3.20],[6.48,6.22,6.22],color=NAVY,lw=1.4) arrow(ax,(3.2,6.22),(3.2,6.00)) text(ax,.34,5.14,'Sequence generation',12.3,'bold',ha='left') text(ax,.34,4.77,'PepDFM with MOG-DFM',11.1,ha='left') text(ax,3.53,5.14,'Chemical generation',12.3,'bold',ha='left') text(ax,3.53,4.77,'PepMDLM with PepTune',11.1,ha='left') peptide(ax,.46,4.31,1.15) peptide(ax,3.74,4.31,1.15,noncanonical=True) text(ax,2.49,4.32,'Sequence',9.8) text(ax,5.54,4.32,'SMILES',9.8) text(ax,.34,3.89,'Guide sampling with functional and property scores',11.4,ha='left') text(ax,.34,3.53,'Combine compatible predictors for each endpoint',11.4,ha='left') text(ax,3.25,3.13,r'Maximize the weakest context margin $\min_z m_{kz}(x)$',12) arrow(ax,(6.45,4.35),(7.06,4.35)) protein(ax,7.75,5.03,.30);peptide(ax,7.68,4.83,.63) text(ax,8.6,5.04,'Check target and countertarget complexes',10.8,ha='left') text(ax,7.38,4.54,'Compare external ADMET predictions',11.3,ha='left') text(ax,7.38,4.08,'Check synthesis and formulation requirements',11.3,ha='left') text(ax,7.38,3.61,'Evaluate every required biological context',11.3,ha='left') text(ax,7.38,3.15,'Save scores, uncertainty and failed checks',11.3,'bold',ha='left') # One bounded computational return and a separate forward path to final output. arrow(ax,(9.50,2.78),(3.6,2.78),rad=-.10,color=ROSE) text(ax,6.74,2.33,'Use failed computational checks for one redesign pass',11.2,color=ROSE) arrow(ax,(12.9,2.80),(12.9,1.91)) box(.1,.16,13.36,1.66,'Select final sequences that meet the complete design specification',6) peptide(ax,.41,1.00,1.29,noncanonical=True) text(ax,.35,.50,'Canonical or noncanonical',10.1,ha='left') text(ax,3.08,1.01,'Molecular identity',12.2,'bold',ha='left') text(ax,3.08,.62,'Sequence, monomers and bonds',10.3,ha='left') text(ax,6.89,1.01,'Complete property report',12.2,'bold',ha='left') text(ax,6.89,.62,'PeptiVerse and external scores',10.3,ha='left') text(ax,10.53,1.01,'Reproducible records',12.2,'bold',ha='left') text(ax,10.53,.62,'Sources and execution trace',10.3,ha='left') save(fig,'figure1') # Empty spaces for pending results. Captions remain in the manuscript. for n in range(2,7): fig=plt.figure(figsize=(10,2.25));ax=fig.add_axes([.012,.045,.976,.91]);ax.set(xlim=(0,1),ylim=(0,1));ax.axis('off') ax.add_patch(Rectangle((.002,.002),.996,.996,fill=False,ec='#DDE3EB',lw=.8)) save(fig,f'figure{n}') print(OUT)