Image analysis for the Drosophila early embryo body plan

(c) 2016 Muir Morrison and Manuel Razo-Mejia. This work is licensed under a Creative Commons Attribution License CC-BY 4.0. All code contained herein is licensed under an MIT license.

In [1]:
import numpy as np # our numerical workhorse
import matplotlib.pyplot as plt # plotting library
import seaborn as sns # extra plotting features
import skimage.io # image analysis functionality

# plotting backend 
%matplotlib
Using matplotlib backend: TkAgg

Setting up the problem.

As seen in class the French-flag model describes the process through which a morphogen gradient, in this case bicoid, which is deposited by the mother in the anterior end of the embryo defines the location of the cephalic furrow.

The beauty of the model is that it makes strict quantitative predictions of how the gene dosage, i.e. the number of copies and level of expression of the bicoid gene in the fly genome, should affect the location of this morphological feature. So in order to test this model, in the homework you will use Python to measure the cephalic furrow position for different gene dosage embryos. This tutorial will show you the tools to do so. You should read the homework for more details on the biology and the why questions; this tutorial will focus on the computing side of things.

Image analysis

First thing we need to do is load an image. Plot it to see what we're dealing with.

IMPORTANT NOTE:

In the first cell of this notebook we called `%matplotlib` rather than the usual `%matplotlib inline`. The latter will not allow us to use the `ginput` tool we need below. With `%matplotlib`, all plotting commands will spawn in an external window, so you will have switch to that window to see anything (e.g., using cmd-tab or alt-tab, etc.)

In [2]:
# read the image using scikit-image
im = skimage.io.imread('data/embryo_furrow.tif')

# This removes the default white grid placed by seaborn but only for this plot
with sns.axes_style("white"):
    plt.imshow(im)

You can see the cell nuclei arranged around the periphery of the embryo, and the cephalic furrow is just beginning to form. This is the two small bumps in the line of cells, about a third of the way along the long axis from the lower right end. We want to measure the position of the furrow as a fraction of the distance along the long axis of the embryo.

You should contemplate how you would define the position of the furrow. A variety of metrics have been chosen by different people. One standard is to mount embryos on their side and measure arc length along the anterior boundary. But our sample image here, and some of your homework images, are mounted on their dorsal sides, making this impossible.

The metric we propose is to draw a line along the long axis connecting the anterior-most and posterior-most points. Then we take the location where the furrow crosses this line as the position of the furrow. The distance from here to the anterior divided by the length of the original line along the long axis is then the fractional location of the furrow along the embryo.

Clicking to compute distances

In the tutorials for Homework 7 we emphasized the power of automating image analysis tasks. But computers are not nearly as smart as our eyes, and distinguishing fairly uniform dark cells from bright background is a relatively easy task for a computer. Much harder is asking it to identify more subtle morphological features, which is what we need to do here. So instead, to measure the position of the cephalic furrow in early Drosophila embryos, we will manually click to specify points, and then have the computer do the arithmetic for us.

For this we will use the matplotlib function ginput that stands for graphical input. This function allows us to click on an image and register the x and y positions of where we click.

I want to record two clicks on the image: the first at the anterior end, the second at the posterior end. The syntax is one simple line. When you execute the cell, switch to the external window with the figure, click twice on it, and switch back. The image shows which is which: note the furrow is closer to the anterior.

In [ ]:
clicks = plt.ginput(2) # Will record two clicks.

What is the clicks object that this returns? Let's take a look.

In [4]:
clicks
Out[4]:
[(2303.958087367178, 1892.9285714285713),
 (556.57910271546632, 552.40200708382531)]

So ginput returns a list, and each element is a tuple containing the (x,y) coordinates of the locations we clicked. Let's unpack these values to make the upcoming arithmetic more readable.

In [5]:
# extract x & y coords of anterior & posterior clicks
ant_x = clicks[0][0]
ant_y = clicks[0][1]
post_x = clicks[1][0]
post_y = clicks[1][1]

Now I want to plot the points I just clicked on the image, connected by a line. The following syntax does just that, and image shows what the result should resemble.

In [6]:
with sns.axes_style("white"):
    plt.plot((ant_x, post_x), (ant_y, post_y), color='r', marker='o')

Since the furrow line is very faint in the interior of the embryo, I want to draw a line connecting the two furrow ingressions. Then I can just click on the intersection of the lines to find the furrow. To do this I will grab two more clicks...

In [7]:
clicks = plt.ginput(2) # Will record two more clicks.
/Users/muir/anaconda/lib/python3.5/site-packages/matplotlib/backend_bases.py:2445: MatplotlibDeprecationWarning: Using default event loop until function specific to this GUI is implemented
  warnings.warn(str, mplDeprecation)

...unpack their coordinates...

In [8]:
# extract x & y coords of 2 lateral clicks
lat1_x = clicks[0][0]
lat1_y = clicks[0][1]
lat2_x = clicks[1][0]
lat2_y = clicks[1][1]

...and add them to the plot as well. Again you should see something like what is shown below.

In [9]:
with sns.axes_style("white"):
    plt.plot((lat1_x, lat2_x), (lat1_y, lat2_y), color='r', marker='o')

Now let's click once more to get the position of the furrow.

In [10]:
furrow_click = plt.ginput(1)
furr_x = furrow_click[0][0]
furr_y = furrow_click[0][1]
/Users/muir/anaconda/lib/python3.5/site-packages/matplotlib/backend_bases.py:2445: MatplotlibDeprecationWarning: Using default event loop until function specific to this GUI is implemented
  warnings.warn(str, mplDeprecation)

Computing distances

We're almost done. All we need is the distance formula for the distance $\overline{AB}$ between points $A$ and $B$ is given by \begin{equation} \overline{AB} = \sqrt{ \left(x_B - x_A \right)^2 + \left(y_B - y_A \right)^2}. \end{equation} We just need to compute two distances, one from the anterior to the furrow and the other from the anterior to the posterior. Then take their ratio and (in the homework) you can compare to the French Flag model predictions.

In [11]:
# distances between clicks. First find Anterior-posterior distance.
ant_post = np.sqrt((post_y - ant_y)**2 + (post_x - ant_x)**2)
# then anterior-Furrow distance
ant_furr = np.sqrt((furr_y - ant_y)**2 + (furr_x - ant_x)**2)

# fractional position along embryo is their ratio
rel_furrow_pos = ant_furr / ant_post

Finally, the position of the furrow is...

In [12]:
rel_furrow_pos
Out[12]:
0.33678854377349354

In the homework you will run this procedure for a few different images of embryos with varying dosages of bicoid, see how the furrow position changes, and if it agrees with the predictions of the French Flag model.