<jupyter_start><jupyter_text>Relative Binding Free Energy Lambda Sequence Generator**With Bokeh!**- The idea is a simple and *interactive* way to generate charge, vdW and bond lambdas for a relative free energy of binding calculation.    - These values are available to copy (and note there is no enter in the long string of numbers although the text has flowed)    - Graph output is also a sanity check.- Comment on coding style: Umm, yeah this is a hack. Have done some awful things. Comments welcome.- Has this been done before: Maybe there is already something out there. IDK.- Will this look and work better in Bokeh or Plotly - probably<jupyter_code>from ipywidgets import interact
import numpy as np

from bokeh.io import push_notebook, show, output_notebook
from bokeh.plotting import figure
output_notebook()
# default data

x = np.arange(40)
y = np.fromstring("0.00 0.11 0.22 0.33 0.44 0.56 0.67 0.78 0.89 1.00 1.00 1.00 1.00 1.00 1.00 1.00 1.00 1.00 1.00 1.00 1.00 1.00 1.00 1.00 1.00 1.00 1.00 1.00 1.00 1.00 1.00 1.00 1.00 1.00 1.00 1.00 1.00 1.00 1.00 1.00",dtype=float,sep=' ')
y2 = np.fromstring("0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.04 0.08 0.11 0.15 0.19 0.23 0.27 0.30 0.34 0.38 0.42 0.46 0.49 0.53 0.57 0.61 0.65 0.68 0.72 0.76 0.80 0.84 0.87 0.91 0.95 0.97 0.98 0.99 0.99 1.00",dtype=float,sep=' ')

# Set up the figure in Bokeh
p = figure(title="RBFE Lambdas", plot_height=600, plot_width=800, y_range=(-0.1,1.3),
           background_fill_color='whitesmoke', tools="reset, tap, hover")

p.xaxis.axis_label = "Number of bins"
p.yaxis.axis_label = "Lambda value"
r = p.scatter(x, y, color="blue", line_width=2, alpha=0.8, marker="square", size=8, legend_label="Charge Perturbation")
r2 = p.scatter(x, y2, color="green", line_width=2, alpha=0.8, marker="triangle", size=8, legend_label="vdW Perturbation")
p.legend.orientation = "horizontal"
def update(total_bins=40, charge_bins=10, taper1_bins=3,  taper1_val=0.95, taper2_bins=3, taper2_val=0.99):

    # total_bins is the total number of free energy bins (indexed from 1)
    # charge_bins is the total bins to use for charge perturbation
    # taper1_val is the taper value to start with e.g. 0.98
    # taper 2_val is the value to end taper 1 at and start taper 2
    # taper1_bins is number of bins or pnts to taper over e.g. 3 bins
    # taper2_bins is number of bins or pnts to taper over e.g. the last 3 bins then put in 3
    
    #inelegant yet simple parameter error resolution
    if total_bins<10: total_bins=10
    if taper1_val<0: taper1_val=0
    if taper2_val<taper1_val: taper2_val=taper1_val
    if taper2_val>1: taper2_val=1
    if taper1_val>taper2_val: taper1_val=taper2_val
    if taper1_bins<0: taper1_bins=0
    if taper2_bins<0: taper2_bins=0
        
    if charge_bins+taper1_bins+taper2_bins>total_bins: 
        return("ERROR: sum of charge bins and taper bins> total bins")
        
    x = np.arange(total_bins)
    if charge_bins==0:
        
        vdw_y_taper =  np.append(np.append(np.linspace(0.0,taper1_val, num=total_bins-taper1_bins-taper2_bins, endpoint=False),
                         np.linspace(taper1_val,taper2_val, num=taper1_bins, endpoint=False)),
                         np.linspace(taper2_val,1.0, num=taper2_bins, endpoint=True))
    else:
        charge_y = np.append(np.linspace(0.0,1.0, num=charge_bins, endpoint=True),np.linspace(1.0,1.0,num=total_bins-charge_bins, endpoint=True))
        vdw_y_taper =  np.append(np.append(np.append(np.linspace(0.0,0.0,num=charge_bins-1, endpoint=True),np.linspace(0.0,taper1_val, num=total_bins-charge_bins-taper1_bins-taper2_bins+1, endpoint=False)),
                         np.linspace(taper1_val,taper2_val, num=taper1_bins, endpoint=False)),
                         np.linspace(taper2_val,1.0, num=taper2_bins, endpoint=True))
    
    print("Total bins (zero-based indexing):",total_bins-1)
    if charge_bins>0: print("Charge: ", np.array_str(charge_y, precision=2, max_line_width=10000).replace('[','').replace(']',''))
    print("VDW: ", np.array_str(vdw_y_taper, precision=2, max_line_width=10000).replace('[','').replace(']',''))
    print("Bond: ", np.array_str(vdw_y_taper, precision=2, max_line_width=10000).replace('[','').replace(']',''))

    r2.data_source.data =  {'x': x,
        'y': vdw_y_taper}
    if charge_bins>0:
        r.data_source.data =  {'x': x,
        'y': charge_y}
    else:
        r.data_source.data =  {'x': x,
        'y': np.zeros(len(x))}
   
    
    push_notebook()
show(p, notebook_handle=True)
interact(update,total_bins=(10,80,1), charge_bins=(0,20,1),taper1_val=(0,1,0.01),taper2_val=(0,1,0.01))<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.13203091455560326, 'fraction_numerical': 0.08673250322026621, 'mean_word_length': 3.635820895522388, 'pattern_counts': {'":': 0, '<': 10, '<?xml version=': 0, '>': 11, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 8, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '1', 'dir': 'jupyter-structured-clean-dedup', 'id': '621058', 'license': 'MIT', 'n_tokens_mistral': 2056, 'n_tokens_neox': 1780, 'n_words': 447, 'path': 'Sequence_generator_bokeh.ipynb', 'repo_name': 'scientificomputing/rbfe_sequence_generator', 'size': '4658'}