{"name":"napari-turing","display_name":"Turing Patterns","visibility":"public","icon":"","categories":[],"schema_version":"0.2.0","on_activate":null,"on_deactivate":null,"contributions":{"commands":[{"id":"napari-turing.TuringViewer","title":"Turing Patterns","python_name":"napari_turing._widget:TuringViewer","short_title":null,"category":null,"icon":null,"enablement":null}],"readers":null,"writers":null,"widgets":[{"command":"napari-turing.TuringViewer","display_name":"Turing Patterns","autogenerate":false}],"sample_data":null,"themes":null,"menus":{},"submenus":null,"keybindings":null,"configuration":[]},"package_metadata":{"metadata_version":"2.1","name":"napari-turing","version":"0.3.2","dynamic":null,"platform":null,"supported_platform":null,"summary":"A plugin to run simmple simulations of Turing patterns","description":"# napari-turing\n\n[![License MIT](https://img.shields.io/pypi/l/napari-turing.svg?color=green)](https://github.com/leoguignard/napari-turing/raw/main/LICENSE)\n[![PyPI](https://img.shields.io/pypi/v/napari-turing.svg?color=green)](https://pypi.org/project/napari-turing)\n[![Python Version](https://img.shields.io/pypi/pyversions/napari-turing.svg?color=green)](https://python.org)\n[![tests](https://github.com/leoguignard/napari-turing/workflows/tests/badge.svg)](https://github.com/leoguignard/napari-turing/actions)\n[![codecov](https://codecov.io/gh/leoguignard/napari-turing/branch/main/graph/badge.svg)](https://codecov.io/gh/leoguignard/napari-turing)\n[![napari hub](https://img.shields.io/endpoint?url=https://api.napari-hub.org/shields/napari-turing)](https://napari-hub.org/plugins/napari-turing)\n\nA plugin to run simple simulations of Turing patterns\n\n----------------------------------\n\nThis [napari] plugin was generated with [Cookiecutter] using [@napari]'s [cookiecutter-napari-plugin] template.\n\n\n![example 1](img/turing_patterns.gif)\n![example 2](img/turing_patterns2.gif)\n\n## Installation\n\nYou can install `napari-turing` via [pip] after downloading the content of\n\n pip install napari-turing\n\n\nTo install latest version :\n\n pip install git+https://github.com/leoguignard/napari-turing.git\n\n## Troubleshooting\n\nIf the installation does not work just with the previous command, it might be useful to first install [napari] for example that way:\n\n conda install napari\n\n## Creating a new model\n\nTo create your own model, you can use the template for models [here](src/napari_turing/Models/ModelTemplate.py).\n\nNote that a bit of knowledge in Python is probably necessary and it might not be completely trivial at first but you'll manage :)\n\nFirst you need to name the concentrations that you will use with the following [line](src/napari_turing/Models/ModelTemplate.py#L40):\n```python\n _concentration_names = [\"A\", \"I\"]\n```\n\nThen, you need to declare its variables. For example you can create a parameter named `mu_a` the following way ([here in the code](src/napari_turing/Models/ModelTemplate.py#L53-L60)):\n```python\n mu_a = ModelParameter(\n name=\"mu_a\", # Name of the parameter\n description=\"Activator diffusion coefficient (10^-4)\", # Description of the parameter for napari\n value=2.8, # Initial and default value\n min=1, # Minimum value the parameter can take\n max=5, # Maximum value the parameter can take\n exponent=1e-4, # All values given to this instance of the class will but multiplied by this value\n )\n```\n\nThen you need to list the parameters that are necessary to run the model (usually all the paramaters declared previously) and the parameters that you will allow the user to tune (for example, sometimes some of the parameters are co-dependent and there is no point in being able to tune both of them). That should be done the following way ([here in the code](src/napari_turing/Models/ModelTemplate.py#L86-89)):\n```python\n # These are the parameters that are necessary to run the equations.\n _necessary_parameters = [tau, k, mu_a, mu_i]\n # These are the parameters that can be modified via napari\n _tunable_parameters = _necessary_parameters\n```\n\nIf you want, you can specify what the method will return as a string, it will be displayed in the napari viewer ([here in the code](src/napari_turing/Models/ModelTemplate.py#L90-L98)):\n```python\n # This function allows to display some information about the model\n # in napari\n def __str__(self) -> str:\n return (\n \"Equations (FitzHugh-Nagumo model):\\n\"\n \" Concentration of Activator (a) and Inhibitor (i)\\n\"\n \" - da/dt = mu_a * diffusion(a) + a - a^3 - i + k\\n\"\n \" - tau * di/dt = mu_i * diffusion(i) + a - i\"\n )\n```\n\nNow that the basics are declared, you will need to declare how to initialize your concentrations the following way ([here in the code](src/napari_turing/Models/ModelTemplate.py#L100-L116)):\n```python\n # The following allows to reset the values of the concentrations.\n # The function takes the name of the concentration to initialize.\n # If no name is given or if it is None all the concentrations are\n # reinitialized.\n #\n # The reason why this function is useful is that some models \n # require specific initialisations for them to work correctly\n # In the following example the concentrations are reintinalized\n # to a random value between -1 and 1.\n # This is the default behavior, so if you don't need to change\n # it you don't have to implement the function.\n def init_concentrations(self, C: Optional[str] = None) -> None:\n if C is None:\n for ci in self.concentration_names():\n self[ci] = np.random.random((self.size, self.size)) * 2 - 1\n else:\n self[C] = np.random.random((self.size, self.size)) * 2 - 1\n```\nIn the previous example, the all concentrations are initialized the same way. If you need to have different initializations, you can do it the following way for example ([from the GrayScott model](src/napari_turing/Models/GrayScott.py#L68-L76)):\n```python\n def init_concentrations(self, C: Optional[str] = None) -> None:\n if C == \"X\" or C is None:\n self[\"X\"] = np.ones((self.size, self.size))\n if C == \"Y\" or C is None:\n Y = np.zeros((self.size, self.size))\n nb_pos = 20\n pos = (np.random.random((2, nb_pos)) * self.size).astype(int)\n Y[pos[0], pos[1]] = 1\n self[\"Y\"] = Y\n```\nIn this model, there are two concentrations, `X` and `Y` which are initialized differenty. Note that they can be accessed using `self[\"X\"]` or `self.X`.\n\nFinally, you of course have to define the reaction equations and the diffusion equations. The way it is defined is with two functions, one for the reaction and one for the diffusion, that take as an input the name of the concentration to apply the function to and returns the new values. Then for each of your concentrations, their new values will be computed as followed:\n```python\nnew_concentration = current_concentration + dt*(reaction + diffusion)\n```\n\nHere is an example for the reaction function ([here in the code](src/napari_turing/Models/ModelTemplate.py#L127-L136)):\n```python \n # This function defines the equations of the reactions.\n # It takes as an input which concentration to compute\n # (in this example we have to define how to compute A and I)\n def _reaction(self, c: str) -> np.ndarray:\n if c == \"A\":\n # Below is the reaction part of the equation (1)\n return self.A - self.A**3 - self.I + self.k \n elif c == \"I\":\n # Below is the reaction part of the equation (2)\n return (self.A - self.I) / self.tau\n```\nOf course, if you have more concentrations, you will need to define more equations.\n\nHere is an example for the reaction function ([here in the code](src/napari_turing/Models/ModelTemplate.py#L138-L166)):\n```python\n # This function defines the equations of the diffusion.\n # It takes as an input which concentration to compute\n # (in this example we have to define how to compute A and I)\n # Here we compute the diffusion as follow:\n # A cell gives an equal fraction mu of its concentration to its neighbors\n # A cell recieves an equal fraction mu of concentration from its neighbors\n # Neighbors = (left, right, above, below)\n # In the case of oriented diffusion the amount recieved and given to the neighbors\n # is imbalanced according to the position of the neighbor.\n def _diffusion(self, c: str) -> np.ndarray:\n if c == \"A\":\n arr = self.A # Define the array of concentrations to diffuse for the reageant A\n mu = self.mu_a # Define the diffusion coefficient for the reageant A\n elif c == \"I\":\n arr = self.I # Define the array of concentrations to diffuse for the reageant I\n mu = self.mu_i # Define the diffusion coefficient for the reageant I\n \n # Computes what is recieved from neighboring cells\n from_cell = convolve(arr, self.kernel.value, mode=\"constant\", cval=0)\n # Computes what is given to neighboring cells\n to_cell = self.nb_neighbs * arr\n\n # Computes the diffusion\n out = mu * (from_cell - to_cell) / (self.dx * self.dy)\n\n # In our case, the equation (2), for I specify that it has to be divided by tau\n if c == \"I\":\n out /= self.tau\n return out\n```\nThe diffusion function is usually a standard one so it might not be necessary to overly change it.\n\nYou can find other model examples:\n- [Brusselator](src/napari_turing/Models/Brusselator.py)\n- [GrayScott](src/napari_turing/Models/GrayScott.py)\n- [GameOfLife](src/napari_turing/Models/GameOfLife.py)\n\nOnce all that is done, let say you've saved your new model in the folder [Models](src/napari_turing/Models) under the name `NewModel.py` and the model class created is name `NewModel`. Then you need to declare you model in the [`_model_list.py`](src/napari_turing/Models/_model_list.py) file. To do so you need to add the following lines in the file:\n```python\nfrom enum import Enum\nfrom .FitzHughNagumo import FitzHughNagumo\nfrom .Brusselator import Brusselator\nfrom .GrayScott import GrayScott\nfrom .GameOfLife import GameOfLife\nfrom .NewModel import NewModel ## THAT LINE HERE\n\nclass AvailableModels(Enum):\n FitzHughNagumo = FitzHughNagumo\n Brusselator = Brusselator\n GrayScott = GrayScott\n GameOfLife = GameOfLife\n NewModel = NewModel ## AND THAT OTHER LINE HERE\n```\n\n## Contributing\n\nContributions are very welcome.\n\n## License\n\nDistributed under the terms of the [MIT] license,\n\"napari-turing\" is free and open source software\n\n## Issues\n\nIf you encounter any problems, please [file an issue] along with a detailed description.\n\n[napari]: https://github.com/napari/napari\n[Cookiecutter]: https://github.com/audreyr/cookiecutter\n[@napari]: https://github.com/napari\n[MIT]: http://opensource.org/licenses/MIT\n[BSD-3]: http://opensource.org/licenses/BSD-3-Clause\n[GNU GPL v3.0]: http://www.gnu.org/licenses/gpl-3.0.txt\n[GNU LGPL v3.0]: http://www.gnu.org/licenses/lgpl-3.0.txt\n[Apache Software License 2.0]: http://www.apache.org/licenses/LICENSE-2.0\n[Mozilla Public License 2.0]: https://www.mozilla.org/media/MPL/2.0/index.txt\n[cookiecutter-napari-plugin]: https://github.com/napari/cookiecutter-napari-plugin\n\n[file an issue]: https://github.com/leoguignard/napari-turing/issues\n\n[napari]: https://github.com/napari/napari\n[tox]: https://tox.readthedocs.io/en/latest/\n[pip]: https://pypi.org/project/pip/\n[PyPI]: https://pypi.org/\n","description_content_type":"text/markdown","keywords":null,"home_page":"https://github.com/leoguignard/napari-turing","download_url":null,"author":"Léo Guignard","author_email":"leo.guignard@univ-amu.fr","maintainer":null,"maintainer_email":null,"license":"MIT","classifier":["Development Status :: 2 - Pre-Alpha","Framework :: napari","Intended Audience :: Developers","License :: OSI Approved :: MIT License","Operating System :: OS Independent","Programming Language :: Python","Programming Language :: Python :: 3","Programming Language :: Python :: 3 :: Only","Programming Language :: Python :: 3.8","Programming Language :: Python :: 3.9","Programming Language :: Python :: 3.10","Topic :: Scientific/Engineering :: Image Processing"],"requires_dist":["numpy","scipy","scikit-image","magicgui","qtpy","napari","tox ; extra == 'testing'","pytest ; extra == 'testing'","pytest-cov ; extra == 'testing'","pytest-qt ; extra == 'testing'","napari ; extra == 'testing'","pyqt5 ; extra == 'testing'"],"requires_python":">=3.8","requires_external":null,"project_url":["Bug Tracker, https://github.com/leoguignard/napari-turing/issues","Documentation, https://github.com/leoguignard/napari-turing#README.md","Source Code, https://github.com/leoguignard/napari-turing","User Support, https://github.com/leoguignard/napari-turing/issues"],"provides_extra":["testing"],"provides_dist":null,"obsoletes_dist":null},"npe1_shim":false}