Download scripts/make_figures.py from ChatterjeeLab/PepPA: direct link, hf CLI and curl.
- Browser
- Download file 6.3 kB
-
https://huggingface.co/ChatterjeeLab/PepPA/resolve/main/scripts/make_figures.py
- Command line
-
hf download hf://ChatterjeeLab/PepPA/scripts/make_figures.py
-
curl -L -o make_figures.py https://huggingface.co/ChatterjeeLab/PepPA/resolve/main/scripts/make_figures.py
6.3 kB
| """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) | |