def tetheredYN(L0, KxStar, Rtot, Kav, fully=True): """ Compare tethered (bispecific) vs monovalent """ if fully: return polyc(L0, KxStar, Rtot, [[1, 1]], [1.0], Kav)[2][0] / \ polyfc(L0 * 2, KxStar, 1, Rtot, [0.5, 0.5], Kav)[0] else: return polyc(L0, KxStar, Rtot, [[1, 1]], [1.0], Kav)[0][0] / \ polyfc(L0 * 2, KxStar, 1, Rtot, [0.5, 0.5], Kav)[0]
def selectivity(pop1name, pop2name, L0, KxStar, Cplx, Ctheta, Kav, fully=True, untethered=False): """ Always calculate the full binding of the 1st kind of complex """ pop1 = cellPopulations[pop1name][0], cellPopulations[pop1name][1] pop2 = cellPopulations[pop2name][0], cellPopulations[pop2name][1] if untethered: # mixture of monovalent return polyfc(L0, KxStar, 1, np.power(10, pop1), [0.5, 0.5], Kav)[0] \ / polyfc(L0, KxStar, 1, np.power(10, pop2), [0.5, 0.5], Kav)[0] if fully: return np.sum(polyc(L0, KxStar, np.power(10, pop1), Cplx, Ctheta, Kav)[2]) \ / np.sum(polyc(L0, KxStar, np.power(10, pop2), Cplx, Ctheta, Kav)[2]) else: return np.sum(polyc(L0, KxStar, np.power(10, pop1), Cplx, Ctheta, Kav)[0]) \ / np.sum(polyc(L0, KxStar, np.power(10, pop2), Cplx, Ctheta, Kav)[0])
def vieqPlot(ax, recCount, val): "Demonstrate effect of valency" vieqDF = pds.DataFrame( columns=["Degree of Binding", "# Ligand Bound", "$K_d$ nM"]) Conc = 1e-9 affs = [1e8, 1e7, 1e6] afflabs = ["10", "100", "1000"] for ii, aff in enumerate(affs): vieq = polyfc(Conc / (val), KxStarP, val, recCount, [1], np.array([[aff]]))[2] # val + 1 for jj, bound in enumerate(vieq): ligboundDF = pds.DataFrame({ "Degree of Binding": jj + 1, "# Ligand Bound": [bound], "$K_d$ nM": afflabs[ii] }) vieqDF = vieqDF.append(ligboundDF) sns.stripplot(x="Degree of Binding", y="# Ligand Bound", hue="$K_d$ nM", data=vieqDF, ax=ax) ax.set(yscale="log", ylim=(0.1, 1e4), title="Binding Degrees Distribution, " + str(int(recCount)) + " receptors", ylabel="Ligand Bound", xlabel="Degree of Binding")
def heatmapNorm(ax, R0, L0, KxStar, Kav, Comp, f=None, Cplx=None, vrange=(0, 5), title="", cbar=False, layover=2, highlight=[], lineN=101, recFactor=1.0): assert bool(f is None) != bool(Cplx is None) nAbdPts = 70 abundRange = (LR + np.log10(recFactor), HR + np.log10(recFactor)) abundScan = np.logspace(abundRange[0], abundRange[1], nAbdPts) if f is None: func = np.vectorize(lambda abund1, abund2: polyc(L0, KxStar, [abund1, abund2], Cplx, Comp, Kav)[2][0]) else: func = np.vectorize(lambda abund1, abund2: polyfc(L0, KxStar, f, [abund1, abund2], Comp, Kav)[0]) func0 = func(10**(R0[0] + np.log10(recFactor)), 10**(R0[1] + np.log10(recFactor))) X, Y = np.meshgrid(abundScan, abundScan) Z = func(X, Y) / func0 contours1 = ax.contour(X, Y, Z, levels=np.logspace(0, 10, (lineN - 1) // 2 + 1)[1:], colors="black", linewidths=0.5) contours0 = ax.contour(X, Y, Z, levels=np.logspace(-10, 0, (lineN - 1) // 2 + 1), colors="white", linewidths=0.5) ax.set_xscale("log") ax.set_yscale("log") ax.set_title(title) plt.clabel(contours1, inline=True, fontsize=8, fmt="%3.1g") plt.clabel(contours0, inline=True, fontsize=8, fmt="%3.1g") ax.pcolor(X, Y, Z, cmap='viridis', vmin=vrange[0], vmax=vrange[1]) norm = plt.Normalize(vmin=vrange[0], vmax=vrange[1]) if cbar: cbar = ax.figure.colorbar(cm.ScalarMappable(norm=norm, cmap='viridis'), ax=ax) cbar.set_label("Relative Ligand Bound") # layover: 2 = with name; 1 = only pop w/o name; 0 = none if layover == 2: overlapCellPopulation(ax, abundRange, highlight=highlight, recFactor=np.log10(recFactor), pname=True) elif layover == 1: overlapCellPopulation(ax, abundRange, highlight=highlight, recFactor=np.log10(recFactor), pname=False)
def minSelecFunc(x, tPops, offTPops): """Provides the function to be minimized to get optimal selectivity""" offTargetBound = 0 tMeans, offTMeans = genPopMeans(tPops), genPopMeans(offTPops) targetBound = polyfc( np.exp(x[0]), np.exp(x[1]), x[2], [10**tMeans[0][0], 10**tMeans[0][1]], [x[3], 1 - x[3]], np.array([[np.exp(x[4]), np.exp(x[5])], [np.exp(x[6]), np.exp(x[7])]]))[0] for means in offTMeans: offTargetBound += polyfc( np.exp(x[0]), np.exp(x[1]), x[2], [10**means[0], 10**means[1]], [x[3], 1 - x[3]], np.array([[np.exp(x[4]), np.exp(x[5])], [np.exp(x[6]), np.exp(x[7])]]))[0] return (offTargetBound) / (targetBound)
def xeno(ax, KxStarX, valencies): "Plots Xenograft targeting ratios" df = pd.DataFrame(columns=["Ligand", "ratio"]) for i, lig in enumerate([[8, 0, 0], [4, 0, 4], [0, 8, 0], [0, 4, 4]]): mcf = polyfc(50 * 1e-9, KxStarX, valencies[i], [Recep["MCF"]], lig, Kav)[0] mda = polyfc(50 * 1e-9, KxStarX, valencies[i], [Recep["MDA"]], lig, Kav)[0] df = df.append({ "Ligand": ligandDict[str(lig)], "ratio": (mcf / mda) }, ignore_index=True) sns.barplot(x="Ligand", y="ratio", data=df, ax=ax) ax.set(xlabel="", ylabel="Binding Ratio") ax.set_xticklabels(ax.get_xticklabels(), rotation=25, horizontalalignment='center') ax.set(ylim=(0, 100)) return ax
def sigmaPop(name, L0, KxStar, f, LigC, Kav, quantity=0, h=None, recFactor=1.0): return np.array([ polyfc(L0, KxStar, f, Rtot, LigC, Kav)[quantity] for Rtot in sigmapts(name, h=h, recFactor=recFactor) ]).reshape(-1)
def discrim2(ax, KxStarD, slopeC5, slopeB22, valencies): "Returns predicted fluorescent values over a range of abundances with unique slopes for C5 and B22" df = pd.DataFrame(columns=["Ligand", "Receptor", "value"]) for i, lig in enumerate([[8, 0, 0], [4, 0, 4]]): for rec in Recep.values(): res = polyfc(50 * 1e-9, KxStarD, valencies[i], [rec], lig, Kav) df = df.append( { "Ligand": ligandDict[str(lig)], "Recep": rec, "value": res[0] * slopeC5 }, ignore_index=True) # * (lig[0] + lig[1]) for j, lig in enumerate([[0, 8, 0], [0, 4, 4]]): for rec in Recep.values(): res = polyfc(50 * 1e-9, KxStarD, valencies[j], [rec], lig, Kav) df = df.append( { "Ligand": ligandDict[str(lig)], "Recep": rec, "value": res[0] * slopeB22 }, ignore_index=True) # * (lig[0] + lig[1]) sns.lineplot(x="Recep", y="value", hue="Ligand", style="Ligand", markers=True, data=df, ax=ax) ax.set(xlabel="Receptor Abundance", ylabel="Ligand Bound") ax.set_xscale("log") ax.set_yscale("log") ax.set(xlim=(1e4, 1e7), ylim=(10, 1e5)) return ax
def model_predict(df, KxStarP, LigC, slopeP, abund, valencies): "Gathers predicted and measured fluorescent intensities for a given population" predicted, measured = [], [] for _, row in df.iterrows(): val = valencies[valDict[row.valency]] res = polyfc( row.monomer * 1e-9 / 8, KxStarP, val, abund, np.array(LigC) * row.valency / 8 + [0, 0, 1 - sum(np.array(LigC) * row.valency / 8)], Kav) Lbound, _ = res[0] * slopeP, res[1] predicted.append(Lbound) measured.append(row.intensity) return np.array(predicted), np.array(measured)
def ConcValPlot(ax): "Keep valency constant and high - vary concentration" concScan = np.logspace(-11, -7, 5) valency = 4 recScan = np.logspace(0, 8, 100) percHold = np.zeros(100) for conc in concScan: for jj, recCount in enumerate(recScan): percHold[jj] = polyfc(conc / valency, KxStarP, valency, recCount, [1], np.array([[affinity]]))[0] / recCount ax.plot(recScan, percHold, label=str(conc * 1e9) + " nM") ax.set(xlim=(1, 100000000), xlabel="Receptor Abundance", ylabel="Lig Bound / Receptor", xscale="log") # ylim=(0, 1), ax.legend(prop={"size": 6})
def valDemo(ax): "Demonstrate effect of valency" affs = [1e8, 1e7] colors = ["royalblue", "orange", "limegreen", "orangered"] lines = ["-", ":"] nPoints = 100 recScan = np.logspace(0, 8, nPoints) labels = ["Monovalent", "Bivalent", "Trivalent", "Tetravalent"] percHold = np.zeros(nPoints) for ii, aff in enumerate(affs): for jj, valencyLab in enumerate(labels): for kk, recCount in enumerate(recScan): percHold[kk] = polyfc(ligConc / (jj + 1), KxStarP, jj + 1, recCount, [1], np.array([[aff]]))[0] / recCount ax.plot(recScan, percHold, label=valencyLab, linestyle=lines[ii], color=colors[jj]) ax.set(xlim=(1, 100000000), xlabel="Receptor Abundance", ylabel="Lig bound / Receptor", xscale="log") # ylim=(0, 1), handles, _ = ax.get_legend_handles_labels() handles = handles[0:4] line = Line2D([], [], color="black", marker="_", linestyle="None", markersize=6, label="High Affinity") point = Line2D([], [], color="black", marker=".", linestyle="None", markersize=6, label="Low Affinity") handles.append(line) handles.append(point) ax.legend(handles=handles, prop={"size": 6})
def heatmap(ax, L0, KxStar, Kav, Comp, f=None, Cplx=None, vrange=(-2, 4), title="", cbar=False, layover=2, fully=False, highlight=[]): assert bool(f is None) != bool(Cplx is None) nAbdPts = 70 abundRange = (LR, HR) abundScan = np.logspace(abundRange[0], abundRange[1], nAbdPts) if f is None: if fully: func = np.vectorize(lambda abund1, abund2: np.sum(polyc(L0, KxStar, [abund1, abund2], Cplx, Comp, Kav)[2])) else: func = np.vectorize(lambda abund1, abund2: np.sum(polyc(L0, KxStar, [abund1, abund2], Cplx, Comp, Kav)[0])) else: func = np.vectorize(lambda abund1, abund2: polyfc(L0, KxStar, f, [abund1, abund2], Comp, Kav)[0]) X, Y = np.meshgrid(abundScan, abundScan) logZ = np.log(func(X, Y)) vmed = int((vrange[0] + vrange[1]) / 2) contours0 = ax.contour(X, Y, logZ, levels=np.arange(-20, vmed, 1), colors="white", linewidths=0.5) contours1 = ax.contour(X, Y, logZ, levels=np.arange(vmed, 20, 1), colors="black", linewidths=0.5) ax.set_xscale("log") ax.set_yscale("log") ax.yaxis.set_major_formatter(mticker.ScalarFormatter(useOffset=False, useMathText=True)) ax.set_title(title) plt.clabel(contours0, inline=True, fontsize=8) plt.clabel(contours1, inline=True, fontsize=8) ax.pcolor(X, Y, logZ, cmap='viridis', vmin=vrange[0], vmax=vrange[1]) norm = plt.Normalize(vmin=vrange[0], vmax=vrange[1]) if cbar: cbar = ax.figure.colorbar(cm.ScalarMappable(norm=norm, cmap='viridis'), ax=ax) cbar.set_label("Log Ligand Bound") # layover: 2 = with name; 1 = only pop w/o name; 0 = none if layover == 2: overlapCellPopulation(ax, abundRange, highlight=highlight, pname=True) elif layover == 1: overlapCellPopulation(ax, abundRange, highlight=highlight, pname=False)
def affHeatMap(ax, names, Kav, L0, KxStar, f, Title, Cbar=True): "Makes a heatmap comparing binding ratios of populations at a range of binding affinities" npoints = 3 ticks = np.full([npoints], None) affScan = np.logspace(Kav[0], Kav[1], npoints) ticks[0], ticks[-1] = "${}$".format(int(10**(9 - Kav[0]))), "${}$".format(int(10**(9 - Kav[1]))) sampMeans = np.zeros(npoints) ratioDF = pds.DataFrame(columns=affScan, index=affScan) for ii, aff1 in enumerate(affScan): for jj, aff2 in enumerate(np.flip(affScan)): recMeans0 = np.array([cellPopulations[names[0]][0], cellPopulations[names[0]][1]]) recMeans1 = np.array([cellPopulations[names[1]][0], cellPopulations[names[1]][1]]) sampMeans[jj] = polyfc(L0, KxStar, f, np.power(10, recMeans0), [1], np.array([[aff1, aff2]]))[0] / polyfc(L0, KxStar, f, np.power(10, recMeans1), [1], np.array([[aff1, aff2]]))[0] ratioDF[ratioDF.columns[ii]] = sampMeans if ratioDF.max().max() < 15: sns.heatmap(ratioDF, ax=ax, xticklabels=ticks, yticklabels=np.flip(ticks), vmin=0, vmax=10, cbar=Cbar, cbar_kws={'label': 'Binding Ratio'}, annot=True) else: max = np.round(np.ceil(ratioDF.max().max() / 10) * 10, -1) sns.heatmap(ratioDF, ax=ax, xticklabels=ticks, yticklabels=np.flip(ticks), vmin=0, vmax=max, cbar=Cbar, cbar_kws={'label': 'Binding Ratio'}, annot=True) ax.set(xlabel="Rec 1 Affinity ($K_d$ [nM])", ylabel="Rec 2 Affinity ($K_d$ [nM])") ax.set_title(Title, fontsize=10)