├── .bumpversion.cfg ├── .github ├── ISSUE_TEMPLATE.md ├── dependabot.yml └── workflows │ ├── main.yml │ ├── pypi_release.yml │ └── pypi_test.yml ├── .gitignore ├── .readthedocs.yaml ├── CONTRIBUTING.rst ├── LICENSE.txt ├── changelog.rst ├── convert └── matlab_2d.m ├── distribution ├── README.md ├── create_installer.bat ├── create_linux_shortcuts.py ├── picasso-script.py ├── picasso.iss ├── pypi │ ├── install_pypi_wheel.sh │ ├── install_test_pypi_wheel.sh │ └── prepare_pypi_wheel.sh └── test_installer.bat ├── docs ├── .gitignore ├── Makefile ├── average.png ├── average.rst ├── average3.png ├── cmd.png ├── cmd.rst ├── conf.py ├── design.png ├── design.rst ├── faq.rst ├── files.rst ├── filter.png ├── filter.rst ├── index.rst ├── localize.png ├── localize.rst ├── main_render.png ├── make.bat ├── nanotron.png ├── nanotron.rst ├── plugins.png ├── plugins.rst ├── postprocessing.rst ├── readme.rst ├── render.png ├── render.rst ├── render_resi.png ├── requirements.txt ├── server.png ├── server.rst ├── server_cmd.png ├── server_compare.png ├── server_compare_histogram.png ├── server_history.png ├── server_localize.png ├── server_main.png ├── server_preview.png ├── server_watcher_pg.png ├── simulate.png ├── simulate.rst ├── spinna.rst ├── spinna_mask_generation_tab.png ├── spinna_nnd_plot_settings.png ├── spinna_simulate_tab_after_fit.png ├── spinna_simulate_tab_before_load.png ├── spinna_structures_tab.png └── table01.csv ├── main_render.png ├── picasso ├── __init__.py ├── __main__.py ├── __version__.py ├── aim.py ├── avgroi.py ├── clusterer.py ├── config_template.yaml ├── design.py ├── design_sequences.py ├── ext │ ├── __init__.py │ └── bitplane.py ├── gausslq.py ├── gaussmle.py ├── gui │ ├── __init__.py │ ├── average.py │ ├── average3.py │ ├── createShortcuts.ps1 │ ├── design.py │ ├── filter.py │ ├── icons │ │ ├── average.ico │ │ ├── design.ico │ │ ├── filter.ico │ │ ├── localize.ico │ │ ├── nanotron.ico │ │ ├── picasso_server.png │ │ ├── render.ico │ │ ├── server.ico │ │ ├── simulate.ico │ │ ├── spinna.ico │ │ └── toraw.ico │ ├── localize.py │ ├── nanotron.py │ ├── plugins │ │ └── __init__.py │ ├── render.py │ ├── rotation.py │ ├── simulate.py │ ├── spinna.py │ └── toraw.py ├── imageprocess.py ├── io.py ├── lib.py ├── localize.py ├── model │ ├── default_model.sav │ └── default_model.yaml ├── nanotron.py ├── postprocess.py ├── render.py ├── server │ ├── __init__.py │ ├── app.py │ ├── compare.py │ ├── helper.py │ ├── history.py │ ├── preview.py │ ├── status.py │ └── watcher.py ├── simulate.py ├── spinna.py └── zfit.py ├── plugin_template.py ├── readme.rst ├── release ├── logos │ └── localize.ico ├── one_click_windows_gui │ ├── create_installer_windows.bat │ └── picasso_innoinstaller.iss ├── pyinstaller │ ├── picasso.spec │ ├── picasso_pyinstaller.py │ └── picassow.spec └── pypi │ ├── install_pypi_wheel.sh │ ├── install_test_pypi_wheel.sh │ └── prepare_pypi_wheel.sh ├── requirements.txt ├── resources └── icons │ ├── average.png │ ├── average.svg │ ├── design.png │ ├── design.svg │ ├── filter.png │ ├── filter.svg │ ├── localize.png │ ├── localize.svg │ ├── picasso_server.png │ ├── picasso_server.svg │ ├── render.png │ ├── render.svg │ ├── simulate.png │ ├── simulate.svg │ ├── spinna.png │ ├── spinna.svg │ ├── toraw.png │ └── toraw.svg ├── samples ├── SampleNotebook.ipynb ├── SampleNotebook2.ipynb ├── SampleNotebook3.ipynb ├── SampleNotebook4.ipynb ├── egfr_mols.hdf5 └── egfr_mols.yaml ├── setup.py └── tests ├── __init__.py ├── data ├── testdata.raw ├── testdata.yaml ├── testdata_locs.hdf5 └── testdata_locs.yaml └── test_localize.py /.bumpversion.cfg: -------------------------------------------------------------------------------- 1 | [bumpversion] 2 | current_version = 0.8.0 3 | commit = True 4 | tag = False 5 | parse = (?P\d+)\.(?P\d+)\.(?P\d+)(\-(?P[a-z]+)(?P\d+))? 6 | serialize = 7 | {major}.{minor}.{patch}-{release}{build} 8 | {major}.{minor}.{patch} 9 | 10 | [bumpversion:part:release] 11 | 12 | [bumpversion:part:build] 13 | 14 | [bumpversion:file:./distribution/picasso.iss] 15 | 16 | [bumpversion:file:./picasso/__init__.py] 17 | 18 | [bumpversion:file:./picasso/__version__.py] 19 | 20 | [bumpversion:file:./release/one_click_windows_gui/picasso_innoinstaller.iss] 21 | 22 | [bumpversion:file:./docs/conf.py] 23 | 24 | [bumpversion:file:./release/one_click_windows_gui/create_installer_windows.bat] 25 | 26 | [bumpversion:file:setup.py] 27 | search = {current_version} 28 | replace = {new_version} 29 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | * Picasso version: 2 | * Python version: 3 | * Operating System: 4 | 5 | ### Description 6 | 7 | Describe what you were trying to get done. 8 | Tell us what happened, what went wrong, and what you expected to happen. 9 | If you can, upload the dataset that caused the problem. 10 | 11 | ### What I Did 12 | 13 | ``` 14 | Paste the command(s) you ran and the output. 15 | If there was a crash, please include the traceback here. 16 | ``` 17 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: pip 4 | directory: "/" 5 | schedule: 6 | interval: daily 7 | time: "04:00" 8 | open-pull-requests-limit: 10 9 | ignore: 10 | - dependency-name: matplotlib 11 | versions: 12 | - 3.3.4 13 | - 3.4.0 14 | - dependency-name: scipy 15 | versions: 16 | - 1.6.0 17 | - 1.6.1 18 | - 1.6.2 19 | - dependency-name: numba 20 | versions: 21 | - 0.53.0 22 | - dependency-name: tqdm 23 | versions: 24 | - 4.56.0 25 | - 4.56.1 26 | - 4.56.2 27 | - 4.57.0 28 | - 4.58.0 29 | - 4.59.0 30 | - dependency-name: h5py 31 | versions: 32 | - 3.1.0 33 | - 3.2.0 34 | - dependency-name: numpy 35 | versions: 36 | - 1.19.5 37 | - 1.20.0 38 | - 1.20.1 39 | - dependency-name: scikit-learn 40 | versions: 41 | - 0.24.1 42 | -------------------------------------------------------------------------------- /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | # This workflow will install Python dependencies, run tests and lint with a single version of Python 2 | # For more information see: https://help.github.com/actions/language-and-framework-guides/using-python-with-github-actions 3 | 4 | name: CI 5 | 6 | on: 7 | push: 8 | branches: [ master ] 9 | pull_request: 10 | branches: [ master ] 11 | 12 | jobs: 13 | build: 14 | 15 | runs-on: ubuntu-latest 16 | 17 | steps: 18 | - uses: actions/checkout@v3 19 | - name: Set up Python 3.10 20 | uses: actions/setup-python@v5 21 | with: 22 | python-version: 3.10.13 23 | - name: Install dependencies 24 | run: | 25 | python -m pip install --upgrade pip 26 | pip install -r requirements.txt 27 | - name: Lint with flake8 28 | run: | 29 | pip install flake8 30 | # stop the build if there are Python syntax errors or undefined names 31 | flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics 32 | # exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide 33 | flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics 34 | - name: Test with pytest 35 | run: | 36 | pip install pytest 37 | pytest 38 | -------------------------------------------------------------------------------- /.github/workflows/pypi_release.yml: -------------------------------------------------------------------------------- 1 | on: 2 | push: 3 | branches: [ main ] 4 | workflow_dispatch: 5 | 6 | 7 | name: Publish on PyPi 8 | 9 | jobs: 10 | Create_PyPi_Release: 11 | runs-on: ubuntu-latest 12 | steps: 13 | - name: Checkout code 14 | uses: actions/checkout@v2 15 | - uses: conda-incubator/setup-miniconda@v2 16 | with: 17 | auto-update-conda: true 18 | python-version: ${{ matrix.python-version }} 19 | - name: Conda info 20 | shell: bash -l {0} 21 | run: conda info 22 | - name: Prepare distribution 23 | shell: bash -l {0} 24 | run: | 25 | cd distribution/pypi 26 | . ./prepare_pypi_wheel.sh 27 | - name: Publish distribution to Test PyPI 28 | uses: pypa/gh-action-pypi-publish@master 29 | with: 30 | password: ${{ secrets.TEST_PYPI_API_TOKEN }} 31 | repository_url: https://test.pypi.org/legacy/ 32 | - name: Test PyPI test release 33 | shell: bash -l {0} 34 | run: | 35 | cd distribution/pypi 36 | . ./install_test_pypi_wheel.sh 37 | - name: Publish distribution to PyPI 38 | uses: pypa/gh-action-pypi-publish@master 39 | with: 40 | password: ${{ secrets.PYPI_API_TOKEN }} 41 | Test_PyPi_Release: 42 | name: Test_PyPi_version_on_${{ matrix.os }} 43 | runs-on: ${{ matrix.os }} 44 | needs: Create_PyPi_Release 45 | strategy: 46 | matrix: 47 | os: [ubuntu-latest, macOS-latest, windows-latest] 48 | steps: 49 | - uses: actions/checkout@v2 50 | - uses: conda-incubator/setup-miniconda@v2 51 | with: 52 | auto-update-conda: true 53 | miniconda-version: "latest" 54 | python-version: ${{ matrix.python-version }} 55 | - name: Conda info 56 | shell: bash -l {0} 57 | run: conda info 58 | - name: Test pip installation from PyPi 59 | shell: bash -l {0} 60 | run: | 61 | cd distribution/pypi 62 | . ./install_pypi_wheel.sh 63 | -------------------------------------------------------------------------------- /.github/workflows/pypi_test.yml: -------------------------------------------------------------------------------- 1 | on: 2 | push: 3 | branches: [ main ] 4 | workflow_dispatch: 5 | 6 | name: Default installation and tests 7 | 8 | jobs: 9 | install: 10 | name: Test on ${{ matrix.os }} 11 | runs-on: ${{ matrix.os }} 12 | strategy: 13 | matrix: 14 | os: [ubuntu-latest, macOS-latest, windows-latest] 15 | steps: 16 | - uses: actions/checkout@v2 17 | - uses: conda-incubator/setup-miniconda@v2 18 | with: 19 | auto-update-conda: true 20 | python-version: ${{ matrix.python-version }} 21 | - name: Conda info 22 | shell: bash -l {0} 23 | run: conda info 24 | - name: Test pip installation 25 | shell: bash -l {0} 26 | run: | 27 | conda create -n picasso python=3.10 -y 28 | conda activate picasso 29 | pip install picassosr 30 | conda deactivate 31 | - name: Testing modules 32 | shell: bash -l {0} 33 | run: | 34 | conda activate picasso 35 | picasso 36 | conda deactivate 37 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | env/ 12 | build/ 13 | develop-eggs/ 14 | dist/ 15 | downloads/ 16 | eggs/ 17 | .eggs/ 18 | lib/ 19 | lib64/ 20 | parts/ 21 | sdist/ 22 | var/ 23 | wheels/ 24 | *.egg-info/ 25 | .installed.cfg 26 | *.egg 27 | 28 | # Plugins 29 | picasso/gui/plugins/ 30 | 31 | # Camera configuration 32 | picasso/config.yaml 33 | 34 | # PyInstaller 35 | # Usually these files are written by a python script from a template 36 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 37 | *.manifest 38 | *.spec 39 | 40 | # Installer logs 41 | pip-log.txt 42 | pip-delete-this-directory.txt 43 | 44 | # Unit test / coverage reports 45 | htmlcov/ 46 | .tox/ 47 | .coverage 48 | .coverage.* 49 | .cache 50 | nosetests.xml 51 | coverage.xml 52 | *.cover 53 | .hypothesis/ 54 | .pytest_cache/ 55 | 56 | # Translations 57 | *.mo 58 | *.pot 59 | 60 | # Django stuff: 61 | *.log 62 | local_settings.py 63 | 64 | # Flask stuff: 65 | instance/ 66 | .webassets-cache 67 | 68 | # Scrapy stuff: 69 | .scrapy 70 | 71 | # Sphinx documentation 72 | docs/_build/ 73 | 74 | # PyBuilder 75 | target/ 76 | 77 | # Mac Desktop Service Store 78 | **/.DS_Store 79 | 80 | # vscode settings 81 | .vscode/ 82 | 83 | # Jupyter Notebook 84 | .ipynb_checkpoints 85 | 86 | # pyenv 87 | .python-version 88 | 89 | # celery beat schedule file 90 | celerybeat-schedule 91 | 92 | # SageMath parsed files 93 | *.sage.py 94 | 95 | # dotenv 96 | .env 97 | 98 | # virtualenv 99 | .venv 100 | venv/ 101 | ENV/ 102 | 103 | # Spyder project settings 104 | .spyderproject 105 | .spyproject 106 | 107 | # Rope project settings 108 | .ropeproject 109 | 110 | # mkdocs documentation 111 | /site 112 | 113 | # mypy 114 | .mypy_cache/ 115 | -------------------------------------------------------------------------------- /.readthedocs.yaml: -------------------------------------------------------------------------------- 1 | # Read the Docs configuration file for Sphinx projects 2 | # See https://docs.readthedocs.io/en/stable/config-file/v2.html for details 3 | 4 | # Required 5 | version: 2 6 | 7 | # Set the OS, Python version and other tools you might need 8 | build: 9 | os: ubuntu-22.04 10 | tools: 11 | python: "3.12" 12 | 13 | 14 | # Build documentation in the "docs/" directory with Sphinx 15 | sphinx: 16 | configuration: docs/conf.py 17 | # You can configure Sphinx to use a different builder, for instance use the dirhtml builder for simpler URLs 18 | # builder: "dirhtml" 19 | # Fail on all warnings to avoid broken references 20 | # fail_on_warning: true 21 | 22 | # Optionally build your docs in additional formats such as PDF and ePub 23 | # formats: 24 | # - pdf 25 | # - epub 26 | 27 | # Optional but recommended, declare the Python requirements required 28 | # to build your documentation 29 | # See https://docs.readthedocs.io/en/stable/guides/reproducible-builds.html 30 | python: 31 | install: 32 | - requirements: docs/requirements.txt -------------------------------------------------------------------------------- /CONTRIBUTING.rst: -------------------------------------------------------------------------------- 1 | ============ 2 | Contributing 3 | ============ 4 | 5 | Contributions are welcome, and they are greatly appreciated! Every 6 | little bit helps, and credit will always be given. 7 | 8 | You can contribute in many ways: 9 | 10 | Types of Contributions 11 | ---------------------- 12 | 13 | Report Bugs 14 | ~~~~~~~~~~~ 15 | 16 | Report bugs at https://github.com/jungmannlab/picasso/issues. 17 | 18 | If you are reporting a bug, please include: 19 | 20 | * Your operating system name and version. 21 | * Any details about your local setup that might be helpful in troubleshooting. 22 | * Detailed steps to reproduce the bug. 23 | 24 | Fix Bugs 25 | ~~~~~~~~ 26 | 27 | Look through the GitHub issues for bugs. Anything tagged with "bug" 28 | and "help wanted" is open to whoever wants to implement it. 29 | 30 | Implement Features 31 | ~~~~~~~~~~~~~~~~~~ 32 | 33 | Look through the GitHub issues for features. Anything tagged with "enhancement" 34 | and "help wanted" is open to whoever wants to implement it. 35 | 36 | Write Documentation 37 | ~~~~~~~~~~~~~~~~~~~ 38 | 39 | Picasso could always use more documentation, whether as part of the 40 | official Picasso docs, in docstrings, or even on the web in blog posts, 41 | articles, and such. 42 | 43 | Submit Feedback 44 | ~~~~~~~~~~~~~~~ 45 | 46 | The best way to send feedback is to file an issue at https://github.com/jungmannlab/picasso/issues. 47 | 48 | If you are proposing a feature: 49 | 50 | * Explain in detail how it would work. 51 | * Keep the scope as narrow as possible, to make it easier to implement. 52 | * Remember that this is a volunteer-driven project, and that contributions 53 | are welcome :) 54 | 55 | Get Started! 56 | ------------ 57 | 58 | Ready to contribute? Here's how to set up `picasso` for local development. 59 | 60 | 1. Fork the `picasso` repo on GitHub. 61 | 2. Clone your fork locally:: 62 | 63 | $ git clone git@github.com:your_name_here/picasso.git 64 | 65 | 3. Follow the installation instructions in the readme to install a picasso environment. 66 | 67 | 4. (Optionally) Build the docs (Note that you need to install sphinx and the rtd-theme):: 68 | 69 | $ cd docs/ 70 | $ make html # docs will found in _build/html/. Open `index.html` to view the docs; macOS users can do `open _build/html/index.html` to open the docs in your default browser. 71 | 72 | 4. Create a branch for local development:: 73 | 74 | $ git checkout -b name-of-your-bugfix-or-feature 75 | 76 | Now you can make your changes locally. 77 | 78 | 5. When you're done making changes, check that your changes pass pycodestyle and the tests:: 79 | 80 | $ py.test 81 | $ cd picasso 82 | $ pycodestyle . 83 | 84 | To get flake8 and tox, just pip install them into your virtualenv. 85 | 86 | 6. Commit your changes and push your branch to GitHub:: 87 | 88 | $ git add . 89 | $ git commit -m "Your detailed description of your changes." 90 | $ git push origin name-of-your-bugfix-or-feature 91 | 92 | 7. Submit a pull request through the GitHub website. 93 | 94 | Pull Request Guidelines 95 | ----------------------- 96 | 97 | Before you submit a pull request, check that it meets these guidelines: 98 | 99 | 1. The pull request should include tests. 100 | 2. If the pull request adds functionality, the docs should be updated. 101 | 3. The pull request should work for Python 3.5. 102 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2016 Jungmann Lab jungmannlab.org 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /convert/matlab_2d.m: -------------------------------------------------------------------------------- 1 | function savepicasso(PathName, FileName, locs) 2 | 3 | %savepicasso: save molecule list as hdf5 file and additional yaml file to 4 | %be readable with picasso 5 | %HDF5 import modified from the 'h5ex_t_cmpd.m' example from hdfgroup.com 6 | 7 | %Input: PathName: old file path e.g. C:/users/ 8 | %Input: FileName: old FileName with ending e.g. locs.mat 9 | %Input: struct locs: 10 | %locs.frame: frames, picasso frames start with 0 11 | %locs.x: x-coordinates in pixels, make sure that x>0 12 | %locs.y: y-coordinates in pixels, make sure that y>0 13 | %locs.lpx: localization precision in x in pixels 14 | %locs.lpy: localization precision in y in pixels 15 | 16 | %2017 m.strauss@biochem.mpg.de 17 | 18 | %Make sure all fields are double 19 | 20 | locs.frame = double(locs.frame); 21 | locs.x = double(locs.x); 22 | locs.y = double(locs.y); 23 | locs.lpx = double(locs.lpx); 24 | locs.lpy = double(locs.lpy); 25 | 26 | %get parameters for yaml 27 | width = ceil(max(locs.x)); 28 | height = ceil(max(locs.y)); 29 | frames = max(locs.frame); 30 | 31 | %Create and hdf5 file with /locs 32 | saveName = fullfile(PathName,strcat(FileName,'.mat.hdf5')); 33 | DATASET = '/locs'; 34 | dims = length(locs.frame); 35 | 36 | 37 | file = H5F.create (saveName, 'H5F_ACC_TRUNC',... 38 | 'H5P_DEFAULT', 'H5P_DEFAULT'); 39 | 40 | % Assign the required data types (all as double) 41 | 42 | doubleType=H5T.copy('H5T_NATIVE_DOUBLE'); 43 | sz(1) =H5T.get_size(doubleType); 44 | doubleType=H5T.copy('H5T_NATIVE_DOUBLE'); 45 | sz(2) =H5T.get_size(doubleType); 46 | doubleType=H5T.copy('H5T_NATIVE_DOUBLE'); 47 | sz(3) =H5T.get_size(doubleType); 48 | doubleType=H5T.copy('H5T_NATIVE_DOUBLE'); 49 | sz(4) =H5T.get_size(doubleType); 50 | doubleType=H5T.copy('H5T_NATIVE_DOUBLE'); 51 | sz(5) =H5T.get_size(doubleType); 52 | 53 | % Computer the offsets to each field. The first offset is always zero. 54 | offset(1)=0; 55 | offset(2:5)=cumsum(sz(1:4)); 56 | 57 | % Create the compound datatype for memory. 58 | memtype = H5T.create ('H5T_COMPOUND', sum(sz)); 59 | H5T.insert (memtype,... 60 | 'frame',offset(1), doubleType); 61 | H5T.insert (memtype,... 62 | 'x',offset(2), doubleType); 63 | H5T.insert (memtype,... 64 | 'y',offset(3), doubleType); 65 | H5T.insert (memtype,... 66 | 'lpx',offset(4), doubleType); 67 | H5T.insert (memtype,... 68 | 'lpy',offset(5), doubleType); 69 | 70 | %Create the compound datatype with the required fields - 'frame', 'x', 'y', 71 | %'lpx' %'lpy' 72 | filetype = H5T.create ('H5T_COMPOUND', sum(sz)); 73 | H5T.insert (filetype, 'frame', offset(1),doubleType); 74 | H5T.insert (filetype, 'x', offset(2), doubleType); 75 | H5T.insert (filetype, 'y',offset(3), doubleType); 76 | H5T.insert (filetype, 'lpx',offset(4), doubleType); 77 | H5T.insert (filetype, 'lpy',offset(5), doubleType); 78 | 79 | % Create dataspace. Setting maximum size to [] sets the maximum 80 | % size to be the current size. 81 | space = H5S.create_simple (1,fliplr( dims), []); 82 | 83 | % Create the dataset and write the compound data to it. 84 | dset = H5D.create (file, DATASET, filetype, space, 'H5P_DEFAULT'); 85 | H5D.write (dset, memtype, 'H5S_ALL', 'H5S_ALL', 'H5P_DEFAULT', locs); 86 | 87 | % Close and release resources. 88 | H5D.close (dset); 89 | H5S.close (space); 90 | H5T.close (filetype); 91 | H5F.close (file); 92 | 93 | %Also create a yaml file for picasso to import 94 | yamlName = fullfile(PathName,strcat(FileName,'.mat.yaml')); 95 | fileID = fopen(yamlName,'wt'); 96 | fprintf(fileID,'Byte Order: <\n'); %the byte-order and data type should not matter at this point as the raw data is already localizaed 97 | fprintf(fileID,'Data Type: uint16 \n'); 98 | fprintf(fileID,['Frames: ',num2str(frames),' \n']); 99 | fprintf(fileID,['Width: ',num2str(width),' \n']); 100 | fprintf(fileID,['Height: ',num2str(height),' \n']); 101 | fprintf(fileID,'Generated by: Picasso Convert\n'); 102 | fclose(fileID); 103 | end 104 | -------------------------------------------------------------------------------- /distribution/README.md: -------------------------------------------------------------------------------- 1 | # Packaging Picasso and Creating an Installer 2 | This document describes the procedure to generate a Windows installer for Picasso end-users. The result is that Picasso (and Python) is installed in a single folder, the command line interface is exposed and start menu shortcuts are created. The first step is to package Picasso and its underlying Python distribution into a single folder. 3 | 4 | ## Requirements 5 | - A Miniconda or Anaconda Python installation with a separate environment called `picasso` (See Picasso readme). In this environment should be installed: 6 | - Picasso requirements 7 | - Additionally install Pyinstaller (pip install pyinstaller) 8 | - Inno Setup (free program, download it from the internet) 9 | 10 | ## Creating the Installer 11 | 1. Navigate to ./picasso/distribution 12 | 2. Make sure that in `create_installer.bat`, the Inno Setup executable points to the correct file installation path. 13 | 3. Run `create_installer.bat` 14 | 15 | You will now find the installer executable in the folder `Output`, ready for distribution. 16 | 17 | # Creating shortcuts for Linux 18 | The script `create_linux_shortcuts.py` creates application menu entries (`*.desktop` files following the desktop entry specification by freedesktop.org) and an executable that can be called from the terminal without explicitly activating the picasso environment. 19 | 20 | 1. Clone/download picasso, set up the picasso environment using `python -m venv path/to/environment`, activate the environment, install the requirements and run `python setup.py install`. 21 | 2. With the picasso environment activated, run the script `create_linux_shortcuts.py`. 22 | 23 | When `create_linux_shortcuts.py` is run as root, the picasso script is created as `/usr/bin/picasso` and the desktop files are created in `/usr/share/applications`. 24 | For non-root users, the picasso script is created as `~/bin/picasso`, assuming that `~/bin` is on your `$PATH`, and the desktop files are created in `~/.local/share/applications`. 25 | The picasso script can then be run without explicitly activating the picasso environment. 26 | Note that this setup was only tested with environments created using venv; it may not work with conda environments. 27 | -------------------------------------------------------------------------------- /distribution/create_installer.bat: -------------------------------------------------------------------------------- 1 | call DEL /F/Q/S build > NUL 2 | call DEL /F/Q/S dist > NUL 3 | call RMDIR /Q/S build 4 | call RMDIR /Q/S dist 5 | call conda env remove -n picasso_installer 6 | call conda create -n picasso_installer python=3.10 -y 7 | call conda activate picasso_installer 8 | call pip install pyinstaller==4.2 9 | cd %~dp0\.. 10 | call DEL /F/Q/S dist > NUL 11 | call RMDIR /Q/S dist 12 | call pip install -r requirements.txt 13 | call python setup.py install 14 | cd %~dp0 15 | pyinstaller -y --hidden-import=h5py.defs --hidden-import=h5py.utils --hidden-import=h5py.h5ac --hidden-import=h5py._proxy --hidden-import=sklearn.neighbors.typedefs --hidden-import=sklearn.neighbors.quad_tree --hidden-import=sklearn.tree --hidden-import=sklearn.tree._utils --hidden-import=scipy._lib.messagestream -n picasso picasso-script.py 16 | pyinstaller -y --hidden-import=h5py.defs --hidden-import=h5py.utils --hidden-import=h5py.h5ac --hidden-import=h5py._proxy --hidden-import=sklearn.neighbors.typedefs --hidden-import=sklearn.neighbors.quad_tree --hidden-import=sklearn.tree --hidden-import=sklearn.tree._utils --hidden-import=scipy._lib.messagestream --noconsole -n picassow picasso-script.py 17 | copy dist\picassow\picassow.exe dist\picasso\picassow.exe 18 | copy dist\picassow\picassow.exe.manifest dist\picasso\picassow.exe.manifest 19 | "C:\Program Files (x86)\Inno Setup 6\ISCC.exe" picasso.iss 20 | call conda deactivate 21 | -------------------------------------------------------------------------------- /distribution/create_linux_shortcuts.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | import sys 3 | import os 4 | import os.path as op 5 | 6 | try: 7 | import picasso 8 | except ImportError: 9 | print( 10 | "This script must be run within an environment " 11 | "in which picasso is installed!", 12 | file=sys.stderr, 13 | ) 14 | raise 15 | 16 | SUBCMD = ("average", "design", "filter", "localize", "render", "simulate", "spinna") 17 | SCRIPT_PATH_ROOT = (os.sep, "usr", "bin", "picasso") 18 | DESKTOP_PATH_ROOT = (os.sep, "usr", "share", "applications", "picasso_{subcmd}.desktop") 19 | SCRIPT_PATH_USER = ("~", "bin", "picasso") 20 | DESKTOP_PATH_USER = ("~", ".local", "share", "applications", "picasso_{subcmd}.desktop") 21 | 22 | DESKTOP_TEMPLATE = """[Desktop Entry] 23 | Name=Picasso {subcmd_cap} 24 | Exec={exec_path} -m picasso {subcmd} 25 | Terminal=false 26 | Type=Application 27 | Icon={icon_path} 28 | Categories=Education; 29 | """ 30 | 31 | SCRIPT_TEMPLATE = """#!{exec_path} 32 | if __name__ == "__main__": 33 | from picasso.__main__ import main 34 | main() 35 | """ 36 | 37 | 38 | def main(exec_path=None, icon_path=None, script_path=None, desktop_path=None): 39 | if exec_path is None: 40 | exec_path = sys.executable 41 | if icon_path is None: 42 | import picasso.gui 43 | 44 | icon_path = op.join(op.dirname(picasso.gui.__file__), "icons") 45 | if os.geteuid() == 0: 46 | if script_path is None: 47 | script_path = op.join(*SCRIPT_PATH_ROOT) 48 | if desktop_path is None: 49 | desktop_path = op.join(*DESKTOP_PATH_ROOT) 50 | else: 51 | if script_path is None: 52 | script_path = op.expanduser(op.join(*SCRIPT_PATH_USER)) 53 | if desktop_path is None: 54 | desktop_path = op.expanduser(op.join(*DESKTOP_PATH_USER)) 55 | 56 | print("Writing files:") 57 | with open(script_path, "xt") as f: 58 | f.write(SCRIPT_TEMPLATE.format(exec_path=exec_path)) 59 | print(script_path) 60 | os.chmod(script_path, 0o755) 61 | 62 | for subcmd in SUBCMD: 63 | icon_file = op.join(icon_path, f"{subcmd}.ico") 64 | desktop_file = op.join(desktop_path.format(subcmd=subcmd)) 65 | with open(desktop_file, "xt") as f: 66 | f.write( 67 | DESKTOP_TEMPLATE.format( 68 | subcmd=subcmd, 69 | subcmd_cap=subcmd.capitalize(), 70 | exec_path=exec_path, 71 | icon_path=icon_file, 72 | ) 73 | ) 74 | print(desktop_file) 75 | os.chmod(desktop_file, 0o755) 76 | 77 | 78 | if __name__ == "__main__": 79 | if sys.platform != "linux": 80 | raise RuntimeError("Other operating system than Linux detected.") 81 | main() -------------------------------------------------------------------------------- /distribution/picasso-script.py: -------------------------------------------------------------------------------- 1 | from multiprocessing import freeze_support 2 | 3 | 4 | if __name__ == "__main__": 5 | # This line is needed so that pyinstaller can handle multiprocessing 6 | freeze_support() 7 | from picasso.__main__ import main 8 | 9 | main() 10 | -------------------------------------------------------------------------------- /distribution/picasso.iss: -------------------------------------------------------------------------------- 1 | [Setup] 2 | AppName=Picasso 3 | AppPublisher=Jungmann Lab, Max Planck Institute of Biochemistry 4 | 5 | AppVersion=0.8.0 6 | DefaultDirName={commonpf}\Picasso 7 | DefaultGroupName=Picasso 8 | OutputBaseFilename="Picasso-Windows-64bit-0.8.0" 9 | ArchitecturesAllowed=x64 10 | ArchitecturesInstallIn64BitMode=x64 11 | 12 | [Files] 13 | Source: "dist\picasso\*"; DestDir: "{app}"; Flags: recursesubdirs createallsubdirs 14 | 15 | [Icons] 16 | Name: "{group}\Design"; Filename: "{app}\picassow.exe"; Parameters: "design"; IconFilename: "{app}\picasso\gui\icons\design.ico" 17 | Name: "{group}\Simulate"; Filename: "{app}\picassow.exe"; Parameters: "simulate"; IconFilename: "{app}\picasso\gui\icons\simulate.ico" 18 | Name: "{group}\Localize"; Filename: "{app}\picassow.exe"; Parameters: "localize"; IconFilename: "{app}\picasso\gui\icons\localize.ico" 19 | Name: "{group}\Filter"; Filename: "{app}\picassow.exe"; Parameters: "filter"; IconFilename: "{app}\picasso\gui\icons\filter.ico" 20 | Name: "{group}\Render"; Filename: "{app}\picassow.exe"; Parameters: "render"; IconFilename: "{app}\picasso\gui\icons\render.ico" 21 | Name: "{group}\Average"; Filename: "{app}\picassow.exe"; Parameters: "average"; IconFilename: "{app}\picasso\gui\icons\average.ico" 22 | Name: "{group}\Server"; Filename: "{app}\picasso.exe"; Parameters: "server"; IconFilename: "{app}\picasso\gui\icons\server.ico" 23 | Name: "{group}\SPINNA"; Filename: "{app}\picasso.exe"; Parameters: "spinna"; IconFilename: "{app}\picasso\gui\icons\spinna.ico" 24 | 25 | Name: "{autodesktop}\Design"; Filename: "{app}\picassow.exe"; Parameters: "design"; IconFilename: "{app}\picasso\gui\icons\design.ico" 26 | Name: "{autodesktop}\Simulate"; Filename: "{app}\picassow.exe"; Parameters: "simulate"; IconFilename: "{app}\picasso\gui\icons\simulate.ico" 27 | Name: "{autodesktop}\Localize"; Filename: "{app}\picassow.exe"; Parameters: "localize"; IconFilename: "{app}\picasso\gui\icons\localize.ico" 28 | Name: "{autodesktop}\Filter"; Filename: "{app}\picassow.exe"; Parameters: "filter"; IconFilename: "{app}\picasso\gui\icons\filter.ico" 29 | Name: "{autodesktop}\Render"; Filename: "{app}\picassow.exe"; Parameters: "render"; IconFilename: "{app}\picasso\gui\icons\render.ico" 30 | Name: "{autodesktop}\Average"; Filename: "{app}\picassow.exe"; Parameters: "average"; IconFilename: "{app}\picasso\gui\icons\average.ico" 31 | Name: "{autodesktop}\Server"; Filename: "{app}\picasso.exe"; Parameters: "server"; IconFilename: "{app}\picasso\gui\icons\server.ico" 32 | Name: "{autodesktop}\SPINNA"; Filename: "{app}\picasso.exe"; Parameters: "spinna"; IconFilename: "{app}\picasso\gui\icons\spinna.ico" 33 | 34 | [Registry] 35 | Root: HKLM; Subkey: "SYSTEM\CurrentControlSet\Control\Session Manager\Environment"; \ 36 | ValueType: expandsz; ValueName: "Path"; ValueData: "{olddata};{app}"; \ 37 | Check: NeedsAddPath('{app}') 38 | 39 | [Code] 40 | 41 | function NeedsAddPath(Param: string): boolean; 42 | var 43 | OrigPath: string; 44 | ParamExpanded: string; 45 | begin 46 | //expand the setup constants like {app} from Param 47 | ParamExpanded := ExpandConstant(Param); 48 | if not RegQueryStringValue(HKEY_LOCAL_MACHINE, 49 | 'SYSTEM\CurrentControlSet\Control\Session Manager\Environment', 50 | 'Path', OrigPath) 51 | then begin 52 | Result := True; 53 | exit; 54 | end; 55 | // look for the path with leading and trailing semicolon and with or without \ ending 56 | // Pos() returns 0 if not found 57 | Result := Pos(';' + UpperCase(ParamExpanded) + ';', ';' + UpperCase(OrigPath) + ';') = 0; 58 | if Result = True then 59 | Result := Pos(';' + UpperCase(ParamExpanded) + '\;', ';' + UpperCase(OrigPath) + ';') = 0; 60 | end; -------------------------------------------------------------------------------- /distribution/pypi/install_pypi_wheel.sh: -------------------------------------------------------------------------------- 1 | conda create -n picasso_pip_test python=3.10 -y 2 | conda activate picasso_pip_test 3 | pip install "picassosr" 4 | picasso 5 | conda deactivate 6 | -------------------------------------------------------------------------------- /distribution/pypi/install_test_pypi_wheel.sh: -------------------------------------------------------------------------------- 1 | conda create -n picasso_pip_test python=3.10 -y 2 | conda activate picasso_pip_test 3 | pip install --index-url https://test.pypi.org/simple/ --extra-index-url https://pypi.org/simple "picassosr" 4 | picasso 5 | conda deactivate 6 | -------------------------------------------------------------------------------- /distribution/pypi/prepare_pypi_wheel.sh: -------------------------------------------------------------------------------- 1 | cd ../.. 2 | conda create -n picasso_pypi_wheel python=3.10 3 | conda activate picasso_pypi_wheel 4 | pip install twine 5 | rm -rf dist 6 | rm -rf build 7 | python setup.py sdist bdist_wheel 8 | twine check dist/* 9 | conda deactivate 10 | -------------------------------------------------------------------------------- /distribution/test_installer.bat: -------------------------------------------------------------------------------- 1 | cd %~dp0\dist\picasso 2 | picasso.exe localize 3 | picasso.exe render 4 | picasso.exe simulate 5 | picasso.exe design 6 | picasso.exe average 7 | picasso.exe average3 8 | picasso.exe spinna 9 | cd %~dp0 10 | -------------------------------------------------------------------------------- /docs/.gitignore: -------------------------------------------------------------------------------- 1 | _build 2 | _static 3 | _templates -------------------------------------------------------------------------------- /docs/Makefile: -------------------------------------------------------------------------------- 1 | # Minimal makefile for Sphinx documentation 2 | # 3 | 4 | # You can set these variables from the command line. 5 | SPHINXOPTS = 6 | SPHINXBUILD = sphinx-build 7 | SOURCEDIR = . 8 | BUILDDIR = _build 9 | 10 | # Put it first so that "make" without argument is like "make help". 11 | help: 12 | @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 13 | 14 | .PHONY: help Makefile 15 | 16 | # Catch-all target: route all unknown targets to Sphinx using the new 17 | # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). 18 | %: Makefile 19 | @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) -------------------------------------------------------------------------------- /docs/average.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jungmannlab/picasso/7ada94433f6b189a929008e14d42027a6da8ced3/docs/average.png -------------------------------------------------------------------------------- /docs/average.rst: -------------------------------------------------------------------------------- 1 | average 2 | ======= 3 | 4 | .. image:: ../docs/average.png 5 | :scale: 50 % 6 | :alt: UML Design 7 | 8 | Particle Averaging 9 | ------------------ 10 | The averaging module uses 2D cross-correlation to determine the rotational and translational offset. 11 | 12 | 1. In ``Picasso: Render``, pick structures to be averaged. 13 | 2. Save the picked localizations by selecting ``File`` > ``Save picked localizations``. 14 | 3. Load the resulting file with picked localizations into ``Picasso: Average`` by selecting ``File`` > ``Open`` or dragging and dropping it into the window. It will start a parallel pool to increase computational speed. 15 | 4. ``Picasso: Average`` will immediately perform a center-of-mass alignment of the picked structures and display an average image. Rotational and translational alignment will follow in the next steps. 16 | 5. Select ``Process`` > ``Parameters`` and adjust the ``Oversampling`` parameter. We recommend choosing the highest number at which the average image still appears smooth. High oversampling values result in substantial computational time and can cause artifacts. Hence, it might be useful to first use low oversampling to generate a less-refined average image and then perform subsequent averaging steps with higher oversampling for optimized resolution. 17 | 6. Adjust the number of average iterations in the ``Iterations`` field. In most cases, a value of 10 is more than sufficient. If you are unsure about the computational time of the process, choose one iteration as a starting point. More iterations can be added later by repeating the processing steps. After a certain number of iterations, the average image will converge, meaning that it will not change with more iterations. If you experience that one localization spot is overemphasized, try again with less oversampling and few iterations. The 2D cross-correlation is prone to lock in bright spots. 18 | 7. Select ``Process`` > ``Average`` to perform particle averaging with the current oversampling for the set number of iterations. This step can be repeated with different settings. The program will use the current average image as a starting point. 19 | 8. Once the average image has converged, save the transformed localizations by selecting ``File`` > ``Save``. The resulting HDF5 localization file contains the aligned localizations in the center of the movie dimensions. It can be loaded like any other HDF5 localization file into ``Picasso: Render``. 20 | 21 | -------------------------------------------------------------------------------- /docs/average3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jungmannlab/picasso/7ada94433f6b189a929008e14d42027a6da8ced3/docs/average3.png -------------------------------------------------------------------------------- /docs/cmd.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jungmannlab/picasso/7ada94433f6b189a929008e14d42027a6da8ced3/docs/cmd.png -------------------------------------------------------------------------------- /docs/cmd.rst: -------------------------------------------------------------------------------- 1 | CMD 2 | === 3 | 4 | .. image:: ../docs/cmd.png 5 | :scale: 50 % 6 | :alt: UML Picasso cmd 7 | 8 | Here is a list of command-line commands that can be used with picasso. 9 | 10 | localize 11 | -------- 12 | Reconstructing images via command line is possible. Type: ``python -m picasso localize args`` within an environment or ``picasso localize args`` if Picasso is installed. 13 | 14 | Batch process a folder 15 | ~~~~~~~~~~~~~~~~~~~~~~ 16 | To batch process a folder simply type the folder name (or drag in drop into the console), e.g. ``python -m picasso localize foldername``. Picasso will analyze the folder and process all *.ome.tif in files in the folder. If the files have consecutive names (e.g., File.ome.tif, File_1.ome.tif, File_2.ome.tif), they will be treated as one. 17 | 18 | If you want to analyze *.raw files, Picasso will check whether a *.raw file has a corresponding *.yaml file. If none is found, you can enter the specifications for each raw file. It is possible to use the same specifications for all *.raw files in that run. 19 | 20 | Adding additional arguments 21 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ 22 | The reconstruction parameters can be specified by adding respective arguments. If they are not specified the default values are chosen. 23 | 24 | :: 25 | 26 | ‘-b’, ‘–box-side-length’, type=int, default=7, help=‘box side length’ 27 | ‘-a’, ‘–fit-method’, choices=["mle", "lq", "lq-gpu", "lq-3d", "lq-gpu-3d", "avg"], default=‘mle’ 28 | ‘-g’, ‘–gradient’, type=int, default=5000, help=‘minimum net gradient’ 29 | ‘-d’, ‘–drift’, type=int, default=1000, help=‘segmentation size for subsequent RCC, 0 to deactivate’ 30 | ‘-r’, ‘-roi‘, type=int, nargs=4, default=None, help=‘ROI (y_min, x_min, y_max, x_max) in camera pixels’ 31 | ‘-bl’, ‘–baseline’, type=int, default=0, help=‘camera baseline’ 32 | ‘-s’, ‘–sensitivity’, type=int, default=1, help=‘camera sensitivity’ 33 | ‘-ga’, ‘–gain’, type=int, default=1, help=‘camera gain’ 34 | ‘-qe’, ‘–qe’, type=int, default=1, help=‘camera quantum efficiency’ 35 | 36 | Note 1: Localize will automatically try to perform an RCC drift correction on the dataset. As this will not always work with the default 37 | settings after an unsuccessful attempt, the program will continue with the next file. If the drift correction succeeds, another hdf5 file with the 38 | drift corrected locs will be created. 39 | 40 | Note 2: Make sure to set the camera settings correctly; otherwise Photon counts are wrong plus the MLE might have problems. 41 | 42 | Note 3: If you select one of the 3D algorithms (lq-3d or lq-gpu-3d) the program will ask you to enter the magnification factor and the path to the 3D calibration file. 43 | 44 | Example 45 | ^^^^^^^ 46 | This example shows the batch process of a folder, with movie ome.tifs that are supposed to be reconstructed and drift corrected with the ``lq``-Algorithm and a gradient of 4000. 47 | 48 | ``python -m picasso localize foldername -a lq -g 4000`` or 49 | ``picasso localize foldername -a lq -g 4000`` 50 | 51 | csv2hdf 52 | ------- 53 | Convert csv files (thunderSTORM) to hdf. Type ``python -m picasso csv2hdf filepath pixelsize``. Note that the following columns need to be present: 54 | ``frame, x_nm, y_nm, sigma_nm, intensity_photon, offset_photon, uncertainty_xy_nm`` for 2D files 55 | ``frame, x_nm, y_nm, z_nm, sigma1_nm, sigma2_nm, intensity_photon, offset_photon, uncertainty_xy_nm`` for 3D files 56 | 57 | join 58 | ---- 59 | Combine two hdf5 localization files. Type ``python -m picasso join file1 file2``. A new joined file will be created. Note that the frame information is preserved, i.e., frame 1 now can contain localizations from file 1 and file 2. Therefore, do not perform kinetic analysis and drift correction on joined files. 60 | 61 | link 62 | ---- 63 | Link localizations in consecutive frames. 64 | 65 | cluster_combine 66 | --------------- 67 | Combines the localizations in each cluster of a group. 68 | 69 | cluster_combine_dist 70 | -------------------- 71 | Calculate the nearest neighbor for each combined cluster 72 | 73 | clusterfilter 74 | ------------- 75 | Filter localizations by properties of their clusters. 76 | 77 | undrift 78 | ------- 79 | Correct localization coordinates for drift with RCC. 80 | 81 | aim 82 | ------- 83 | Correct localization coordinates for drift with AIM. 84 | 85 | density 86 | ------- 87 | Compute the local density of localizations 88 | 89 | dbscan 90 | ------ 91 | Cluster localizations with the dbscan clustering algorithm. 92 | 93 | hdbscan 94 | ------- 95 | Cluster localizations with the hdbscan clustering algorithm. 96 | 97 | smlm_cluster 98 | ------------ 99 | Cluster localizations with the custom SMLM clustering algorithm. 100 | 101 | The algorithm finds localizations with the most neighbors within a specified radius and finds clusters based on such "local maxima". 102 | 103 | dark 104 | ---- 105 | Compute the dark time for grouped localizations. 106 | 107 | align 108 | ----- 109 | Align one localization file to antoher via RCC. 110 | Type ``python -m picasso align file1 file2`` 111 | 112 | groupprops 113 | ---------- 114 | Calculate the properties of localization groups 115 | 116 | pc 117 | -- 118 | Calculate the pair-correlation of localizations 119 | 120 | nneighbor 121 | --------- 122 | Calculate the nearest neighbor within a clustered dataset 123 | 124 | render 125 | ------ 126 | Start the render module 127 | 128 | design 129 | ------ 130 | Start the design module. 131 | 132 | simulate 133 | -------- 134 | Start the simulation module. 135 | 136 | average 137 | ------- 138 | Start the 2D averaging module 139 | 140 | average3 141 | -------- 142 | Start the 3D averaging module 143 | 144 | 145 | 146 | 147 | -------------------------------------------------------------------------------- /docs/conf.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # Configuration file for the Sphinx documentation builder. 4 | # 5 | # This file does only contain a selection of the most common options. For a 6 | # full list see the documentation: 7 | # http://www.sphinx-doc.org/en/master/config 8 | 9 | # -- Path setup -------------------------------------------------------------- 10 | 11 | # If extensions (or modules to document with autodoc) are in another directory, 12 | # add these directories to sys.path here. If the directory is relative to the 13 | # documentation root, use os.path.abspath to make it absolute, like shown here. 14 | # 15 | # import os 16 | # import sys 17 | # sys.path.insert(0, os.path.abspath('.')) 18 | 19 | 20 | # -- Project information ----------------------------------------------------- 21 | 22 | project = "Picasso" 23 | copyright = "2019, Maximilian Thomas Strauss" 24 | author = "Maximilian T. Strauss" 25 | 26 | # The short X.Y version 27 | version = "" 28 | # The full version, including alpha/beta/rc tags 29 | release = "0.8.0" 30 | 31 | # -- General configuration --------------------------------------------------- 32 | 33 | # If your documentation needs a minimal Sphinx version, state it here. 34 | # 35 | # needs_sphinx = '1.0' 36 | 37 | # Add any Sphinx extension module names here, as strings. They can be 38 | # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom 39 | # ones. 40 | extensions = [] 41 | 42 | # Add any paths that contain templates here, relative to this directory. 43 | templates_path = ["_templates"] 44 | 45 | # The suffix(es) of source filenames. 46 | # You can specify multiple suffix as a list of string: 47 | # 48 | # source_suffix = ['.rst', '.md'] 49 | source_suffix = ".rst" 50 | 51 | # The master toctree document. 52 | master_doc = "index" 53 | 54 | # The language for content autogenerated by Sphinx. Refer to documentation 55 | # for a list of supported languages. 56 | # 57 | # This is also used if you do content translation via gettext catalogs. 58 | # Usually you set "language" from the command line for these cases. 59 | language = None 60 | 61 | # List of patterns, relative to source directory, that match files and 62 | # directories to ignore when looking for source files. 63 | # This pattern also affects html_static_path and html_extra_path. 64 | exclude_patterns = ["_build", "Thumbs.db", ".DS_Store"] 65 | 66 | # The name of the Pygments (syntax highlighting) style to use. 67 | pygments_style = None 68 | 69 | 70 | # -- Options for HTML output ------------------------------------------------- 71 | 72 | # The theme to use for HTML and HTML Help pages. See the documentation for 73 | # a list of builtin themes. 74 | # 75 | html_theme = "sphinx_rtd_theme" 76 | 77 | # Theme options are theme-specific and customize the look and feel of a theme 78 | # further. For a list of options available for each theme, see the 79 | # documentation. 80 | # 81 | # html_theme_options = {} 82 | 83 | # Add any paths that contain custom static files (such as style sheets) here, 84 | # relative to this directory. They are copied after the builtin static files, 85 | # so a file named "default.css" will overwrite the builtin "default.css". 86 | html_static_path = ["_static"] 87 | 88 | # Custom sidebar templates, must be a dictionary that maps document names 89 | # to template names. 90 | # 91 | # The default sidebars (for documents that don't match any pattern) are 92 | # defined by theme itself. Builtin themes are using these templates by 93 | # default: ``['localtoc.html', 'relations.html', 'sourcelink.html', 94 | # 'searchbox.html']``. 95 | # 96 | # html_sidebars = {} 97 | 98 | 99 | # -- Options for HTMLHelp output --------------------------------------------- 100 | 101 | # Output file base name for HTML help builder. 102 | htmlhelp_basename = "Picassodoc" 103 | 104 | 105 | # -- Options for LaTeX output ------------------------------------------------ 106 | 107 | latex_elements = { 108 | # The paper size ('letterpaper' or 'a4paper'). 109 | # 110 | # 'papersize': 'letterpaper', 111 | # The font size ('10pt', '11pt' or '12pt'). 112 | # 113 | # 'pointsize': '10pt', 114 | # Additional stuff for the LaTeX preamble. 115 | # 116 | # 'preamble': '', 117 | # Latex figure (float) alignment 118 | # 119 | # 'figure_align': 'htbp', 120 | } 121 | 122 | # Grouping the document tree into LaTeX files. List of tuples 123 | # (source start file, target name, title, 124 | # author, documentclass [howto, manual, or own class]). 125 | latex_documents = [ 126 | ( 127 | master_doc, 128 | "Picasso.tex", 129 | "Picasso Documentation", 130 | "Maximilian Thomas Strauss", 131 | "manual", 132 | ), 133 | ] 134 | 135 | 136 | # -- Options for manual page output ------------------------------------------ 137 | 138 | # One entry per manual page. List of tuples 139 | # (source start file, name, description, authors, manual section). 140 | man_pages = [(master_doc, "picasso", "Picasso Documentation", [author], 1)] 141 | 142 | 143 | # -- Options for Texinfo output ---------------------------------------------- 144 | 145 | # Grouping the document tree into Texinfo files. List of tuples 146 | # (source start file, target name, title, author, 147 | # dir menu entry, description, category) 148 | texinfo_documents = [ 149 | ( 150 | master_doc, 151 | "Picasso", 152 | "Picasso Documentation", 153 | author, 154 | "Picasso", 155 | "One line description of project.", 156 | "Miscellaneous", 157 | ), 158 | ] 159 | 160 | 161 | # -- Options for Epub output ------------------------------------------------- 162 | 163 | # Bibliographic Dublin Core info. 164 | epub_title = project 165 | 166 | # The unique identifier of the text. This can be a ISBN number 167 | # or the project homepage. 168 | # 169 | # epub_identifier = '' 170 | 171 | # A unique identification for the text. 172 | # 173 | # epub_uid = '' 174 | 175 | # A list of files that should not be packed into the epub file. 176 | epub_exclude_files = ["search.html"] 177 | -------------------------------------------------------------------------------- /docs/design.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jungmannlab/picasso/7ada94433f6b189a929008e14d42027a6da8ced3/docs/design.png -------------------------------------------------------------------------------- /docs/design.rst: -------------------------------------------------------------------------------- 1 | design 2 | ====== 3 | 4 | .. image:: ../docs/design.png 5 | :scale: 50 % 6 | :alt: UML Design 7 | 8 | Design rectangular DNA origami 9 | ------------------------------ 10 | 11 | - Start the design module. A canvas with hexagons, corresponding to the flat origami sheet will appear. 12 | - Design a pattern of DNA-PAINT binding sites by clicking on the hexagons. 13 | - Select a color by clicking on the color palette on the right side. 14 | - Each color corresponds to a different extension that can be defined later. 15 | - The default state of a hexagon (gray color) indicates that this staple will not be extended. Click on the ``Clear``-Button to reset all hexagons. 16 | - Some hexagons are marked with a ``V`` after coloring. This indicates that this staple, in contrast to all the others is pointing downwards at its 3'-end 17 | - Click on “Extensions” to define the sequence for each extension. 18 | - Use ``Get plates`` to get an excel sheet with all needed sequences in a plate format. 19 | - Use ``Pipetting scheme`` and select the folder with your plate list to generate a pipetting scheme. 20 | - Use ``Folding scheme`` to get a table for pipetting folding mixes 21 | - A design can be saved and loaded using the ``Save`` and ``Load``-Buttons. 22 | - A saved design can also be loaded into the ``Picasso: Simulate`` module. 23 | -------------------------------------------------------------------------------- /docs/faq.rst: -------------------------------------------------------------------------------- 1 | FAQ 2 | === 3 | 4 | Localize 5 | -------- 6 | 7 | What doest MLE / LQ stand for? 8 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 9 | - MLE, integrated Gaussian (based on `Smith et al., 2014 `_.) 10 | - LQ, Gaussian (least squares) 11 | 12 | 13 | Picasso freezes during the localization step 14 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 15 | This was a bug that could occur in the old picasso versions and should be fixed with version 0.2.4. 16 | 17 | If it is always at the same localization: 18 | 19 | - Try fitting with the LQ method; it tends to be more robust 20 | - Try increasing the gradient 21 | - Make sure to set the correct camera parameters (Baseline etc.) 22 | -------------------------------------------------------------------------------- /docs/files.rst: -------------------------------------------------------------------------------- 1 | filetypes 2 | ========= 3 | 4 | This section describes the different file format and name conventions used in Picasso. 5 | 6 | Movie Files 7 | ----------- 8 | 9 | Picasso accepts three types of raw movie files: TIFF (preferably from μManager), raw binary data (file extension “.raw”) and the Nikon format .nd2. 10 | 11 | When loading raw binary files, the user will be prompted for movie metadata such as the number of frames, number of pixels, etc. Alternatively, this metadata can be supplied by an accompanying metadata file with the same filename as the raw binary file, but with the extension .yaml. See ``YAML Metadata Files`` for more details. 12 | 13 | HDF5 Files 14 | ---------- 15 | 16 | HDF5 is a generic and efficient binary file format for storing data. In Picasso, HDF5 files are used for storing tabular data of localization properties with the file extension .hdf5. Furthermore, Picasso saves the statistical properties of groups of localizations in an HDF5 file. 17 | 18 | Generally, several datasets can be stored within an HDF5 file. These datasets are accessible by specifying a path within the HDF5 file, similar to a path of an operating system. When saving localizations, Picasso stores tabular data under the path ``/locs``. When saving statistical properties of groups of localizations, Picasso saves the table under the path ``/groups``. 19 | 20 | 21 | Importing HDF5 files in Pandas, MATLAB and Origin 22 | ------------------------------------------------- 23 | 24 | In Pandas, use ``pandas.read_hdf(key='locs')`` or ``pandas.read_hdf(keys='group')``. 25 | 26 | In MATLAB, execute the command ``locs = h5read(filename, dataset)``. Replace dataset with ``/locs`` for localization files and with ``/groups`` for pick property files. 27 | 28 | In Origin, select ``File > Import > HDF5`` or drag and drop the file into the main window. 29 | 30 | Picasso uses ``h5py``. To load localizations, Picasso uses the function ``load_locs(filename)``` located in the ``io.py`` package of Picasso. 31 | 32 | Localization HDF5 Files 33 | ----------------------- 34 | 35 | Localization HDF5 files must always be accompanied by a YAML metadata file with the same filename, but with the extension .yaml. See ``YAML Metadata File`` for more details. The localization table is stored as a dataset of the HDF5 file in the path ``/locs``. This table can be visualized by opening the HDF5 file with ``Picasso: Filter``. The localization table can have an unlimited number of columns. Table 1 describes the meaning of Picasso’s main column names. 36 | 37 | .. csv-table:: Table 1: Name, description and data type for the main columns used in Picasso. 38 | :file: table01.csv 39 | :widths: 20, 20, 20 40 | :header-rows: 1 41 | 42 | 43 | HDF5 Pick Property Files 44 | ------------------------ 45 | 46 | When selecting ``File > Save pick properties`` in ``Picasso: Render``, the properties of picked regions are stored in an HDF5 file. Within the HDF5 file, the data table is stored in the path ``/groups``. 47 | Each row in the “groups” table corresponds to one picked region. For each localization property (see Table 1), two columns are generated in the ``groups`` table: the mean and standard deviation of the respective column over the localizations in a pick region. For example, if the localization table contains a column ``len``, the “groups” table will contain a column ``len_mean`` and ``len_std``. 48 | Furthermore, the following columns are included: ``group`` (the group identifier), ``n_events`` (the number of localizations in the region) and ``n_units`` (the number of units from a qPAINT measurement). 49 | 50 | YAML Metadata Files 51 | ------------------- 52 | 53 | YAML files are document-oriented text files that can be opened and changed with any text editor. In Picasso, YAML files are used to store metadata of movie or localization files. 54 | Each localization HDF5 file must always be accompanied with a YAML file of the same filename, except for the extension, which is ``.yaml``. **Deleting this YAML metadata file will result in failure of the Picasso software!** 55 | 56 | Raw binary files (i.e., with extension ``.raw``) may be accompanied by a YAML metadata file to store data about the movie dimensions, etc. While the metadata file, in this case, is not required, it reduces the effort of typing in this metadata each time the movie is loaded with ``Picasso: Localize``. To generate such a YAML metadata file, load the raw movie into ``Picasso: Localize``, then enter all required information in the appearing dialog. Check the checkbox ``Save info to yaml file`` and click ok. The movie will be loaded and the metadata saved in a YAML file. This file will be detected the next time this raw movie is loaded, and the metadata does not need to be entered again. -------------------------------------------------------------------------------- /docs/filter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jungmannlab/picasso/7ada94433f6b189a929008e14d42027a6da8ced3/docs/filter.png -------------------------------------------------------------------------------- /docs/filter.rst: -------------------------------------------------------------------------------- 1 | filter 2 | ======= 3 | 4 | .. image:: ../docs/filter.png 5 | :scale: 50 % 6 | :alt: UML Design 7 | 8 | Filtering of localizations 9 | -------------------------- 10 | Open a localization HDF5 file in ``Picasso: Filter`` by dragging it into the main window or by selecting ``File`` > ``Open``. The displayed table shows the properties of each localization in rows. Each column represents one property (e.g., coordinates, number of photons); see the filetypes section for details. 11 | 12 | To display a histogram from values of one property, select the respective column in the header and select ``Plot`` > 'Histogram' (Ctrl + h). 2D histograms can be displayed by selecting two columns (press Ctrl to select multiple columns) and then selecting ``Plot`` > ``2D Histogram`` (Ctrl + d). 13 | 14 | Left-click and hold the mouse button down to drag a selection area in a 1D or 2D histogram. The selected area will be shaded in green. Each localization event with histogram properties outside the selected area is immediately removed from the localization list. 15 | 16 | In Picasso 0.5.0, an alternative approach was introduced: In the menu bar, click ``Filter`` > ``Filter``. A dialog is displayed where the user can numerically filter values for any of the columns. Click the ``Filter`` button in the dialog to remove localizations which do not fit in the input parameters. 17 | 18 | Save the filtered localization table by selecting ``File`` > ``Save``. -------------------------------------------------------------------------------- /docs/index.rst: -------------------------------------------------------------------------------- 1 | .. Picasso documentation master file, created by 2 | sphinx-quickstart on Tue Oct 16 13:38:24 2018. 3 | You can adapt this file completely to your liking, but it should at least 4 | contain the root `toctree` directive. 5 | 6 | Welcome to Picasso's documentation! 7 | =================================== 8 | 9 | This documentation is based on the `Nature Protocols publication `__. Its aim is to cover all the recent updates. 10 | 11 | .. toctree:: 12 | :maxdepth: 2 13 | :caption: Contents: 14 | 15 | readme 16 | design 17 | simulate 18 | server 19 | localize 20 | filter 21 | render 22 | average 23 | spinna 24 | files 25 | cmd 26 | postprocessing 27 | nanotron 28 | plugins 29 | faq 30 | 31 | Indices and tables 32 | ================== 33 | 34 | * :ref:`genindex` 35 | * :ref:`modindex` 36 | * :ref:`search` 37 | -------------------------------------------------------------------------------- /docs/localize.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jungmannlab/picasso/7ada94433f6b189a929008e14d42027a6da8ced3/docs/localize.png -------------------------------------------------------------------------------- /docs/localize.rst: -------------------------------------------------------------------------------- 1 | localize 2 | ======== 3 | 4 | .. image:: ../docs/localize.png 5 | :scale: 50 % 6 | :alt: UML Localize 7 | 8 | Localize allows performing super-resolution reconstruction of image stacks. For spot detection, a gradient-based approach is used. For Fitting, the following algorithms are implemented: 9 | 10 | - MLE, integrated Gaussian (based on `Smith et al., 2014 `_.) 11 | - LQ, Gaussian (least squares) 12 | - Average of ROI (finds summed intensity of spots) 13 | 14 | **Please note:** Picasso Localize supports five file formats: ``.ome.tif``, ``NDTiffStack`` with extension ``.tif``, ``.raw``, ``.ims`` and ``.nd2``. If your file has the extension ``.tiff`` or ``.ome.tiff``, it cannot be read. Usually it is enough to change the extension to ``.ome.tif``, i.e., remove the last letter. 15 | 16 | Identification and fitting of single-molecule spots 17 | --------------------------------------------------- 18 | 19 | 1. In ``Picasso: Localize``, open a movie file by dragging the file into the window or by selecting ``File`` > ``Open movie``. If the movie is split into multiple μManager .tif files, open only the first file. Picasso will automatically detect the remaining files according to their file names. When opening a .raw file, a dialog will appear for file specifications. When opening an IMS file it should be displayed immediately in the localize window. When opening an IMS file with multiple channels, a dialog window will appear allowing you to select the channel that should be loaded. You can navigate through the file using the arrow keys on your keyboard. The current frame is displayed in the lower right corner. 20 | 2. Adjust the image contrast (select ``View`` > ``Contrast``) so that the single-molecule spots are clearly visible. 21 | 3. To adjust spot identification and fit parameters, open the ``Parameters`` dialog (select ``Analyze`` > ``Parameters``). 22 | 4. In the ``Identification`` group, set the ``Box side length`` to the rounded integer value of 6 × σ + 1, where σ is the standard deviation of the PSF. In an optimized microscope setup, σ is one pixel, and the respective ``Box side length`` should be set to 7. The value of ``Min. net gradient`` specifies a minimum threshold above which spots should be considered for fitting. The net gradient value of a spot is roughly proportional to its intensity, independent of its local background. By checking ``Preview``, the spots identified with the current settings will be marked in the displayed frame. Adjust ``Min. net gradient`` to a value at which only spots are detected (no background). 23 | 5. (Optional) The ``Identification`` group contains an extra box to input the region of interest (ROI) that is to be considered during identification (units in camera pixels). Alternatively, the ROI can be selected with clicking on the display with the left mouse button and dragging the displayed rectangle. 24 | 6. In the ``Photon conversion`` group, adjust ``EM Gain``, ``Baseline``, ``Sensitivity`` and ``Quantum Efficiency`` according to your camera specifications and the experimental conditions. Set ``EM Gain`` to 1 for conventional output amplification. ``Baseline`` is the average dark camera count. ``Sensitivity`` is the conversion factor (electrons per analog-to-digital (A/D) count). ``Quantum Efficiency`` is not used since version 0.6.0 and is kept for backward compatibility only. These parameters are critical to converting camera counts to photons correctly. The quality of the upcoming maximum likelihood fit strongly depends on a Poisson photon noise model, and thus on the absolute photon count. For simulated data, generated with ``Picasso: Simulate``, set the parameters as follows: ``EM Gain`` = 1, ``Baseline`` = 0, ``Sensitivity`` = 1. 25 | 7. From the menu bar, select ``Analyze`` > ``Localize (Identify & Fit)`` to start spot identification and fitting in all movie frames. The status of this computation is displayed in the window's status bar. After completion, the fit results will be saved in a new file in the same folder as the movie, in which the filename is the base name of the movie file with the extension ``_locs.hdf5``. Furthermore, information about the movie and analysis procedure will be saved in an accompanying file with the extension ``_locs.yaml``; this file can be inspected using a text editor. 26 | 27 | Camera Config 28 | ------------- 29 | 30 | Picasso can remember default cameras and will use saved camera parameters. In order to use camera configs, create a file named ``config.yaml`` in the picasso folder. To start with a template, modify ``config_template.yaml`` that can be found in the folder per default. Picasso will compare the entries with Micro-Manager-Metadata and match the sensitivity values. If no matching entries can be found (e.g., if the file was not created with Micro-Manager) the config file will still be used to create a dropdown menu to select the different categories. The camera config can also be used to define a default camera that will always be used. Indentions are used for definitions. 31 | 32 | Example: Default Camera 33 | ~~~~~~~~~~~~~~~~~~~~~~~ 34 | 35 | :: 36 | 37 | Cameras: 38 | Camera1: 39 | Baseline: 100 40 | Sensitivity: 0.5 41 | Quantum Efficiency: 1.0 42 | 43 | If there is only one camera entry, picasso will create a dropdown menu that has always selected this camera. 44 | 45 | Gain 46 | ^^^^ 47 | If the string ``Gain Property Name`` can be found in the config, picasso will search for a value for this key in the Micro-Manager metadata and match if found. 48 | 49 | Sensitivity 50 | ^^^^^^^^^^^ 51 | 52 | If the string ``Sensitivity Categories`` can be found in the config, picasso will create a dropdown menu for each entry, and if the property can be located in the Micro-Manager Metadata, it will be automatically set. 53 | 54 | :: 55 | 56 | Cameras: 57 | Camera1: 58 | Baseline: 100 59 | Quantum Efficiency: 60 | 525: 0.5 61 | Sensitivity Categories: 62 | - PixelReadoutRate 63 | - Sensitivity/DynamicRange 64 | Sensitivity: 65 | 540 MHz - fastest readout: 66 | 12-bit (high well capacity): 7.18 67 | 12-bit (low noise): 0.29 68 | 16-bit (low noise & high well capacity): 0.46 69 | 200 MHz - lowest noise: 70 | 12-bit (high well capacity): 7.0 71 | 12-bit (low noise): 0.26 72 | 16-bit (low noise & high well capacity): 0.45 73 | 74 | Here, two Sensitivity Categories are given ``PixelReadoutRate`` and ``Sensitivity/DynamicRange``. In the upper dropdown menu, one now will be able to choose from ``540 MHz - fastest readout`` and 75 | ``200 MHz - lowest noise``. Within 540 MHz it will be ``12-bit (high well capacity): 7.18``, ``12-bit (low noise): 0.29`` and ``16-bit (low noise & high well capacity): 0.46``. Accordingly for the 200 MHz entry. The dropdown menus can be further nested, e.g., when considering Gain modes: 76 | 77 | :: 78 | 79 | Sensitivity: 80 | Electron Multiplying: 81 | 17.000 MHz: 82 | Gain 1: 15.9 83 | Gain 2: 9.34 84 | Gain 3: 5.32 85 | 86 | Quantum Efficiency 87 | ^^^^^^^^^^^^^^^^^^ 88 | 89 | This feature is not used since Picasso 0.6.0. It is kept for backward compatibility only. 90 | 91 | Several Cameras 92 | ^^^^^^^^^^^^^^^ 93 | 94 | :: 95 | 96 | Cameras: 97 | Camera1: 98 | Camera2: 99 | Camera3: 100 | 101 | Once there are several cameras present, Picasso will select the camera who's name matches the Micro-Manager Metadata. If no camera is found, the first one is automatically selected. 102 | 103 | 3D-Calibration 104 | -------------- 105 | 106 | Theory 107 | ~~~~~~ 108 | 109 | 3D Calibration is performed by an adapted version of `Huang et al., 2008 `_. 110 | 111 | 112 | Calibrating z 113 | ~~~~~~~~~~~~~ 114 | 115 | After entering the step size, picasso will calculate the mean and the variance for sigma_x and sigma_y for each z position. Localizations that are not within one standard deviation are discarded. A six-degree polynomial is fitted to the mean values of x and y. 116 | 117 | - mean_sx = cx[6]z0 + cx[5]z1 .. + cx[0]z6 118 | - mean_sy = cy[6]z0 + cy[5]z1 .. + cy[0]z6 119 | 120 | The calibration coefficients are stored in the YAML file and contain the parameters of cx and cy. The first entry being c[0], the last being c[6]. 121 | 122 | Fitting z 123 | ~~~~~~~~~ 124 | 125 | For each localization, sigma_x and sigma_y is determined. Similar to the Science paper, the following equation is used to minimize the Distance D: ``D = (sx0.5 - wx0.5)^2 + (sy0.5 - wy0.5)^2`` with w being ``c[6]z0 + 126 | c[5]z1 .. + c[0]z6``. -------------------------------------------------------------------------------- /docs/main_render.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jungmannlab/picasso/7ada94433f6b189a929008e14d42027a6da8ced3/docs/main_render.png -------------------------------------------------------------------------------- /docs/make.bat: -------------------------------------------------------------------------------- 1 | @ECHO OFF 2 | 3 | pushd %~dp0 4 | 5 | REM Command file for Sphinx documentation 6 | 7 | if "%SPHINXBUILD%" == "" ( 8 | set SPHINXBUILD=sphinx-build 9 | ) 10 | set SOURCEDIR=. 11 | set BUILDDIR=_build 12 | 13 | if "%1" == "" goto help 14 | 15 | %SPHINXBUILD% >NUL 2>NUL 16 | if errorlevel 9009 ( 17 | echo. 18 | echo.The 'sphinx-build' command was not found. Make sure you have Sphinx 19 | echo.installed, then set the SPHINXBUILD environment variable to point 20 | echo.to the full path of the 'sphinx-build' executable. Alternatively you 21 | echo.may add the Sphinx directory to PATH. 22 | echo. 23 | echo.If you don't have Sphinx installed, grab it from 24 | echo.http://sphinx-doc.org/ 25 | exit /b 1 26 | ) 27 | 28 | %SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% 29 | goto end 30 | 31 | :help 32 | %SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% 33 | 34 | :end 35 | popd 36 | -------------------------------------------------------------------------------- /docs/nanotron.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jungmannlab/picasso/7ada94433f6b189a929008e14d42027a6da8ced3/docs/nanotron.png -------------------------------------------------------------------------------- /docs/nanotron.rst: -------------------------------------------------------------------------------- 1 | ======== 2 | nanoTRON 3 | ======== 4 | The training module uses `scikit-learn `_ 5 | 's multi-layer perceptron (MLP) to train an artificial neural network (ANN). 6 | If you use nanoTRON, please cite the publication: 7 | 8 | - A Auer, M T Strauss, S Strauss, and R Jungmann. ”nanoTRON: a Picasso module for MLP-based classification of super-resolution data”. Bioinformatics, 2020. doi: `10.1093/bioinformatics/btaa154 `_ 9 | 10 | Detailed recommendation for the use of nanoTRON can be found in the supplementary information, `here `_. 11 | 12 | .. image:: ../docs/nanotron.png 13 | :scale: 50 % 14 | :alt: UML Design 15 | 16 | nanoTRON Train 17 | -------------- 18 | Train a MLP model for nanopattern prediction using nanoTRON. 19 | 20 | 1. In ``Picasso: nanoTRON``, select ``Tools`` > ``Train Model`` to open the training user interface. 21 | 2. Set the number of different classes of the model via ``Number of Classes`` and press ``Generate Data Set``. 22 | 3. Load all the training files via the various buttons ``Load File``. Greyed out buttons indicate that the data set slot is loaded. 23 | 4. Name every data set (class) with a unique name. 24 | 5. Set up the image parameters in the box ``Image Parameter``. Set the oversampling factor via ``Oversampling``. This factor determines the sub-pixel resolution of the training images. We recommend lower resolution as the data would provide for better generalization. Augment the training data sets via the check button ``Expand Training Set``. Here every data set point is rotated eleven times. Exemplary images training data images can be exported via ``Export Image Subset``. 25 | 6. If the data is loaded and the image parameters are set, press ``Prepare Data`` to convert the localization (molecule) tables into images. 26 | 7. Set up the MLP in the box ``Perceptron`` Set the number of hidden layers via ``Hidden Layers``. The number of nodes in every layer can be set via ``Nodes``. Choose the type of training algorithm via the dropdown box ``Solver``. We recommend using ``adam``. Choose the activation function of the layer via the dropdown box ``Activation``. Note, the activation function can only be set for the whole network. 27 | 8. Set up the training in the box ``Training``. Set the maximum number of iterations (epochs) via the box ``Iterations``. Set the learning rate via ``Learning Rate`` (only necessary if SGD solver is chosen). 28 | 9. To start the training, press ``Train Model``. Depending on the CPU and the size of the training data, this can take up to a few hours. 29 | 10. When the training is finished, the learning curve and the confusion matrix can be plotted via ``Show Learning History``. 30 | 11. A summary of the achieved train and test accuracies is given at the bottom of the ``Train Model`` window. 31 | 12. Save the model for later use via ``Save Model``. 32 | 33 | nanoTRON Predict 34 | ---------------- 35 | Use a trained nanoTRON model to classify nanopatterns on new data. 36 | 37 | 1. Load the model via ``Tools`` > ``Train Model``. The different classes should now be listed on the right side. 38 | 2. Drag and drop the Picasso localization table file (HDF5) that should be used for prediction into the large grey box. If the file was loaded correctly, the box displays the image. 39 | 3. Start the classification via the button ``Predict``. 40 | 4. Choose the classes that should be exported in the box ``Export Structures``. By default, each class is exported. 41 | 5. Set the export parameters in the box ``Export``. The distribution of the prediction probability can be plotted via the button ``Show Probabilities``. Optional, set a probability filter via the check button ``Filter Probabilities``. Optional, enable the additional export of the pick regions via the check button ``Export Pick Regions``. Choose if the new localization files, segmented by the classified nanopatterns, should be regrouped via the check button ``Regroup Export Files``. Note, the group id in every exported file start with 0 then. Identification of picks in the original file will be lost. 42 | -------------------------------------------------------------------------------- /docs/plugins.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jungmannlab/picasso/7ada94433f6b189a929008e14d42027a6da8ced3/docs/plugins.png -------------------------------------------------------------------------------- /docs/plugins.rst: -------------------------------------------------------------------------------- 1 | ======= 2 | Plugins 3 | ======= 4 | 5 | Usage 6 | ----- 7 | Starting in version 0.5.0, Picasso supports plugins. Please find the instructions on how to add them to your Picasso below. 8 | 9 | Please keep in mind that the ``__init__.py`` file in the ``picasso/picasso/gui/plugins`` folder must not be modified or deleted. 10 | 11 | GitHub 12 | ~~~~~~ 13 | If you cloned the GitHub repository, you can add plugins by following these steps: 14 | - Find the directory where you cloned the GitHub repository with Picasso. 15 | - Go to ``picasso/picasso/gui/plugins``. 16 | - Copy the plugin(s) to this folder. 17 | 18 | PyPI 19 | ~~~~ 20 | If you installed Picasso using ``pip install picassosr``, you can add plugins by following these steps: 21 | - To find the location of the environment where ``picassosr`` is installed, type ``conda env list``. 22 | - If your environment can be found under ``YOUR_ENVIRONMENT``, go to ``YOUR_ENVIRONMENT/Lib/site-packages/picasso/gui/plugins``. 23 | - Copy the plugin(s) to this folder. 24 | 25 | One click installer 26 | ~~~~~~~~~~~~~~~~~~~ 27 | **NOTE**: After deinstalling Picasso, ``Program Files/Picasso`` folder needs to be deleted manually, as the uninstaller currently does not remove the plugins automatically. 28 | 29 | - Find the location where you installed Picasso. By default, it is ``C:/Program Files/Picasso``. 30 | - Go to the following subfolder in the `Picasso` directory: ``picasso/gui/plugins``. 31 | - Copy the plugin(s) to this folder. 32 | 33 | .. **NOTE**: Plugins added in this distribution will not be able to use packages that are not installed automatically (from the file ``requirements.txt``). 34 | 35 | For developers 36 | -------------- 37 | To create a plugin, you can use the template provided in ``picasso/plugin_template.py``, see below. 38 | 39 | .. image:: ../docs/plugins.png 40 | :scale: 70 % 41 | :alt: Plugins 42 | 43 | As an example, please see any of the plugins in the `GitHub repo `_. -------------------------------------------------------------------------------- /docs/postprocessing.rst: -------------------------------------------------------------------------------- 1 | Postprocessing 2 | ============== 3 | 4 | Jupyter Notebooks 5 | ----------------- 6 | For additional postprocessing steps, one might want to use different libraries without having to install the picasso package. For this check out the samples folder. Here you can find sample jupyter notebooks that show how the Picasso package can be used. 7 | 8 | SampleNotebook 9 | ~~~~~~~~~~~~~~ 10 | This notebook shows some basic interaction with the .hdf5 files using the pandas library. 11 | 12 | SampleNotebook1 13 | ~~~~~~~~~~~~~~~ 14 | This notebook shows some basic interaction with the picasso library, e.g. how to directly call functions from a Jupyter Notebook. 15 | 16 | SampleNotebook2 17 | ~~~~~~~~~~~~~~~ 18 | This notebook shows how to perform HDBSCAN clustering with picasso. 19 | 20 | 21 | -------------------------------------------------------------------------------- /docs/readme.rst: -------------------------------------------------------------------------------- 1 | .. include:: ../README.rst -------------------------------------------------------------------------------- /docs/render.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jungmannlab/picasso/7ada94433f6b189a929008e14d42027a6da8ced3/docs/render.png -------------------------------------------------------------------------------- /docs/render_resi.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jungmannlab/picasso/7ada94433f6b189a929008e14d42027a6da8ced3/docs/render_resi.png -------------------------------------------------------------------------------- /docs/requirements.txt: -------------------------------------------------------------------------------- 1 | sphinx==5.3.0 2 | sphinx_rtd_theme==1.1.1 3 | readthedocs-sphinx-search==0.1.1 -------------------------------------------------------------------------------- /docs/server.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jungmannlab/picasso/7ada94433f6b189a929008e14d42027a6da8ced3/docs/server.png -------------------------------------------------------------------------------- /docs/server.rst: -------------------------------------------------------------------------------- 1 | server 2 | ====== 3 | 4 | .. image:: ../docs/server_main.png 5 | :scale: 10 % 6 | :alt: Main 7 | 8 | 9 | Functionality 10 | ------------- 11 | Picasso Server allows to continuously track performance metrics of your super-resolution experiments. 12 | It does so by recording the metadata, derived summary statistics, and results of post-processing algorithms (such as the NeNA value) to a local SQL database. 13 | The database can be interactively explored via a browser application. 14 | 15 | You can also set up a ``Watcher`` that allows to continuously process new files in a folder. 16 | 17 | 18 | Database 19 | -------- 20 | The local SQL database will be stored in the ``.picasso`` folder in your home directory. The path is also displayed in the `Getting started`-tab in the `Status` page. To directly access the database 21 | the tool `DB Browser for SQLite `_ is recommended. 22 | 23 | Localize 24 | -------- 25 | The integration within ``Localize`` is by pressing the ``Estimate``- button in the ``Sample Quality`` field in ``Parameters``. 26 | The button can be pressed once the image stack has been localized. It calculates Localizations per Frame, NeNA, Drift and bright time based on a subset of the data (i.e. max. 1 Mio localizations). 27 | The estimate and additional summary statistics will then be stored in the local database. 28 | 29 | .. image:: ../docs/server_localize.png 30 | :scale: 20 % 31 | :alt: Localize 32 | 33 | Server 34 | ------ 35 | Server is a tool to interactively explore the database and to enable continuous processing workflows. 36 | When launching server, i.e. clicking on the shortcut or executing the Python command ``picasso server``, the command line will start and show you the local IP address on where the server is running. 37 | When launching picasso server, it should open your default browser automatically and redirect to the Picasso Server page. 38 | You can also use this IP to e.g., connect to ``Picasso Server`` from within a network. For this, take the ``Network URL`` that is displayed in the command line and access it via browser. 39 | 40 | .. image:: ../docs/server_cmd.png 41 | :scale: 40 % 42 | :alt: CMD 43 | 44 | In case you close the website tab or the browser, ``Picasso Server`` will run in the background until the command line window is closed. 45 | You can go back to the website by re-entering the URL. 46 | 47 | Status 48 | ~~~~~~ 49 | Displays the current database status and documentation. 50 | The page also has a menu called ``Manually add file to database.``. Here, you can add folders with already processed files to the database. 51 | 52 | History 53 | ~~~~~~~ 54 | 55 | .. image:: ../docs/server_history.png 56 | :scale: 10 % 57 | :alt: History 58 | 59 | Explore summary statistics of processed files. 60 | It is possible to filter by filename and group. 61 | The following modes of display exist: 62 | 63 | - Table: A table of the results. Each field contains a barplot showing the value relative to the column's maximum. 64 | - Scatter: Scatterplot of results. This also allows to draw trendlines 65 | - Boxplot: Daily Boxplot 66 | 67 | Compare 68 | ~~~~~~~ 69 | Compare two files against each other. 70 | 71 | **The database will store the file path when it is localized. If the file is moved, it will not be selectable.** 72 | 73 | .. image:: ../docs/server_compare.png 74 | :scale: 10 % 75 | :alt: Localize 76 | 77 | To compare experiments, select one or multiple experiments from the dropdown menu. 78 | If multiple hdf files are present, you can select hdf files that belong to the same file family. 79 | 80 | **Comparing files will load the entire hdf file and could mean that one is comparing millions of localizations. 81 | Creating the plots might, therefore, not be instantaneous.** 82 | 83 | - Localizations per frame: this will plot the localization per frame. This is useful to inspect the performance of an experiment over time. 84 | - Histogram: creates a histogram for the population. This is useful e.g., for comparing background signals. 85 | 86 | .. image:: ../docs/server_compare_histogram.png 87 | :scale: 10 % 88 | :alt: Histogram 89 | 90 | Watcher 91 | ~~~~~~~ 92 | - Set up a file watcher to process files in a folder with pre-defined settings automatically. 93 | - All new files and raw files that aren't yet in the database will be processed. 94 | - You can define different parameter groups so that a file will be processed with different settings. 95 | - You can also chain custom commands to the watcher. 96 | - The watcher will check for the following filetypes: ('.raw', '.ome.tif', '.ims') 97 | - The watcher will be able to process consecutive files created with MicroManager (e.g. `Pos0`, `Pos0_1`, `Pos0_2`) if they contain `MMStack_Pos0` in the filename 98 | 99 | Logging 100 | """"""" 101 | Each watcher will write their statust to a logfile. The path is visible when setting up the logfile and when checking the currently running watchers. To view the log, select the logfile and expand the `Log`-field. 102 | 103 | Multiple Parameter Groups 104 | """"""""""""""""""""""""" 105 | .. image:: ../docs/server_watcher_pg.png 106 | :scale: 10 % 107 | :alt: Histogram 108 | 109 | With multiple parameter groups a file will be processed with different settings. To make multiple parameter groups available, set the `Number of Parameter Groups` to a value larger than 1. 110 | The file ending will be different according to the parameter group used. E.g. if you have two parameter groups, file `testfile.raw` will be processed as `testfile_pg_1_locs.hdf5` and `testfile_pg_2_locs.hdf5`. 111 | 112 | 113 | Custom commands 114 | """"""""""""""" 115 | You can use the "Custom command" to execute a custom script after a file was processed. 116 | Consider the following example for a script that you want to execute named test.py::: 117 | 118 | import sys 119 | from slack_sdk.webhook import WebhookClient 120 | url = "REPLACE_WITH_SLACKHOOK" 121 | webhook = WebhookClient(url) 122 | 123 | _, filename = sys.argv[0], sys.argv[1] 124 | 125 | response = webhook.send(text=f"Processed file {filename}!") 126 | 127 | This script would send a message to a slack webhook with the first argument as filename. To call this from the watcher, we need to point to a python environment. 128 | E.g. for a conda installation at ``C:\ProgramData\Miniconda3\python.exe`` and the script being located at ``C:\Users\Maximilian\Desktop\test.py`` the complete command to enter in Picasso server would be: 129 | ``C:\ProgramData\Miniconda3\python.exe C:\Users\Maximilian\Desktop\test.py $FILENAME``. 130 | 131 | When having an existing Picasso one-click installation, Picasso can directly be called via the command-line. Some example commands would then be: 132 | 133 | * ``picasso undrift $FILENAME`` for drift correction 134 | * ``picasso link $FILENAME`` for linking localizations 135 | * ``picasso dbscan $FILENAME 0.1 2`` for performing DBSCAN cluster analysis with 0.1 / 2 136 | 137 | 138 | Preview 139 | ~~~~~~~ 140 | Preview will render the super-resolution data in the browser. 141 | 142 | .. image:: ../docs/server_preview.png 143 | :scale: 10 % 144 | :alt: Histogram 145 | 146 | **The database will store the file path when it is localized. If the file is moved, it will not be selectable.** 147 | 148 | 149 | Docker 150 | ~~~~~~ 151 | If you want to install picasso server in a headless linux or mac system, the provided dockerfile might be useful for installation. 152 | * Build the docker image from the dockerfile (clone the github repository): ``docker build -t picasso .`` 153 | * Run the docker image (interactive mode, port forwarding and with a mounted drive): ``docker run -it -p 8501:8501 --volume "C:/Users/Maximilian/Desktop/data:/home/picasso/data" picasso`` Note that you need to replace the respective paths. 154 | * Launch picasso server in the docker image: ``python3 -m picasso server`` 155 | -------------------------------------------------------------------------------- /docs/server_cmd.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jungmannlab/picasso/7ada94433f6b189a929008e14d42027a6da8ced3/docs/server_cmd.png -------------------------------------------------------------------------------- /docs/server_compare.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jungmannlab/picasso/7ada94433f6b189a929008e14d42027a6da8ced3/docs/server_compare.png -------------------------------------------------------------------------------- /docs/server_compare_histogram.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jungmannlab/picasso/7ada94433f6b189a929008e14d42027a6da8ced3/docs/server_compare_histogram.png -------------------------------------------------------------------------------- /docs/server_history.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jungmannlab/picasso/7ada94433f6b189a929008e14d42027a6da8ced3/docs/server_history.png -------------------------------------------------------------------------------- /docs/server_localize.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jungmannlab/picasso/7ada94433f6b189a929008e14d42027a6da8ced3/docs/server_localize.png -------------------------------------------------------------------------------- /docs/server_main.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jungmannlab/picasso/7ada94433f6b189a929008e14d42027a6da8ced3/docs/server_main.png -------------------------------------------------------------------------------- /docs/server_preview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jungmannlab/picasso/7ada94433f6b189a929008e14d42027a6da8ced3/docs/server_preview.png -------------------------------------------------------------------------------- /docs/server_watcher_pg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jungmannlab/picasso/7ada94433f6b189a929008e14d42027a6da8ced3/docs/server_watcher_pg.png -------------------------------------------------------------------------------- /docs/simulate.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jungmannlab/picasso/7ada94433f6b189a929008e14d42027a6da8ced3/docs/simulate.png -------------------------------------------------------------------------------- /docs/simulate.rst: -------------------------------------------------------------------------------- 1 | simulate 2 | ======== 3 | 4 | .. image:: ../docs/simulate.png 5 | :scale: 50 % 6 | :alt: UML Simulate interface 7 | 8 | Picasso's simulation module (``Picasso: Simulate``) is a tool for evaluating experimental conditions for DNA-PAINT and generating ground-truth data for test purposes. This allows systematic analysis of how different experimental parameters such as imager concentration, target density or integration time influence the imaging quality and whether the target structure can be resolved with DNA-PAINT. 9 | By default, ``Picasso: Simulate`` starts with preset parameters that are typical for a DNA-PAINT experiment. Thus, meaningful raw DNA-PAINT data can be readily simulated for a given input structure without the need of a super-resolution microscope. The simulation output is a movie file in .raw format, as it would be generated during an in vitro DNA-PAINT experiment on a microscope. 10 | 11 | Simulate DNA-PAINT image acquistions 12 | ------------------------------------ 13 | 14 | 1. Start ``Picasso: Simulate``. 15 | 2. Define the number and type of structures that should be simulated in the group ``Structure``. Predefined grid- and circle-like structures can be readily defined by their number of columns and rows, or their diameter and the number of handles, respectively. Alternatively, a custom structure can be defined in an arbitrary coordinate system. To do so, enter comma-separated coordinates into ``Structure X`` and ``Structure Y``. The unit of length of the respective axes can be changed by setting the spacing in ``Spacing X, Y``. For each coordinate point, an identifier for the docking site sequence needs to be set in ``Exchange labels`` as a comma-separated list. Correctly defined points will be updated live in the ``Structure [nm]`` window. Note that entries with missing x coordinate, y coordinate or exchange label will be disregarded. When a structure has been previously designed with ``Picasso: Design``, it can be imported with ``Import structure from design``. A probability for the presence of a handle can be set with ``Incorporation``. By default, all structures are arranged on a grid with boundaries defined by ``Image size`` in ``Camera parameters`` and the ``Frame`` parameter in the ``Structure`` group. ``Random arrangement`` distributes the structures randomly within that area, whereas ``Random orientation`` rotates the structures randomly. Selecting the button ``Generate positions`` will generate a list of positions with the current settings and update the preview panels. A preview of the arrangement of all structures is shown in ``Positions [Px]``, whereas an individual structure is shown in ``Structure [nm]``. 16 | 3. The group ``PAINT Parameters`` allows adjustment of the duty cycle of the DNA-PAINT imaging system. The mean dark time is calculated by τd = 1/(kon·c). The mean ON time in a DNA-PAINT system is dependent on the DNA duplex properties. For typical 9-bp imager/docking interactions, the ON time is ~500 ms. 17 | 4. In ``Imager Parameters``, fluorophore characteristics such as PSF width and photon budget can be set. Adjusting the ``Power density`` field affects the simulation analogously to changing the laser power in an experiment. 18 | 5. The ``Camera parameters`` group allows the user to set the number of acquisition frames and integration time. The default image size is set to 32 pixels. As the computation time increases considerably with image size, it is recommended to simulate only a subset of the actual camera field of view. 19 | 6. Select ``Simulate data`` to start the simulation. The simulation will begin by calculating the photons for each handle site of every structure and then converting it to a movie that will be saved as a .raw file, ready for subsequent localization. All simulation settings are saved and can be loaded at a later time with ``Load from previous simulation``. 20 | 7. (Optional step for multiplexing) Multiplexed Exchange-PAINT data can be simulated by adjusting the ``Exchange Labels`` setting. For each handle in the custom coordinate system (``Structure X``, ``Structure Y``), an Exchange round can be specified. The different imaging rounds can be visually identified by color in the ``Structure [nm]`` figure. For each round, a new movie file will be generated. By default, the simulation software detects the number of exchange rounds based on the structure definition and will simulate all multiplexing rounds with the same imaging parameters. It is possible to have different imaging parameters for each round, e.g. when using image s with different ON-times. To do so, one can simulate multiplexing rounds individually. In the ``Exchange rounds to be simulated`` field, enter only the rounds that should be simulated with the current set of parameters. Change the set parameters and the multiplexing round and simulate the next data sets. Repeat until all multiplexing rounds are simulated. 21 | 22 | -------------------------------------------------------------------------------- /docs/spinna_mask_generation_tab.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jungmannlab/picasso/7ada94433f6b189a929008e14d42027a6da8ced3/docs/spinna_mask_generation_tab.png -------------------------------------------------------------------------------- /docs/spinna_nnd_plot_settings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jungmannlab/picasso/7ada94433f6b189a929008e14d42027a6da8ced3/docs/spinna_nnd_plot_settings.png -------------------------------------------------------------------------------- /docs/spinna_simulate_tab_after_fit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jungmannlab/picasso/7ada94433f6b189a929008e14d42027a6da8ced3/docs/spinna_simulate_tab_after_fit.png -------------------------------------------------------------------------------- /docs/spinna_simulate_tab_before_load.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jungmannlab/picasso/7ada94433f6b189a929008e14d42027a6da8ced3/docs/spinna_simulate_tab_before_load.png -------------------------------------------------------------------------------- /docs/spinna_structures_tab.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jungmannlab/picasso/7ada94433f6b189a929008e14d42027a6da8ced3/docs/spinna_structures_tab.png -------------------------------------------------------------------------------- /docs/table01.csv: -------------------------------------------------------------------------------- 1 | Column Name,Description,C Data Type 2 | frame ,"The frame in which the localization occurred, starting with zero for the first frame. ",unsigned long 3 | x ,The subpixel x coordinate in camera pixels.,float 4 | y ,The subpixel y coordinate in camera pixels.,float 5 | photons ,"The total number of detected photons from this event, not including background or camera offset.",float 6 | sx ,The Point Spread Function width in camera pixels.,float 7 | sy ,The Point Spread Function height in camera pixels.,float 8 | bg ,"The number of background photons per pixel, not including the camera offset.",float 9 | lpx ,"The localization precision in x direction, in camera pixels, as estimated by the Cramer-Rao Lower Bound of the Maximum Likelihood fit (Mortensen et al., Nat Meth, 2010). ",float 10 | lpy ,"The localization precision in y direction, in camera pixels, as estimated by the Cramer-Rao Lower Bound of the Maximum Likelihood fit (Mortensen et al., Nat Meth, 2010). ",float 11 | net_gradient ,"The net gradient of this spot which is defined by the sum of gradient vector magnitudes within the fitting box, projected to the spot center. ",float 12 | z,(Optional) The z coordinate fitted in 3D in nm. Please note the units are different for x and y coordinates.,float 13 | d_zcalib,"(Optional) The value of the D function used for z fitting with astigmatism, see the supplement to Huang et al. 2008.",float 14 | likelihood ,The log-likelihood of the fit. Only available for MLE fitting.,float 15 | iterations ,The number of iterations of the fit procedure. Only available for MLE fitting.,long 16 | group ,"(Optional) An identifier to assign multiple localizations to groups, for example by picking regions of interest .",long 17 | len ,"(Optional) The length of the event, if localizations from consecutive frames have been linked.",long 18 | n ,"(Optional) The number of localizations in this event, if localizations from consecutive frames have been linked, potentially diverging from the “len” column due to a transient dark time tolerance.",long 19 | photon_rate ,"(Optional) The mean number of photons per frame, if localizations from consecutive frames have been linked. The total number of photons is set in the “photons” column. ",float -------------------------------------------------------------------------------- /main_render.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jungmannlab/picasso/7ada94433f6b189a929008e14d42027a6da8ced3/main_render.png -------------------------------------------------------------------------------- /picasso/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | picasso/__init__.py 3 | ~~~~~~~~~~~~~~~~~~~~ 4 | 5 | :authors: Joerg Schnitzbauer, Maximilian Thomas Strauss, Rafal Kowalewski 2016-2023 6 | :copyright: Copyright (c) 2016-2023 Jungmann Lab, MPI of Biochemistry 7 | """ 8 | import os.path as _ospath 9 | import yaml as _yaml 10 | 11 | __version__ = "0.8.0" 12 | 13 | _this_file = _ospath.abspath(__file__) 14 | _this_dir = _ospath.dirname(_this_file) 15 | try: 16 | with open(_ospath.join(_this_dir, "config.yaml"), "r") as config_file: 17 | CONFIG = _yaml.full_load(config_file) 18 | if CONFIG is None: 19 | CONFIG = {} 20 | except FileNotFoundError: 21 | CONFIG = {} -------------------------------------------------------------------------------- /picasso/__version__.py: -------------------------------------------------------------------------------- 1 | VERSION_NO = "0.8.0" 2 | -------------------------------------------------------------------------------- /picasso/avgroi.py: -------------------------------------------------------------------------------- 1 | """ 2 | picasso.avgroi 3 | ~~~~~~~~~~~~~~~~ 4 | 5 | Return average intensity of Spot 6 | 7 | :author: Maximilian Thomas Strauss, 2016 8 | :copyright: Copyright (c) 2016 Jungmann Lab, MPI of Biochemistry 9 | """ 10 | 11 | from scipy import optimize as _optimize 12 | import numpy as _np 13 | from tqdm import tqdm as _tqdm 14 | import numba as _numba 15 | import multiprocessing as _multiprocessing 16 | from concurrent import futures as _futures 17 | from . import postprocess as _postprocess 18 | 19 | 20 | @_numba.jit(nopython=True, nogil=True) 21 | def _sum(spot, size): 22 | _sum_ = 0.0 23 | for i in range(size): 24 | for j in range(size): 25 | _sum_ += spot[i, j] 26 | 27 | return _sum_ 28 | 29 | 30 | def fit_spot(spot): 31 | size = spot.shape[0] 32 | avg_roi = _sum(spot, size) 33 | # result is [x, y, photons, bg, sx, sy] 34 | result = [0, 0, avg_roi, avg_roi, 1, 1] 35 | return result 36 | 37 | 38 | def fit_spots(spots): 39 | theta = _np.empty((len(spots), 6), dtype=_np.float32) 40 | theta.fill(_np.nan) 41 | for i, spot in enumerate(spots): 42 | theta[i] = fit_spot(spot) 43 | return theta 44 | 45 | 46 | def fit_spots_parallel(spots, asynch=False): 47 | n_workers = min( 48 | 60, max(1, int(0.75 * _multiprocessing.cpu_count())) 49 | ) # Python crashes when using >64 cores 50 | n_spots = len(spots) 51 | n_tasks = 100 * n_workers 52 | spots_per_task = [ 53 | int(n_spots / n_tasks + 1) if _ < n_spots % n_tasks else int(n_spots / n_tasks) 54 | for _ in range(n_tasks) 55 | ] 56 | start_indices = _np.cumsum([0] + spots_per_task[:-1]) 57 | fs = [] 58 | executor = _futures.ProcessPoolExecutor(n_workers) 59 | for i, n_spots_task in zip(start_indices, spots_per_task): 60 | fs.append(executor.submit(fit_spots, spots[i : i + n_spots_task])) 61 | if asynch: 62 | return fs 63 | with _tqdm(total=n_tasks, unit="task") as progress_bar: 64 | for f in _futures.as_completed(fs): 65 | progress_bar.update() 66 | return fits_from_futures(fs) 67 | 68 | 69 | def fits_from_futures(futures): 70 | theta = [_.result() for _ in futures] 71 | return _np.vstack(theta) 72 | 73 | 74 | def locs_from_fits(identifications, theta, box, em): 75 | # box_offset = int(box/2) 76 | x = theta[:, 0] + identifications.x # - box_offset 77 | y = theta[:, 1] + identifications.y # - box_offset 78 | lpx = _postprocess.localization_precision( 79 | theta[:, 2], theta[:, 4], theta[:, 3], em=em 80 | ) 81 | lpy = _postprocess.localization_precision( 82 | theta[:, 2], theta[:, 5], theta[:, 3], em=em 83 | ) 84 | a = _np.maximum(theta[:, 4], theta[:, 5]) 85 | b = _np.minimum(theta[:, 4], theta[:, 5]) 86 | ellipticity = (a - b) / a 87 | if hasattr(identifications, "n_id"): 88 | locs = _np.rec.array( 89 | ( 90 | identifications.frame, 91 | x, 92 | y, 93 | theta[:, 2], 94 | theta[:, 4], 95 | theta[:, 5], 96 | theta[:, 3], 97 | lpx, 98 | lpy, 99 | ellipticity, 100 | identifications.net_gradient, 101 | identifications.n_id, 102 | ), 103 | dtype=[ 104 | ("frame", "u4"), 105 | ("x", "f4"), 106 | ("y", "f4"), 107 | ("photons", "f4"), 108 | ("sx", "f4"), 109 | ("sy", "f4"), 110 | ("bg", "f4"), 111 | ("lpx", "f4"), 112 | ("lpy", "f4"), 113 | ("ellipticity", "f4"), 114 | ("net_gradient", "f4"), 115 | ("n_id", "u4"), 116 | ], 117 | ) 118 | locs.sort(kind="mergesort", order="n_id") 119 | else: 120 | locs = _np.rec.array( 121 | ( 122 | identifications.frame, 123 | x, 124 | y, 125 | theta[:, 2], 126 | theta[:, 4], 127 | theta[:, 5], 128 | theta[:, 3], 129 | lpx, 130 | lpy, 131 | ellipticity, 132 | identifications.net_gradient, 133 | ), 134 | dtype=[ 135 | ("frame", "u4"), 136 | ("x", "f4"), 137 | ("y", "f4"), 138 | ("photons", "f4"), 139 | ("sx", "f4"), 140 | ("sy", "f4"), 141 | ("bg", "f4"), 142 | ("lpx", "f4"), 143 | ("lpy", "f4"), 144 | ("ellipticity", "f4"), 145 | ("net_gradient", "f4"), 146 | ], 147 | ) 148 | locs.sort(kind="mergesort", order="frame") 149 | return locs 150 | -------------------------------------------------------------------------------- /picasso/config_template.yaml: -------------------------------------------------------------------------------- 1 | Cameras: 2 | Andor Zyla 4.2 Plus: 3 | Pixelsize: 130 4 | Baseline: 100 5 | Quantum Efficiency: 6 | 525: 0.8 7 | 595: 0.82 8 | 700: 0.74 9 | Sensitivity Categories: 10 | - PixelReadoutRate 11 | - Sensitivity/DynamicRange 12 | Sensitivity: 13 | 540 MHz - fastest readout: 14 | 12-bit (high well capacity): 7.18 15 | 12-bit (low noise): 0.29 16 | 16-bit (low noise & high well capacity): 0.46 17 | 200 MHz - lowest noise: 18 | 12-bit (high well capacity): 7.0 19 | 12-bit (low noise): 0.26 20 | 16-bit (low noise & high well capacity): 0.45 21 | Channel Device: 22 | # This information is used to automatically set the emission wavelength based on MicroManager metadata 23 | Name: FilterTurret1-Label 24 | Emission Wavelengths: 25 | 1-TIRF 488: 525 26 | 2-TIRF 560: 595 27 | 3-TIRF 640: 700 28 | Andor iXon X-9603: 29 | Baseline: 200 30 | Gain Property Name: Gain 31 | Sensitivity Categories: 32 | - Output_Amplifier 33 | - ReadoutMode 34 | - Pre-Amp-Gain 35 | Sensitivity: 36 | Electron Multiplying: 37 | 17.000 MHz: 38 | Gain 1: 15.9 39 | Gain 2: 9.34 40 | Gain 3: 5.32 41 | 10.000 MHz: 42 | Gain 1: 16.5 43 | Gain 2: 8.4 44 | Gain 3: 5.12 45 | 5.000 MHz: 46 | Gain 1: 18.1 47 | Gain 2: 8.74 48 | Gain 3: 4.63 49 | 1.000 MHz: 50 | Gain 1: 18.3 51 | Gain 2: 8.86 52 | Gain 3: 4.58 53 | Conventional: 54 | 3.000 MHz: 55 | Gain 1: 4.03 56 | Gain 2: 3.14 57 | Gain 3: 1.47 58 | 1.000 MHz: 59 | Gain 1: 4.09 60 | Gain 2: 3.09 61 | Gain 3: 1.47 62 | 0.080 MHz: 63 | Gain 1: 4.04 64 | Gain 2: 3.09 65 | Gain 3: 1.44 66 | Channel Device: 67 | # This information is used to automatically set the emission wavelength based on MicroManager metadata 68 | Name: TIFilterBlock1-Label 69 | Emission Wavelengths: 70 | 1-R640: 700 71 | 2-G561: 595 72 | 3-B489: 525 73 | Quantum Efficiency: 74 | # Emission wavelength 75 | 525: 0.95 76 | 595: 0.96 77 | 700: 0.9 78 | Andor Zyla VSC-01223: 79 | Baseline: 100 80 | Quantum Efficiency: 81 | 525: 0.7 82 | 595: 0.72 83 | 700: 0.64 84 | Sensitivity Categories: 85 | - PixelReadoutRate 86 | - Sensitivity/DynamicRange 87 | Sensitivity: 88 | 540 MHz - fastest readout: 89 | 12-bit (high well capacity): 7.18 90 | 12-bit (low noise): 0.29 91 | 16-bit (low noise & high well capacity): 0.46 92 | 200 MHz - lowest noise: 93 | 12-bit (high well capacity): 7.0 94 | 12-bit (low noise): 0.26 95 | 16-bit (low noise & high well capacity): 0.45 96 | Channel Device: 97 | # This information is used to automatically set the emission wavelength based on MicroManager metadata 98 | Name: TIFilterBlock1-Label 99 | Emission Wavelengths: 100 | 1-R640: 700 101 | 2-G561: 595 102 | 3-B489: 525 103 | HamamatsuHam_DCAM: 104 | Baseline: 100 105 | Quantum Efficiency: 106 | 525: 0.81 107 | 595: 0.83 108 | 700: 0.72 109 | Channel Device: 110 | # This information is used to automatically set the emission wavelength based on MicroManager metadata 111 | Name: TIFilterBlock1-Label 112 | Emission Wavelengths: 113 | 1-R640: 700 114 | 2-G561: 595 115 | 3-B489: 525 116 | Sensitivity: 0.47 117 | Simulation: 118 | Pixelsize: 130 119 | Baseline: 0 120 | Sensitivity: 1.0 121 | Quantum Efficiency: 1.0 -------------------------------------------------------------------------------- /picasso/design.py: -------------------------------------------------------------------------------- 1 | """ 2 | picasso.design 3 | ~~~~~~~~~~~~~~~~ 4 | 5 | Design rectangular rothemund origami (RRO) 6 | 7 | :author: Maximilian Thomas Strauss, 2016-2018 8 | :copyright: Copyright (c) 2016-2018 Jungmann Lab, MPI of Biochemistry 9 | """ 10 | import csv 11 | from . import io as _io 12 | 13 | 14 | def saveInfo(filename, info): 15 | _io.save_info(filename, [info], default_flow_style=True) 16 | 17 | 18 | def convertPlateIndex(plate, platename): 19 | # convert from canvas index [CANVAS_INDEX, OLIGONAME, SEQUENCE] 20 | # format for ordering [PLATE NAME, PLATE POSITION, OLIGONAME, SEQUENCE] 21 | 22 | platerow = [ 23 | "A", 24 | "B", 25 | "C", 26 | "D", 27 | "E", 28 | "F", 29 | "G", 30 | "H", 31 | "A", 32 | "B", 33 | "C", 34 | "D", 35 | "E", 36 | "F", 37 | "G", 38 | "H", 39 | ] 40 | platecol = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12] 41 | structurerow = [ 42 | "A", 43 | "B", 44 | "C", 45 | "D", 46 | "E", 47 | "F", 48 | "G", 49 | "H", 50 | "I", 51 | "J", 52 | "K", 53 | "L", 54 | "M", 55 | "N", 56 | "O", 57 | "P", 58 | ] 59 | structurecol = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12] 60 | 61 | newplate = [["PLATE NAME", "PLATE POSITION", "OLIGO NAME", "SEQUENCE"]] 62 | for row in range(0, len(platerow)): 63 | for col in range(0, len(platecol)): 64 | if row < 8: 65 | platenameindex = platename + "_1" 66 | else: 67 | platenameindex = platename + "_2" 68 | structureindex = structurerow[row] + str(structurecol[col]) 69 | oligoname = " " 70 | sequence = " " 71 | for i in range(0, len(plate)): 72 | if plate[i][0] == structureindex: 73 | oligoname = plate[i][1] 74 | sequence = plate[i][2] 75 | newplate.append( 76 | [ 77 | platenameindex, 78 | platerow[row] + str(platecol[col]), 79 | oligoname, 80 | sequence, 81 | ] 82 | ) 83 | 84 | return newplate 85 | 86 | 87 | def convertPlateIndexColor(plate, platename): 88 | # convert from canvas index [CANVAS_INDEX, OLIGONAME, SEQUENCE] 89 | # format for ordering [PLATE NAME, PLATE POSITION, OLIGONAME, SEQUENCE] 90 | 91 | platerow = [ 92 | "A", 93 | "B", 94 | "C", 95 | "D", 96 | "E", 97 | "F", 98 | "G", 99 | "H", 100 | "A", 101 | "B", 102 | "C", 103 | "D", 104 | "E", 105 | "F", 106 | "G", 107 | "H", 108 | ] 109 | platecol = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12] 110 | structurerow = [ 111 | "A", 112 | "B", 113 | "C", 114 | "D", 115 | "E", 116 | "F", 117 | "G", 118 | "H", 119 | "I", 120 | "J", 121 | "K", 122 | "L", 123 | "M", 124 | "N", 125 | "O", 126 | "P", 127 | ] 128 | structurecol = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12] 129 | 130 | newplate = [["PLATE NAME", "PLATE POSITION", "OLIGO NAME", "SEQUENCE", "COLOR"]] 131 | for row in range(0, len(platerow)): 132 | for col in range(0, len(platecol)): 133 | if row < 8: 134 | platenameindex = platename + "_1" 135 | else: 136 | platenameindex = platename + "_2" 137 | structureindex = structurerow[row] + str(structurecol[col]) 138 | oligoname = " " 139 | sequence = " " 140 | for i in range(0, len(plate)): 141 | if plate[i][0] == structureindex: 142 | oligoname = plate[i][1] 143 | sequence = plate[i][2] 144 | color = plate[i][3] 145 | newplate.append( 146 | [ 147 | platenameindex, 148 | platerow[row] + str(platecol[col]), 149 | oligoname, 150 | sequence, 151 | color, 152 | ] 153 | ) 154 | 155 | return newplate 156 | 157 | 158 | def readPlate(filename): 159 | File = open(filename) 160 | Reader = csv.reader(File) 161 | data = list(Reader) 162 | return data 163 | 164 | 165 | def savePlate(filename, data): 166 | with open(filename, "w", newline="") as csvfile: 167 | Writer = csv.writer( 168 | csvfile, delimiter=",", quotechar="|", quoting=csv.QUOTE_MINIMAL 169 | ) 170 | for j in range(0, len(data)): 171 | exportdata = data[j] 172 | for i in range(0, len(exportdata)): 173 | Writer.writerow(exportdata[i]) 174 | -------------------------------------------------------------------------------- /picasso/ext/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jungmannlab/picasso/7ada94433f6b189a929008e14d42027a6da8ced3/picasso/ext/__init__.py -------------------------------------------------------------------------------- /picasso/gui/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jungmannlab/picasso/7ada94433f6b189a929008e14d42027a6da8ced3/picasso/gui/__init__.py -------------------------------------------------------------------------------- /picasso/gui/createShortcuts.ps1: -------------------------------------------------------------------------------- 1 | $s=(New-Object -COM WScript.Shell).CreateShortcut("$PSScriptRoot/../../ToRaw.lnk") 2 | $s.TargetPath="pythonw" 3 | $s.Arguments="-m picasso toraw" 4 | $s.IconLocation="$PSScriptRoot/icons/toraw.ico" 5 | $s.Save() 6 | 7 | $s=(New-Object -COM WScript.Shell).CreateShortcut("$PSScriptRoot/../../Design.lnk") 8 | $s.TargetPath="pythonw" 9 | $s.Arguments="-m picasso design" 10 | $s.IconLocation="$PSScriptRoot/icons/design.ico" 11 | $s.Save() 12 | 13 | $s=(New-Object -COM WScript.Shell).CreateShortcut("$PSScriptRoot/../../Simulate.lnk") 14 | $s.TargetPath="pythonw" 15 | $s.Arguments="-m picasso simulate" 16 | $s.IconLocation="$PSScriptRoot/icons/simulate.ico" 17 | $s.Save() 18 | 19 | $s=(New-Object -COM WScript.Shell).CreateShortcut("$PSScriptRoot/../../Localize.lnk") 20 | $s.TargetPath="pythonw" 21 | $s.Arguments="-m picasso localize" 22 | $s.IconLocation="$PSScriptRoot/icons/localize.ico" 23 | $s.Save() 24 | 25 | $s=(New-Object -COM WScript.Shell).CreateShortcut("$PSScriptRoot/../../Filter.lnk") 26 | $s.TargetPath="pythonw" 27 | $s.Arguments="-m picasso filter" 28 | $s.IconLocation="$PSScriptRoot/icons/filter.ico" 29 | $s.Save() 30 | 31 | $s=(New-Object -COM WScript.Shell).CreateShortcut("$PSScriptRoot/../../Render.lnk") 32 | $s.TargetPath="pythonw" 33 | $s.Arguments="-m picasso render" 34 | $s.IconLocation="$PSScriptRoot/icons/render.ico" 35 | $s.Save() 36 | 37 | $s=(New-Object -COM WScript.Shell).CreateShortcut("$PSScriptRoot/../../Average.lnk") 38 | $s.TargetPath="pythonw" 39 | $s.Arguments="-m picasso average" 40 | $s.IconLocation="$PSScriptRoot/icons/average.ico" 41 | $s.Save() 42 | 43 | $s=(New-Object -COM WScript.Shell).CreateShortcut("$PSScriptRoot/../../Average3.lnk") 44 | $s.TargetPath="pythonw" 45 | $s.Arguments="-m picasso average3" 46 | $s.IconLocation="$PSScriptRoot/icons/average.ico" 47 | $s.Save() 48 | 49 | $s=(New-Object -COM WScript.Shell).CreateShortcut("$PSScriptRoot/../../SPINNA.lnk") 50 | $s.TargetPath="pythonw" 51 | $s.Arguments="-m picasso spinna" 52 | $s.IconLocation="$PSScriptRoot/icons/spinna.ico" 53 | $s.Save() -------------------------------------------------------------------------------- /picasso/gui/icons/average.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jungmannlab/picasso/7ada94433f6b189a929008e14d42027a6da8ced3/picasso/gui/icons/average.ico -------------------------------------------------------------------------------- /picasso/gui/icons/design.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jungmannlab/picasso/7ada94433f6b189a929008e14d42027a6da8ced3/picasso/gui/icons/design.ico -------------------------------------------------------------------------------- /picasso/gui/icons/filter.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jungmannlab/picasso/7ada94433f6b189a929008e14d42027a6da8ced3/picasso/gui/icons/filter.ico -------------------------------------------------------------------------------- /picasso/gui/icons/localize.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jungmannlab/picasso/7ada94433f6b189a929008e14d42027a6da8ced3/picasso/gui/icons/localize.ico -------------------------------------------------------------------------------- /picasso/gui/icons/nanotron.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jungmannlab/picasso/7ada94433f6b189a929008e14d42027a6da8ced3/picasso/gui/icons/nanotron.ico -------------------------------------------------------------------------------- /picasso/gui/icons/picasso_server.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jungmannlab/picasso/7ada94433f6b189a929008e14d42027a6da8ced3/picasso/gui/icons/picasso_server.png -------------------------------------------------------------------------------- /picasso/gui/icons/render.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jungmannlab/picasso/7ada94433f6b189a929008e14d42027a6da8ced3/picasso/gui/icons/render.ico -------------------------------------------------------------------------------- /picasso/gui/icons/server.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jungmannlab/picasso/7ada94433f6b189a929008e14d42027a6da8ced3/picasso/gui/icons/server.ico -------------------------------------------------------------------------------- /picasso/gui/icons/simulate.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jungmannlab/picasso/7ada94433f6b189a929008e14d42027a6da8ced3/picasso/gui/icons/simulate.ico -------------------------------------------------------------------------------- /picasso/gui/icons/spinna.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jungmannlab/picasso/7ada94433f6b189a929008e14d42027a6da8ced3/picasso/gui/icons/spinna.ico -------------------------------------------------------------------------------- /picasso/gui/icons/toraw.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jungmannlab/picasso/7ada94433f6b189a929008e14d42027a6da8ced3/picasso/gui/icons/toraw.ico -------------------------------------------------------------------------------- /picasso/gui/plugins/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jungmannlab/picasso/7ada94433f6b189a929008e14d42027a6da8ced3/picasso/gui/plugins/__init__.py -------------------------------------------------------------------------------- /picasso/gui/toraw.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | """ 3 | gui/toraw 4 | ~~~~~~~~~~~~~~~~~~~~ 5 | 6 | Graphical user interface for converting movies to raw files 7 | 8 | :author: Joerg Schnitzbauer, 2015 9 | :copyright: Copyright (c) 2015 Jungmann Lab, MPI of Biochemistry 10 | """ 11 | 12 | import sys, os, importlib, pkgutil 13 | import os.path 14 | from PyQt5 import QtCore, QtGui, QtWidgets 15 | import traceback 16 | from .. import io, lib 17 | 18 | 19 | class TextEdit(QtWidgets.QTextEdit): 20 | def __init__(self, parent=None): 21 | super().__init__(parent) 22 | # self.setAcceptDrops(True) 23 | 24 | def canInsertFromMimeData(self, source): 25 | if source.hasUrls(): 26 | return True 27 | return False 28 | 29 | def dragEnterEvent(self, event): 30 | if event.mimeData().hasUrls(): 31 | event.accept() 32 | else: 33 | event.ignore() 34 | 35 | def dropEvent(self, event): 36 | urls = event.mimeData().urls() 37 | paths = [url.toLocalFile() for url in urls] 38 | valid_paths = [] 39 | for path in paths: 40 | base, extension = os.path.splitext(path) 41 | if extension.lower() in [".tif", ".tiff"]: 42 | valid_paths.append(path) 43 | for root, dirs, files in os.walk(path): 44 | for name in files: 45 | candidate = os.path.join(root, name) 46 | base, extension = os.path.splitext(candidate) 47 | if extension.lower() in [".tif", ".tiff"]: 48 | valid_paths.append(candidate) 49 | self.set_paths(valid_paths) 50 | 51 | def set_paths(self, paths): 52 | for path in paths: 53 | self.append(path) 54 | 55 | 56 | class Window(QtWidgets.QWidget): 57 | def __init__(self): 58 | super().__init__() 59 | # Init GUI 60 | self.setWindowTitle("Picasso: ToRaw") 61 | self.resize(768, 512) 62 | this_directory = os.path.dirname(os.path.realpath(__file__)) 63 | icon_path = os.path.join(this_directory, "icons", "toraw.ico") 64 | icon = QtGui.QIcon(icon_path) 65 | self.setWindowIcon(icon) 66 | vbox = QtWidgets.QVBoxLayout() 67 | self.setLayout(vbox) 68 | vbox.addWidget(QtWidgets.QLabel("Files:")) 69 | self.path_edit = TextEdit() 70 | vbox.addWidget(self.path_edit) 71 | hbox = QtWidgets.QHBoxLayout() 72 | vbox.addLayout(hbox) 73 | self.browse_button = QtWidgets.QPushButton("Browse") 74 | self.browse_button.clicked.connect(self.browse) 75 | hbox.addWidget(self.browse_button) 76 | hbox.addStretch(1) 77 | to_raw_button = QtWidgets.QPushButton("To raw") 78 | to_raw_button.clicked.connect(self.to_raw) 79 | hbox.addWidget(to_raw_button) 80 | 81 | def browse(self): 82 | paths, exts = QtWidgets.QFileDialog.getOpenFileNames( 83 | self, "Open files to convert", filter="*.tif; **.tiff" 84 | ) 85 | self.path_edit.set_paths(paths) 86 | 87 | def to_raw(self): 88 | text = self.path_edit.toPlainText() 89 | paths = text.splitlines() 90 | movie_groups = io.get_movie_groups(paths) 91 | n_movies = len(movie_groups) 92 | if n_movies == 1: 93 | text = "Converting 1 movie..." 94 | else: 95 | text = "Converting {} movies...".format(n_movies) 96 | self.progress_dialog = QtWidgets.QProgressDialog( 97 | text, "Cancel", 0, n_movies, self 98 | ) 99 | progress_bar = QtWidgets.QProgressBar(self.progress_dialog) 100 | progress_bar.setTextVisible(False) 101 | self.progress_dialog.setBar(progress_bar) 102 | self.progress_dialog.setMaximum(n_movies) 103 | self.progress_dialog.setWindowTitle("Picasso: ToRaw") 104 | self.progress_dialog.setWindowModality(QtCore.Qt.WindowModal) 105 | self.progress_dialog.canceled.connect(self.cancel) 106 | self.progress_dialog.closeEvent = self.cancel 107 | self.worker = Worker(movie_groups) 108 | self.worker.progressMade.connect(self.update_progress) 109 | self.worker.finished.connect(self.on_finished) 110 | self.worker.start() 111 | self.progress_dialog.show() 112 | 113 | def cancel(self, event=None): 114 | self.worker.terminate() 115 | 116 | def update_progress(self, n_done): 117 | self.progress_dialog.setValue(n_done) 118 | 119 | def on_finished(self, done): 120 | self.progress_dialog.close() 121 | QtWidgets.QMessageBox.information( 122 | self, "Picasso: ToRaw", "Conversion complete." 123 | ) 124 | 125 | 126 | class Worker(QtCore.QThread): 127 | 128 | progressMade = QtCore.pyqtSignal(int) 129 | finished = QtCore.pyqtSignal(int) 130 | interrupted = QtCore.pyqtSignal() 131 | 132 | def __init__(self, movie_groups): 133 | super().__init__() 134 | self.movie_groups = movie_groups 135 | 136 | def run(self): 137 | for i, (basename, paths) in enumerate(self.movie_groups.items()): 138 | io.to_raw_combined(basename, paths) 139 | self.progressMade.emit(i + 1) 140 | self.finished.emit(i) 141 | 142 | 143 | def main(): 144 | app = QtWidgets.QApplication(sys.argv) 145 | window = Window() 146 | 147 | from . import plugins 148 | 149 | def iter_namespace(pkg): 150 | return pkgutil.iter_modules(pkg.__path__, pkg.__name__ + ".") 151 | 152 | plugins = [ 153 | importlib.import_module(name) 154 | for finder, name, ispkg 155 | in iter_namespace(plugins) 156 | ] 157 | 158 | for plugin in plugins: 159 | p = plugin.Plugin(window) 160 | if p.name == "toraw": 161 | p.execute() 162 | 163 | window.show() 164 | 165 | def excepthook(type, value, tback): 166 | lib.cancel_dialogs() 167 | message = "".join(traceback.format_exception(type, value, tback)) 168 | errorbox = QtWidgets.QMessageBox.critical(window, "An error occured", message) 169 | errorbox.exec_() 170 | sys.__excepthook__(type, value, tback) 171 | 172 | sys.excepthook = excepthook 173 | 174 | sys.exit(app.exec_()) 175 | 176 | 177 | if __name__ == "__main__": 178 | main() 179 | -------------------------------------------------------------------------------- /picasso/imageprocess.py: -------------------------------------------------------------------------------- 1 | """ 2 | picasso.imageprocess 3 | ~~~~~~~~~~~~~~~~~~~~ 4 | 5 | Image processing functions 6 | 7 | :author: Joerg Schnitzbauer, 2016 8 | :copyright: Copyright (c) 2016 Jungmann Lab, MPI of Biochemistry 9 | """ 10 | import matplotlib.pyplot as _plt 11 | import numpy as _np 12 | from numpy import fft as _fft 13 | import lmfit as _lmfit 14 | from tqdm import tqdm as _tqdm 15 | from . import lib as _lib 16 | from . import render as _render 17 | from . import localize as _localize 18 | from . import postprocess as _postprocess 19 | 20 | _plt.style.use("ggplot") 21 | 22 | 23 | def xcorr(imageA, imageB): 24 | FimageA = _fft.fft2(imageA) 25 | CFimageB = _np.conj(_fft.fft2(imageB)) 26 | return _fft.fftshift(_np.real(_fft.ifft2((FimageA * CFimageB)))) / _np.sqrt( 27 | imageA.size 28 | ) 29 | 30 | 31 | def get_image_shift(imageA, imageB, box, roi=None, display=False): 32 | """Computes the shift from imageA to imageB""" 33 | if (_np.sum(imageA) == 0) or (_np.sum(imageB) == 0): 34 | return 0, 0 35 | # Compute image correlation 36 | XCorr = xcorr(imageA, imageB) 37 | # Cut out center roi 38 | Y, X = imageA.shape 39 | if roi is not None: 40 | Y_ = int((Y - roi) / 2) 41 | X_ = int((X - roi) / 2) 42 | if Y_ > 0: 43 | XCorr = XCorr[Y_:-Y_, :] 44 | else: 45 | Y_ = 0 46 | if X_ > 0: 47 | XCorr = XCorr[:, X_:-X_] 48 | else: 49 | X_ = 0 50 | else: 51 | Y_ = X_ = 0 52 | # A quarter of the fit ROI 53 | fit_X = int(box / 2) 54 | # A coordinate grid for the fitting ROI 55 | y, x = _np.mgrid[-fit_X : fit_X + 1, -fit_X : fit_X + 1] 56 | # Find the brightest pixel and cut out the fit ROI 57 | y_max_, x_max_ = _np.unravel_index(XCorr.argmax(), XCorr.shape) 58 | FitROI = XCorr[ 59 | y_max_ - fit_X : y_max_ + fit_X + 1, 60 | x_max_ - fit_X : x_max_ + fit_X + 1, 61 | ] 62 | 63 | dimensions = FitROI.shape 64 | 65 | if 0 in dimensions or dimensions[0] != dimensions[1]: 66 | xc, yc = 0, 0 67 | else: 68 | # The fit model 69 | def flat_2d_gaussian(a, xc, yc, s, b): 70 | A = a * _np.exp(-0.5 * ((x - xc) ** 2 + (y - yc) ** 2) / s**2) + b 71 | return A.flatten() 72 | 73 | gaussian2d = _lmfit.Model( 74 | flat_2d_gaussian, name="2D Gaussian", independent_vars=[] 75 | ) 76 | 77 | # Set up initial parameters and fit 78 | params = _lmfit.Parameters() 79 | params.add("a", value=FitROI.max(), vary=True, min=0) 80 | params.add("xc", value=0, vary=True) 81 | params.add("yc", value=0, vary=True) 82 | params.add("s", value=1, vary=True, min=0) 83 | params.add("b", value=FitROI.min(), vary=True, min=0) 84 | results = gaussian2d.fit(FitROI.flatten(), params) 85 | 86 | # Get maximum coordinates and add offsets 87 | xc = results.best_values["xc"] 88 | yc = results.best_values["yc"] 89 | xc += X_ + x_max_ 90 | yc += Y_ + y_max_ 91 | 92 | if display: 93 | _plt.figure(figsize=(17, 10)) 94 | _plt.subplot(1, 3, 1) 95 | _plt.imshow(imageA, interpolation="none") 96 | _plt.subplot(1, 3, 2) 97 | _plt.imshow(imageB, interpolation="none") 98 | _plt.subplot(1, 3, 3) 99 | _plt.imshow(XCorr, interpolation="none") 100 | _plt.plot(xc, yc, "x") 101 | _plt.show() 102 | 103 | xc -= _np.floor(X / 2) 104 | yc -= _np.floor(Y / 2) 105 | 106 | return -yc, -xc 107 | 108 | 109 | def rcc(segments, max_shift=None, callback=None): 110 | n_segments = len(segments) 111 | shifts_x = _np.zeros((n_segments, n_segments)) 112 | shifts_y = _np.zeros((n_segments, n_segments)) 113 | n_pairs = int(n_segments * (n_segments - 1) / 2) 114 | flag = 0 115 | if callback is None: 116 | with _tqdm( 117 | total=n_pairs, desc="Correlating image pairs", unit="pairs" 118 | ) as progress_bar: 119 | for i in range(n_segments - 1): 120 | for j in range(i + 1, n_segments): 121 | progress_bar.update() 122 | shifts_y[i, j], shifts_x[i, j] = get_image_shift( 123 | segments[i], segments[j], 5, max_shift 124 | ) 125 | flag += 1 126 | else: 127 | callback(0) 128 | for i in range(n_segments - 1): 129 | for j in range(i + 1, n_segments): 130 | shifts_y[i, j], shifts_x[i, j] = get_image_shift( 131 | segments[i], segments[j], 5, max_shift 132 | ) 133 | flag += 1 134 | callback(flag) 135 | 136 | return _lib.minimize_shifts(shifts_x, shifts_y) 137 | 138 | 139 | def find_fiducials(locs, info): 140 | """Finds the xy coordinates of regions with high density of 141 | localizations, likely originating from fiducial markers. 142 | 143 | Uses picasso.localize.identify_in_image with threshold set to 99th 144 | percentile of the image histogram. The image is rendered using 145 | one-pixel-blur, see picasso.render.render. 146 | 147 | 148 | Parameters 149 | ---------- 150 | locs : np.recarray 151 | Localizations. 152 | info : list of dicts 153 | Localizations' metadata (from the corresponding .yaml file). 154 | 155 | Returns 156 | ------- 157 | picks : list of (2,) tuples 158 | Coordinates of fiducial markers. Each list element corresponds 159 | to (x, y) coordinates of one fiducial marker. 160 | box : int 161 | Size of the box used for the fiducial marker identification. 162 | Can be set as the pick diameter in pixels for undrifting. 163 | """ 164 | 165 | image = _render.render( 166 | locs=locs, 167 | info=info, 168 | oversampling=1, 169 | viewport=None, 170 | blur_method="smooth", 171 | )[1] 172 | hist = _np.histogram(image.flatten(), bins=256) 173 | threshold = _np.percentile(hist[0], 99) 174 | # box size should be an odd number, corresponding to approximately 175 | # 900 nm 176 | pixelsize = 130 177 | for inf in info: 178 | if val := inf.get("Pixelsize"): 179 | pixelsize = val 180 | break 181 | box = int(_np.round(900 / pixelsize)) 182 | box = box + 1 if box % 2 == 0 else box 183 | 184 | # find the local maxima and translate to pick coordinates 185 | y, x, _ = _localize.identify_in_image(image, threshold, box=box) 186 | picks = [(xi, yi) for xi, yi in zip(x, y)] 187 | 188 | # select the picks with appropriate number of localizations 189 | n_frames = 0 190 | for inf in info: 191 | if val := inf.get("Frames"): 192 | n_frames = val 193 | break 194 | min_n = 0.8 * n_frames 195 | picked_locs = _postprocess.picked_locs( 196 | locs, info, picks, "Circle", pick_size=box/2, add_group=False, 197 | ) 198 | picks = [ 199 | pick for i, pick in enumerate(picks) if len(picked_locs[i]) > min_n 200 | ] 201 | return picks, box -------------------------------------------------------------------------------- /picasso/model/default_model.sav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jungmannlab/picasso/7ada94433f6b189a929008e14d42027a6da8ced3/picasso/model/default_model.sav -------------------------------------------------------------------------------- /picasso/model/default_model.yaml: -------------------------------------------------------------------------------- 1 | Classes: 2 | 0: digit 1 3 | 1: digit 2 4 | 2: digit 3 5 | 3: 20 nm grid 6 | Created on: 2019-10-09 17:49:28.031162 7 | Generated by: 'Picasso nanoTRON : Train' 8 | Model: W:/users/aauer/z.nanotron/1-2-3-20nm.sav 9 | Oversampling: 50 10 | Pick Diameter: 1.0 11 | Scikit-Learn Version: 0.21.3 12 | Training Accuracy: 0.9862703279125566 13 | Training Files: 14 | 0: E:/data/aauer/nanoTron/data/train/1_train.hdf5 15 | 1: E:/data/aauer/nanoTron/data/train/2_train.hdf5 16 | 2: W:/users/aauer/z.microscopy_raw/191004_nanotron/01_3_1/01_3_1_MMStack_Pos0.ome_locs_render_join_picked.hdf5 17 | 3: E:/data/aauer/nanoTron/data/train/20nm_train.hdf5 18 | Training Loss: 0.11043595011602685 19 | -------------------------------------------------------------------------------- /picasso/nanotron.py: -------------------------------------------------------------------------------- 1 | """ 2 | picasso.nanotron 3 | ~~~~~~~~~~ 4 | 5 | Deep learning library for classification of picked localizations 6 | 7 | :author: Alexander Auer, Maximilian Strauss 2020 8 | :copyright: Copyright (c) 2020 Jungmann Lab, MPI of Biochemistry 9 | """ 10 | 11 | import numpy as np 12 | import matplotlib.pyplot as plt 13 | from tqdm import tqdm as tqdm 14 | from scipy import ndimage 15 | 16 | from . import render, lib 17 | 18 | 19 | def prepare_img(img, img_shape, alpha=1, bg=0): 20 | 21 | img = alpha * img - bg 22 | img = img.astype('float') 23 | img = img / img.max() 24 | img = img.clip(min=0) 25 | img = img.reshape(img_shape**2) 26 | 27 | return img 28 | 29 | 30 | def rotate_img(img, angle): 31 | 32 | rot_img = ndimage.rotate(img, angle, reshape=False) 33 | 34 | return rot_img 35 | 36 | def roi_to_img(locs, pick, radius, oversampling, picks=None): 37 | 38 | # Isolate locs from pick 39 | pick_locs = [] 40 | if picks is None: 41 | pick_locs = locs[(locs["group"] == pick)] 42 | else: 43 | x, y = picks 44 | pick_locs = lib.locs_at(x, y, locs, radius) 45 | pick_locs.sort(kind="mergesort", order="frame") 46 | # dirty method to avoid floating point errors with render 47 | radius -= 0.001 48 | 49 | x_mean = np.mean(pick_locs.x) 50 | y_mean = np.mean(pick_locs.y) 51 | 52 | x_min = x_mean - radius 53 | x_max = x_mean + radius 54 | y_min = y_mean - radius 55 | y_max = y_mean + radius 56 | 57 | viewport = (y_min, x_min), (y_max, x_max) 58 | 59 | # for debugging 60 | if False: 61 | print("mean x: {}".format(np.mean(pick_locs.x))) 62 | print('length x: {}'.format(x_max - x_min)) 63 | print("mean y: {}".format(np.mean(pick_locs.y))) 64 | print('length y: {}'.format(y_max - y_min)) 65 | print('radius: {}'.format(radius)) 66 | print('viewport: {}'.format(viewport)) 67 | 68 | # Render locs with Picasso render function 69 | try: 70 | len_x, pick_img = render.render(pick_locs, viewport=viewport, 71 | oversampling=oversampling, 72 | blur_method='smooth') 73 | except: 74 | pass 75 | return pick_img 76 | 77 | 78 | def prepare_data(locs, label, pick_radius, 79 | oversampling, alpha=10, 80 | bg=1, export=False): 81 | 82 | img_shape = int(2 * pick_radius * oversampling) 83 | data = [] 84 | labels = [] 85 | 86 | for pick in tqdm(range(locs.group.max()), desc='Prepare '+str(label)): 87 | 88 | pick_img = roi_to_img(locs, pick, 89 | radius=pick_radius, 90 | oversampling=oversampling) 91 | 92 | if export is True and pick < 10: 93 | filename = 'label' + str(label) + '-' + str(pick) 94 | plt.imsave('./img/' + filename + '.png', (alpha*pick_img-bg), cmap='Greys', vmax=10) 95 | 96 | pick_img = prepare_img(pick_img, img_shape=img_shape, alpha=alpha, bg=bg) 97 | 98 | data.append(pick_img) 99 | labels.append(label) 100 | 101 | return data, label 102 | 103 | 104 | def predict_structure(mlp, locs, pick, pick_radius, oversampling, picks=None): 105 | 106 | img_shape = int(2 * pick_radius * oversampling) 107 | img = roi_to_img(locs, pick=pick, radius=pick_radius, oversampling=oversampling, picks=picks) 108 | img = prepare_img(img, img_shape=img_shape, alpha=10, bg=1) 109 | img = img.reshape(1, img_shape**2) 110 | 111 | pred = mlp.predict(img) 112 | pred_proba = mlp.predict_proba(img) 113 | 114 | return pred, pred_proba -------------------------------------------------------------------------------- /picasso/server/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jungmannlab/picasso/7ada94433f6b189a929008e14d42027a6da8ced3/picasso/server/__init__.py -------------------------------------------------------------------------------- /picasso/server/app.py: -------------------------------------------------------------------------------- 1 | """ 2 | Streamlit application to interface with the database 3 | """ 4 | 5 | import os 6 | import socket 7 | from PIL import Image 8 | import streamlit as st 9 | import pandas as pd 10 | from sqlalchemy import create_engine 11 | from datetime import datetime 12 | 13 | from picasso import localize 14 | from status import status 15 | from preview import preview 16 | from history import history 17 | from watcher import watcher 18 | from compare import compare 19 | 20 | from picasso.__version__ import VERSION_NO 21 | 22 | st.set_page_config(layout="wide") 23 | 24 | 25 | _this_file = os.path.abspath(__file__) 26 | _this_directory = os.path.dirname(_this_file) 27 | 28 | LOGO_PATH = os.path.abspath( 29 | os.path.join(_this_directory, os.pardir, "gui/icons/picasso_server.png") 30 | ) 31 | logo = Image.open(LOGO_PATH) 32 | 33 | c1, c2, c3, c4 = st.sidebar.columns((1, 1, 1, 1)) 34 | c1.image(logo) 35 | c2.write("# Picasso Server") 36 | 37 | engine = create_engine("sqlite:///" + localize._db_filename(), echo=False) 38 | 39 | st.sidebar.code(f"{socket.gethostname()}\nVersion {VERSION_NO}") 40 | 41 | sidebar = { 42 | "Status": status, 43 | "History": history, 44 | "Compare": compare, 45 | "Watcher": watcher, 46 | "Preview": preview, 47 | } 48 | 49 | menu = st.sidebar.radio("", list(sidebar.keys())) 50 | 51 | if menu: 52 | sidebar[menu]() 53 | -------------------------------------------------------------------------------- /picasso/server/compare.py: -------------------------------------------------------------------------------- 1 | import streamlit as st 2 | from helper import _db_filename 3 | from sqlalchemy import create_engine 4 | import pandas as pd 5 | import os 6 | import numpy as np 7 | from picasso import io 8 | from picasso import render 9 | from picasso import lib 10 | import matplotlib.pyplot as plt 11 | import plotly.express as px 12 | import plotly.graph_objects as go 13 | 14 | 15 | @st.cache_data 16 | def load_file(path: str): 17 | """Loads a localization file and returns as pandas Dataframe. 18 | Adds a column with the filename. 19 | 20 | Args: 21 | path (str): Path to localization file. 22 | file (str): filename 23 | """ 24 | 25 | locs, info = io.load_locs(path) 26 | locs = pd.DataFrame(locs) 27 | locs["file"] = os.path.split(path)[-1] 28 | return locs, info 29 | 30 | 31 | def get_file_family(file: str): 32 | """Returns all files that belong to a parent file for picasso. 33 | E.g. for a folder with 'file.hdf5' and 'file_undrift.hdf5', 34 | when searching for 'file.hdf5', both files will be returned. 35 | 36 | Args: 37 | file (str): Path to file. 38 | """ 39 | base = os.path.split(file)[1].split(".")[0] 40 | folder = os.path.dirname(file) 41 | 42 | files = os.listdir(folder) 43 | files = [f for f in files if f.startswith(base) and f.endswith(".hdf5")] 44 | 45 | return files, folder 46 | 47 | 48 | def locs_per_frame_plot(hdf_dict: dict): 49 | """Plots the localizations per frame. 50 | 51 | Args: 52 | hdf_dict (dict): Dictionary with hdf summary information 53 | """ 54 | smooth = st.number_input("Smooth", value=100, min_value=1, max_value=1000) 55 | summary = [] 56 | 57 | for f, df in hdf_dict.items(): 58 | d = df[["frame", "photons"]].groupby("frame").count() 59 | d.columns = ["count"] 60 | d = d.rolling(smooth).mean() 61 | d["file"] = f 62 | d = d.reset_index() 63 | 64 | summary.append(d) 65 | 66 | plot_df = pd.concat(summary, axis=0) 67 | 68 | fig = px.line( 69 | plot_df, x="frame", y="count", title="Locs per Frame", color="file", height=600 70 | ) 71 | 72 | fig.update_layout( 73 | legend=dict( 74 | x=0, 75 | y=-0.5, 76 | ) 77 | ) 78 | 79 | st.plotly_chart(fig) 80 | 81 | 82 | def hist_plot(hdf_dict: dict, locs: pd.DataFrame): 83 | """Plots a histogram for a given hdf dictionary. 84 | 85 | Args: 86 | hdf_dict (dict): Dictionary with summary stats per file. 87 | locs (pd.DataFrame): pandas Dataframe with localizations. 88 | """ 89 | 90 | c1, c2, c3, c4 = st.columns(4) 91 | 92 | fields = locs.columns 93 | field = c1.selectbox("Select field", fields) 94 | 95 | try: 96 | n_bins = c2.number_input( 97 | "Number of bins", value=100, min_value=1, max_value=200 98 | ) 99 | 100 | all_f = {} 101 | for f, df in hdf_dict.items(): 102 | all_f[f] = df[field].values 103 | 104 | all_values = np.concatenate(list(all_f.values())) 105 | 106 | min_ = float(np.min(all_values)) 107 | max_ = float(np.max(all_values)) 108 | 109 | upper = float(np.percentile(all_values, 99)) 110 | lower = float(np.percentile(all_values, 1)) 111 | 112 | min_value = c3.number_input( 113 | "Min value", value=lower, min_value=min_, max_value=max_ 114 | ) 115 | max_value = c4.number_input( 116 | "Max value", value=upper, min_value=min_value, max_value=max_ 117 | ) 118 | 119 | bins = np.linspace(min_value, max_value, n_bins) 120 | 121 | summary = [] 122 | for f, vals in all_f.items(): 123 | 124 | counts, _ = np.histogram(vals, bins=bins) 125 | sub_df = pd.DataFrame([bins[1:] + bins[0] / 2, counts]).T 126 | 127 | sub_df.columns = [field, "count"] 128 | sub_df["file"] = f 129 | summary.append(sub_df) 130 | 131 | plot_df = pd.concat(summary, axis=0) 132 | 133 | fig = px.line( 134 | plot_df, x=field, y="count", title=f"{field}", color="file", height=600 135 | ) 136 | 137 | fig.update_layout( 138 | legend=dict( 139 | x=0, 140 | y=-0.5, 141 | ) 142 | ) 143 | 144 | st.plotly_chart(fig) 145 | except Exception as e: 146 | st.warning(f"An error occured plotting field **{field}**.\n {e}") 147 | 148 | 149 | def compare(): 150 | """Compare streamlit page.""" 151 | st.write("# Compare") 152 | 153 | st.write( 154 | "Compare multiple files from the database. All hdf files with the same base path as the movie will be selectable." 155 | ) 156 | 157 | engine = create_engine("sqlite:///" + _db_filename(), echo=False) 158 | 159 | try: 160 | df = pd.read_sql_table("files", con=engine) 161 | 162 | files = df["filename"].unique() 163 | 164 | selected = st.multiselect("Select files (Hover to see full path)", files) 165 | 166 | if len(selected) > 0: 167 | 168 | file_dict = {} 169 | hdf_dict = {} 170 | for file in selected: 171 | try: 172 | c1, f1 = get_file_family(file) 173 | file_dict[file] = st.multiselect( 174 | f"Select hdf file for {file}", 175 | c1, 176 | None, 177 | ) 178 | 179 | if file_dict[file] is not None: 180 | for _ in file_dict[file]: 181 | path = os.path.dirname(file) 182 | 183 | locs_filename = os.path.join(path, _) 184 | 185 | with st.spinner("Loading files"): 186 | locs, info = load_file(locs_filename) 187 | hdf_dict[locs_filename] = locs 188 | except FileNotFoundError: 189 | st.error( 190 | f"File **{file}** was not found. Please check that this file exists." 191 | ) 192 | 193 | st.write("## Plot") 194 | 195 | if len(hdf_dict) > 0: 196 | with st.spinner("Generating plots"): 197 | plot = st.selectbox( 198 | "Select plot", ["Localizations per frame", "Histogram"] 199 | ) 200 | if plot == "Localizations per frame": 201 | locs_per_frame_plot(hdf_dict) 202 | else: 203 | hist_plot(hdf_dict, locs) 204 | else: 205 | st.warning("Please select HDF files.") 206 | 207 | except ValueError as e: 208 | 209 | st.warning("Database empty. Process files first.") 210 | -------------------------------------------------------------------------------- /picasso/server/helper.py: -------------------------------------------------------------------------------- 1 | import picasso.io 2 | import picasso.postprocess 3 | import os 4 | import numpy as np 5 | import sqlalchemy 6 | from sqlalchemy import create_engine 7 | import pandas as pd 8 | import streamlit as st 9 | import time 10 | import subprocess 11 | import picasso.localize 12 | from picasso.localize import _db_filename 13 | 14 | 15 | def fetch_db(): 16 | """ 17 | Helper function to load the local database and return the files. 18 | """ 19 | try: 20 | DB_PATH = "sqlite:///" + _db_filename() 21 | engine = create_engine(DB_PATH, echo=False) 22 | df = pd.read_sql_table("files", con=engine) 23 | 24 | df = df.sort_values("file_created") 25 | except ValueError: 26 | df = pd.DataFrame() 27 | 28 | return df 29 | 30 | 31 | def fetch_watcher(): 32 | """ 33 | Helper function to load the local database and return running watchers. 34 | """ 35 | try: 36 | engine = create_engine("sqlite:///" + _db_filename(), echo=False) 37 | df = pd.read_sql_table("watcher", con=engine) 38 | except ValueError as e: 39 | print(e) 40 | df = pd.DataFrame() 41 | 42 | return df 43 | 44 | 45 | def refresh(to_wait: int): 46 | """ 47 | Utility function that waits for a given amount and then stops streamlit. 48 | """ 49 | ref = st.empty() 50 | for i in range(to_wait): 51 | ref.write(f"Refreshing in {to_wait-i} s") 52 | time.sleep(1) 53 | st.stop() 54 | -------------------------------------------------------------------------------- /picasso/server/history.py: -------------------------------------------------------------------------------- 1 | import streamlit as st 2 | from helper import fetch_db 3 | from sqlalchemy import create_engine 4 | import pandas as pd 5 | import plotly.express as px 6 | import datetime 7 | import plotly.graph_objs as go 8 | import warnings 9 | 10 | DEFAULT_PLOTS = [ 11 | "nena_px", 12 | "photons_mean", 13 | "frame_std", 14 | "n_locs", 15 | "locs_frame", 16 | "bg_mean", 17 | "drift_x", 18 | "drift_y", 19 | ] 20 | 21 | 22 | @st.cache_data 23 | def convert_df(df: pd.DataFrame): 24 | """ 25 | Helper function to encode a dataframe as utf-8 26 | 27 | Args: 28 | df (pd.DataFrame): Dataframe to convert. 29 | """ 30 | 31 | return df.to_csv().encode("utf-8") 32 | 33 | 34 | def parse_input(input_: str): 35 | """ 36 | Parses an input string and looks for & and |. 37 | Keywords with & will be added to an include list and keywords with | to an exclude list. 38 | 39 | Args: 40 | input_ (str): Input string 41 | """ 42 | 43 | token = ("&", "|") 44 | 45 | mode = "add" 46 | 47 | last_idx = 0 48 | 49 | to_add = [] 50 | to_exclude = [] 51 | 52 | for idx, _ in enumerate(input_): 53 | 54 | if _ in token: 55 | if mode == "add": 56 | to_add.append(input_[last_idx:idx]) 57 | last_idx = idx + 1 58 | else: 59 | to_exclude.append(input_[last_idx:idx]) 60 | last_idx = idx + 1 61 | 62 | if _ == "&": 63 | mode = "add" 64 | elif _ == "|": 65 | mode = "exclude" 66 | 67 | # final cleanup 68 | if mode == "add": 69 | to_add.append(input_[last_idx:]) 70 | else: 71 | to_exclude.append(input_[last_idx:]) 72 | 73 | to_add = [_ for _ in to_add if len(_) > 0] 74 | 75 | return to_add, to_exclude 76 | 77 | 78 | def filter_db(df_: pd.DataFrame): 79 | """ 80 | Utility function to create a user interface to filter a dataframe. 81 | 82 | Args: 83 | df_ (pd.DataFrame): Input dataframe. 84 | """ 85 | 86 | df = df_.copy() 87 | st.write("## Filter") 88 | c1, c2, c3 = st.columns((1, 1, 2)) 89 | 90 | min_date = c1.date_input( 91 | "Minimum acquisition date", 92 | df["file_created"].min() - datetime.timedelta(days=1), 93 | ) 94 | min_date = datetime.datetime.combine(min_date, datetime.datetime.min.time()) 95 | 96 | max_date = c2.date_input( 97 | "Maximum acquisition date", 98 | df["file_created"].max() + datetime.timedelta(days=1), 99 | ) 100 | max_date = datetime.datetime.combine(max_date, datetime.datetime.min.time()) 101 | 102 | input = c3.text_input("Filter for tag in filename (use & and | to add and exclude)") 103 | 104 | input = input.replace(" ", "") 105 | 106 | if input != "": 107 | to_add, to_exclude = parse_input(input) 108 | if (len(to_add) > 0) & (len(to_exclude) > 0): 109 | st.text( 110 | f"Filtering for filenames containing {to_add} but not {to_exclude}." 111 | ) 112 | 113 | elif (len(to_add)) > 0: 114 | st.text(f"Filtering for filenames containing {to_add}.") 115 | 116 | elif (len(to_exclude)) > 0: 117 | st.text(f"Filtering for filenames not containing {to_exclude}.") 118 | 119 | df = filter_by_tags(df, to_add, to_exclude) 120 | 121 | df = df[(df["file_created"] >= min_date) & (df["file_created"] <= max_date)] 122 | 123 | st.text(f"From {len(df_):,} Database entries, {len(df):,} are remaining.") 124 | 125 | return df 126 | 127 | 128 | def filter_by_tags(df: pd.DataFrame, to_add: list, to_exclude: list): 129 | """ 130 | Filters the entries of a dataframe according to an to_add and to_exclude list. 131 | Rows will be removed according to their filename. 132 | 133 | Args: 134 | df (pd.DataFrame): Dataframe 135 | to_add (list): keywords that should be in the filename. 136 | to_exclude (list): keywords that should not be in the filename. 137 | 138 | Returns: 139 | _type_: _description_ 140 | """ 141 | 142 | add = df["filename"].apply(lambda x: True if any(i in x for i in to_add) else False) 143 | 144 | if len(to_exclude) > 0: 145 | exclude = df["filename"].apply( 146 | lambda x: False if any(i in x for i in to_exclude) else True 147 | ) 148 | else: 149 | exclude = [True for _ in range(len(df))] 150 | 151 | exclude = df["filename"].apply( 152 | lambda x: False if any(i in x for i in to_exclude) else True 153 | ) 154 | 155 | return df[add & exclude] 156 | 157 | 158 | def check_group(filename: str, groups: tuple): 159 | """Check if a filename belongs to a group 160 | 161 | Args: 162 | filename (str): filename 163 | groups (tuple): tuple with groups as strings 164 | """ 165 | found = "None" 166 | for g in groups: 167 | if g in filename: 168 | found = g 169 | 170 | return found 171 | 172 | 173 | def history(): 174 | """ 175 | Streamlit page to show the file history. 176 | """ 177 | st.write("# History") 178 | 179 | df_ = fetch_db() 180 | 181 | if len(df_) > 0: 182 | options = df_.columns.tolist() 183 | options.remove("file_created") 184 | 185 | df = filter_db(df_) 186 | df = df.reset_index(drop=True) 187 | 188 | c1, c2 = st.columns(2) 189 | 190 | fields = c1.multiselect("Fields to plot", options, DEFAULT_PLOTS) 191 | groups = c2.text_input( 192 | "Enter tags to group (seperate by comma and no space)." 193 | "\nGroups will be color-coded in scatter and box plots." 194 | ) 195 | groups_ = groups.split(",") 196 | 197 | df["group"] = df["filename"].apply(lambda x: check_group(x, groups_)) 198 | 199 | df["file_created_date"] = df["file_created"].apply(lambda x: x.date()) 200 | 201 | df = df.sort_values("file_created", ascending=False) 202 | 203 | c2.write(df["group"].value_counts()) 204 | 205 | plotmode = st.selectbox("Plotmode", ["Table", "Scatter", "Box"]) 206 | 207 | if plotmode == "Scatter": 208 | trendlines = st.checkbox("Show trendlines") 209 | if trendlines: 210 | trendline = "ols" 211 | else: 212 | trendline = None 213 | 214 | df["file_created_"] = df["file_created"].apply(lambda x: x.timestamp()) 215 | df["file_created_date"] = df["file_created"].apply(lambda x: x.date()) 216 | 217 | with warnings.catch_warnings(): 218 | warnings.simplefilter("ignore", category=RuntimeWarning) 219 | with st.spinner("Creating plots.."): 220 | 221 | if plotmode == "Table": 222 | table = df 223 | 224 | if st.checkbox("Barchart in column"): 225 | table_style = table.style.bar(color="lightgray") 226 | st.write( 227 | table_style.to_html(escape=False), unsafe_allow_html=True 228 | ) 229 | else: 230 | st.dataframe(table) 231 | 232 | csv = convert_df(table) 233 | 234 | st.download_button( 235 | f"Click to download as (csv)", 236 | csv, 237 | "file.csv", 238 | "text/csv", 239 | key="download-csv", 240 | ) 241 | else: 242 | 243 | for field in fields: 244 | median_ = df[field].median() 245 | 246 | if plotmode == "Scatter": 247 | fig = px.scatter( 248 | df, 249 | x="file_created_", 250 | y=field, 251 | color="group", 252 | hover_name="filename_hdf", 253 | hover_data=["file_created"], 254 | title=f"{field} - median {median_:.2f}", 255 | trendline=trendline, 256 | height=400, 257 | ) 258 | 259 | fig.update_xaxes( 260 | tickangle=45, 261 | tickmode="array", 262 | tickvals=df["file_created_"], 263 | ticktext=df["file_created_date"], 264 | ) 265 | 266 | st.plotly_chart(fig) 267 | elif plotmode == "Box": 268 | fig = px.box( 269 | df, 270 | x="file_created_date", 271 | y=field, 272 | color="group", 273 | hover_name="filename_hdf", 274 | hover_data=["file_created"], 275 | title=f"{field} - median {median_:.2f}", 276 | height=400, 277 | ) 278 | 279 | st.plotly_chart(fig) 280 | 281 | else: 282 | pass 283 | else: 284 | st.warning("Database empty. Process files first.") 285 | -------------------------------------------------------------------------------- /picasso/server/preview.py: -------------------------------------------------------------------------------- 1 | import streamlit as st 2 | from helper import _db_filename 3 | from sqlalchemy import create_engine 4 | import pandas as pd 5 | import os 6 | import numpy as np 7 | from picasso import io 8 | from picasso import render 9 | import matplotlib.pyplot as plt 10 | 11 | 12 | @st.cache_data 13 | def load_file(path: str): 14 | """Loads localization from files. Cached version. 15 | 16 | Args: 17 | path (str): Path to file. 18 | """ 19 | locs, info = io.load_locs(path) 20 | return locs, info 21 | 22 | 23 | @st.cache_data 24 | def picasso_render(locs: np.ndarray, viewport: tuple, oversampling: float): 25 | """Helper function to render a viewport. Cached. 26 | 27 | Args: 28 | locs (np.ndarray): Record array with localization data. 29 | viewport (tuple): Viewport as tuple. 30 | oversampling (int): Oversampling. 31 | """ 32 | len_x, image = render.render( 33 | locs, 34 | viewport=viewport, 35 | oversampling=oversampling, 36 | blur_method="smooth", 37 | ) 38 | 39 | return image 40 | 41 | 42 | def preview(): 43 | """ 44 | Streamlit page to preview a file. 45 | """ 46 | st.write("# Preview") 47 | 48 | st.write( 49 | "Select a movie from the database. All hdf files with the same base path as the movie will be selectable." 50 | ) 51 | engine = create_engine("sqlite:///" + _db_filename(), echo=False) 52 | 53 | try: 54 | df = pd.read_sql_table("files", con=engine) 55 | 56 | file = st.selectbox("Select file", df["filename"].unique()) 57 | # Find files in familiy 58 | base = os.path.split(file)[1].split(".")[0] 59 | folder = os.path.dirname(file) 60 | 61 | if os.path.isdir(folder): 62 | 63 | files = os.listdir(folder) 64 | files = [f for f in files if f.startswith(base) and f.endswith(".hdf5")] 65 | 66 | hdf_file = st.selectbox("Select hdf file", [None] + files) 67 | 68 | if hdf_file is not None: 69 | st.write("## File preview") 70 | 71 | st.info( 72 | "Performance Warning: This preview will render the full image, so it might be slow for large oversmapling." 73 | ) 74 | 75 | with st.spinner("Loading file"): 76 | hdf_file_ = os.path.join(folder, hdf_file) 77 | if os.path.isfile(hdf_file_): 78 | locs, info = load_file(hdf_file_) 79 | 80 | x_min = np.min(locs.x) 81 | x_max = np.max(locs.x) 82 | y_min = np.min(locs.y) 83 | y_max = np.max(locs.y) 84 | 85 | viewport = (y_min, x_min), (y_max, x_max) 86 | 87 | c1, c2, c3 = st.columns(3) 88 | 89 | oversampling = c1.number_input( 90 | "Oversampling", value=5.0, min_value=1., max_value=40. 91 | ) 92 | 93 | image = picasso_render(locs, viewport, oversampling) 94 | 95 | vmin = c2.number_input( 96 | "Min density", value=np.min(image.flatten()) 97 | ) 98 | vmax = c3.number_input( 99 | "Max density", value=np.max(image.flatten()) 100 | ) 101 | 102 | # plt.imshow(image, cmap='hot', vmax=10) 103 | fig, ax = plt.subplots() 104 | st.write(f"Image with dimensions {image.shape}") 105 | im = ax.imshow(image, cmap="hot", vmin=vmin, vmax=vmax) 106 | # Hide grid lines 107 | ax.grid(False) 108 | 109 | # Hide axes ticks 110 | ax.set_xticks([]) 111 | ax.set_yticks([]) 112 | st.pyplot(fig) 113 | 114 | st.write(df[df["filename"] == file].iloc[0].to_dict()) 115 | 116 | else: 117 | st.warning(f"File {hdf_file} not found.") 118 | else: 119 | st.error( 120 | f"Couldn't find folder {folder}. Please check if folder was deleted or moved." 121 | ) 122 | 123 | except ValueError: 124 | st.write("Database empty. Process files first.") 125 | -------------------------------------------------------------------------------- /picasso/server/status.py: -------------------------------------------------------------------------------- 1 | import streamlit as st 2 | from helper import fetch_db 3 | from picasso import localize 4 | import pandas as pd 5 | from sqlalchemy import create_engine 6 | import os 7 | 8 | 9 | def check_file(file): 10 | base, ext = os.path.splitext(file) 11 | file_hdf = base + "_locs.hdf5" 12 | 13 | return os.path.isfile(file_hdf) 14 | 15 | 16 | def escape_markdown(text: str) -> str: 17 | """Helper function to escape markdown in text. 18 | Args: 19 | text (str): Input text. 20 | Returns: 21 | str: Converted text to be used in markdown. 22 | """ 23 | MD_SPECIAL_CHARS = "\`*_{}[]()#+-.!" 24 | for char in MD_SPECIAL_CHARS: 25 | text = text.replace(char, "\\" + char) 26 | return text 27 | 28 | 29 | def status(): 30 | """ 31 | Streamlit page to show the status page. 32 | """ 33 | st.write("# Status") 34 | 35 | with st.expander("Getting started"): 36 | st.write( 37 | f"Picasso server allows to monitor perfomance of your super resolution runs. By selecting `Estimate and add to database` in localize, summary statistics of a run will be stored in a local database in the picasso user folder ({escape_markdown(localize._db_filename())})." 38 | ) 39 | st.write( 40 | "- Status: Displays the current database status and documentation." 41 | " \n- History: Explore summary statistics of processed files." 42 | " \n- Compare: Compare two files against each other." 43 | " \n- Watcher: Set up a file watcher to process files automatically." 44 | " \n- Preview: Preview will render the super-resolution data in the browser." 45 | ) 46 | 47 | with st.expander("Database overview"): 48 | st.write( 49 | "If you want to read and modify the database directly use tools like [DB Browser](https://sqlitebrowser.org/)." 50 | ) 51 | df = fetch_db() 52 | if len(df) > 0: 53 | df = df.sort_values("entry_created") 54 | st.write(f"The database currently contains {len(df):,} entries.") 55 | st.write("Preview of the last 10 entries:") 56 | st.write( 57 | df.iloc[-10:][["entry_created", "filename", "nena_px", "file_created"]] 58 | ) 59 | else: 60 | df = pd.DataFrame( 61 | columns=["entry_created", "filename", "nena_px", "file_created"] 62 | ) 63 | st.write("Database is empty.") 64 | 65 | with st.expander("Manually add file to database."): 66 | st.write( 67 | "Here, you can manually add files to the database." 68 | " \n- Enter the path of a image stack (`.raw`, `.ome.tif`) or a folder with multiple image stacks." 69 | " \n- All files that were reconstructed (i.e. have a `_locs.hdf5`-file) will be considered ." 70 | " \n- Drift will only be added if a undrifted file `_undrift.hdf5` is present." 71 | " \n- Files that are already in the database will be ignored." 72 | " \n- Consectuive files (`Pos0.ome.tif`, `Pos0_1.ome.tif`, `Pos0_2.ome.tif`) will be treated as one." 73 | ) 74 | path = st.text_input("Enter file path or folder:") 75 | 76 | if check_file(path) & path.endswith((".raw", ".ome.tif", ".ims")): 77 | 78 | if path not in df["filename"].tolist(): 79 | base, ext = os.path.splitext(path) 80 | target = base + '_locs.hdf5' 81 | 82 | if not os.path.isfile(target): 83 | st.error(f"File {target} does not exist.") 84 | else: 85 | file_hdf = target 86 | 87 | with st.spinner(f"Fetching summary from {file_hdf}."): 88 | summary = localize.get_file_summary(path, file_hdf=file_hdf) 89 | st.write(summary) 90 | if st.button("Add to database"): 91 | engine = create_engine( 92 | "sqlite:///" + localize._db_filename(), echo=False 93 | ) 94 | pd.DataFrame(summary.values(), summary.keys()).T.to_sql( 95 | "files", con=engine, if_exists="append", index=False 96 | ) 97 | st.success("Submitted to DB. Please refresh page.") 98 | else: 99 | st.error("File already in database.") 100 | 101 | elif os.path.isdir(path): 102 | files = [ 103 | _ for _ in os.listdir(path) if _.endswith((".raw", ".ome.tif", ".ims")) 104 | ] # Children files are in there 105 | 106 | n_files = len(files) 107 | st.text(f"A total of {n_files} files in folder.") 108 | 109 | pbar = st.progress(0) 110 | 111 | if st.button("Add files"): 112 | current_file = st.empty() 113 | all_df = [] 114 | for idx, file in enumerate(files): 115 | current_file.text(f"Current file {file}.") 116 | path_ = os.path.join(path, file) 117 | if path_ not in df["filename"].tolist(): 118 | base, ext = os.path.splitext(path_) 119 | file_hdf = base + "_locs.hdf5" 120 | if os.path.isfile(file_hdf): 121 | summary = localize.get_file_summary(path_, file_hdf=file_hdf) 122 | df_ = pd.DataFrame(summary.values(), summary.keys()).T 123 | all_df.append(df_) 124 | else: 125 | st.error(f"File {target} does not exist.") 126 | pbar.progress(int((idx + 1) / (n_files) * 100)) 127 | 128 | if len(all_df) > 0: 129 | stack = pd.concat(all_df) 130 | 131 | st.write(stack) 132 | 133 | 134 | engine = create_engine( 135 | "sqlite:///" + localize._db_filename(), echo=False 136 | ) 137 | stack.to_sql("files", con=engine, if_exists="append", index=False) 138 | 139 | st.success(f"Submitted {len(stack)} entries to the DB.") 140 | st.success("Submitted to DB. Please refresh page.") 141 | else: 142 | st.warning('No files found in folder.') 143 | else: 144 | st.warning(f"Path is not valid or no locs found.") 145 | -------------------------------------------------------------------------------- /plugin_template.py: -------------------------------------------------------------------------------- 1 | """ 2 | Template for creating a Picasso plugin. Any plugin should be moved to 3 | picasso/picasso/gui/plugins/ 4 | Author: 5 | Date: 6 | """ 7 | 8 | # Space to import packages 9 | import numpy as np 10 | 11 | # Do not change the part below unless stated otherwise 12 | class Plugin(): 13 | def __init__(self, window): 14 | self.name = "render" # change if the plugin works for another application 15 | self.window = window 16 | 17 | def execute(self): 18 | """ 19 | This function is called when opening a GUI. 20 | 21 | It should add buttons to the menu bar, connect such actions 22 | to fucntions, etc. 23 | """ 24 | 25 | pass -------------------------------------------------------------------------------- /readme.rst: -------------------------------------------------------------------------------- 1 | Picasso 2 | ======= 3 | .. image:: https://readthedocs.org/projects/picassosr/badge/?version=latest 4 | :target: https://picassosr.readthedocs.io/en/latest/?badge=latest 5 | :alt: Documentation Status 6 | 7 | .. image:: https://github.com/jungmannlab/picasso/workflows/CI/badge.svg 8 | :target: https://github.com/jungmannlab/picasso/workflows/CI/badge.svg 9 | :alt: CI 10 | 11 | .. image:: http://img.shields.io/badge/DOI-10.1038/nprot.2017.024-52c92e.svg 12 | :target: https://doi.org/10.1038/nprot.2017.024 13 | :alt: CI 14 | 15 | .. image:: https://static.pepy.tech/personalized-badge/picassosr?period=total&units=international_system&left_color=black&right_color=brightgreen&left_text=Downloads 16 | :target: https://pepy.tech/project/picassosr 17 | 18 | .. image:: main_render.png 19 | :width: 750 20 | :height: 564 21 | :alt: UML Render view 22 | 23 | A collection of tools for painting super-resolution images. The Picasso software is complemented by our `Nature Protocols publication `__. 24 | A comprehensive documentation can be found here: `Read the Docs `__. 25 | 26 | 27 | Picasso 0.8.0 28 | ------------- 29 | - **New module SPINNA for investigating oligomerization of proteins**, `DOI: 10.1038/s41467-025-59500-z `_. 30 | - NeNA bug fix: old values were too large by a factor of sqrt(2). 31 | 32 | Previous versions 33 | ----------------- 34 | To see all changes introduced in previous versions, click `here `_. 35 | 36 | Installation 37 | ------------ 38 | 39 | Check out the `Picasso release page `__ to download and run the latest compiled one-click installer for Windows. Here you will also find the Nature Protocols legacy version. 40 | 41 | For the platform-independent usage of Picasso (e.g., with Linux and Mac Os X), please follow the advanced installation instructions below. 42 | 43 | Other installation modes (Python 3.10) 44 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 45 | 46 | As an alternative to the stand-alone program for end-users, Picasso can be installed as a Python package. This is the preferred option to use Picasso’s internal routines in custom Python programs. Those can be imported by running, for example, ``from picasso import io`` (see the "Example usage" tab below) to use input/output functions from Picasso. For windows, it is still possible to use Picasso as an end-user by creating the respective shortcuts. This allows Picasso to be used on the same system by both programmers and end-users. 47 | 48 | Via PyPI 49 | ^^^^^^^^ 50 | 51 | 1. Open the console/terminal and create a new conda environment: ``conda create --name picasso python=3.10`` 52 | 2. Activate the environment: ``conda activate picasso``. 53 | 3. Install Picasso package using: ``pip install picassosr``. 54 | 4. You can now run any Picasso function directly from the console/terminal by running: ``picasso render``, ``picasso localize``, etc, or import Picasso functions in your own Python scripts. 55 | 56 | For Developers 57 | ^^^^^^^^^^^^^^ 58 | 59 | If you wish to use your local version of Picasso with your own modifications: 60 | 61 | 1. Open the console/terminal and create a new conda environment: ``conda create --name picasso python=3.10`` 62 | 2. Activate the environment: ``conda activate picasso``. 63 | 3. Change to the directory of choice using ``cd``. 64 | 4. Clone this GitHub repository by running ``git clone https://github.com/jungmannlab/picasso``. Alternatively, `download `__ the zip file and unzip it. 65 | 5. Open the Picasso directory: ``cd picasso``. 66 | 6. You can modify Picasso code in this directory. 67 | 7. To create a *local* Picasso package to use it in other Python scripts, run ``pip install -e .``. When you change the code in the ``picasso`` directory, the changes will be reflected in the package. 68 | 8. You can now run any Picasso function directly from the console/terminal by running: ``picasso render``, ``picasso localize``, etc, or import Picasso functions in your own Python scripts. 69 | 70 | Optional packages 71 | ^^^^^^^^^^^^^^^^^ 72 | 73 | Regardless of whether Picasso was installed via PyPI or by cloning the GitHub repository, some packages may be additionally installed to allow extra functionality: 74 | 75 | - ``pip install pyinstaller`` if you plan to additionally compile your own installer with `Pyinstaller `__. 76 | - *(Windows only)* ``pip install PyImarisWriter==0.7.0`` to enable .ims files in Localize and Render. Note that ``PyImarisWriter`` has been tested only on Windows. 77 | - To enable ``GPU fitting``, follow instructions on `Gpufit `__ to install the Gpufit python library in your conda environment. In practice, this means downloading the zipfile and installing the Python wheel. Picasso Localize will automatically import the library if present and enables a checkbox for GPU fitting when selecting the LQ-Method. 78 | 79 | Updating 80 | ^^^^^^^^ 81 | 82 | If Picasso was installed from PyPI, run the following command: 83 | 84 | ``pip install --upgrade picassosr`` 85 | 86 | Creating shortcuts on Windows (*optional*) 87 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 88 | 89 | Run the PowerShell script “createShortcuts.ps1” in the gui directory. This should be doable by right-clicking on the script and choosing “Run with PowerShell”. Alternatively, run the command 90 | ``powershell ./createShortcuts.ps1`` in the command line. Use the generated shortcuts in the top level directory to start GUI components. Users can drag these shortcuts to their Desktop, Start Menu or Task Bar. 91 | 92 | Example Usage 93 | ------------- 94 | 95 | Besides using the GUI, you can use picasso like any other Python module. Consider the following example::: 96 | 97 | from picasso import io, postprocess 98 | 99 | path = 'testdata_locs.hdf5' 100 | locs, info = io.load_locs(path) 101 | # Link localizations and calcualte dark times 102 | linked_locs = postprocess.link(picked_locs, info, r_max=0.05, max_dark_time=1) 103 | linked_locs_dark = postprocess.compute_dark_times(linked_locs) 104 | 105 | print('Average bright time {:.2f} frames'.format(np.mean(linked_locs_dark.n))) 106 | print('Average dark time {:.2f} frames'.format(np.mean(linked_locs_dark.dark))) 107 | 108 | This codeblock loads data from testdata_locs and uses the postprocess functions programmatically. 109 | 110 | Jupyter Notebooks 111 | ----------------- 112 | 113 | Check picasso/samples/ for Jupyter Notebooks that show how to interact with the Picasso codebase. 114 | 115 | Contributing 116 | ------------ 117 | 118 | If you have a feature request or a bug report, please post it as an issue on the GitHub issue tracker. If you want to contribute, put a PR for it. You can find more guidelines for contributing `here `__. We will gladly guide you through the codebase and credit you accordingly. Additionally, you can check out the ``Projects``-page on GitHub. You can also contact us via picasso@jungmannlab.org. 119 | 120 | Contributions & Copyright 121 | ------------------------- 122 | 123 | | Contributors: Joerg Schnitzbauer, Maximilian Strauss, Rafal Kowalewski, Adrian Przybylski, Andrey Aristov, Hiroshi Sasaki, Alexander Auer, Johanna Rahm 124 | | Copyright (c) 2015-2019 Jungmann Lab, Max Planck Institute of Biochemistry 125 | | Copyright (c) 2020-2021 Maximilian Strauss 126 | | Copyright (c) 2022-2024 Rafal Kowalewski 127 | 128 | Citing Picasso 129 | -------------- 130 | 131 | If you use picasso in your research, please cite our Nature Protocols publication describing the software. 132 | 133 | | J. Schnitzbauer*, M.T. Strauss*, T. Schlichthaerle, F. Schueder, R. Jungmann 134 | | Super-Resolution Microscopy with DNA-PAINT 135 | | Nature Protocols (2017). 12: 1198-1228 DOI: `https://doi.org/10.1038/nprot.2017.024 `__ 136 | | 137 | | If you use some of the functionalities provided by Picasso, please also cite the respective publications: 138 | 139 | - Nearest Neighbor based Analysis (NeNA) for experimental localization precision. DOI: `10.1007/s00418-014-1192-3 `__ 140 | - Theoretical localization precision (Gauss LQ and MLE). DOI: `10.1038/nmeth.1447 `__ 141 | - MLE fitting. DOI: `10.1038/nmeth.1449 `__ 142 | - AIM undrifting. DOI: `10.1126/sciadv.adm776 `__ 143 | - DBSCAN: Ester, et al. Inkdd, 1996. (Vol. 96, No. 34, pp. 226-231). 144 | - HDBSCAN. DOI: `10.1007/978-3-642-37456-2_14 `__ 145 | 146 | Credits 147 | ------- 148 | 149 | - Design icon based on “Hexagon by Creative Stalls" from the Noun 150 | Project 151 | - Simulate icon based on “Microchip by Futishia" from the Noun Project 152 | - Localize icon based on “Mountains" by MONTANA RUCOBO from the Noun 153 | Project 154 | - Filter icon based on “Funnel" by José Campos from the Noun Project 155 | - Render icon based on “Paint Palette" by Vectors Market from the Noun 156 | Project 157 | - Average icon based on “Layers" by Creative Stall from the Noun 158 | Project 159 | - Server icon based on “Database" by Nimal Raj from the Noun Project 160 | - SPINNA icon based on "Spinner" by Viktor Ostrovsky from the Noun Project 161 | -------------------------------------------------------------------------------- /release/logos/localize.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jungmannlab/picasso/7ada94433f6b189a929008e14d42027a6da8ced3/release/logos/localize.ico -------------------------------------------------------------------------------- /release/one_click_windows_gui/create_installer_windows.bat: -------------------------------------------------------------------------------- 1 | call DEL /F/Q/S build > NUL 2 | call DEL /F/Q/S dist > NUL 3 | call RMDIR /Q/S build 4 | call RMDIR /Q/S dist 5 | 6 | call cd %~dp0\..\.. 7 | 8 | call conda create -n picasso_installer python=3.10.15 -y 9 | call conda activate picasso_installer 10 | 11 | call python setup.py sdist bdist_wheel 12 | 13 | call cd release/one_click_windows_gui 14 | call pip install "../../dist/picassosr-0.8.0-py3-none-any.whl" 15 | 16 | call pip install pyinstaller==5.12 17 | call pyinstaller ../pyinstaller/picasso.spec -y --clean 18 | call pyinstaller ../pyinstaller/picassow.spec -y --clean 19 | call conda deactivate 20 | 21 | call robocopy ../../picasso dist/picasso/picasso /E 22 | 23 | copy dist\picassow\picassow.exe dist\picasso\picassow.exe 24 | copy dist\picassow\picassow.exe.manifest dist\picasso\picassow.exe.manifest 25 | 26 | call "C:\Program Files (x86)\Inno Setup 6\ISCC.exe" picasso_innoinstaller.iss -------------------------------------------------------------------------------- /release/one_click_windows_gui/picasso_innoinstaller.iss: -------------------------------------------------------------------------------- 1 | [Setup] 2 | AppName=Picasso 3 | AppPublisher=Jungmann Lab, Max Planck Institute of Biochemistry 4 | AppVersion=0.8.0 5 | DefaultDirName={commonpf}\Picasso 6 | DefaultGroupName=Picasso 7 | OutputBaseFilename="Picasso-Windows-64bit-0.8.0" 8 | ArchitecturesAllowed=x64 9 | ArchitecturesInstallIn64BitMode=x64 10 | 11 | [Files] 12 | Source: "dist\picasso\*"; DestDir: "{app}"; Flags: recursesubdirs createallsubdirs 13 | 14 | [Icons] 15 | Name: "{group}\Design"; Filename: "{app}\picassow.exe"; Parameters: "design"; IconFilename: "{app}\picasso\gui\icons\design.ico" 16 | Name: "{group}\Simulate"; Filename: "{app}\picassow.exe"; Parameters: "simulate"; IconFilename: "{app}\picasso\gui\icons\simulate.ico" 17 | Name: "{group}\Localize"; Filename: "{app}\picassow.exe"; Parameters: "localize"; IconFilename: "{app}\picasso\gui\icons\localize.ico" 18 | Name: "{group}\Filter"; Filename: "{app}\picassow.exe"; Parameters: "filter"; IconFilename: "{app}\picasso\gui\icons\filter.ico" 19 | Name: "{group}\Render"; Filename: "{app}\picassow.exe"; Parameters: "render"; IconFilename: "{app}\picasso\gui\icons\render.ico" 20 | Name: "{group}\Average"; Filename: "{app}\picassow.exe"; Parameters: "average"; IconFilename: "{app}\picasso\gui\icons\average.ico" 21 | Name: "{group}\SPINNA"; Filename: "{app}\picassow.exe"; Parameters: "spinna"; IconFilename: "{app}\picasso\gui\icons\spinna.ico" 22 | Name: "{group}\Server"; Filename: "{app}\picasso.exe"; Parameters: "server"; IconFilename: "{app}\picasso\gui\icons\server.ico" 23 | 24 | 25 | Name: "{autodesktop}\Design"; Filename: "{app}\picassow.exe"; Parameters: "design"; IconFilename: "{app}\picasso\gui\icons\design.ico" 26 | Name: "{autodesktop}\Simulate"; Filename: "{app}\picassow.exe"; Parameters: "simulate"; IconFilename: "{app}\picasso\gui\icons\simulate.ico" 27 | Name: "{autodesktop}\Localize"; Filename: "{app}\picassow.exe"; Parameters: "localize"; IconFilename: "{app}\picasso\gui\icons\localize.ico" 28 | Name: "{autodesktop}\Filter"; Filename: "{app}\picassow.exe"; Parameters: "filter"; IconFilename: "{app}\picasso\gui\icons\filter.ico" 29 | Name: "{autodesktop}\Render"; Filename: "{app}\picassow.exe"; Parameters: "render"; IconFilename: "{app}\picasso\gui\icons\render.ico" 30 | Name: "{autodesktop}\Average"; Filename: "{app}\picassow.exe"; Parameters: "average"; IconFilename: "{app}\picasso\gui\icons\average.ico" 31 | Name: "{autodesktop}\SPINNA"; Filename: "{app}\picassow.exe"; Parameters: "spinna"; IconFilename: "{app}\picasso\gui\icons\spinna.ico" 32 | Name: "{autodesktop}\Server"; Filename: "{app}\picasso.exe"; Parameters: "server"; IconFilename: "{app}\picasso\gui\icons\server.ico" 33 | 34 | [Registry] 35 | Root: HKLM; Subkey: "SYSTEM\CurrentControlSet\Control\Session Manager\Environment"; \ 36 | ValueType: expandsz; ValueName: "Path"; ValueData: "{olddata};{app}"; \ 37 | Check: NeedsAddPath('{app}') 38 | 39 | [Code] 40 | function NeedsAddPath(Param: string): boolean; 41 | var 42 | OrigPath: string; 43 | ParamExpanded: string; 44 | begin 45 | //expand the setup constants like {app} from Param 46 | ParamExpanded := ExpandConstant(Param); 47 | if not RegQueryStringValue(HKEY_LOCAL_MACHINE, 48 | 'SYSTEM\CurrentControlSet\Control\Session Manager\Environment', 49 | 'Path', OrigPath) 50 | then begin 51 | Result := True; 52 | exit; 53 | end; 54 | // look for the path with leading and trailing semicolon and with or without \ ending 55 | // Pos() returns 0 if not found 56 | Result := Pos(';' + UpperCase(ParamExpanded) + ';', ';' + UpperCase(OrigPath) + ';') = 0; 57 | if Result = True then 58 | Result := Pos(';' + UpperCase(ParamExpanded) + '\;', ';' + UpperCase(OrigPath) + ';') = 0; 59 | end; 60 | -------------------------------------------------------------------------------- /release/pyinstaller/picasso.spec: -------------------------------------------------------------------------------- 1 | # -*- mode: python ; coding: utf-8 -*- 2 | 3 | import pkgutil 4 | import os 5 | import sys 6 | from PyInstaller.building.build_main import Analysis, PYZ, EXE, COLLECT, BUNDLE, TOC 7 | import PyInstaller.utils.hooks 8 | import pkg_resources 9 | import importlib.metadata 10 | import picasso 11 | 12 | 13 | ##################### User definitions 14 | exe_name = 'picasso' 15 | script_name = 'picasso_pyinstaller.py' 16 | if sys.platform[:6] == "darwin": 17 | icon = '../logos/localize.icns' 18 | else: 19 | icon = '../logos/localize.ico' 20 | block_cipher = None 21 | location = os.getcwd() 22 | project = "picassosr" 23 | remove_tests = True 24 | bundle_name = "picasso" 25 | ##################### 26 | 27 | 28 | requirements = { 29 | req.split()[0] for req in importlib.metadata.requires(project) 30 | } 31 | requirements.add(project) 32 | requirements.add("distributed") 33 | hidden_imports = set() 34 | datas = [] 35 | binaries = [] 36 | checked = set() 37 | while requirements: 38 | requirement = requirements.pop() 39 | checked.add(requirement) 40 | if requirement in ["pywin32"]: 41 | continue 42 | try: 43 | module_version = importlib.metadata.version(requirement) 44 | except ( 45 | importlib.metadata.PackageNotFoundError, 46 | ModuleNotFoundError, 47 | ImportError 48 | ): 49 | continue 50 | try: 51 | datas_, binaries_, hidden_imports_ = PyInstaller.utils.hooks.collect_all( 52 | requirement, 53 | include_py_files=True 54 | ) 55 | except ImportError: 56 | continue 57 | datas += datas_ 58 | # binaries += binaries_ 59 | hidden_imports_ = set(hidden_imports_) 60 | if "" in hidden_imports_: 61 | hidden_imports_.remove("") 62 | if None in hidden_imports_: 63 | hidden_imports_.remove(None) 64 | requirements |= hidden_imports_ - checked 65 | hidden_imports |= hidden_imports_ 66 | 67 | if remove_tests: 68 | hidden_imports = sorted( 69 | [h for h in hidden_imports if "tests" not in h.split(".")] 70 | ) 71 | else: 72 | hidden_imports = sorted(hidden_imports) 73 | 74 | 75 | hidden_imports = [h for h in hidden_imports if "__pycache__" not in h] 76 | datas = [d for d in datas if ("__pycache__" not in d[0]) and (d[1] not in [".", "Resources", "scripts"])] 77 | 78 | if sys.platform[:5] == "win32": 79 | base_path = os.path.dirname(sys.executable) 80 | library_path = os.path.join(base_path, "Library", "bin") 81 | dll_path = os.path.join(base_path, "DLLs") 82 | libcrypto_dll_path = os.path.join(dll_path, "libcrypto-3-x64.dll") 83 | libssl_dll_path = os.path.join(dll_path, "libssl-3-x64.dll") 84 | libcrypto_lib_path = os.path.join(library_path, "libcrypto-3-x64.dll") 85 | libssl_lib_path = os.path.join(library_path, "libssl-3-x64.dll") 86 | if not os.path.exists(libcrypto_dll_path): 87 | datas.append((libcrypto_lib_path, ".")) 88 | if not os.path.exists(libssl_dll_path): 89 | datas.append((libssl_lib_path, ".")) 90 | 91 | a = Analysis( 92 | [script_name], 93 | pathex=[location], 94 | binaries=binaries, 95 | datas=datas, 96 | hiddenimports=hidden_imports, 97 | hookspath=[], 98 | runtime_hooks=[], 99 | excludes=[h for h in hidden_imports if "datashader" in h], 100 | win_no_prefer_redirects=False, 101 | win_private_assemblies=False, 102 | cipher=block_cipher, 103 | noarchive=False 104 | ) 105 | pyz = PYZ( 106 | a.pure, 107 | a.zipped_data, 108 | cipher=block_cipher 109 | ) 110 | 111 | if sys.platform[:5] == "linux": 112 | exe = EXE( 113 | pyz, 114 | a.scripts, 115 | a.binaries, 116 | a.zipfiles, 117 | a.datas, 118 | name=bundle_name, 119 | debug=False, 120 | bootloader_ignore_signals=False, 121 | strip=False, 122 | upx=True, 123 | console=True, 124 | upx_exclude=[], 125 | icon=icon 126 | ) 127 | else: 128 | exe = EXE( 129 | pyz, 130 | a.scripts, 131 | # a.binaries, 132 | a.zipfiles, 133 | # a.datas, 134 | exclude_binaries=True, 135 | name=exe_name, 136 | debug=False, 137 | bootloader_ignore_signals=False, 138 | strip=False, 139 | upx=True, 140 | console=True, 141 | icon=icon 142 | ) 143 | coll = COLLECT( 144 | exe, 145 | a.binaries, 146 | # a.zipfiles, 147 | a.datas, 148 | strip=False, 149 | upx=True, 150 | upx_exclude=[], 151 | name=exe_name 152 | ) -------------------------------------------------------------------------------- /release/pyinstaller/picasso_pyinstaller.py: -------------------------------------------------------------------------------- 1 | from multiprocessing import freeze_support 2 | 3 | 4 | if __name__ == "__main__": 5 | # This line is needed so that pyinstaller can handle multiprocessing 6 | freeze_support() 7 | from picasso.__main__ import main 8 | 9 | main() 10 | -------------------------------------------------------------------------------- /release/pyinstaller/picassow.spec: -------------------------------------------------------------------------------- 1 | # -*- mode: python ; coding: utf-8 -*- 2 | 3 | import pkgutil 4 | import os 5 | import sys 6 | from PyInstaller.building.build_main import Analysis, PYZ, EXE, COLLECT, BUNDLE, TOC 7 | import PyInstaller.utils.hooks 8 | import pkg_resources 9 | import importlib.metadata 10 | import picasso 11 | 12 | 13 | ##################### User definitions 14 | exe_name = 'picasso' 15 | script_name = 'picasso_pyinstaller.py' 16 | if sys.platform[:6] == "darwin": 17 | icon = '../logos/localize.icns' 18 | else: 19 | icon = '../logos/localize.ico' 20 | block_cipher = None 21 | location = os.getcwd() 22 | project = "picassosr" 23 | remove_tests = True 24 | bundle_name = "picasso" 25 | ##################### 26 | 27 | 28 | requirements = { 29 | req.split()[0] for req in importlib.metadata.requires(project) 30 | } 31 | requirements.add(project) 32 | requirements.add("distributed") 33 | hidden_imports = set() 34 | datas = [] 35 | binaries = [] 36 | checked = set() 37 | while requirements: 38 | requirement = requirements.pop() 39 | checked.add(requirement) 40 | if requirement in ["pywin32"]: 41 | continue 42 | try: 43 | module_version = importlib.metadata.version(requirement) 44 | except ( 45 | importlib.metadata.PackageNotFoundError, 46 | ModuleNotFoundError, 47 | ImportError 48 | ): 49 | continue 50 | try: 51 | datas_, binaries_, hidden_imports_ = PyInstaller.utils.hooks.collect_all( 52 | requirement, 53 | include_py_files=True 54 | ) 55 | except ImportError: 56 | continue 57 | datas += datas_ 58 | # binaries += binaries_ 59 | hidden_imports_ = set(hidden_imports_) 60 | if "" in hidden_imports_: 61 | hidden_imports_.remove("") 62 | if None in hidden_imports_: 63 | hidden_imports_.remove(None) 64 | requirements |= hidden_imports_ - checked 65 | hidden_imports |= hidden_imports_ 66 | 67 | if remove_tests: 68 | hidden_imports = sorted( 69 | [h for h in hidden_imports if "tests" not in h.split(".")] 70 | ) 71 | else: 72 | hidden_imports = sorted(hidden_imports) 73 | 74 | 75 | hidden_imports = [h for h in hidden_imports if "__pycache__" not in h] 76 | datas = [d for d in datas if ("__pycache__" not in d[0]) and (d[1] not in [".", "Resources", "scripts"])] 77 | 78 | if sys.platform[:5] == "win32": 79 | base_path = os.path.dirname(sys.executable) 80 | library_path = os.path.join(base_path, "Library", "bin") 81 | dll_path = os.path.join(base_path, "DLLs") 82 | libcrypto_dll_path = os.path.join(dll_path, "libcrypto-3-x64.dll") 83 | libssl_dll_path = os.path.join(dll_path, "libssl-3-x64.dll") 84 | libcrypto_lib_path = os.path.join(library_path, "libcrypto-3-x64.dll") 85 | libssl_lib_path = os.path.join(library_path, "libssl-3-x64.dll") 86 | if not os.path.exists(libcrypto_dll_path): 87 | datas.append((libcrypto_lib_path, ".")) 88 | if not os.path.exists(libssl_dll_path): 89 | datas.append((libssl_lib_path, ".")) 90 | 91 | a = Analysis( 92 | [script_name], 93 | pathex=[location], 94 | binaries=binaries, 95 | datas=datas, 96 | hiddenimports=hidden_imports, 97 | hookspath=[], 98 | runtime_hooks=[], 99 | excludes=[h for h in hidden_imports if "datashader" in h], 100 | win_no_prefer_redirects=False, 101 | win_private_assemblies=False, 102 | cipher=block_cipher, 103 | noarchive=False 104 | ) 105 | pyz = PYZ( 106 | a.pure, 107 | a.zipped_data, 108 | cipher=block_cipher 109 | ) 110 | 111 | if sys.platform[:5] == "linux": 112 | exe = EXE( 113 | pyz, 114 | a.scripts, 115 | a.binaries, 116 | a.zipfiles, 117 | a.datas, 118 | name=bundle_name, 119 | debug=False, 120 | bootloader_ignore_signals=False, 121 | strip=False, 122 | upx=True, 123 | console=False, 124 | upx_exclude=[], 125 | icon=icon 126 | ) 127 | else: 128 | exe = EXE( 129 | pyz, 130 | a.scripts, 131 | # a.binaries, 132 | a.zipfiles, 133 | # a.datas, 134 | exclude_binaries=True, 135 | name='picassow', 136 | debug=False, 137 | bootloader_ignore_signals=False, 138 | strip=False, 139 | upx=True, 140 | console=False, 141 | icon=icon 142 | ) 143 | coll = COLLECT( 144 | exe, 145 | a.binaries, 146 | # a.zipfiles, 147 | a.datas, 148 | strip=False, 149 | upx=True, 150 | upx_exclude=[], 151 | name='picassow' 152 | ) -------------------------------------------------------------------------------- /release/pypi/install_pypi_wheel.sh: -------------------------------------------------------------------------------- 1 | conda create -n picasso_pip_test python=3.10 -y 2 | conda activate picasso_pip_test 3 | pip install "picassosr" 4 | picasso 5 | conda deactivate -------------------------------------------------------------------------------- /release/pypi/install_test_pypi_wheel.sh: -------------------------------------------------------------------------------- 1 | conda create -n picasso_pip_test python=3.10 -y 2 | conda activate picasso_pip_test 3 | pip install --index-url https://test.pypi.org/simple/ --extra-index-url https://pypi.org/simple "picassosr" 4 | picasso 5 | conda deactivate -------------------------------------------------------------------------------- /release/pypi/prepare_pypi_wheel.sh: -------------------------------------------------------------------------------- 1 | cd ../.. 2 | conda create -n picasso_pypi_wheel python=3.10 3 | conda activate picasso_pypi_wheel 4 | pip install twine 5 | rm -rf dist 6 | rm -rf build 7 | python setup.py sdist bdist_wheel 8 | twine check dist/* 9 | conda deactivate -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | PyQt5 2 | numpy==1.24.3 3 | h5py>=3.3.0 4 | matplotlib==3.7.3 5 | numba==0.58.0 6 | scipy==1.11.2 7 | pandas==2.1.1 8 | pyyaml==6.0.1 9 | scikit-learn==1.3.1 10 | tqdm==4.66.1 11 | lmfit==1.2.2 12 | streamlit==1.27.0 13 | nd2==0.7.2 14 | sqlalchemy==2.0.21 15 | plotly-express==0.4.1 16 | watchdog==3.0.0 17 | psutil==5.9.5 18 | nd2reader==3.3.0 -------------------------------------------------------------------------------- /resources/icons/average.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jungmannlab/picasso/7ada94433f6b189a929008e14d42027a6da8ced3/resources/icons/average.png -------------------------------------------------------------------------------- /resources/icons/average.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | 8 | 11 | 15 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /resources/icons/design.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jungmannlab/picasso/7ada94433f6b189a929008e14d42027a6da8ced3/resources/icons/design.png -------------------------------------------------------------------------------- /resources/icons/design.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 9 | 11 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /resources/icons/filter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jungmannlab/picasso/7ada94433f6b189a929008e14d42027a6da8ced3/resources/icons/filter.png -------------------------------------------------------------------------------- /resources/icons/filter.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | 11 | 12 | -------------------------------------------------------------------------------- /resources/icons/localize.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jungmannlab/picasso/7ada94433f6b189a929008e14d42027a6da8ced3/resources/icons/localize.png -------------------------------------------------------------------------------- /resources/icons/localize.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | 11 | 12 | 17 | 18 | 22 | 23 | 28 | 29 | 30 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /resources/icons/picasso_server.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jungmannlab/picasso/7ada94433f6b189a929008e14d42027a6da8ced3/resources/icons/picasso_server.png -------------------------------------------------------------------------------- /resources/icons/picasso_server.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Produced by OmniGraffle 7.18.5\n2021-08-29 19:07:07 +0000 6 | 7 | Canvas 1 8 | 9 | Layer 1 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /resources/icons/render.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jungmannlab/picasso/7ada94433f6b189a929008e14d42027a6da8ced3/resources/icons/render.png -------------------------------------------------------------------------------- /resources/icons/render.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | 8 | 13 | 23 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /resources/icons/simulate.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jungmannlab/picasso/7ada94433f6b189a929008e14d42027a6da8ced3/resources/icons/simulate.png -------------------------------------------------------------------------------- /resources/icons/simulate.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | tech 8 | Created with Sketch. 9 | 10 | 11 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /resources/icons/spinna.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jungmannlab/picasso/7ada94433f6b189a929008e14d42027a6da8ced3/resources/icons/spinna.png -------------------------------------------------------------------------------- /resources/icons/spinna.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /resources/icons/toraw.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jungmannlab/picasso/7ada94433f6b189a929008e14d42027a6da8ced3/resources/icons/toraw.png -------------------------------------------------------------------------------- /resources/icons/toraw.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | 14 | 15 | -------------------------------------------------------------------------------- /samples/SampleNotebook2.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# Sample Notebook 2 for Picasso\n", 8 | "This notebook shows some basic interaction with the picasso library. It assumes to have a working picasso installation. To install jupyter notebooks in a conda picasso environment use `conda install nb_conda`.\n", 9 | "The sample data was created using Picasso:Simulate. You can download the files here: http://picasso.jungmannlab.org/testdata.zip" 10 | ] 11 | }, 12 | { 13 | "cell_type": "markdown", 14 | "metadata": {}, 15 | "source": [ 16 | "## Load Localizations" 17 | ] 18 | }, 19 | { 20 | "cell_type": "code", 21 | "execution_count": 1, 22 | "metadata": {}, 23 | "outputs": [ 24 | { 25 | "name": "stdout", 26 | "output_type": "stream", 27 | "text": [ 28 | "Loaded 11975 locs.\n" 29 | ] 30 | } 31 | ], 32 | "source": [ 33 | "from picasso import io\n", 34 | "path = 'testdata_locs.hdf5'\n", 35 | "locs, info = io.load_locs(path)\n", 36 | "\n", 37 | "print('Loaded {} locs.'.format(len(locs)))" 38 | ] 39 | }, 40 | { 41 | "cell_type": "markdown", 42 | "metadata": {}, 43 | "source": [ 44 | "## Info file\n", 45 | "The info file is now a list of dictionaries. Each step in picasso adds an element to the list." 46 | ] 47 | }, 48 | { 49 | "cell_type": "code", 50 | "execution_count": 2, 51 | "metadata": {}, 52 | "outputs": [ 53 | { 54 | "name": "stdout", 55 | "output_type": "stream", 56 | "text": [ 57 | "Picasso simulate\n", 58 | "Picasso Localize\n", 59 | "Image height: 32, width: 32\n" 60 | ] 61 | } 62 | ], 63 | "source": [ 64 | "for i in range(len(info)):\n", 65 | " print(info[i]['Generated by'])\n", 66 | " \n", 67 | "# extract width and height:\n", 68 | "width, height = info[0]['Width'], info[0]['Height']\n", 69 | "print('Image height: {}, width: {}'.format(width, height))" 70 | ] 71 | }, 72 | { 73 | "cell_type": "markdown", 74 | "metadata": {}, 75 | "source": [ 76 | "## Filter localizations\n", 77 | "\n", 78 | "Filter localizations, i.e., via sx and sy: Remove all localizations that are not within a circle around a center position." 79 | ] 80 | }, 81 | { 82 | "cell_type": "code", 83 | "execution_count": 3, 84 | "metadata": {}, 85 | "outputs": [ 86 | { 87 | "name": "stdout", 88 | "output_type": "stream", 89 | "text": [ 90 | "Length of locs before filtering 11975, after filtering 9864.\n" 91 | ] 92 | } 93 | ], 94 | "source": [ 95 | "sx_center = 0.82\n", 96 | "sy_center = 0.82\n", 97 | "\n", 98 | "radius = 0.04 \n", 99 | "\n", 100 | "to_keep = (locs.sx-sx_center)**2 + (locs.sy-sy_center)**2 < radius**2\n", 101 | "\n", 102 | "filtered_locs = locs[to_keep]\n", 103 | "print('Length of locs before filtering {}, after filtering {}.'.format(len(locs),len(filtered_locs)))" 104 | ] 105 | }, 106 | { 107 | "cell_type": "markdown", 108 | "metadata": {}, 109 | "source": [ 110 | "## Saving localizations\n", 111 | "Add new info to the yaml file and save everything." 112 | ] 113 | }, 114 | { 115 | "cell_type": "code", 116 | "execution_count": 4, 117 | "metadata": {}, 118 | "outputs": [ 119 | { 120 | "name": "stdout", 121 | "output_type": "stream", 122 | "text": [ 123 | "9864 locs saved to testdata_locs_jupyter.hdf5.\n" 124 | ] 125 | } 126 | ], 127 | "source": [ 128 | "import os.path as _ospath\n", 129 | "# Create a new dictionary for the new info\n", 130 | "new_info = {}\n", 131 | "new_info[\"Generated by\"] = \"Picasso Jupyter Notebook\"\n", 132 | "new_info[\"Filtered\"] = 'Circle'\n", 133 | "new_info[\"sx_center\"] = sx_center\n", 134 | "new_info[\"sy_center\"] = sy_center\n", 135 | "new_info[\"radius\"] = radius\n", 136 | "\n", 137 | "info.append(new_info)\n", 138 | "\n", 139 | "base, ext = _ospath.splitext(path)\n", 140 | "\n", 141 | "new_path = base+'_jupyter'+ext\n", 142 | "\n", 143 | "\n", 144 | "io.save_locs(new_path, filtered_locs, info)\n", 145 | "\n", 146 | "print('{} locs saved to {}.'.format(len(filtered_locs), new_path))" 147 | ] 148 | }, 149 | { 150 | "cell_type": "markdown", 151 | "metadata": {}, 152 | "source": [ 153 | "## Manually export images\n", 154 | "Use the picasso functions to render images." 155 | ] 156 | }, 157 | { 158 | "cell_type": "code", 159 | "execution_count": 5, 160 | "metadata": {}, 161 | "outputs": [], 162 | "source": [ 163 | "# Get minimum / maximum localizations to define the ROI to be rendered \n", 164 | "import numpy as np\n", 165 | "from picasso import render\n", 166 | "import matplotlib.pyplot as plt\n", 167 | "\n", 168 | "x_min = np.min(locs.x) \n", 169 | "x_max = np.max(locs.x)\n", 170 | "y_min = np.min(locs.y)\n", 171 | "y_max = np.max(locs.y)\n", 172 | "\n", 173 | "viewport = (y_min, x_min), (y_max, x_max)\n", 174 | "oversampling = 10\n", 175 | "len_x, image = render.render(locs, viewport = viewport, oversampling=oversampling, blur_method='smooth')\n", 176 | "plt.imsave('test.png', image, cmap='hot', vmax=10)\n", 177 | "\n", 178 | "# Cutom ROI with higher oversampling\n", 179 | "viewport = (5, 5), (10, 10)\n", 180 | "oversampling = 20\n", 181 | "len_x, image = render.render(locs, viewport = viewport, oversampling=oversampling, blur_method='smooth')\n", 182 | "plt.imsave('test_zoom.png', image, cmap='hot', vmax=10)" 183 | ] 184 | }, 185 | { 186 | "cell_type": "markdown", 187 | "metadata": {}, 188 | "source": [ 189 | "## Calculate kinetics\n", 190 | "Use the picasso functions to calculate kinetics." 191 | ] 192 | }, 193 | { 194 | "cell_type": "code", 195 | "execution_count": 7, 196 | "metadata": {}, 197 | "outputs": [ 198 | { 199 | "name": "stdout", 200 | "output_type": "stream", 201 | "text": [ 202 | "Average bright time 2.10 frames\n", 203 | "Average dark time 458.96 frames\n", 204 | "------\n", 205 | "ON Measured 630.49 ms \t Simulated 500.00 ms\n", 206 | "OFF Measured 137688.98 ms \t Simulated 125000.00 ms\n" 207 | ] 208 | } 209 | ], 210 | "source": [ 211 | "from picasso import postprocess\n", 212 | "\n", 213 | "# Note: to calculate dark times you need picked localizations of single binding sites\n", 214 | "path = 'testdata_locs_picked_single.hdf5'\n", 215 | "picked_locs, info = io.load_locs(path)\n", 216 | "\n", 217 | "# Link localizations and calcualte dark times\n", 218 | "linked_locs = postprocess.link(picked_locs, info, r_max=0.05, max_dark_time=1)\n", 219 | "linked_locs_dark = postprocess.compute_dark_times(linked_locs)\n", 220 | "\n", 221 | "print('Average bright time {:.2f} frames'.format(np.mean(linked_locs_dark.n)))\n", 222 | "print('Average dark time {:.2f} frames'.format(np.mean(linked_locs_dark.dark)))\n", 223 | "\n", 224 | "# Compare with simulation settings:\n", 225 | "integration_time = info[0]['Camera.Integration Time']\n", 226 | "tau_b = info[0]['PAINT.taub']\n", 227 | "k_on = info[0]['PAINT.k_on']\n", 228 | "imager = info[0]['PAINT.imager']\n", 229 | "tau_d = 1/(k_on*imager)*10**9*1000\n", 230 | "\n", 231 | "print('------')\n", 232 | "\n", 233 | "print('ON Measured {:.2f} ms \\t Simulated {:.2f} ms'.format(np.mean(linked_locs_dark.n)*integration_time, tau_b))\n", 234 | "print('OFF Measured {:.2f} ms \\t Simulated {:.2f} ms'.format(np.mean(linked_locs_dark.dark)*integration_time, tau_d))\n" 235 | ] 236 | } 237 | ], 238 | "metadata": { 239 | "kernelspec": { 240 | "display_name": "Python [conda env:picasso]", 241 | "language": "python", 242 | "name": "conda-env-picasso-py" 243 | }, 244 | "language_info": { 245 | "codemirror_mode": { 246 | "name": "ipython", 247 | "version": 3 248 | }, 249 | "file_extension": ".py", 250 | "mimetype": "text/x-python", 251 | "name": "python", 252 | "nbconvert_exporter": "python", 253 | "pygments_lexer": "ipython3", 254 | "version": "3.5.6" 255 | } 256 | }, 257 | "nbformat": 4, 258 | "nbformat_minor": 1 259 | } 260 | -------------------------------------------------------------------------------- /samples/egfr_mols.hdf5: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jungmannlab/picasso/7ada94433f6b189a929008e14d42027a6da8ced3/samples/egfr_mols.hdf5 -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | from setuptools import setup 2 | 3 | with open("requirements.txt") as requirements_file: 4 | requirements = [line for line in requirements_file] 5 | 6 | with open("readme.rst", encoding="utf-8") as readme_file: 7 | long_description = readme_file.read() 8 | 9 | setup( 10 | name="picassosr", 11 | version="0.8.0", 12 | author="Joerg Schnitzbauer, Maximilian T. Strauss, Rafal Kowalewski", 13 | author_email=("joschnitzbauer@gmail.com, straussmaximilian@gmail.com, rafalkowalewski998@gmail.com"), 14 | url="https://github.com/jungmannlab/picasso", 15 | long_description=long_description, 16 | long_description_content_type="text/x-rst", 17 | packages=["picasso", "picasso.gui", "picasso.gui.plugins", "picasso.server", "picasso.ext"], 18 | entry_points={ 19 | "console_scripts": ["picasso=picasso.__main__:main"], 20 | }, 21 | install_requires=requirements + ["PyImarisWriter==0.7.0; sys_platform=='win32'"], 22 | classifiers=[ 23 | "Programming Language :: Python", 24 | "Programming Language :: Python :: 3.10", 25 | "License :: OSI Approved :: MIT License", 26 | "Operating System :: OS Independent", 27 | ], 28 | package_data={ 29 | "picasso": [ 30 | "gui/icons/*.ico", 31 | "gui/icons/*.png", 32 | "config_template.yaml", 33 | ] 34 | }, 35 | ) 36 | -------------------------------------------------------------------------------- /tests/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | -------------------------------------------------------------------------------- /tests/data/testdata.raw: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jungmannlab/picasso/7ada94433f6b189a929008e14d42027a6da8ced3/tests/data/testdata.raw -------------------------------------------------------------------------------- /tests/data/testdata_locs.hdf5: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jungmannlab/picasso/7ada94433f6b189a929008e14d42027a6da8ced3/tests/data/testdata_locs.hdf5 -------------------------------------------------------------------------------- /tests/test_localize.py: -------------------------------------------------------------------------------- 1 | """ 2 | Some rudimentary tests. 3 | """ 4 | 5 | from picasso import __main__ as main 6 | 7 | 8 | def test_localize(): 9 | """ 10 | Test localization with mle and drift correction 11 | """ 12 | import argparse 13 | 14 | import os 15 | 16 | cwd = os.getcwd() 17 | print(cwd) 18 | 19 | parser = argparse.ArgumentParser() 20 | args = parser.parse_args() 21 | 22 | args.files = "./tests/data/testdata.raw" 23 | args.fit_method = "mle" 24 | args.box_side_length = 7 25 | args.gradient = 5000 26 | args.baseline = 0 27 | args.sensitivity = 1 28 | args.gain = 1 29 | args.qe = 1 30 | args.roi = None 31 | args.drift = 100 32 | 33 | for fit_method in ["mle"]: 34 | args.fit_method = fit_method 35 | main._localize(args) 36 | --------------------------------------------------------------------------------