Radius Correlation

analysis
microscopy
STORM
Author

Jochem H. Smit

Published

April 5, 2020

In this post we’ll look at what the meaning is of the cell’s radius, measured from the brightfield as explained in the previous post, in relation to the position of the cell’s inner membrane.

We start by loading two sets of cells, of different phenotypes with different radii, and optimizing the coordinate system based on the brightfield and using it to measure the cell’s radius.

%matplotlib notebook
import matplotlib.pyplot as plt
from colicoords import load, iter_subplots, IterCellPlot, CellListPlot

import numpy as np
Warning: Version number not found.
cells_1 = load('Cells_1.hdf5')
cells_2 = load('Cells_2.hdf5')
len(cells_1), len(cells_2)
(15, 18)
cells_1.optimize_mp('brightfield')
cells_1.measure_r(mode='mid')
HBox(children=(FloatProgress(value=0.0, max=15.0), HTML(value='')))
cells_2.optimize_mp('brightfield')
cells_2.measure_r(mode='mid')
HBox(children=(FloatProgress(value=0.0, max=18.0), HTML(value='')))

Both sets of cells have binary and brightfield images as well as a STORM super-resolution dataset of LacY-eYFP, a fluorescent marker which localizes to the inner membrane.

fig, ax = iter_subplots()
icp = IterCellPlot(cells_1)
icp.imshow('brightfield', ax=ax)
icp.plot_outline(ax=ax, color='r')
icp.plot_storm(data_name='storm', method='plot', ax=ax, markersize=1, color='g')
fig.display()
<IPython.core.display.Javascript object>

VBox(children=(HBox(children=(Button(description='First', style=ButtonStyle()), Button(description='Prev', sty…
fig, ax = iter_subplots()
icp = IterCellPlot(cells_2)
icp.imshow('brightfield', ax=ax)
icp.plot_outline(ax=ax, color='r')
icp.plot_storm(data_name='storm', method='plot', ax=ax, markersize=1, color='g')
fig.display()
<IPython.core.display.Javascript object>

VBox(children=(HBox(children=(Button(description='First', style=ButtonStyle()), Button(description='Prev', sty…
fig, ax = plt.subplots()
cp1 = CellListPlot(cells_1)
cp2 = CellListPlot(cells_2)

h = cp1.hist_property('radius', ax)
h = cp2.hist_property('radius', ax)
<IPython.core.display.Javascript object>

We can see that the sets of cells are different populations in terms of their radius. We’ll now investigate if the radius measured from the brightfield correlates to the inner membrane radius measured from STORM super-resolution.

To increase accuracy and because the super-resolution localzations appear slightly offets with respect to the brightfield image, we make copy of the cells and optimize these based on their STORM dataset.

cells_1_sr = cells_1.copy()
cells_2_sr = cells_2.copy()

res = cells_1_sr.optimize_mp('storm')
res = cells_2_sr.optimize_mp('storm')
HBox(children=(FloatProgress(value=0.0, max=15.0), HTML(value='')))






HBox(children=(FloatProgress(value=0.0, max=18.0), HTML(value='')))
fig, ax = iter_subplots()
icp = IterCellPlot(cells_1_sr)
icp.imshow('brightfield', ax=ax)
icp.plot_outline(ax=ax, color='r')
icp.plot_storm(data_name='storm', method='plot', ax=ax, markersize=1, color='g')
fig.display()
<IPython.core.display.Javascript object>

VBox(children=(HBox(children=(Button(description='First', style=ButtonStyle()), Button(description='Prev', sty…
fig, ax = iter_subplots()
icp = IterCellPlot(cells_2_sr)
icp.imshow('brightfield', ax=ax)
icp.plot_outline(ax=ax, color='r')
icp.plot_storm(data_name='storm', method='plot', ax=ax, markersize=1, color='g')
fig.display()
<IPython.core.display.Javascript object>

VBox(children=(HBox(children=(Button(description='First', style=ButtonStyle()), Button(description='Prev', sty…

From the plots above we can see that by optimizing the coordinate system from the STORM super-resolution data we get an accurate description of the bacterial inner membrane. Now lets see how this inner membrane radius relates to the brightfield radius.

bf_r1 = np.array([cell.coords.r for cell in cells_1])
bf_r2 = np.array([cell.coords.r for cell in cells_2])

storm_r1 = np.array([cell.coords.r for cell in cells_1_sr])
storm_r2 = np.array([cell.coords.r for cell in cells_2_sr])
plt.figure()
plt.scatter(bf_r1, storm_r1, label='Cells 1')
plt.scatter(bf_r2, storm_r2, label='Cells 2')

plt.xlabel('Cell radius (brightfield)')
plt.ylabel('Cell radius (STORM)')

ratio1 = (bf_r1 / storm_r1).mean()
ratio2 = (bf_r2 / storm_r2).mean()

r_all = np.mean(np.concatenate([bf_r1, bf_r2]) / np.concatenate([storm_r1, storm_r2]))

r = np.linspace(bf_r1.min(), bf_r2.max(), num=2, endpoint=True)
plt.plot(r, r/ratio1)
plt.plot(r, r/ratio2)
plt.plot(r, r/r_all, color='k')
plt.legend()
ratio1, ratio2, r_all
<IPython.core.display.Javascript object>

(1.340360118411173, 1.2622867459536964, 1.2977746425252765)

In the figure above the brightfield radius is plotted agains the STORM radius. We can see that the two clearly correlate and we can calculate a conversion ratio between the two. Here, the ratios are shown as lines for the different sets of cells individually and for all cells combined. The values are slightly different but overall quite close to eachother, suggesting is possible to convert the cell’s radius measured from the brightfield image to inner membrane radius over a large range of radii.

This conversion factor will depend of the type of brightfield images taken by a particular microscope as well as the exact focal level within the cells. Howwever, if done concsistenly with a large enough sample size, this method provides a way of calibrating a brightfield-to-inner membrane conversion ratio.

As an application, lets apply the conversion ratio found to the brightfield-optimized set of cells and plot their volume. This volume should now accurately describe the cyctoplasmic volume.

cells_1_corrected = cells_1.copy()
cells_2_corrected = cells_2.copy()
for cell in cells_1_corrected:
    cell.coords.r /= r_all
    
for cell in cells_2_corrected:
    cell.coords.r /= r_all
cp1_c = CellListPlot(cells_1_corrected)
cp2_c = CellListPlot(cells_2_corrected)

cp1_sr = CellListPlot(cells_1_sr)
cp2_sr = CellListPlot(cells_2_sr)

bins= np.linspace(0.4, 3, num=10, endpoint=True)

fig, (ax1, ax2) = plt.subplots(2)
cp1_c.hist_property('volume', ax=ax1, alpha=0.5, bins=bins, label='Corrected')
cp2_c.hist_property('volume', ax=ax2, alpha=0.5, bins=bins, color='#ff7f0e', label='Corrected')

cp1_sr.hist_property('volume', ax=ax1, histtype='step', color='#1f77b4', linewidth=2, bins=bins, label='STORM')
cp2_sr.hist_property('volume', ax=ax2, histtype='step', color='#ff7f0e', linewidth=2, bins=bins, label='STORM')

ax1.legend()
ax2.legend()

plt.tight_layout()
<IPython.core.display.Javascript object>

In the graph above we compare the cell volume for both sets of cells calculated from measuring the radius in the brightfield iamges and correcting the radius by using the calibration ratio number, to the volume of the cells directly obtain from STORM meaurements.

More statistics are needed to make the conversion more robust but by using this approach the cell’s cytoplasmic volume can be determined from the brightfield image with high accuracy. The found values for E. coli cytoplasm of ~1-2 \(\mu m^3\) is in line with typical literature values (Milo, 2013)