diff --git a/.github/workflows/python-package.yml b/.github/workflows/python-package.yml new file mode 100644 index 0000000..40fa2fb --- /dev/null +++ b/.github/workflows/python-package.yml @@ -0,0 +1,41 @@ +# This workflow will install Python dependencies, run tests and lint with a variety of Python versions +# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-python + +name: Python package + +on: + push: + branches: [ "master" ] + pull_request: + branches: [ "master" ] + +jobs: + build: + + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + python-version: ["3.7"] #["3.7", "3.8", "3.9"] + + steps: + - uses: actions/checkout@v3 + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v3 + with: + python-version: ${{ matrix.python-version }} + - name: Install dependencies + run: | + python -m pip install --upgrade pip + python -m pip install pytest + if [ -f requirements.txt ]; then pip install -r requirements.txt; fi + # Display the Python version being used + - name: Display Python version + run: python -c "import sys; print(sys.version)" + # Install the package using the setup.py + - name: Install package + run: pip install git+https://github.com/fabrylab/pyTFM.git + # Install pytest (you can use some other testing utility) + - name: Test with pytest + run: | + pytest test_pyTFM.py diff --git a/README.md b/README.md index fd50faf..4b8abce 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,7 @@ +[![Python package](https://github.com/martinschatz-cz/pyTFM/actions/workflows/python-package.yml/badge.svg?event=push)](https://github.com/martinschatz-cz/pyTFM/actions/workflows/python-package.yml) + +[![Python 3.6](https://img.shields.io/badge/python-3.6-green.svg)]() [![Python 3.7](https://img.shields.io/badge/python-3.7-green.svg)]() [![Python 3.8](https://img.shields.io/badge/python-3.8-red.svg)]() [![Python 3.9](https://img.shields.io/badge/python-3.9-red.svg)]() + ## Readme pyTFM is a python package that allows you to analyze force generation and stresses in cell colonies and confluent cell layers growing on a 2 dimensional surface. This package implements the procedures of [Traction Force Microscopy](https://www.ncbi.nlm.nih.gov/pubmed/11832345) and [Monolayer Stress Microscopy](https://journals.plos.org/plosone/article?id=10.1371/journal.pone.0055172). In addition to the standard measures for stress and force generation, it @@ -5,3 +9,24 @@ also includes the line tension, a measure for the force transfer exclusively acr pyTFM includes an addon for the image annotation tool [clickpoints](https://clickpoints.readthedocs.io/en/latest/) allowing you to quickly analyze and vizualize large datasets. Please refer to the [Documentation](https://pytfm.readthedocs.io/en/latest/) of pyTFM for detailed instructions on installation and usage. + +## Conda enviroment creation +You need to create python 3.6 enviroment. +``` +conda create --name pyTFM python=3.6 +conda activate pyTFM +``` + +Note: python 3.7 works too, but clickpoints need python 3.6. + +pyTFM package install +``` +pip install git+https://github.com/fabrylab/pyTFM.git +``` + +If you want to use jupyterlab +``` +pip install jupyterlab +jupyter-lab +``` +Sometimes it is necessary to reinstall pyTFM again through the JupyterLab because of scikit-image package. diff --git a/test_pyTFM.py b/test_pyTFM.py new file mode 100644 index 0000000..9658d7d --- /dev/null +++ b/test_pyTFM.py @@ -0,0 +1,106 @@ +import numpy as np +import pytest +import matplotlib.pyplot as plt +import numpy as np +import openpiv.filters +import scipy.fft + +from openpiv.pyprocess import extended_search_area_piv +import openpiv.scaling +import openpiv.tools +import openpiv.validation +from matplotlib.colors import LinearSegmentedColormap +from mpl_toolkits.axes_grid1 import make_axes_locatable +from pyTFM.utilities_TFM import suppress_warnings +from scipy.ndimage.filters import median_filter, gaussian_filter +from scipy.ndimage.filters import uniform_filter +from pyTFM.TFM_functions import ffttc_traction +from pyTFM.TFM_functions import get_xy_for_quiver +from pyTFM.TFM_functions import strain_energy_points +from pyTFM.TFM_functions import contractillity + +def test_ffttc_traction_output_shape(): + # create test inputs + u = np.zeros((10, 10)) + v = np.zeros((10, 10)) + pixelsize1 = 0.1 + pixelsize2 = 0.1 + young = 1e6 + + # call the function + tx_filter, ty_filter = ffttc_traction(u, v, pixelsize1, pixelsize2, young) + + # assert that the output shape is as expected + assert tx_filter.shape == (10, 10) + assert ty_filter.shape == (10, 10) + +def test_ffttc_traction_output_type(): + # create test inputs + u = np.zeros((10, 10)) + v = np.zeros((10, 10)) + pixelsize1 = 0.1 + pixelsize2 = 0.1 + young = 1e6 + + # call the function + tx_filter, ty_filter = ffttc_traction(u, v, pixelsize1, pixelsize2, young) + + # assert that the output is of the correct type + assert isinstance(tx_filter, np.ndarray) + assert isinstance(ty_filter, np.ndarray) + +def test_ffttc_traction_output_values(): + # create test inputs + u = np.zeros((10, 10)) + v = np.zeros((10, 10)) + pixelsize1 = 0.1 + pixelsize2 = 0.1 + young = 1e6 + + # call the function + tx_filter, ty_filter = ffttc_traction(u, v, pixelsize1, pixelsize2, young) + + # assert that the output is as expected + assert np.allclose(tx_filter, 0) + assert np.allclose(ty_filter, 0) + +def test_ffttc_traction_input_shape(): + # create test inputs with incorrect shape + u = np.zeros((10, 10, 10)) + v = np.zeros((10, 10)) + pixelsize1 = 0.1 + pixelsize2 = 0.1 + young = 1e6 + + # assert that a ValueError is raised for incorrect input shape + with pytest.raises(ValueError): + ffttc_traction(u, v, pixelsize1, pixelsize2, young) + +def test_ffttc_traction_input_type(): + # create test inputs with incorrect type + u = np.zeros((10, 10)) + v = "not an array" + pixelsize1 = 0.1 + pixelsize2 = 0.1 + young = 1e6 + + # assert that a TypeError is raised for incorrect input type + with pytest.raises(TypeError): + ffttc_traction(u, v, pixelsize1, pixelsize2, young) + +########get_xy_for_quiver +def test_get_xy_for_quiver(): + u = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]]) + xs, ys = get_xy_for_quiver(u) + + # Test the shape of xs and ys + assert np.shape(xs) == np.shape(u) + assert np.shape(ys) == np.shape(u) + + # Test the values of xs + for i in range(np.shape(u)[0]): + assert np.array_equal(xs[i, :], np.arange(0, np.shape(u)[1], 1)) + + # Test the values of ys + for j in range(np.shape(u)[1]): + assert np.array_equal(ys[:, j], np.arange(0, np.shape(u)[0], 1))