In this notebook we will plot neutralization curves from GFP-based neutralization assays. The GFP-based neutralization assay system is described in detail here.
All the curves plotted here represent the mean and standard deviation of three replicates, with each replicate in a separate column of a 96-well plate.
The curves fit are the Hill-style neutralization functions fit and plotted by the neutcurve package.
import collections
import itertools
import os
import re
import warnings
import xml.etree.ElementTree as ElementTree
import cairosvg
from IPython.display import display, HTML
import matplotlib.pyplot as plt
import numpy
import pandas as pd
import svgutils.compose
import yaml
from dms_tools2.ipython_utils import showPDF
import neutcurve
from neutcurve.colorschemes import CBPALETTE
import neutcurve.parse_excel
print(f"Using neutcurve version {neutcurve.__version__}")
Using neutcurve version 0.3.0
Interactive matplotlib plotting:
plt.ion()
Suppress warnings that can clutter output:
warnings.simplefilter('ignore')
Read general configuration from config.yaml, which in turn specifies additional configuration files:
with open('config.yaml') as f:
config = yaml.safe_load(f)
Read the neutralization assay configuration from the specified file:
print(f"Reading neutralization assay setup from {config['neut_config']}")
with open(config['neut_config']) as f:
neut_config = yaml.safe_load(f)
Reading neutralization assay setup from data/neut_assays/neut_config.yaml
Get the output directory:
outdir = config['neutresultsdir']
os.makedirs(outdir, exist_ok=True)
print(f"Output will be written to {outdir}")
Output will be written to results/neutralization_assays
Next, for each dict in neut_config, we use neutcurve.parse_excel.parseRachelStyle2019 to parse the raw Excel files to create a tidy data frame appropriate for passing to neutcurve.CurveFits. We then concatenate all the tidy data frames to get our neutralization data. This is essentially the workflow explained here:
neutdata = [] # store all data frame, then concatenate at end
for sampledict in neut_config:
assert len(sampledict) == 1
sampleset, kwargs = list(sampledict.items())[0]
print(f"Parsing data for {sampleset}...")
neutdata.append(neutcurve.parse_excel.parseRachelStyle2019(**kwargs))
neutdata = pd.concat(neutdata)
print(f"Read data for {len(neutdata.groupby('serum'))} sera and "
f"{len(neutdata.groupby(['serum', 'virus']))} serum / virus pairs.")
Parsing data for VIDD1... Parsing data for VIDD2... Parsing data for VIDD3... Parsing data for VIDD4... Parsing data for VIDD5... Parsing data for 557v1... Parsing data for 557v2... Parsing data for 574v1... Parsing data for 574v2... Parsing data for 589v1... Parsing data for 589v2... Parsing data for 571v1... Parsing data for 571v2... Parsing data for ferret-Pitt-1-preinf... Parsing data for ferret-Pitt-1-postinf... Parsing data for ferret-Pitt-2-preinf... Parsing data for ferret-Pitt-2-postinf... Parsing data for ferret-Pitt-3-preinf... Parsing data for ferret-Pitt-3-postinf... Parsing data for ferret-WHO-Perth2009... Parsing data for ferret-WHO-Victoria2011... Parsing data for antibody-5A01... Parsing data for antibody-3C06... Parsing data for antibody-3C04... Parsing data for antibody-4C01... Parsing data for antibody-4F03... Parsing data for antibody-1C04... Read data for 27 sera and 119 serum / virus pairs.
These data look like this:
display(HTML(neutdata.head().to_html(index=False)))
serum | virus | replicate | concentration | fraction infectivity |
---|---|---|---|---|
2010-age-21 | wt | 1 | 0.000024 | 1.010575 |
2010-age-21 | wt | 1 | 0.000046 | 0.981598 |
2010-age-21 | wt | 1 | 0.000086 | 0.997023 |
2010-age-21 | wt | 1 | 0.000163 | 0.954407 |
2010-age-21 | wt | 1 | 0.000308 | 1.005039 |
Write the neutralization data to a CSV file in our output directory:
neutdatafile = os.path.join(outdir, 'neutdata.csv')
neutdata.to_csv(neutdatafile, index=False)
print(f"Wrote neutralization data to {neutdatafile}")
Wrote neutralization data to results/neutralization_assays/neutdata.csv
We get the mean concentration over the three replicates:
mean_concentration = (
pd.read_csv(os.path.join(config['selectiontabledir'], 'serum_dilution_table.csv'))
.rename(columns={'serum_name_formatted': 'serum'})
.drop(columns='serum_group')
.query('not serum.str.contains("antibody")')
.set_index('serum')
.apply(pd.to_numeric, errors='coerce')
.mean(axis=1, numeric_only=True)
.dropna()
.rename('concentration')
.reset_index()
)
display(HTML(mean_concentration.to_html(index=False)))
serum | concentration |
---|---|
2015-age-25-prevacc | 0.005833 |
2015-age-25-vacc | 0.000750 |
2015-age-29-prevacc | 0.015333 |
2015-age-29-vacc | 0.001208 |
2015-age-48-prevacc | 0.017833 |
2015-age-48-vacc | 0.000542 |
2015-age-49-prevacc | 0.018500 |
2015-age-49-vacc | 0.011167 |
2009-age-53 | 0.005417 |
2009-age-53-plus-2-months | 0.006083 |
2009-age-64 | 0.003142 |
2009-age-65 | 0.002083 |
2010-age-21 | 0.009833 |
ferret-Pitt-1-postinf | 0.000433 |
ferret-Pitt-1-preinf | 0.000750 |
ferret-Pitt-2-postinf | 0.001458 |
ferret-Pitt-2-preinf | 0.002000 |
ferret-Pitt-3-postinf | 0.001792 |
ferret-Pitt-3-preinf | 0.004917 |
ferret-WHO-Perth2009 | 0.011167 |
ferret-WHO-Victoria2011 | 0.003750 |
Now convert to dict appropriate for passing to neutcurve.CurveFits.plotSera
as vlines
parameter:
vlines = {tup.serum: [{'x': tup.concentration}] for tup in
mean_concentration.itertuples(index=False)}
Now we fit the neutralization curves with a neutcurve.CurveFits
:
fits = neutcurve.CurveFits(neutdata)
Make a big panel of plots of the across-replicate averages for all sera and antibodies, drawing a vertical line at the mean serum concentration used in the mutational antigenic profiling of the sera:
for is_antibody, ptype, xlabel in [(False, 'sera', 'serum dilution'),
(True, 'antibody', 'concentration ($\mu$g/ml)')]:
plotfile = os.path.join(outdir, f"all_{ptype}_plots.pdf")
print(f"\nPlotting all {ptype} curves to {plotfile}...")
fig, _ = fits.plotSera(
sera=[s for s in fits.sera if ('antibody' in s) == is_antibody],
xlabel=xlabel,
max_viruses_per_subplot=6,
vlines=vlines,
)
display(fig)
fig.savefig(plotfile)
plt.close(fig)
Plotting all sera curves to results/neutralization_assays/all_sera_plots.pdf...
Plotting all antibody curves to results/neutralization_assays/all_antibody_plots.pdf...
Now get the curve fit parameters (e.g., IC50s):
fitparams = fits.fitParams()
Here is a list of all of the IC50s for the replicate-averages for each serum / virus pair. Note that for sera there are dilutions, and for antibodies that are $\mu$g/ml:
display(HTML(fitparams
.query('replicate == "average"')
.drop(columns=['midpoint', 'top', 'bottom', 'replicate',
'ic50', 'ic50_bound', 'slope', 'nreplicates'])
.to_html(index=False)
))
serum | virus | ic50_str |
---|---|---|
2010-age-21 | wt | 0.00118 |
2010-age-21 | F193D | >0.014 |
2010-age-21 | syn | 0.00164 |
2010-age-21 | K189D | 0.0018 |
2010-age-21 | L157D | 0.00107 |
2010-age-21 | wt2 | 0.00148 |
2010-age-21 | F159G | 0.00148 |
2010-age-21 | K160T | 0.00329 |
2009-age-53 | wt | 0.00124 |
2009-age-53 | L157D | 0.00481 |
2009-age-53 | K160T | 0.00338 |
2009-age-53 | F193D | 0.00234 |
2009-age-53 | syn | 0.00153 |
2009-age-53 | wt2 | 0.00144 |
2009-age-53 | K189D | 0.000548 |
2009-age-53 | F159G | 0.00122 |
2009-age-53-plus-2-months | wt | 0.00172 |
2009-age-53-plus-2-months | L157D | 0.00931 |
2009-age-53-plus-2-months | K160T | 0.00387 |
2009-age-53-plus-2-months | F193D | 0.00418 |
2009-age-53-plus-2-months | F159G | 0.00174 |
2009-age-64 | wt | 0.000318 |
2009-age-64 | F159G | 0.0108 |
2009-age-64 | K189D | 0.000258 |
2009-age-64 | F193D | 0.000386 |
2009-age-64 | wt2 | 0.000231 |
2009-age-64 | K160T | 0.000649 |
2009-age-64 | L157D | 0.000213 |
2009-age-64 | syn | 0.000386 |
2009-age-65 | wt | 0.000328 |
2009-age-65 | F193D | >0.0109 |
2009-age-65 | K160T | 0.00145 |
2009-age-65 | syn | 0.000412 |
2009-age-65 | N121E | 0.000332 |
2009-age-65 | F159G | 0.000805 |
2009-age-65 | wt2 | 0.000192 |
2009-age-65 | L157D | 0.00027 |
2009-age-65 | K189D | 0.000202 |
2015-age-25-prevacc | wt | 0.00126 |
2015-age-25-prevacc | F159G | >0.0102 |
2015-age-25-prevacc | R220D | >0.0102 |
2015-age-25-prevacc | K189D | 0.000868 |
2015-age-25-prevacc | wt-2 | 0.00109 |
2015-age-25-prevacc | F159G-2 | >0.0102 |
2015-age-25-prevacc | R220D-2 | >0.0102 |
2015-age-25-vacc | wt | 8.54e-05 |
2015-age-25-vacc | F159G | >0.00117 |
2015-age-25-vacc | syn | 0.000141 |
2015-age-25-vacc | wt2 | 0.000113 |
2015-age-25-vacc | R220D | 0.000141 |
2015-age-25-vacc | K189D | 0.000132 |
2015-age-25-vacc | wt-2 | 0.000114 |
2015-age-25-vacc | F159G-2 | >0.00117 |
2015-age-25-vacc | R220D-2 | 0.00014 |
2015-age-29-prevacc | wt | 0.00637 |
2015-age-29-prevacc | F159G | 0.00954 |
2015-age-29-prevacc | K144E | 0.00561 |
2015-age-29-vacc | wt | 0.000299 |
2015-age-29-vacc | K144E | 0.000559 |
2015-age-29-vacc | F159G | 0.000293 |
2015-age-48-prevacc | wt | >0.00617 |
2015-age-48-vacc | wt | 8.33e-05 |
2015-age-48-vacc | K189D | 0.000413 |
2015-age-48-vacc | F159G | 0.000149 |
2015-age-48-vacc | R220D | 5.53e-06 |
2015-age-48-vacc | K144E | 7.23e-05 |
2015-age-49-prevacc | wt | >0.00617 |
2015-age-49-vacc | wt | 0.00343 |
2015-age-49-vacc | G75(HA2)H | 0.00277 |
ferret-Pitt-1-preinf | wt | >0.00617 |
ferret-Pitt-1-postinf | wt | 9.84e-05 |
ferret-Pitt-1-postinf | K189D | 0.000292 |
ferret-Pitt-1-postinf | F193D | 0.000484 |
ferret-Pitt-1-postinf | syn | 9.9e-05 |
ferret-Pitt-1-postinf | F159G | 0.000186 |
ferret-Pitt-1-postinf | K144E | 0.000176 |
ferret-Pitt-2-preinf | wt | >0.00206 |
ferret-Pitt-2-postinf | wt | 0.000343 |
ferret-Pitt-2-postinf | K189D | 0.000724 |
ferret-Pitt-2-postinf | F193D | 0.0012 |
ferret-Pitt-2-postinf | K144E | 0.000636 |
ferret-Pitt-2-postinf | wt2 | 0.000387 |
ferret-Pitt-2-postinf | R220D | 4.65e-05 |
ferret-Pitt-2-postinf | L157D | 0.000486 |
ferret-Pitt-2-postinf | F159G | 0.000341 |
ferret-Pitt-3-preinf | wt | >0.00617 |
ferret-Pitt-3-postinf | wt | 0.000375 |
ferret-Pitt-3-postinf | K189D | 0.00113 |
ferret-Pitt-3-postinf | F193D | 0.00505 |
ferret-Pitt-3-postinf | K160T | 0.000471 |
ferret-Pitt-3-postinf | L157D | 0.000265 |
ferret-Pitt-3-postinf | wt2 | 0.000732 |
ferret-Pitt-3-postinf | R220D | 8.47e-05 |
ferret-WHO-Perth2009 | wt | 0.00476 |
ferret-WHO-Victoria2011 | wt | 0.00192 |
ferret-WHO-Victoria2011 | K189D | 0.0115 |
ferret-WHO-Victoria2011 | F193D | >0.0125 |
ferret-WHO-Victoria2011 | F159G | 0.00601 |
ferret-WHO-Victoria2011 | K160T | 0.00871 |
antibody-5A01 | wt | 0.0884 |
antibody-5A01 | F159G | >1 |
antibody-5A01 | syn | 0.142 |
antibody-5A01 | K160T | 0.549 |
antibody-3C06 | wt | 0.00726 |
antibody-3C06 | F159G | >0.5 |
antibody-3C06 | K160T | 0.0269 |
antibody-3C04 | wt | 0.00774 |
antibody-3C04 | K160T | >0.5 |
antibody-3C04 | K160S | 0.333 |
antibody-4C01 | wt | 0.0207 |
antibody-4C01 | F193D | >0.5 |
antibody-4C01 | syn | 0.0112 |
antibody-4C01 | K160T | 0.0202 |
antibody-4F03 | wt | 0.362 |
antibody-4F03 | N121E | >3 |
antibody-4F03 | F193D | 0.13 |
antibody-4F03 | F159G | 0.0649 |
antibody-1C04 | wt | 0.0868 |
antibody-1C04 | K82A | >5 |
Write all of the fit parameters (including IC50s) for all replicates to a file:
fitfile = os.path.join(outdir, 'fitparams.csv')
print(f"Writing fit parameters to {fitfile}")
fitparams.to_csv(fitfile, index=False, float_format='%.3g')
Writing fit parameters to results/neutralization_assays/fitparams.csv
Now we are going to make versions of the neutralization curves that are combined with the logo plots created by analyze_map.ipynb to serve as figures.
Get the colors that we have specified for viruses in each serum group for these figures:
with open(config['figure_config']) as f:
figure_config = yaml.safe_load(f)
Get data frame with all sera for each figure:
sera_df = pd.concat(
[pd.DataFrame({'figure': figure,
'sera': figure_d['sera']})
for figure, figure_d in figure_config['figures'].items()
],
ignore_index=True
)
Now draw the plots as single-column figures that can be aligned with the logo plots and save them as SVGs:
sera_viruses_plotted = [] # list 2-tuples of serum / viruses plotted
neutsvgfiles = []
for figure, df in sera_df.groupby('figure'):
ifigconfig = figure_config['figures'][figure]
colors = ifigconfig['colors']
sera = [s for s in df['sera'].unique() if s in fits.sera]
xlabel = ['concentration ($\mu$g/ml)' if 'antibody' in s else 'serum dilution' for s in sera]
# do we have one or multiple x-axis labels, which determines whether we try to align to logos
if len(set(xlabel)) == 1:
xlabel = xlabel[0]
align_to_dmslogo_facet={'height_per_ax': 2.5,
'hspace': 0.8,
'tmargin': 0.4,
'bmargin': 1.3,
'right': 0.75,
'left': 0.2,
}
heightscale = 1
widthscale = 1.37
sharex = True
else:
align_to_dmslogo_facet = False
heightscale = 1.23
widthscale = 1.1
sharex = False
viruses = list(colors.keys())
ignore_serum_virus = (ifigconfig['ignore_serum_virus'] if
'ignore_serum_virus' in ifigconfig else None)
sera_viruses_plotted += [(s, v) for s, v in itertools.product(sera, viruses)
if not ignore_serum_virus or
s not in ignore_serum_virus or
v not in ignore_serum_virus[s]]
fig, _ = fits.plotSera(
sera=sera,
viruses=viruses,
ignore_serum_virus=ignore_serum_virus,
titles=[ifigconfig['sera_names'][s] for s in sera] if 'sera_names' in ifigconfig
else [s.replace('-', ' ') for s in sera],
virus_to_color_marker=colors,
xlabel=xlabel,
max_viruses_per_subplot=len(colors),
ncol=1,
titlesize=17,
labelsize=17,
legendfontsize=14,
ticksize=12,
widthscale=widthscale,
heightscale=heightscale,
markersize=7,
align_to_dmslogo_facet=align_to_dmslogo_facet,
despine=True,
yticklocs=[0, 0.5, 1],
sharex=sharex,
vlines=None if 'spikein' in figure else vlines,
)
neutsvgfile = os.path.join(config['figsdir'], f"{figure}_neut.svg")
print(f"Saving plot for {figure} to {neutsvgfile}")
if sharex:
fig.savefig(neutsvgfile)
else:
fig.savefig(neutsvgfile, bbox_inches='tight')
plt.close(fig)
neutsvgfiles.append(neutsvgfile)
Saving plot for 2009_age_53_samples to results/figures/2009_age_53_samples_neut.svg Saving plot for Hensley_sera to results/figures/Hensley_sera_neut.svg Saving plot for VIDD_sera to results/figures/VIDD_sera_neut.svg Saving plot for antibody_lower_head to results/figures/antibody_lower_head_neut.svg Saving plot for antibody_region_B to results/figures/antibody_region_B_neut.svg Saving plot for antibody_spikein to results/figures/antibody_spikein_neut.svg Saving plot for ferret to results/figures/ferret_neut.svg
Now we will combine the logo and SVG files.
First, we need to define a function to get the width / height of a SVG file in points (see here):
def svg_dim(svgfile, dim):
"""Get width or height `dim` of `svgfile` in points."""
return float(ElementTree.parse(svgfile).getroot().attrib[dim].replace('pt', ''))
We also define a function that converts a SVG into a PDF or PNG:
def svg_to_pdf(svgfile):
"""`svgfile` to PDF, return converted file name."""
with open(svgfile) as f:
svg = f.read()
# need to eliminate units that `svgutils` incorrectly puts in viewBox
viewbox_match = re.compile('viewBox="' + ' '.join(['\d+\.{0,1}\d*(px){0,1}'] * 4) + '"')
if len(viewbox_match.findall(svg)) != 1:
raise ValueError(f"did not find exactly one viewBox in {svgfile}")
viewbox = viewbox_match.search(svg).group(0)
svg = svg.replace(viewbox, viewbox.replace('px', ''))
outfile = os.path.splitext(svgfile)[0] + '.pdf'
cairosvg.svg2pdf(bytestring=svg, write_to=outfile)
return outfile
Now we combine the neutralization curve SVGs with the logo-plot SVGs (which should already exist as output of analyze_map.ipynb) as here:
for neutsvgfile in neutsvgfiles:
logosvgfile = neutsvgfile.replace('_neut', '_logo')
assert os.path.isfile(logosvgfile), f"cannot find {logosvgfile}"
svgfile = neutsvgfile.replace('_neut', '_logo_and_neut')
plots = [logosvgfile, neutsvgfile]
widths = [svg_dim(p, 'width') for p in plots]
heights = [svg_dim(p, 'height') for p in plots]
xshifts = numpy.cumsum(widths) - numpy.array(widths)
xshifts = numpy.clip(xshifts - 1, 0, None) # reduce by one to avoid gaps
figure = os.path.basename(neutsvgfile).replace('_neut.svg', '')
letters = [figure_config['figures'][figure]['logo_panel_label'],
figure_config['figures'][figure]['neut_panel_label']]
fig_elements = []
for letter, p, x in zip(letters, plots, xshifts):
fig_elements.append(svgutils.compose.SVG(p).move(x, 0))
fig_elements.append(svgutils.compose.Text(letter, 15, 25, weight='bold',
size='26', font='Arial').move(x, 0))
f = svgutils.compose.Figure(sum(widths), max(heights), *fig_elements)
f.save(svgfile)
pdffile = svg_to_pdf(svgfile)
print(f"\nWriting figure to {svgfile} and {pdffile}")
showPDF(pdffile)
Writing figure to results/figures/2009_age_53_samples_logo_and_neut.svg and results/figures/2009_age_53_samples_logo_and_neut.pdf
Writing figure to results/figures/Hensley_sera_logo_and_neut.svg and results/figures/Hensley_sera_logo_and_neut.pdf
Writing figure to results/figures/VIDD_sera_logo_and_neut.svg and results/figures/VIDD_sera_logo_and_neut.pdf
Writing figure to results/figures/antibody_lower_head_logo_and_neut.svg and results/figures/antibody_lower_head_logo_and_neut.pdf
Writing figure to results/figures/antibody_region_B_logo_and_neut.svg and results/figures/antibody_region_B_logo_and_neut.pdf
Writing figure to results/figures/antibody_spikein_logo_and_neut.svg and results/figures/antibody_spikein_logo_and_neut.pdf
Writing figure to results/figures/ferret_logo_and_neut.svg and results/figures/ferret_logo_and_neut.pdf
Now tabulate the fit parameters for the serum / viruses that we plotted in the figures:
fit_table = (
fits.fitParams()
.query('replicate == "average"')
.merge(pd.DataFrame.from_records(sera_viruses_plotted, columns=['serum', 'virus']),
how='inner')
[['serum', 'virus', 'ic50_str', 'slope', 'top', 'bottom']]
.drop_duplicates()
.sort_values(['serum', 'virus'], ascending=[True, False])
)
display(HTML(fit_table.to_html(index=False)))
fit_table_file = os.path.join(outdir, 'neut_assay_figs_fit_params.csv')
print(f"Writing table to {fit_table_file}")
fit_table.to_csv(fit_table_file, index=False, float_format='%.3g')
serum | virus | ic50_str | slope | top | bottom |
---|---|---|---|---|---|
2009-age-53 | wt | 0.00124 | 1.779855 | 1 | 0 |
2009-age-53 | syn | 0.00153 | 2.317307 | 1 | 0 |
2009-age-53 | L157D | 0.00481 | 1.976588 | 1 | 0 |
2009-age-53 | K189D | 0.000548 | 1.858524 | 1 | 0 |
2009-age-53 | K160T | 0.00338 | 2.118436 | 1 | 0 |
2009-age-53 | F193D | 0.00234 | 1.856294 | 1 | 0 |
2009-age-53 | F159G | 0.00122 | 1.937589 | 1 | 0 |
2009-age-53-plus-2-months | wt | 0.00172 | 1.208404 | 1 | 0 |
2009-age-53-plus-2-months | L157D | 0.00931 | 2.644220 | 1 | 0 |
2009-age-53-plus-2-months | K160T | 0.00387 | 2.206106 | 1 | 0 |
2009-age-53-plus-2-months | F193D | 0.00418 | 1.843438 | 1 | 0 |
2009-age-64 | wt | 0.000318 | 2.252406 | 1 | 0 |
2009-age-64 | syn | 0.000386 | 1.669909 | 1 | 0 |
2009-age-64 | L157D | 0.000213 | 1.780584 | 1 | 0 |
2009-age-64 | K189D | 0.000258 | 1.550414 | 1 | 0 |
2009-age-64 | K160T | 0.000649 | 1.976921 | 1 | 0 |
2009-age-64 | F193D | 0.000386 | 2.065217 | 1 | 0 |
2009-age-64 | F159G | 0.0108 | 3.297095 | 1 | 0 |
2009-age-65 | wt | 0.000328 | 2.008450 | 1 | 0 |
2009-age-65 | syn | 0.000412 | 2.109484 | 1 | 0 |
2009-age-65 | N121E | 0.000332 | 1.993601 | 1 | 0 |
2009-age-65 | L157D | 0.00027 | 1.996908 | 1 | 0 |
2009-age-65 | K189D | 0.000202 | 1.603608 | 1 | 0 |
2009-age-65 | K160T | 0.00145 | 2.568102 | 1 | 0 |
2009-age-65 | F193D | >0.0109 | 21.576706 | 1 | 0 |
2009-age-65 | F159G | 0.000805 | 1.974978 | 1 | 0 |
2010-age-21 | wt | 0.00118 | 1.989081 | 1 | 0 |
2010-age-21 | syn | 0.00164 | 2.586569 | 1 | 0 |
2010-age-21 | L157D | 0.00107 | 2.076028 | 1 | 0 |
2010-age-21 | K189D | 0.0018 | 2.127158 | 1 | 0 |
2010-age-21 | K160T | 0.00329 | 2.515296 | 1 | 0 |
2010-age-21 | F193D | >0.014 | 10.432859 | 1 | 0 |
2010-age-21 | F159G | 0.00148 | 2.362529 | 1 | 0 |
2015-age-25-prevacc | wt | 0.00126 | 2.430043 | 1 | 0 |
2015-age-25-prevacc | R220D | >0.0102 | 23.974538 | 1 | 0 |
2015-age-25-prevacc | K189D | 0.000868 | 1.782274 | 1 | 0 |
2015-age-25-prevacc | F159G | >0.0102 | 9.591964 | 1 | 0 |
2015-age-25-vacc | wt | 8.54e-05 | 2.609425 | 1 | 0 |
2015-age-25-vacc | R220D | 0.000141 | 3.151577 | 1 | 0 |
2015-age-25-vacc | K189D | 0.000132 | 1.937381 | 1 | 0 |
2015-age-25-vacc | F159G | >0.00117 | 1.170513 | 1 | 0 |
2015-age-29-prevacc | wt | 0.00637 | 2.061859 | 1 | 0 |
2015-age-29-prevacc | K144E | 0.00561 | 1.921607 | 1 | 0 |
2015-age-29-prevacc | F159G | 0.00954 | 3.335905 | 1 | 0 |
2015-age-29-vacc | wt | 0.000299 | 3.208098 | 1 | 0 |
2015-age-29-vacc | K144E | 0.000559 | 3.473683 | 1 | 0 |
2015-age-29-vacc | F159G | 0.000293 | 2.981604 | 1 | 0 |
2015-age-48-prevacc | wt | >0.00617 | 2.134402 | 1 | 0 |
2015-age-48-vacc | wt | 8.33e-05 | 1.779256 | 1 | 0 |
2015-age-48-vacc | K189D | 0.000413 | 1.311547 | 1 | 0 |
2015-age-48-vacc | K144E | 7.23e-05 | 2.387690 | 1 | 0 |
2015-age-48-vacc | F159G | 0.000149 | 1.457277 | 1 | 0 |
2015-age-49-prevacc | wt | >0.00617 | 0.303021 | 1 | 0 |
2015-age-49-vacc | wt | 0.00343 | 1.773101 | 1 | 0 |
antibody-1C04 | wt | 0.0868 | 1.439844 | 1 | 0 |
antibody-1C04 | K82A | >5 | 9.513325 | 1 | 0 |
antibody-4C01 | wt | 0.0207 | 2.773914 | 1 | 0 |
antibody-4C01 | K160T | 0.0202 | 2.271633 | 1 | 0 |
antibody-4C01 | F193D | >0.5 | 10.334572 | 1 | 0 |
antibody-4F03 | wt | 0.362 | 1.502185 | 1 | 0 |
antibody-4F03 | N121E | >3 | 9.580069 | 1 | 0 |
antibody-4F03 | F193D | 0.13 | 1.819803 | 1 | 0 |
antibody-4F03 | F159G | 0.0649 | 1.831487 | 1 | 0 |
antibody-5A01 | wt | 0.0884 | 2.103692 | 1 | 0 |
antibody-5A01 | K160T | 0.549 | 1.852408 | 1 | 0 |
antibody-5A01 | F159G | >1 | 1.384432 | 1 | 0 |
ferret-Pitt-1-postinf | wt | 9.84e-05 | 2.659119 | 1 | 0 |
ferret-Pitt-1-postinf | K189D | 0.000292 | 2.014105 | 1 | 0 |
ferret-Pitt-1-postinf | K144E | 0.000176 | 3.166316 | 1 | 0 |
ferret-Pitt-1-postinf | F193D | 0.000484 | 3.940897 | 1 | 0 |
ferret-Pitt-1-postinf | F159G | 0.000186 | 2.015143 | 1 | 0 |
ferret-Pitt-1-preinf | wt | >0.00617 | 8.567956 | 1 | 0 |
ferret-Pitt-2-postinf | wt | 0.000343 | 2.671063 | 1 | 0 |
ferret-Pitt-2-postinf | L157D | 0.000486 | 2.964182 | 1 | 0 |
ferret-Pitt-2-postinf | K189D | 0.000724 | 2.611096 | 1 | 0 |
ferret-Pitt-2-postinf | K144E | 0.000636 | 2.802963 | 1 | 0 |
ferret-Pitt-2-postinf | F193D | 0.0012 | 3.102091 | 1 | 0 |
ferret-Pitt-2-postinf | F159G | 0.000341 | 2.252597 | 1 | 0 |
ferret-Pitt-2-preinf | wt | >0.00206 | 9.757383 | 1 | 0 |
ferret-Pitt-3-postinf | wt | 0.000375 | 2.435213 | 1 | 0 |
ferret-Pitt-3-postinf | L157D | 0.000265 | 1.905240 | 1 | 0 |
ferret-Pitt-3-postinf | K189D | 0.00113 | 1.981848 | 1 | 0 |
ferret-Pitt-3-postinf | K160T | 0.000471 | 2.376600 | 1 | 0 |
ferret-Pitt-3-postinf | F193D | 0.00505 | 3.129703 | 1 | 0 |
ferret-Pitt-3-preinf | wt | >0.00617 | 8.589477 | 1 | 0 |
ferret-WHO-Perth2009 | wt | 0.00476 | 2.111494 | 1 | 0 |
ferret-WHO-Victoria2011 | wt | 0.00192 | 2.256116 | 1 | 0 |
ferret-WHO-Victoria2011 | K189D | 0.0115 | 3.008475 | 1 | 0 |
ferret-WHO-Victoria2011 | K160T | 0.00871 | 2.421736 | 1 | 0 |
ferret-WHO-Victoria2011 | F193D | >0.0125 | 2.561249 | 1 | 0 |
ferret-WHO-Victoria2011 | F159G | 0.00601 | 2.520402 | 1 | 0 |
Writing table to results/neutralization_assays/neut_assay_figs_fit_params.csv