Covid Era Work

In [1]:
import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt
import scipy
plt.rcParams["figure.figsize"] = (7.5,5)

def combineMultipleScans(df, colName, newName=None):
    cols = list(filter(lambda col: colName in col, df.columns))
    n = len(cols)
    if newName == None:
        newName = "{0} (n={1})".format(colName, n)
    df[newName] = (df[cols].sum(axis=1))/n
    df.drop(columns=cols, inplace=True)

def setWLSAxis(ax):
    ax.set_xlabel("Wavelength (nm)")
    ax.set_ylabel("Absorbance (A)")
    
def getLinearFits(df, xcol, ycols):
    linearFits = {}
    for col in ycols:
        linearFits[col] = scipy.stats.linregress(df[xcol], df[col])
    return pd.DataFrame(linearFits, index=["slope", "intercept", "r_value", "p_value", "std_err"])

AuNP-B1 Synthesis

In [2]:
AuNPB1 = pd.read_excel("05272020-AuNP-B1-FULLBANDSCAN.xlsx", skiprows=12, index_col=0, 
              usecols=lambda x: x not in ["No."])
display(AuNPB1)
BLANKABS1ABS2ABS3ABS4ABS5Average
Wavelength
750.00.00010.30270.30430.30500.30500.30710.30482
749.80.00020.30270.30480.30530.30540.30730.30510
749.60.00020.30310.30450.30550.30560.30760.30526
749.40.00000.30390.30520.30600.30610.30850.30594
749.2-0.00020.30430.30570.30660.30690.30880.30646
........................
400.8-0.00022.43512.42652.42652.40982.41812.42320
400.60.00012.43382.42522.42522.40852.40852.42024
400.40.00012.43252.42392.42392.40732.40732.41898
400.20.00002.43092.42232.42232.40562.40562.41734
400.0-0.00012.42952.42092.42092.40422.40422.41594

1751 rows × 7 columns

In [3]:
ax = sns.lineplot(x=AuNPB1.index, y="Average", data=AuNPB1)
ax.set_title("Gold Nanoparticle Synthesis, Batch 1: Full Band Scan (AuNP-B1, n=5)")
setWLSAxis(ax)

Concentration Calculations

In [4]:
AuNPB1Conc = pd.read_excel("05272020-AuNP-B1-AND-NOCITRATE.xlsx", skiprows=11, index_col=0,
                       usecols=lambda x: not any(s in x for s in ["Unnamed", "Remark", "Conc."]))
display(AuNPB1Conc) # all measurements take @ 525nm
NameAbs.Tran.StatusMeasuring time
No.
1blank0.000199.9759Measured2020-05-27 20:35:13
2blank0.000199.9759Measured2020-05-27 20:35:14
3blank0.000199.9799Measured2020-05-27 20:35:17
4blank0.0000100.0040Measured2020-05-27 20:35:18
5blank0.000199.9718Measured2020-05-27 20:35:19
6aunp-b12.65500.2213Measured2020-05-27 20:35:26
7aunp-b12.65500.2213Measured2020-05-27 20:35:27
8aunp-b12.65500.2213Measured2020-05-27 20:35:28
9aunp-b12.65500.2213Measured2020-05-27 20:35:29
10aunp-b12.65500.2213Measured2020-05-27 20:35:30
11aunp-b12.65500.2213Measured2020-05-27 20:35:30
12aunp-b12.65500.2213Measured2020-05-27 20:35:31
13aunp-b12.66290.2173Measured2020-05-27 20:35:32
14aunp-b12.65500.2213Measured2020-05-27 20:35:33
15aunp-b12.65500.2213Measured2020-05-27 20:35:33
16blank0.000199.9799Measured2020-05-27 20:38:22
17blank0.0000100.0040Measured2020-05-27 20:38:23
18blank0.000199.9678Measured2020-05-27 20:38:24
19blank0.000199.9718Measured2020-05-27 20:38:24
20blank0.000199.9839Measured2020-05-27 20:38:25
21aunp-b1-noc2.28130.5232Measured2020-05-27 20:38:51
22aunp-b1-noc2.28130.5232Measured2020-05-27 20:38:52
23aunp-b1-noc2.27800.5272Measured2020-05-27 20:38:53
24aunp-b1-noc2.28130.5232Measured2020-05-27 20:38:53
25aunp-b1-noc2.27800.5272Measured2020-05-27 20:38:54
26aunp-b1-noc2.27800.5272Measured2020-05-27 20:38:55
27aunp-b1-noc2.27800.5272Measured2020-05-27 20:38:56
28aunp-b1-noc2.27800.5272Measured2020-05-27 20:38:56
29aunp-b1-noc2.27800.5272Measured2020-05-27 20:38:57
30aunp-b1-noc2.27800.5272Measured2020-05-27 20:38:58

using the Beer-Lambert law $A=\epsilon\cdot l \cdot c$ with a pathlength $l=$1cm and an extinction coefficient of $2.7\cdot10^8$ M$^{−1}$ cm$^{−1}$ at 525 nm, we have: $$c=\frac{A}{2.7}10^{-8}M=\frac{10\cdot A}{2.7}nM$$ Constant from Alsager2015: "The concentration of AuNPs was estimated to be 14 nM from the calculation based on the Beer−Lambert law using an extinction coefficient of $2.7\cdot10^8 M^{−1} cm^{−1}$ at 525 nm."

In [5]:
mean = AuNPB1Conc.groupby("Name").mean()
mean["Concentration (nM)"] = (10*mean["Abs."]/2.7)
display(mean)
nocTransferRatio = (mean.loc["aunp-b1-noc"]["Concentration (nM)"]/mean.loc["aunp-b1"]["Concentration (nM)"])*100
print("De-citrated sample transfer percentage: {}%".format(round(nocTransferRatio)))
Abs.Tran.Concentration (nM)
Name
aunp-b12.655790.220909.836259
aunp-b1-noc2.278990.526008.440704
blank0.0000899.981490.000296
De-citrated sample transfer percentage: 86.0%

A transfer percentage of 86% doesn't make sense, as we expect the upper bound to be 33% since the last step involved a 3X dilution.

TODO:We need to do a dilution curve of AuNP-B1 to ensure linearity / test for equipment issues.

with these numbers, I added Alsa1535 (an E2 aptamer) for a 1:3 Au:Apt ratio (75.969pmol for 3mL of AuNP-B1-NOC)

In [6]:
SaltAndAptamer = pd.read_excel("05272020-APTAMER-AND-SALT-ADDITIONS.xlsx", skiprows=12, index_col=0,
                       usecols=lambda x: not any(s in x for s in ["No.", "Unnamed", "Remark", "Conc.", "Abs10", "Visible"]))
display(SaltAndAptamer)

#SaltAndAptamer["AuNP-B1"] = (SaltAndAptamer["AuNP-B1"]+SaltAndAptamer["AuNP-B1.1"])/2
#SaltAndAptamer.drop(columns=["AuNP-B1.1"], inplace=True)

for sample in ["Post Alsa1535", "AuNP-B1"]:
    combineMultipleScans(SaltAndAptamer, sample)


SaltAndAptamer.rename(columns={
    "Salt1": "NaCl (7.93mM)",
    "Salt2": "NaCl (15.9mM)",
    "Salt3": "NaCl (23.8mM)"
}, inplace=True)
display(SaltAndAptamer)
Post Alsa1535Post Alsa1535.1Post Alsa1535.2AuNP-B1AuNP-B1.1Salt1Salt2Salt3Re-scan for equib verification
Wavelength
750.00.08770.08770.08750.31420.31420.14580.19030.25310.2688
749.80.08790.08770.08770.31480.31440.14570.19070.25300.2694
749.60.08810.08790.08790.31530.31520.14610.19060.25360.2695
749.40.08820.08810.08780.31570.31570.14640.19070.25360.2696
749.20.08840.08850.08800.31630.31640.14620.19110.25410.2706
..............................
400.81.36281.36211.36062.40942.40941.35621.34621.33501.3322
400.61.36351.36211.36132.40792.41611.35691.34681.33561.3328
400.41.36361.36211.36212.40652.41481.35771.34751.33621.3335
400.21.36441.36291.36222.40512.40511.35771.34761.33621.3334
400.01.36521.36301.36232.40362.40361.35851.34831.33691.3341

1751 rows × 9 columns

NaCl (7.93mM)NaCl (15.9mM)NaCl (23.8mM)Re-scan for equib verificationPost Alsa1535 (n=3)AuNP-B1 (n=2)
Wavelength
750.00.14580.19030.25310.26880.0876330.31420
749.80.14570.19070.25300.26940.0877670.31460
749.60.14610.19060.25360.26950.0879670.31525
749.40.14640.19070.25360.26960.0880330.31570
749.20.14620.19110.25410.27060.0883000.31635
.....................
400.81.35621.34621.33501.33221.3618332.40940
400.61.35691.34681.33561.33281.3623002.41200
400.41.35771.34751.33621.33351.3626002.41065
400.21.35771.34761.33621.33341.3631672.40510
400.01.35851.34831.33691.33411.3635002.40360

1751 rows × 6 columns

In [7]:
ax = SaltAndAptamer[["AuNP-B1 (n=2)", "Post Alsa1535 (n=3)"]].plot()
setWLSAxis(ax)
ax.set_title("AuNP-B1 with and without DNA Aptamer (Alsa1535)")
plt.savefig("rawAuNPwithandwithoutAptamer.png", dpi=300)

A .. very interesting change in the absorbtion spectra when the aptamer is introduced - no visual change was detectable.

In [8]:
ax = SaltAndAptamer[["Post Alsa1535 (n=3)"]+[x for x in SaltAndAptamer.columns if "NaCl" in x]].plot()
setWLSAxis(ax)
ax = SaltAndAptamer.loc[580:450, ["Post Alsa1535 (n=3)"]+[x for x in SaltAndAptamer.columns if "NaCl" in x]].plot()
setWLSAxis(ax)
In [9]:
df = SaltAndAptamer.loc[[523,625], ["Post Alsa1535 (n=3)"]+[x for x in SaltAndAptamer.columns if "NaCl" in x]].T
df["625/523"] = df[625]/df[523]
df["NaCl Conc. (mM)"] = [0, 7.93, 15.9, 23.8]

    
display(df)

linearFits = getLinearFits(df, "NaCl Conc. (mM)", [625, 523, "625/523"])

display(linearFits)

ax = sns.regplot(x="NaCl Conc. (mM)", y="625/523", data=df)
ax.set_title("Salt Concentration vs Absorbtion ratio (625nm:523nm), R$^2={}$"
             .format(round(linearFits.loc["r_value", "625/523"],4)))
Wavelength523625625/523NaCl Conc. (mM)
Post Alsa1535 (n=3)2.2653670.3719670.1641970.00
NaCl (7.93mM)2.2380000.4264000.1905277.93
NaCl (15.9mM)2.2084000.4822000.21834815.90
NaCl (23.8mM)2.1702000.5657000.26066723.80
625523625/523
slope0.008025-0.0039700.003996
intercept0.3660152.2677600.160850
r_value0.993851-0.9967620.992733
p_value0.0061490.0032380.007267
std_err0.0006320.0002260.000343
Out[9]:
Text(0.5, 1.0, 'Salt Concentration vs Absorbtion ratio (625nm:523nm), R$^2=0.9927$')
In [10]:
E2 = pd.read_excel("05272020-E2-ADDITIONS.xlsx", skiprows=10, index_col=0,
                     usecols=lambda x: not any(s in x for s in ["Abs", "No.", "Unnamed", "Remark", 
                                                                "Conc.", "Abs10", "Visible"]))
display(E2)
ax = E2.plot()
setWLSAxis(ax)
ax.set_title("Estradiol Valerate Titration in AuNP-B1-NOC with Alsa1535")
plt.savefig("05272020-e2-additions-curve.png", dpi=300)
BASELINE5NM50NM100NM200NM300NM600NM900NM1200NM4800NM8400NM12000NM
Wavelength
7500.28640.28580.29370.29930.30670.31710.33800.36860.40170.60450.82700.9606
7490.28720.28730.29490.30020.30790.31880.33980.37040.40390.60960.83330.9676
7480.28870.28850.29680.30190.30950.32040.34190.37300.40720.61530.84020.9743
7470.29000.28980.29800.30310.31080.32190.34400.37540.40990.62070.84700.9814
7460.29140.29130.29950.30480.31290.32410.34600.37820.41310.62680.85450.9888
.......................................
4041.31011.31201.31261.31011.30391.29431.29251.28781.28541.25271.20501.1589
4031.31211.31461.31461.31211.30651.29721.29481.29051.28751.25531.20611.1605
4021.31421.31681.31751.31491.30911.29901.29781.29281.28981.25751.20781.1623
4011.31731.31921.31991.31661.31141.30231.29981.29601.29231.25931.21021.1633
4001.31891.32091.32231.31961.31421.30431.30241.29791.29471.26161.21201.1651

351 rows × 12 columns

In [11]:
ax = E2.loc[580:450, :].plot()
setWLSAxis(ax)
In [12]:
df = E2.loc[[523,625], :].T
df["625/523"] = df[625]/df[523]
df["E2V Conc. (nM)"] = [0, 5, 50, 100, 200, 300, 600, 900, 1200, 4800, 8400, 12000]
In [13]:
display(df)

linearFits = getLinearFits(df, "E2V Conc. (nM)", [625, 523, "625/523"])

display(linearFits)

ax = sns.regplot(x="E2V Conc. (nM)", y="625/523", data=df)
ax.set_title("Salt Concentration vs Absorbtion ratio (625nm:523nm), R$^2={}$"
             .format(round(linearFits.loc["r_value", "625/523"],4)))
Wavelength523625625/523E2V Conc. (nM)
BASELINE2.14530.60810.2834570
5NM2.14030.60720.2836995
50NM2.14030.63020.29444550
100NM2.12590.65230.306835100
200NM2.11200.67250.318419200
300NM2.09410.70420.336278300
600NM2.06850.76990.372202600
900NM2.04440.83970.410732900
1200NM2.01420.90640.4500051200
4800NM1.83451.22690.6687934800
8400NM1.68321.31930.7838058400
12000NM1.57781.32380.83901612000
625523625/523
slope0.000065-4.818046e-054.919550e-05
intercept0.7005652.113024e+003.285755e-01
r_value0.922475-9.873044e-019.647174e-01
p_value0.0000192.542745e-094.058253e-07
std_err0.0000092.451199e-064.245758e-06
Out[13]:
Text(0.5, 1.0, 'Salt Concentration vs Absorbtion ratio (625nm:523nm), R$^2=0.9647$')
In [14]:
dff = df.drop(["4800NM", "8400NM", "12000NM"])
display(dff)

linearFits = getLinearFits(dff, "E2V Conc. (nM)", [625, 523, "625/523"])

display(linearFits)

ax = sns.regplot(x="E2V Conc. (nM)", y="625/523", data=dff)
ax.set_title("E2V Concentration vs Absorbtion ratio (625nm:523nm), R$^2={}$"
             .format(round(linearFits.loc["r_value", "625/523"],4)))
plt.savefig("estradiolValerateTitrationLinearFit.png", dpi=300)
Wavelength523625625/523E2V Conc. (nM)
BASELINE2.14530.60810.2834570
5NM2.14030.60720.2836995
50NM2.14030.63020.29444550
100NM2.12590.65230.306835100
200NM2.11200.67250.318419200
300NM2.09410.70420.336278300
600NM2.06850.76990.372202600
900NM2.04440.83970.410732900
1200NM2.01420.90640.4500051200
625523625/523
slope2.454628e-04-1.071154e-041.365924e-04
intercept6.185525e-012.138264e+002.886448e-01
r_value9.967999e-01-9.903263e-019.975058e-01
p_value6.085192e-092.904142e-072.545327e-09
std_err7.440122e-065.672607e-063.653186e-06

The results above cannot be attributed to the absorbtion spectrum of estradiol valerate

  • The effects are too large
  • The effects are not fully consistent with the absorbtion spectrum of estradiol (below)
In [16]:
rawE2 = pd.read_excel("05292020-E2-FULLBANDSCAN.xlsx", skiprows=12, index_col=0, 
                      usecols=["Abs{}".format(i) for i in range(1,14)]+["Wavelength"])

rawE2.rename(columns={"Abs1":"Blank"}, inplace=True)
display(rawE2)
display(rawE2.plot())

window = 30
windowType = "triang"
rollingE2 = rawE2.rolling(window, win_type=windowType).mean()
newCol = "E2 Raw (n=11)"
combineMultipleScans(rollingE2, "Abs", newName=newCol)
rollingE2["E2 Rolling Avg. (n=11)"] = rollingE2["E2 Raw (n=11)"]-rollingE2["Blank"]
rollingE2 = rollingE2.rolling(window, win_type=windowType).mean()

plt.show()

combineMultipleScans(rawE2, "Abs", newName="E2 Raw (n=11)")
rawE2["E2 Raw (n=11)"] = rawE2["E2 Raw (n=11)"]-rawE2["Blank"]
rawE2.shift()


ax = sns.lineplot(x=rawE2.index, y="E2 Raw (n=11)", data=rawE2, color="red", label="E2 Raw (n=11)", alpha=0.33)
ax = sns.lineplot(x=rollingE2.index, y="E2 Rolling Avg. (n=11)", 
                  label="E2 Rolling Avg. (n=11)", color="blue",
                  data=rollingE2.shift(-window), ax=ax, alpha=1)
setWLSAxis(ax)
ax.set_title("Estradiol Valerate Absorbtion Spectrum")
plt.savefig("estradiol-valerate-abs.png", dpi=300)
BlankAbs2Abs3Abs4Abs5Abs6Abs7Abs8Abs9Abs10Abs11Abs12Abs13
Wavelength
750.0-0.0003-0.00010.00000.00010.0000-0.0004-0.0004-0.0005-0.0005-0.0004-0.0006-0.0004-0.0008
749.5-0.00020.00020.00040.00000.0001-0.0005-0.0002-0.0004-0.0003-0.0006-0.0004-0.0004-0.0007
749.0-0.00010.00030.00040.00010.0002-0.00030.0000-0.0005-0.0005-0.0005-0.0002-0.0002-0.0006
748.5-0.0001-0.00010.00010.0000-0.0004-0.0005-0.0002-0.0005-0.0003-0.0008-0.0006-0.0008-0.0007
748.0-0.00020.00010.00040.00040.0000-0.0002-0.0001-0.00010.0000-0.0003-0.0001-0.0002-0.0001
..........................................
402.00.00000.00480.00470.00460.00470.00450.00440.00450.00460.00450.00460.00470.0049
401.50.00000.00490.00500.00460.00480.00450.00440.00430.00440.00450.00440.00460.0049
401.00.00030.00540.00550.00490.00500.00500.00480.00480.00470.00500.00490.00490.0053
400.50.00020.00500.00490.00480.00480.00490.00460.00460.00450.00480.00470.00490.0050
400.00.00080.00530.00510.00480.00490.00480.00470.00450.00470.00470.00510.00510.0051

701 rows × 13 columns

<matplotlib.axes._subplots.AxesSubplot at 0x7f6449081dc0>
In [ ]: