{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Basic Usage of the `tyssue` library" ] }, { "cell_type": "markdown", "metadata": { "collapsed": true }, "source": [ "## Easy creation of a 2D epithelial sheet" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "%matplotlib inline\n", "\n", "# Core object\n", "from tyssue import Sheet\n", "# Simple 2D geometry\n", "from tyssue import PlanarGeometry as geom\n", "# Visualisation\n", "from tyssue.draw import sheet_view\n", "\n", "sheet = Sheet.planar_sheet_2d('basic2D', nx=6, ny=7,\n", " distx=1, disty=1)\n", "geom.update_all(sheet)\n", "\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "fig, ax = sheet_view(sheet, mode=\"2D\")\n", "fig.set_size_inches(8, 8)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We can have a cleaner, better order `sheet` with the `sanitize` method:\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Give the tissue a nice hear cut ;)\n", "sheet.sanitize(trim_borders=True, order_edges=True)\n", "geom.update_all(sheet)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "fig, ax = sheet_view(sheet, mode=\"2D\")\n", "fig.set_size_inches(8, 8)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### A remark on the half-edge data structure\n", "\n", "\n", "As is represented in the above graph, each edge between two cells is composed of two half-edges (only one half-edge is present in the border ones). This makes it easier to compute many cell-specific quantities, as well as keeping a well oriented mesh. This is inspired by CGAL [polyhedral surfaces](https://doc.cgal.org/4.2/CGAL.CGAL.3D-Polyhedral-Surface/html/index.html)." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Datasets and specifications\n", "\n", "\n", "The data associated with the mesh displayed above, i.e. the points positions,\n", "the connectivity information, etc. is stored in pandas [DataFrame](http://pandas.pydata.org/pandas-docs/stable/dsintro.html#dataframe) objects, hold together in the `datasets` dictionnary.\n", "\n", "\n", "Depending on the geometry, the following dataframes are populated:\n", "* `datasets[\"edge\"]` or `sheet.edge_df`: The edge related dataframe contains \n", " - the connectivity information: source and target vertices, associated face and (for thick tissues)\n", " the associated cell body.\n", " - geometry data associated with the edge, such as its length\n", " - any suplemental data, such as a color or a dynamical parameter (an elasticity for example)\n", "\n", "* `datasets[\"vert\"]` or `sheet.vert_df`: The vertices related dataframe. In the apical junction mesh above, \n", " those are the vertices at the cells junctions. It usually holds the coordinates of the points, \n", " and geometry or dynamical data.\n", "\n", "* `datasets[\"face\"]` or `sheet.face_df`: The faces related dataframe. For a thin, 2D tissue, this corresponds to\n", " a cell of the epithelium, delimited by its edges. In thick, 3D models, one cell has several faces\n", " (the apical, sagittal and basal ones for a 3D monolayer, for example).\n", " \n", "* `datasets[\"cell\"]` or `sheet.cell_df`: The cells related dataframe, only for 3D, thick, epithelium.\n", " Each cell have several faces.\n", " \n", " \n", " ![datastructures in `tyssue`](../illus/tyssue_data_management.png)\n", " " ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "for element, data in sheet.datasets.items():\n", " print(element, ':', data.shape)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "sheet.datasets['edge'].head()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The `edge_df` dataframe contains most of the information. In particular, each time the geometry is updated with the `geom.update_all(sheet)` function, the positions of the source and target vertices of each edge are copied to the `\"sx\", \"sy\"` and `\"tx\", \"ty\"` columns, respectively.\n", "\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "sheet.face_df.head()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We can use all the goodies from pandas DataFrames objects. For example, it is possible to \n", "compute the average edge length for each face like so:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "sheet.edge_df.groupby('face')['length'].mean().head()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**Specifications** are defined as a nested dictionnary, `sheet.specs`. For each element, the specification defines the columns of the corresonding DataFrame and their default values. An extra key at the root of the specification is called `\"settings\"`, and can hold specific parameters, for example the arguments for an energy minimization procedure." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "sheet.specs" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "It is possible to update dynamically the data structure. For example, let's assume we want to put quasi-static model to minimize energy for the tyssue. For this we need three things.\n", "* A specification dictionnary with the required data\n", "* A model\n", "* A solver" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "from tyssue.config.dynamics import quasistatic_plane_spec\n", "from tyssue.dynamics.planar_vertex_model import PlanarModel\n", "from tyssue.solvers import QSSolver\n", "\n", "# Update the specs\n", "sheet.update_specs(quasistatic_plane_spec())\n", "\n", "# Find energy minimum\n", "solver = QSSolver()\n", "res = solver.find_energy_min(sheet, \n", " geom,\n", " PlanarModel)\n", "\n", "print(\"Successfull gradient descent? \", res['success'])\n", "fig, ax = sheet_view(sheet)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Upcasting and downcasting data\n", "\n", "\n", "### Upcasting\n", "\n", "Geometry or physics computations often require to access for example\n", "the cell related data on each of the cell's edges. The `Epithelium`\n", "class and its derivatives defines utilities to make this,\n", "i.e copying the area of each face to each of its edges:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "print('Faces associated with the first edges:')\n", "print(sheet.edge_df['face'].head())\n", "print('\\n')\n", "\n", "# First edge associated face\n", "face = sheet.edge_df.loc[0, 'face']\n", "\n", "print('Area of cell # {}:'.format(int(face)))\n", "print(sheet.face_df.loc[face, 'area'])\n", "\n", "print('\\n')\n", "print('Upcasted areas over the edges:')\n", "print(sheet.upcast_face(sheet.face_df['area']).head())" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The values have indeed be upcasted. This can also be done with the source and target vertices \n", "(`sheet.upcast_srce`, `sheet.upcast_trgt`) and cells in the 3D case (`sheet.upcast_cell`).\n", "\n", "### Downcasting\n", "\n", "This is usually done by `groupby` operations as shown above.\n", "Syntactic sugar is available for summation, e.g. over every edges with a given source: " ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "sheet.sum_srce(sheet.edge_df['line_tension']).head()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Input and Output\n", "\n", "The 'native' format is to save the datasets to hdf5 via [`pandas.HDFStore`](https://pandas.pydata.org/pandas-docs/stable/cookbook.html#hdfstore). The `io.obj` also provides functions to export the junction mesh or triangulations to the wavefront `OBJ` format (requires `vispy`), for easy import in 3D software such as Blender.\n", "\n", "Here is the code to save the data in wavefront `OBJ`:\n", "```python\n", "obj.save_junction_mesh('junctions.obj', sheet)\n", "```" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The standard data format for the datasets is HDF:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "from tyssue.io import hdf5" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Writing" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "hdf5.save_datasets('tmp_data.hdf5', sheet)\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Reading" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "dsets = hdf5.load_datasets('tmp_data.hdf5')\n", "sheet2 = Sheet('reloaded', dsets)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "!rm tmp_data.hdf5" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Specs can be saved as json files:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "import json\n", "\n", "with open(\"tmp_specs.json\", \"w\") as jh:\n", " json.dump(sheet.specs, jh)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "And reloaded accordingly" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "with open(\"tmp_specs.json\", \"r\") as jh:\n", " specs = json.load(jh)\n", "\n", "sheet2.update_specs(specs, reset=False)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "!rm tmp_specs.json" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.7.6" } }, "nbformat": 4, "nbformat_minor": 1 }