Part III: Post analysis (Python/Jupyter/Colab)#
This tutorial is a Jupyter notebook that illustrates how to load & open output files from Tapqir analysis. To work with the live version of the notebook run it in Google Colab using the link above.
Set up the environment#
Connect Google Drive to be able to save the analysis output (to view Files & Folders click on a Folder icon on the left):
[ ]:
# Run this cell to connect to Google Drive
from google.colab import drive
drive.mount("/content/drive")
Mounted at /content/drive
Run the cell below to install
tapqir
(takes about a minute):
[ ]:
!pip install --quiet tapqir > install.log
Load data & analysis results#
Extracted AOI images are stored in a data.tpqr
file; analysis results are stored in a cosmos-channel0-params.tpqr
and cosmos-channel0-summary.csv
files. We will import cosmos
model from tapqir
, create its instance, and then call .load
method to load these files:
[1]:
# import cosmos model
from tapqir.models import Cosmos
# create a cosmos model instance
model = Cosmos()
# load analysis results from the working directory
model.load(path="/content/drive/MyDrive/tutorial", data_only=False)
AOI images#
[2]:
# data can be accessed through .data attribute
model.data
[2]:
CosmosDataset: Rpb1SNAP549
images tensor(N=331 on-target AOIs, Nc=526 off-target AOIs, F=790 frames, C=1 channels, P=14 pixels, P=14 pixels)
x tensor(N=331 on-target AOIs, Nc=526 off-target AOIs, F=790 frames, C=1 channels)
y tensor(N=331 on-target AOIs, Nc=526 off-target AOIs, F=790 frames, C=1 channels)
offset.samples tensor([ 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103,
104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116],
dtype=torch.int32)
.weights tensor([2.8129e-06, 6.7511e-05, 4.1210e-04, 1.7932e-03, 7.1871e-03, 2.1366e-02,
4.7677e-02, 9.0093e-02, 1.3192e-01, 1.6421e-01, 1.5248e-01, 1.0433e-01,
7.7949e-02, 5.2655e-02, 3.5667e-02, 2.2335e-02, 1.9520e-02, 1.6328e-02,
1.2553e-02, 8.6892e-03, 7.2546e-03, 5.8228e-03, 4.4402e-03, 3.1153e-03,
2.5893e-03, 2.3038e-03, 7.2433e-03], dtype=torch.float32)
Data is stored as a CosmosDataset
object that has a title (Rpb1SNAP549
), images
attribute for AOI images (torch.Tensor object with (N+Nc, F, C, P, P)
shape), x
attribute for target locations on the x-axis (torch.Tensor with (N+Nc, F, C)
shape), and y
attribute for target locations on the y-axis (torch.Tensor with (N+Nc, F, C)
shape), and offset
attribute for camera offset data.
As an example let’s plot frames 625, 628, 630, 633, 635, 638, 640, 643, 645 from AOI 163 and also show target locations (red +
sign).
[3]:
# import matplotlib for plotting
import matplotlib.pyplot as plt
fig = plt.figure(figsize=(15, 1.5))
n = 163 # AOI
c = 0 # color channel
frames = [625, 628, 630, 633, 635, 638, 640, 643, 645]
for i, f in enumerate(frames):
ax = fig.add_subplot(1, 9, i + 1)
ax.imshow(model.data.images[n, f, c].numpy(), vmin=340, vmax=635, cmap="gray")
ax.scatter(
model.data.x[n, f, c].item(),
model.data.y[n, f, c].item(),
c="r",
s=100,
marker="+",
)
ax.set_title(f, fontsize=16)
ax.axis("off")
Offset distribution#
offset
is an OffsetData
object that has samples
attribute for camera offset values and weights
attribute for their probabilities (together they define and Empirical distribution for the offset signal). Let’s plot it.
[4]:
plt.figure(figsize=(3, 3))
plt.bar(model.data.offset.samples, model.data.offset.weights)
plt.title("Offset", fontsize=16)
plt.ylabel("Density", fontsize=16)
plt.xlabel("Intensity", fontsize=16)
plt.show()
Parameters#
Model parameters with 95% CI (credible interval) are stored in cosmos-params.tpqr
file (nested dictionary of torch.Tensor
s). It can be accessed using a .params
attribute:
[5]:
# list all parameters
model.params.keys()
[5]:
dict_keys(['gain', 'proximity', 'lamda', 'pi', 'Keq', 'height', 'width', 'x', 'y', 'background', 'm_probs', 'theta_probs', 'z_probs', 'z_map', 'p_specific', 'time1', 'ttb', 'h_specific', 'chi2'])
gain
- \(g\) camera gainproximity
- \(\sigma^{xy}\) proximitylamda
- \(\lambda\) off-target binding ratepi
- \(\pi\) average on-target binding probabilityKeq
- equilibrium constant calculated as \(\frac{\pi}{1-\pi}\)z_probs
- \(p(z=1|D)\) probability of there being any target-specific spot in an AOI imagep_specific
- \(p(\mathsf{specific})\) probability of there being any target-specific spot in an AOI imagez_map
- most likely value (0 or 1) for target-specific spot presence (obtained from \(p(\mathsf{specific})\) using 0.5 cutoff)theta_probs
- \(p(\theta=k|D)\) target-specific spot index probabilitiesm_probs
- \(p(m=1|D)\) spot presence probabilitiesheight
- \(h\) spot intensitywidth
- \(w\) spot widthx
- \(x\) spot position on x-axisy
- \(y\) spot position on y-axisbackground
- \(b\) background intensity
For example, let’s look at gain \(g\):
[6]:
model.params["gain"]
[6]:
{'LL': tensor(6.7341), 'UL': tensor(6.7392), 'Mean': tensor(6.7366)}
It is a dictionary with the values of the mean (Mean
), 95% credible interval lower-limit (LL
) and upper-limit (UL
).
Let’s plot \(p(\mathsf{specific})\) for AOI 163 and frames from 625 to 645:
[7]:
n = 163
f1, f2 = 625, 645
plt.figure(figsize=(10, 2))
plt.plot(range(f1, f2), model.params["z_probs"][n, f1:f2], "o-", color="C2")
plt.ylabel(r"$p(\mathsf{specific})$", fontsize=12)
plt.xlabel("Time (frame)", fontsize=12)
plt.xticks(range(f1, f2))
plt.show()
To plot credible intervals we can use pyplot
’s fill_between
method. Here is the plot of intensity \(h\) for spot 1 in the same range of frames:
[8]:
k = 0 # spot 1
n = 163 # AOI
f1, f2 = 625, 645 # frame range
plt.figure(figsize=(10, 2))
plt.plot(range(f1, f2), model.params["height"]["Mean"][k, n, f1:f2], "-", color="C0")
plt.fill_between(
range(f1, f2),
model.params["height"]["LL"][k, n, f1:f2],
model.params["height"]["UL"][k, n, f1:f2],
color="C0",
alpha=0.3,
)
plt.ylabel(r"$h$ (spot 1)", fontsize=12)
plt.xlabel("Time (frame)", fontsize=12)
plt.xticks(range(f1, f2))
plt.show()
Here we plot ntensities of target-specifics. Target-specific spot is selected from two spots using 0.5 probability cut-off.
[9]:
n = 163 # AOI
theta_mask = model.params["theta_probs"][:, n] > 0.5
height_mean = (model.params["height"]["Mean"][:, n] * theta_mask).sum(0)
height_ll = (model.params["height"]["LL"][:, n] * theta_mask).sum(0)
height_ul = (model.params["height"]["UL"][:, n] * theta_mask).sum(0)
plt.figure(figsize=(10, 2))
plt.plot(range(0, model.data.F), height_mean, "-", color="C2")
plt.fill_between(
range(0, model.data.F),
height_ll,
height_ul,
color="C2",
alpha=0.3,
)
plt.ylabel(r"$h$ (specific)", fontsize=12)
plt.xlabel("Time (frame)", fontsize=12)
plt.show()
Probabilistic rastergram#
We can plot \(p(\mathsf{specific})\) as a probabilistic rastergram.
[10]:
import matplotlib as mpl
plt.figure(figsize=(10, 5))
plt.imshow(
model.params["z_probs"][: model.data.N],
norm=mpl.colors.Normalize(vmin=0, vmax=1),
aspect="equal",
interpolation="none",
)
plt.ylabel("AOI")
plt.xlabel("Time (frame)")
plt.show()
Probabilistic rastergram with AOIs ordered by time-to-first binding:
[16]:
from tapqir.utils.imscroll import time_to_first_binding
# sorted on-target
ttfb = time_to_first_binding(model.params["z_map"][: model.data.N])
# sort ttfb
sdx = torch.argsort(ttfb, descending=True)
plt.figure(figsize=(10, 5))
norm = mpl.colors.Normalize(vmin=0, vmax=1)
im = plt.imshow(
model.params["z_probs"][: model.data.N][sdx][::3, ::2],
norm=norm,
aspect="equal",
interpolation="none",
)
plt.xlabel("Time (frame)")
plt.ylabel("AOI")
cbar = plt.colorbar(im, ax=ax, aspect=8, shrink=0.9)
cbar.set_label(label=r"$p(\mathsf{specific})$")
Global parameters#
summary
attribute (loaded from the cosmos-channel0-summary.csv
file) contains values of global parameters (for easy access).
[11]:
model.summary
[11]:
Mean | 95% LL | 95% UL | |
---|---|---|---|
gain | 6.736577 | 6.734092 | 6.739194 |
proximity | 0.607815 | 0.604436 | 0.611418 |
lamda | 0.288701 | 0.287115 | 0.290384 |
pi | 0.092999 | 0.092036 | 0.093988 |
Keq | 0.102533 | 0.101366 | 0.103738 |
SNR | 1.606830 | NaN | NaN |