MorphoNet

Tutorial 1: Investigation on shape changes of endodermal cells during gastrulation in Phallusia mammillata embryos

This tutorial shows, step by step, how to employ Python and MorphoNet to visualize and analyze complex 3D+time dynamics. It guides users from segmented data to final results.

Requirements

For this tutorial, you need python 3.x and the API of morphonet. You can easly install it using pip install morphonet

The API has some dependecies scipy , numpy, scikit-image, vtk

Part 1: Dataset creation

1.1 Data acquisition and segmentation

Three dimentional data of live embryonic development at single-cell resolution were taken through light-sheet microscopy and segmented using the automatic segmentation pipeline ASTEC, as explained in Guignard L, Fiúza UM, Leggio B, Laussu J, Faure E, Michelin G, Biasuz K, Hufnagel L, Malandain G, Godin C, Lemaire P. Contact area-dependent cell communication and the morphological invariance of ascidian embryogenesis. Science. 2020 Jul 10; 369(6500):eaar5663.

In this tutorial we take as example the data corresponding to the embryo referred to as PM1 in the paper.

Data for this embryo can be found at:https://figshare.com/s/765d4361d1b073beedd5. You need to download the segmentation files ('Astec-pm1_post.tar.gz'), the fused files ('Astec-pm1_fuse.tar.gz') and the properties ('Astec-pm1-properties.tar.gz')

Theses files contains 180 segmented time steps and the associated quantitative information.

1.2 Data import, mesh creation and upload to MorphoNet

Each image corresponds to the 3D reconstruction of the whole embryo at a given time. Two consecutive images are separated by a timegap of two minutes. Segmented images are divided into elementary objects, each identified by its corresponding numeric ID. Each cell is an object with an ID>1. The background, important to identify external the embryonic surface, corresponds to the ID=1.

Remark:Segmented and Raw images data are in .inr format. To read them in Python we use the internal library ImageHandling but you can use your own reader.

In [ ]:
dataset_name="Phallusia Mammillata PM1"
segmented_files="Astec-pm1/POST/POST_RELEASE/Astec-pm1_post_t{:03d}.inr.gz" #Segmented images filename
fused_files="Astec-pm1/FUSE/FUSE_RELEASE/Astec-Pm1_fuse_t{:03d}.inr.gz"   #Fused images filename
properties_file="Astec-pm1/properties/Astec-pm1_properties.pkl" #Properties file 
begin=1 #first timepoint of dataset
end=180 #last timepoint of dataset

The output of f_img is a 3D matrix, each dimension of which corresponds to one of the spatial dimensions x,y,z of the corresponding data. Each entry of the matrix at position x,y,z is a integer number >0, identifying which object is present at the specific position.

Once imported, these volumetric images can be converted to suface meshes through the Meshing library provided together with MorphoNet. Surface meshes are the standard format used by MorphoNet, and can then be directly uploaded to the MorphoNet database via its API. We begin by creating a new dataset.

In [ ]:
import morphonet
#Connection to MorphoNet database with your MorphoNet Login credentials
mn=morphonet.Net("your login","your password")

mn.selectDataSetByName(dataset_name) # Creation of a new dataset
#A specific dataset is selected here. All future API interactions will concern this database, unless a new one is selected later on
if mn.id_dataset==-1: #If the dataset does not yet exist
    mn.createDataSet(dataset_name,begin,end)  #Creation of a dataset containing end-begin timepoints, 
else: #If the dataset already exists
    mn.clearDataSet() #Clears all meshes and infos associated with this dataset

Now that a new dataset is created, we will transform each segmented image into an .obj containing the surface mesh and the objects identities, following the standard MorphoNet format. One .obj file is created for each timepoint and uploaded to the MorphoNet database to the new dataset we just created.

In [ ]:
for t in range(begin,end+1):
    segmented_img=morphonet.tools.imread(segmented_files.format(t))
    obj=morphonet.tools.convertToOBJ(segmented_img,t,background=1) #Convert 3D Images in Meshes
    mn.uploadMesh(t,obj) #Upload Meshes for timepoint t to selected dataset 

Now that a new dataset is created, and the segmented data upload, we will upload the raw images data to the MorphoNet database

In [ ]:
import numpy as np
factor=4
for t in range(begin,end+1):
    fuse=morphonet.tools.imread(fused_files.format(t)) # Read fused images
    fuse=np.uint8(255*np.float32(fuse[::factor,::factor,::factor])/fuse.max()) #Reduce and convert them in uint8
    mn.uploadRawImages(t,fuse,scale=factor) #Upload the images to the morphonet server

1.3 Information import and upload to MorphoNet

The dataset now contains a time series of surface meshes divided in objects. We can now upload several morphological tracks by using the standard MorphoNet format for morphological information. Information such as cellular lineage tree and cell names are provided for these data under the form of Pickle files, which we import and convert to MorphoNet format.

In [ ]:
import pickle as pkl
with open(properties_file, 'rb') as file:
    properties=pkl.load(file,encoding='latin1')
#Read each propertie
lineage_tree=properties['cell_lineage']
cell_names=properties['cell_name']
cell_vols=properties['cell_volume']
In [ ]:
#We need some function to convert the data in the morphonet format
def get_objname(idx): #ID of the cell 
    cell_name=idx%10**4
    return str(int((idx-cell_name)/10**4))+","+str(cell_name)

#Construct a generic MorphoNet information from a dictionnary
def get_inf(prop,ptype,comments="#Upload from MorphoNet Tutorial "):
    inf=comments+"type:"+ptype+"\n" 
    for x in prop.keys():
        inf+=get_objname(x)+":"+str(prop[x])+"\n"
    return inf

These files are python dictionaries, with cells as keys and corresponding information as values. Cells are given here as t*10^4+cell_id, so for instance cell 45 at time 11 corresponds to key 110045. We will now transform these files into the MorphoNet information format.

In [ ]:
comments="#Dataset "+dataset_name+"\n" 
comments+="#Upload by "+mn_login+"\n" 
##### Lineage Tree information. This is a time relation information
lineage_inf=comments+"type:time"+"\n" 
for x in lineage_tree.keys():
    for y in lineage_tree[x]: #daugthers of cell x or snapshot of cell x at next timepoint
        lineage_inf+=get_objname(x)+":"+get_objname(y)+"\n"
mn.uploadInfos("Lineage",lineage_inf) #We can now upload the cell lineage to the MorphoNet database

##### Names information. This is a qualitative information
mn.uploadInfos("Names",get_inf(cell_names,"string",comments=comments))

##### Volutiom information. This is a quantitative information 
mn.uploadInfos("Volumes",get_inf(cell_vols,"float",comments=comments))    

You can now find your dataset at http://www.morphonet.org