├── .github └── workflows │ └── release.yml ├── .gitignore ├── .image-config.json ├── CellProfiler-Analyst.py ├── LICENSE ├── Properties_README.txt ├── README.md ├── cpa ├── CreateMasterTableWizard.py ├── Integration.mathematica ├── PlateMapBrowser.bat ├── PlateMapBrowser.command ├── __init__.py ├── _classifier.c ├── boxplot.py ├── change_malloc_zone.c ├── classifier.py ├── colorbarpanel.py ├── columnfilter.py ├── cpaprefs.py ├── cpatool.py ├── datamodel.py ├── datatable.py ├── dbconnect.py ├── density.py ├── dimensionreduction.py ├── dirichletintegrate.py ├── errors.py ├── fastgentleboosting.py ├── fastgentleboostingmulticlass.py ├── fastgentleboostingworkermulticlass.py ├── gating.py ├── generalclassifier.py ├── guiutils.py ├── helpmenu.py ├── histogram.py ├── hypergeom.py ├── icons │ ├── __init__.py │ ├── boxplot.png │ ├── brightness.png │ ├── classifier.png │ ├── cpa.icns │ ├── cpa.ico │ ├── cpa_128.png │ ├── cpa_32.png │ ├── data_grid.png │ ├── density.png │ ├── dimensionality.png │ ├── filter.png │ ├── filter.psd │ ├── filter_16.psd │ ├── filter_new.png │ ├── gate.png │ ├── gate.psd │ ├── gate_16.psd │ ├── gate_new.png │ ├── gate_tool.png │ ├── gate_tool.psd │ ├── histogram.png │ ├── image_gallery.png │ ├── image_viewer.png │ ├── lasso.png │ ├── lasso_tool.png │ ├── normalize.png │ ├── pixelclassifier.png │ ├── platemapbrowser.png │ ├── scatter.png │ ├── staticimage.png │ ├── timelapse.png │ ├── timelapse.psd │ └── zoom.png ├── imagecontrolpanel.py ├── imagegallery.py ├── imagelist.py ├── imagepanel.py ├── imagereader.py ├── imagetile.py ├── imagetilesizer.py ├── imagetools.py ├── imageviewer.py ├── incell.py ├── logistic_normal_scoring.py ├── multiclasssql.py ├── multiclasssql_legacy.py ├── mysql_plugins │ ├── classifier_narrow.c │ └── classify.c ├── normalizationtool.py ├── normalize.py ├── parseperkinelmer.py ├── per_image to per_object.py ├── pilfix.py ├── platemappanel.py ├── plateviewer.py ├── polyafit.py ├── properties.py ├── querymaker.py ├── scatter.py ├── scoreall.py ├── scoreall_manual_validation.py ├── scoredialog.py ├── shell.py ├── singleton.py ├── sortbin.py ├── sqltools.py ├── tableviewer.py ├── tests │ ├── 32-bit-grayscale.tif │ ├── __init__.py │ ├── test.py │ ├── test2.py │ ├── test_datamodel.py │ ├── test_dbconnect.py │ ├── test_imagereader.py │ ├── test_multiclasssql.py │ ├── test_properties.py │ ├── test_properties_old_filter.properties │ ├── test_pylab.py │ ├── test_sqltools.py │ ├── test_sqltools_old_filter.properties │ ├── testclassifier.py │ ├── testdbconnect.py │ ├── testimagereader.py │ ├── testscoring.py │ └── threadingexample.py ├── tilecollection.py ├── trainingset.py ├── tsne.py ├── updatechecker.py ├── util │ ├── __init__.py │ ├── frozen_version.py │ └── version.py └── utils.py ├── distribution ├── macos │ ├── CellProfiler-Analyst.spec │ ├── Info.plist │ ├── Makefile │ ├── add-osx-certificate.sh │ ├── entitlements.plist │ └── osx-codesign.sh └── windows │ ├── CellProfiler-Analyst.iss │ └── CellProfiler-Analyst.spec ├── docs ├── LICENSE ├── Makefile ├── README.md ├── build │ └── doctrees │ │ ├── 0_introduction.doctree │ │ ├── 10_histogram_plot.doctree │ │ ├── 11_density_plot.doctree │ │ ├── 12_boxplot.doctree │ │ ├── 13_workspaces.doctree │ │ ├── 14_image_gallery.doctree │ │ ├── 15_normalization_tool.doctree │ │ ├── 1_preliminary_requirements.doctree │ │ ├── 2_installation.doctree │ │ ├── 3_properties_file.doctree │ │ ├── 4_cpa_interface.doctree │ │ ├── 5_classifier.doctree │ │ ├── 6_table_viewer.doctree │ │ ├── 7_image_viewer.doctree │ │ ├── 8_plate_viewer.doctree │ │ ├── 9_scatter_plot.doctree │ │ ├── environment.pickle │ │ └── index.doctree └── source │ ├── 0_introduction.rst │ ├── 10_histogram_plot.rst │ ├── 11_density_plot.rst │ ├── 12_boxplot.rst │ ├── 13_workspaces.rst │ ├── 14_image_gallery.rst │ ├── 15_normalization_tool.rst │ ├── 16_dimensionality_reduction.rst │ ├── 17_FAQ.rst │ ├── 1_preliminary_requirements.rst │ ├── 2_installation.rst │ ├── 3_properties_file.rst │ ├── 4_cpa_interface.rst │ ├── 5_classifier.rst │ ├── 6_table_viewer.rst │ ├── 7_image_viewer.rst │ ├── 8_plate_viewer.rst │ ├── 9_scatter_plot.rst │ ├── __init__.py │ ├── conf.py │ ├── index.rst │ ├── manual.pdf │ └── static │ ├── 01_01.jpg │ ├── 01_02.jpg │ ├── 03_01.jpg │ ├── 03_02.jpg │ ├── 04_01.jpg │ ├── 04_02.jpg │ ├── 04_03.jpg │ ├── 04_04.jpg │ ├── 05_00.jpg │ ├── 05_01.jpg │ ├── 05_02.jpg │ ├── 05_03.jpg │ ├── 05_04.jpg │ ├── 05_04b.jpg │ ├── 05_05.jpg │ ├── 05_06.jpg │ ├── 05_06b.jpg │ ├── 05_07.jpg │ ├── 05_08.jpg │ ├── 05_09.jpg │ ├── 05_09a.jpg │ ├── 05_09b.jpg │ ├── 05_10.jpg │ ├── 05_11.jpg │ ├── 05_11b.jpg │ ├── 05_12.jpg │ ├── 05_13.jpg │ ├── 05_14.jpg │ ├── 05_15.jpg │ ├── 05_16.jpg │ ├── 05_17.jpg │ ├── 05_18.jpg │ ├── 05_19.jpg │ ├── 05_20.jpg │ ├── 05_a.jpg │ ├── 05_b.jpg │ ├── 05_e.jpg │ ├── 05_f.jpg │ ├── 05_y.jpg │ ├── 05_z.jpg │ ├── 06_01.jpg │ ├── 06_02.jpg │ ├── 06_04.jpg │ ├── 07_01.jpg │ ├── 07_02.jpg │ ├── 07_03.jpg │ ├── 07_pic1.jpg │ ├── 08_00.jpg │ ├── 08_001.jpg │ ├── 08_01.jpg │ ├── 08_02.jpg │ ├── 08_03.jpg │ ├── 08_04.jpg │ ├── 08_05.jpg │ ├── 08_06.jpg │ ├── 08_08.jpg │ ├── 08_09.jpg │ ├── 08_10.jpg │ ├── 08_11.jpg │ ├── 08_13.jpg │ ├── 08_14.jpg │ ├── 08_15.jpg │ ├── 08_16.jpg │ ├── 08_x.jpg │ ├── 08_y.jpg │ ├── 08_z.jpg │ ├── 09_01.jpg │ ├── 09_02.jpg │ ├── 09_z.jpg │ ├── 10_01.jpg │ ├── 11_01.jpg │ ├── 12_01.jpg │ ├── 14_01.jpg │ ├── 15_01.jpg │ ├── 16_01.jpg │ ├── 5_c.jpg │ └── 5_d.jpg ├── manual └── cpa_manual.doc ├── requirements.txt └── setup.py /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: create-release 2 | on: 3 | push: 4 | # branches: [ master ] 5 | tags: 6 | - "*" 7 | 8 | jobs: 9 | build: 10 | name: build 11 | runs-on: ${{ matrix.os }} 12 | steps: 13 | - if: ${{ matrix.os == 'windows-2019' }} 14 | uses: actions/cache@v2 15 | with: 16 | path: ~\AppData\Local\pip\Cache 17 | key: ${{ runner.os }}-pip-${{ hashFiles('setup.py') }} 18 | restore-keys: | 19 | ${{ runner.os }}-pip- 20 | - if: ${{ matrix.os == 'macos-10.15' }} 21 | uses: actions/cache@v2 22 | with: 23 | path: ~/Library/Caches/pip 24 | key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }} 25 | restore-keys: | 26 | ${{ runner.os }}-pip- 27 | - uses: actions/checkout@v2 28 | - uses: actions/setup-python@v2 29 | with: 30 | architecture: x64 31 | python-version: ${{ matrix.python-version }} 32 | - uses: actions/setup-java@v1 33 | with: 34 | java-version: '14.0.1' # The JDK version to make available on the path. 35 | java-package: jdk 36 | architecture: x64 37 | - run: | 38 | pip install --upgrade pip setuptools wheel 39 | pip install numpy 40 | pip install pyinstaller==4.3 41 | - env: 42 | LDFLAGS: -L/usr/local/opt/openssl/lib 43 | CERTIFICATE_OSX_APPLICATION: ${{ secrets.CERTIFICATE_OSX_APPLICATION }} 44 | CERTIFICATE_PASSWORD: ${{ secrets.CERTIFICATE_PASSWORD }} 45 | if: ${{ matrix.os == 'macos-10.15' }} 46 | run: | 47 | sed -i '' 's/4.0.0/3.0.4/' Info.plist 48 | brew install mysql 49 | git clone https://github.com/CellProfiler/python-javabridge.git 50 | cd python-javabridge/ 51 | git checkout print 52 | pip install -e . 53 | cd .. 54 | make 55 | chmod +x add-osx-certificate.sh && ./add-osx-certificate.sh 56 | chmod +x osx-codesign.sh && ./osx-codesign.sh 57 | ditto -ck --keepParent --rsrc --sequesterRsrc ./dist/CellProfiler-Analyst.app ./dist/CellProfiler-Analyst-macOS-3.0.4.zip 58 | working-directory: ./distribution/macos 59 | - env: 60 | JDK_HOME: C:\hostedtoolcache\windows\jdk\14.0.1\x64 61 | if: ${{ matrix.os == 'windows-2019' }} 62 | run: | 63 | pip install cython 64 | pip install --editable . 65 | - if: ${{ matrix.os == 'windows-2019' }} 66 | run: | 67 | pyinstaller distribution/windows/CellProfiler-Analyst.spec 68 | iscc /dMyAppVersion="3.0.4" "distribution/windows/CellProfiler-Analyst.iss" 69 | - if: ${{ matrix.os == 'macos-10.15' }} 70 | uses: actions/upload-artifact@v1 71 | with: 72 | name: CellProfiler-Analyst-macOS-3.0.4.zip 73 | path: ./distribution/macos/dist/CellProfiler-Analyst-macOS-3.0.4.zip 74 | - if: ${{ matrix.os == 'windows-2019' }} 75 | uses: actions/upload-artifact@v2 76 | with: 77 | name: CellProfiler-Analyst-Windows-3.0.4.exe 78 | path: ./distribution/windows/Output/CellProfiler-Analyst-Windows-3.0.4.exe 79 | strategy: 80 | matrix: 81 | os: [macos-10.15, windows-2019] 82 | python-version: [ "3.8" ] 83 | upload: 84 | name: upload 85 | needs: build 86 | runs-on: ubuntu-latest 87 | steps: 88 | - uses: actions/checkout@v2 89 | - env: 90 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 91 | id: create_release 92 | uses: actions/create-release@v1 93 | with: 94 | draft: true 95 | prerelease: true 96 | release_name: ${{ github.ref }} 97 | tag_name: ${{ github.ref }} 98 | - uses: actions/download-artifact@v1 99 | with: 100 | name: CellProfiler-Analyst-macOS-3.0.4.zip 101 | path: ./ 102 | - uses: actions/download-artifact@v1 103 | with: 104 | name: CellProfiler-Analyst-Windows-3.0.4.exe 105 | path: ./ 106 | - env: 107 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 108 | uses: actions/upload-release-asset@v1 109 | with: 110 | asset_content_type: application/zip 111 | asset_name: CellProfiler-Analyst-macOS-3.0.4.zip 112 | asset_path: /home/runner/work/CellProfiler-Analyst/CellProfiler-Analyst/CellProfiler-Analyst-macOS-3.0.4.zip 113 | upload_url: ${{ steps.create_release.outputs.upload_url }} 114 | - env: 115 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 116 | uses: actions/upload-release-asset@v1 117 | with: 118 | asset_content_type: application/exe 119 | asset_name: CellProfiler-Analyst-Windows-3.0.4.exe 120 | asset_path: /home/runner/work/CellProfiler-Analyst/CellProfiler-Analyst/CellProfiler-Analyst-Windows-3.0.4.exe 121 | upload_url: ${{ steps.create_release.outputs.upload_url }} 122 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | **/.DS_Store 2 | **/Thumbs.db 3 | *.dll 4 | *.exe 5 | *.jar 6 | *.pdb 7 | *.pyc 8 | *.pyd 9 | *.so 10 | *\# 11 | *~ 12 | *.egg 13 | .eggs/ 14 | build 15 | dist 16 | output 17 | /cpa/_description.py 18 | /cpa/version.iss 19 | /images 20 | **/.idea 21 | .vscode 22 | .*.swp 23 | /docs/build/html 24 | -------------------------------------------------------------------------------- /.image-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "storePath": "/images", 3 | "wwwRoot": "/", 4 | "grammars": { 5 | "Markdown": { 6 | "url": "![](${url})" 7 | }, 8 | "GitHub Markdown": { 9 | "url": "![](${url})" 10 | }, 11 | "HTML": { 12 | "url": "\"\"" 13 | } 14 | } 15 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The BSD 3-Clause License 2 | 3 | Copyright © 2003 - 2024 Broad Institute, Inc. All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions are met: 7 | 8 | 1. Redistributions of source code must retain the above copyright notice, 9 | this list of conditions and the following disclaimer. 10 | 11 | 2. Redistributions in binary form must reproduce the above copyright 12 | notice, this list of conditions and the following disclaimer in the 13 | documentation and/or other materials provided with the distribution. 14 | 15 | 3. Neither the name of the Broad Institute, Inc. nor the names of its 16 | contributors may be used to endorse or promote products derived from 17 | this software without specific prior written permission. 18 | 19 | THIS SOFTWARE IS PROVIDED “AS IS.” BROAD MAKES NO EXPRESS OR IMPLIED 20 | REPRESENTATIONS OR WARRANTIES OF ANY KIND REGARDING THE SOFTWARE AND 21 | COPYRIGHT, INCLUDING, BUT NOT LIMITED TO, WARRANTIES OF MERCHANTABILITY, 22 | FITNESS FOR A PARTICULAR PURPOSE, CONFORMITY WITH ANY DOCUMENTATION, 23 | NONINFRINGEMENT, OR THE ABSENCE OF LATENT OR OTHER DEFECTS, WHETHER OR NOT 24 | DISCOVERABLE. IN NO EVENT SHALL BROAD, THE COPYRIGHT HOLDERS, OR CONTRIBUTORS 25 | BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 26 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO PROCUREMENT OF SUBSTITUTE 27 | GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 | HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 30 | OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF, HAVE REASON TO KNOW, OR IN 31 | FACT SHALL KNOW OF THE POSSIBILITY OF SUCH DAMAGE. 32 | 33 | If, by operation of law or otherwise, any of the aforementioned warranty 34 | disclaimers are determined inapplicable, your sole remedy, regardless of the 35 | form of action, including, but not limited to, negligence and strict 36 | liability, shall be replacement of the software with an updated version if one 37 | exists. 38 | 39 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |
2 |

3 |
4 | ----------------- 5 | 6 | | **`Version`** | **`Documentation`** | **`Forum`** | 7 | |---------------|----------------|-----------------| 8 | | [![Build Status](https://img.shields.io/badge/version-3.0.4-green.svg)](https://cellprofileranalyst.org/releases) | [![Build Status](https://img.shields.io/badge/documentation-3.0-brightgreen.svg)](https://cellprofiler-manual.s3.amazonaws.com/CellProfiler-Analyst-3.0.0/index.html) | [![Build Status](https://img.shields.io/badge/forum-CPA-blue.svg)](https://forum.image.sc/tag/cellprofiler-analyst) | 9 | 10 | **CellProfiler Analyst** allows interactive exploration and analysis of data, 11 | particularly from high-throughput, image-based experiments. Included is a 12 | supervised machine learning system which can be trained to recognize complex 13 | and subtle phenotypes, for automatic scoring of millions of cells. 14 | 15 |
16 |

17 |
18 | 19 | ## Learn more about CellProfiler Analyst 20 | This is the developer site for CellProfiler Analyst. 21 | The regular home page for CellProfiler Analyst is here: https://cellprofileranalyst.org/ 22 | 23 | ## Installation 24 | 25 | Download [CellProfiler Analyst](https://cellprofileranalyst.org/releases) 26 | 27 | When running from source, CellProfiler Analyst requires [JDK 1.8](http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html) to be installed (not just JRE). 28 | Check the Java path. 29 | 30 | Please note that this is the development branch of CPA and it will be updated on regular basis. 31 | 32 | Find all releases [here](https://cellprofileranalyst.org/previously-released-versions-cellprofiler-analyst). 33 | 34 | For a head start, download example dataset here: [Example Dataset for CPA (zipped)](http://d1zymp9ayga15t.cloudfront.net/content/Examplezips/cpa_2.0_example.zip) 35 | 36 | ## Developer build 37 | 38 | Building CPA on your machine requires CellProfiler dependencies. Check the wiki 39 | for more detailed installation instructions. 40 | 41 | * Pandas 42 | * Seaborn 43 | * Scikit-learn 44 | * Python-Javabridge 45 | * Verlib 46 | * Python-bioformats 47 | 48 | ## Documentation 49 | 50 | > https://cellprofileranalyst.org/manuals 51 | 52 | ## Wiki 53 | 54 | > https://github.com/CellProfiler/CellProfiler-Analyst/wiki 55 | 56 | ## Forum 57 | 58 | CellProfiler Analyst development is discussed on the CellProfiler Forum 59 | list. 60 | 61 | > https://forum.image.sc/tag/cellprofiler-analyst/ 62 | 63 | ## How to file new issues 64 | 65 | Please attach sufficient information to reproduce the bug. For many 66 | bugs, it is appropriate to attach a properties file, a training set, 67 | or a screenshot. 68 | 69 | ## How to cite 70 | 71 | *David Dao, Adam N Fraser, Jane Hung, Vebjorn Ljosa, Shantanu Singh and Anne E Carpenter* 72 | __[CellProfiler Analyst: interactive data exploration, analysis and classification of large biological image sets][bioinformatics]__ 73 | Bioinformatics (2016) doi:10.1093/bioinformatics/btw390 74 | 75 | *Thouis R Jones, In Han Kang, Douglas B Wheeler, Robert A Lindquist, Adam Papallo, David M Sabatini, Polina Golland and Anne E Carpenter*
76 | __[CellProfiler Analyst: data exploration and analysis software for complex image-based screens][bmc]__
77 | BMC Bioinformatics (2008) doi:10.1186/1471-2105-9-482 78 | 79 | 80 | [bioinformatics]: http://bioinformatics.oxfordjournals.org/content/early/2016/07/24/bioinformatics.btw390 81 | [bmc]: https://bmcbioinformatics.biomedcentral.com/articles/10.1186/1471-2105-9-482 82 | 83 | 84 | ## Contributors 85 | 86 | David Dao, Adam Fraser, David Stirling, Pearl Ryder, Beth Cimini, Vebjorn Ljosa, Thouis R. Jones, Jane Hung, Shantanu Singh, Mark Bray, Lee Kamentsky, Anne Carpenter 87 | 88 | ## Kudos 89 | 90 | David Logan, Allen Goodman, Alison Kozol, Mohammad Hossein Rohban 91 | 92 | *Copyright 2021, The Broad Institute of MIT and Harvard. 93 | Distributed under the BSD license.* 94 | -------------------------------------------------------------------------------- /cpa/Integration.mathematica: -------------------------------------------------------------------------------- 1 | FullSimplify[Integrate[PDF[BetaDistribution[s*a,s*b],x]*CDF[BetaDistribution[a,b],x],{x,0,1}], {a>0,b>0,b \[NotElement] Integers, s>1}] 2 | 3 | 4 | In[1]:= Integrate[PDF[BetaDistribution[c,d],x]*CDF[BetaDistribution[a,b],x],{x,0,1},Assumptions->{a>0,b>0,c>0,d>0}] 5 | 6 | Out[1]= (Gamma[a] Gamma[a + c] Gamma[d] 7 | 8 | > HypergeometricPFQRegularized[{a, 1 - b, a + c}, {1 + a, a + c + d}, 1]) 9 | 10 | > / (Beta[a, b] Beta[c, d]) 11 | 12 | http://functions.wolfram.com/HypergeometricFunctions/HypergeometricPFQRegularized/02/0001/MainEq1.gif 13 | 14 | 15 | Integrate[PDF[BetaDistribution[111.52056534719972, 0.31516669716616263],x]*CDF[BetaDistribution[90.520565347199721, 0.31516669716616263],x],{x,0,1}] 16 | 17 | 18 | Integrate[PDF[BetaDistribution[a+c,b+d],x]*CDF[BetaDistribution[a,b],x],{x,0,1},Assumptions->{a>0,b>0,c>=0,d>=0,(c+d)>0,c in Integers, d in Integers}] 19 | 20 | 21 | A useful identity: 22 | HypergeometricPFQ[{a, b, c}, {d, a - 1}, 1] == ((Gamma[d] Gamma[d - b 23 | - c])/(Gamma[d - b] Gamma[d - c])) (1 - (b c)/((a - 1) (1 + b + c - 24 | d))) /; Re[d - b - c] > 1 25 | 26 | 27 | Combined with: 28 | (a_i - 1) F = (a_i - a_j - 1) F(a_i - 1) + a_j F(a_i - 1, a_j + 1) 29 | 30 | 31 | FullSimplify[Integrate[w^(-1-c) Hypergeometric2F1[a+c,1-d, a+c+b, 1/w], {w,1,Infinity}], {a>0, b>0, c>0, d>0}] 32 | FullSimplify[Integrate[w^(a-1) Hypergeometric2F1[a+c,1-b, a+c+d, w], {w,0,1}], {a>0, b>0, c>0, d>0}] 33 | 34 | FullSimplify[Integrate[p^(b+d-1) (1-p)^(c+b-1) AppellF1[b, a+b+c+d-2, 1-a, b+c, 1-p, 1-p^2], {p, 0, 1}], {a>0, b>0, c>0, d>0}] -------------------------------------------------------------------------------- /cpa/PlateMapBrowser.bat: -------------------------------------------------------------------------------- 1 | cd /d %~dp0 2 | python plateviewer.py -------------------------------------------------------------------------------- /cpa/PlateMapBrowser.command: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | cd `dirname $0` 3 | 4 | python plateviewer.py 5 | 6 | -------------------------------------------------------------------------------- /cpa/__init__.py: -------------------------------------------------------------------------------- 1 | from cpa.util.version import __version__ 2 | 3 | from . import properties, util 4 | from . import dbconnect 5 | 6 | p = properties.Properties() 7 | db = dbconnect.DBConnect() 8 | -------------------------------------------------------------------------------- /cpa/_classifier.c: -------------------------------------------------------------------------------- 1 | /* _classifier.c - */ 2 | 3 | // Compile (for testing) with: 4 | // python setup.py build_ext -i 5 | 6 | #include "sqlite3.h" 7 | #include "Python.h" 8 | #include "numpy/arrayobject.h" 9 | #include 10 | 11 | #define MAX_STUMPS 100 // Default limit for sqlite3 12 | #define MAX_CLASSES 100 13 | 14 | static struct { 15 | int num_classes; 16 | int num_stumps; 17 | double thresholds[MAX_STUMPS]; 18 | double stump_weights_a[MAX_STUMPS][MAX_CLASSES]; 19 | double stump_weights_b[MAX_STUMPS][MAX_CLASSES]; 20 | int valid; 21 | } classifier_data; 22 | 23 | #define TYPE_ERROR(str, fail_label) {PyErr_SetString(PyExc_TypeError, (str)); goto fail_label;} 24 | #define VALUE_ERROR(str, fail_label) {PyErr_SetString(PyExc_ValueError, (str)); goto fail_label;} 25 | 26 | static PyObject *setup_classifier(PyObject *self, PyObject *args) 27 | { 28 | PyObject *weak_learners; 29 | PyArrayObject *wl_array; 30 | int i, j; 31 | 32 | if (! PyArg_ParseTuple(args, "O", &weak_learners)) 33 | TYPE_ERROR("one argument required", fail_1); 34 | 35 | wl_array = (PyArrayObject *) PyArray_FROM_OTF(weak_learners, NPY_DOUBLE, NPY_IN_ARRAY); 36 | if (! wl_array) 37 | return NULL; 38 | 39 | if (wl_array->nd != 2) 40 | TYPE_ERROR("argument must be 2D array of floats (or convertable to same)", fail_2); 41 | 42 | if ((PyArray_DIM(wl_array, 1) % 2) == 0) 43 | TYPE_ERROR("argument must have an odd dimenions along axis 1", fail_2); 44 | 45 | classifier_data.num_stumps = PyArray_DIM(wl_array, 0); 46 | classifier_data.num_classes = PyArray_DIM(wl_array, 1) / 2; 47 | 48 | if (classifier_data.num_stumps > MAX_STUMPS) 49 | VALUE_ERROR("maximum number of stumps (100) exceeded.", fail_2); 50 | 51 | for (i = 0; i < classifier_data.num_stumps; i++) { 52 | classifier_data.thresholds[i] = * (double *) PyArray_GETPTR2(wl_array, i, 0); 53 | 54 | for (j = 0; j < classifier_data.num_classes; j++) { 55 | classifier_data.stump_weights_a[i][j] = * (double *) PyArray_GETPTR2(wl_array, i, 1 + j); 56 | classifier_data.stump_weights_b[i][j] = * (double *) PyArray_GETPTR2(wl_array, i, 1 + classifier_data.num_classes + j); 57 | } 58 | } 59 | 60 | classifier_data.valid = 1; 61 | 62 | Py_DECREF(wl_array); 63 | Py_INCREF(Py_None); 64 | return Py_None; 65 | 66 | fail_2: 67 | Py_DECREF(wl_array); 68 | fail_1: 69 | return NULL; 70 | } 71 | 72 | static void c_classifier(sqlite3_context* context, int argc, sqlite3_value** argv) 73 | { 74 | int stumps[MAX_STUMPS], i, j; 75 | double best_score = -3 * classifier_data.num_stumps; 76 | int best_class = 0; 77 | 78 | if (! classifier_data.valid) { 79 | sqlite3_result_error(context, "setup_classifier() must be called before using classifier() in SQL.", -1); 80 | return; 81 | } 82 | 83 | if (argc != classifier_data.num_stumps) { 84 | sqlite3_result_error(context, "The number of arguments to classifier() must be the same as the number passed to setup_classifier()", -1); 85 | return; 86 | } 87 | 88 | // compute the stumps 89 | for (i = 0; i < argc; i++) { 90 | stumps[i] = sqlite3_value_double(argv[i]) > classifier_data.thresholds[i]; 91 | } 92 | 93 | // compute the scores 94 | for (i = 0; i < classifier_data.num_classes; i++) { 95 | double score = 0.0; 96 | for (j = 0; j < classifier_data.num_stumps; j++) 97 | score += stumps[j] ? classifier_data.stump_weights_a[j][i] : classifier_data.stump_weights_b[j][i]; 98 | if (score > best_score) { 99 | best_score = score; 100 | best_class = i; 101 | } 102 | } 103 | 104 | sqlite3_result_int(context, best_class + 1); 105 | } 106 | 107 | 108 | // NB: this will blow up if the pysqlite_Connection structure changes. 109 | // This is just the first few bytes of the structure, so we can get the db. 110 | typedef struct 111 | { 112 | PyObject_HEAD 113 | sqlite3* db; 114 | } pysqlite_Connection; 115 | 116 | static PyObject* create_classifier_function(PyObject* self, PyObject* args) 117 | { 118 | int rc; 119 | pysqlite_Connection *conn; 120 | 121 | if (!PyArg_ParseTuple(args, "O", &conn)) 122 | return NULL; 123 | 124 | if (SQLITE_VERSION_NUMBER >= 3006020) 125 | sqlite3_initialize(); 126 | rc = sqlite3_create_function(conn->db, "classifier", -1, SQLITE_UTF8, NULL, c_classifier, NULL, NULL); 127 | 128 | if (rc != SQLITE_OK) { 129 | return NULL; 130 | } else { 131 | Py_INCREF(Py_None); 132 | return Py_None; 133 | } 134 | } 135 | 136 | static PyMethodDef ClassifierMethods[] = { 137 | {"setup_classifier", setup_classifier, METH_VARARGS, "Set up a run of the classifier function"}, 138 | {"create_classifier_function", create_classifier_function, METH_VARARGS, "Create the C classifier function on a connection."}, 139 | {NULL, NULL, 0, NULL} 140 | }; 141 | 142 | 143 | #ifdef __cplusplus 144 | extern "C" 145 | #endif 146 | PyMODINIT_FUNC init_classifier(void) 147 | { 148 | PyObject *m; 149 | 150 | classifier_data.valid = 0; 151 | 152 | m = Py_InitModule("_classifier", ClassifierMethods); 153 | import_array(); 154 | 155 | if (m == NULL) 156 | return; 157 | } 158 | -------------------------------------------------------------------------------- /cpa/change_malloc_zone.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | void *(*system_malloc)(malloc_zone_t *zone, size_t size); 6 | void (*system_free)(malloc_zone_t *zone, void *ptr); 7 | 8 | #define KEEP_SIZE 4096 9 | #define KEEP_NUM 100 10 | static void* keep_list[KEEP_NUM]; 11 | static void** tail; 12 | 13 | 14 | void *mymalloc(malloc_zone_t *zone, size_t size) 15 | { 16 | if (size >= KEEP_SIZE) { // big? 17 | if (tail > keep_list) { // available? 18 | void **entry; 19 | for (entry = tail - 1; entry >= keep_list; entry--) { 20 | if (zone->size(zone, *entry) >= size) { 21 | void *retval = *entry; 22 | tail--; 23 | *entry = *tail; 24 | //fprintf(stderr, "fulfill %d w/ %d, %d on list\n", size, zone->size(zone, *entry), keep_list - tail); 25 | return retval; 26 | } 27 | } 28 | } 29 | } 30 | 31 | // fprintf(stderr, "malloc %d\n", size); 32 | return system_malloc(zone, size); 33 | } 34 | 35 | void myfree(malloc_zone_t *zone, void *ptr) 36 | { 37 | size_t sz = zone->size(zone, ptr); 38 | if (sz >= KEEP_SIZE) { // big? 39 | if ((tail - keep_list) < KEEP_NUM) { // space available? 40 | *tail = ptr; 41 | tail++; 42 | //fprintf(stderr, "kept %d, %d on list\n", sz, keep_list - tail); 43 | return; 44 | } 45 | } 46 | // fprintf(stderr, "free %d\n", sz); 47 | system_free(zone, ptr); 48 | } 49 | 50 | void setup() 51 | { 52 | malloc_zone_t * zone = malloc_default_zone(); 53 | 54 | tail = keep_list; 55 | system_malloc = zone->malloc; 56 | zone->malloc = mymalloc; 57 | system_free = zone->free; 58 | zone->free = myfree; 59 | } 60 | 61 | void teardown() 62 | { 63 | malloc_zone_t * zone = malloc_default_zone(); 64 | 65 | while (tail > keep_list) { 66 | tail--; 67 | system_free(zone, *tail); 68 | } 69 | 70 | zone->malloc = system_malloc; 71 | zone->free = system_free; 72 | } 73 | -------------------------------------------------------------------------------- /cpa/cpaprefs.py: -------------------------------------------------------------------------------- 1 | import wx 2 | 3 | CHECK_FOR_UPDATES = 'CheckForUpdates' 4 | CHECKFORNEWVERSIONS = 'CheckForNewVersions' 5 | SKIPVERSION = 'SkipVersion' 6 | 7 | def get_config(): 8 | try: 9 | config = wx.Config.Get(False) 10 | except wx.PyNoAppError: 11 | app = wx.App(0) 12 | config = wx.Config.Get(False) 13 | if not config: 14 | wx.Config.Set(wx.Config('CellProfilerAnalyst','BroadInstitute','CellProfilerAnalystLocal.cfg','CellProfilerAnalystGlobal.cfg',wx.CONFIG_USE_LOCAL_FILE)) 15 | config = wx.Config.Get() 16 | return config 17 | 18 | def get_check_new_versions(): 19 | if not get_config().Exists(CHECKFORNEWVERSIONS): 20 | # should this check for whether we can actually save preferences? 21 | return True 22 | return get_config().ReadBool(CHECKFORNEWVERSIONS) 23 | 24 | def set_check_new_versions(val): 25 | old_val = get_check_new_versions() 26 | get_config().WriteBool(CHECKFORNEWVERSIONS, bool(val)) 27 | # If the user turns on version checking, they probably don't want 28 | # to skip versions anymore. 29 | if val and (not old_val): 30 | set_skip_version(0) 31 | 32 | def get_skip_version(): 33 | if not get_config().Exists(SKIPVERSION): 34 | return 0 35 | return get_config().ReadInt(SKIPVERSION) 36 | 37 | def set_skip_version(ver): 38 | get_config().WriteInt(SKIPVERSION, ver) 39 | 40 | def get_check_update(): 41 | if not get_config().Exists(CHECK_FOR_UPDATES): 42 | return "Never" 43 | return get_config().Read(CHECK_FOR_UPDATES) 44 | 45 | 46 | def get_check_update_bool(): 47 | if not get_config().Exists(CHECK_FOR_UPDATES): 48 | return True 49 | update_str = get_config().Read(CHECK_FOR_UPDATES) 50 | if update_str == "Disabled": 51 | return False 52 | else: 53 | return True 54 | 55 | 56 | def set_check_update(val): 57 | if str(val) == "False": 58 | val = "Disabled" 59 | elif str(val) == "True": 60 | val = "Never" 61 | get_config().Write(CHECK_FOR_UPDATES, val) 62 | -------------------------------------------------------------------------------- /cpa/cpatool.py: -------------------------------------------------------------------------------- 1 | ''' 2 | ''' 3 | import wx 4 | 5 | class CPATool(object): 6 | '''Any tool or visualization whose state may be saved and recalled from a 7 | series of settings and corresponding values.''' 8 | def __init__(self): 9 | # Set the name of the tool based on the class name. A subclass can 10 | # override this by declaring a tool_name attribute in the class 11 | # definition 12 | if 'tool_name' not in self.__dict__: 13 | self.tool_name = self.__class__.__name__ 14 | 15 | def save_settings(self): 16 | '''Override this method when defining a new tool or visualization. 17 | 18 | save_settings is called when saving a workspace to file. 19 | 20 | returns a dictionary mapping setting names to values encoded as strings 21 | ''' 22 | raise NotImplementedError 23 | 24 | def load_settings(self, settings): 25 | '''Override this method when defining a new tool or visualization. 26 | 27 | load_settings is called when loading a workspace from file. 28 | 29 | settings - a dictionary mapping setting names to values encoded as 30 | strings. 31 | ''' 32 | raise NotImplementedError 33 | -------------------------------------------------------------------------------- /cpa/errors.py: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | def show_exception_as_dialog(type, value, tb, raisefurther=True): 5 | """Exception handler that show a dialog.""" 6 | import traceback 7 | import wx 8 | 9 | # if tb: 10 | # print((traceback.format_tb(tb))) 11 | 12 | if isinstance(value, ClearException): 13 | wx.MessageBox(value, value.heading, wx.OK | wx.ICON_ERROR) 14 | else: 15 | from wx.lib.dialogs import ScrolledMessageDialog 16 | lines = ['An error occurred in the program:\n'] 17 | lines += traceback.format_exception_only(type, value) 18 | lines += ['\nTraceback (most recent call last):\n'] 19 | if tb: 20 | lines += traceback.format_tb(tb) 21 | dlg = ScrolledMessageDialog(None, "".join(lines), 'Error', style=wx.DEFAULT_DIALOG_STYLE|wx.RESIZE_BORDER) 22 | dlg.ShowModal() 23 | if raisefurther: 24 | raise value 25 | 26 | 27 | class ClearException(Exception): 28 | """ 29 | AN exception where what happened is so clear that it is 30 | unnecessary to show a stack trace. 31 | 32 | """ 33 | def __init__(self, message, heading='Error', *args, **kwargs): 34 | super(ClearException, self).__init__(message, *args, **kwargs) 35 | self.heading = heading 36 | 37 | 38 | -------------------------------------------------------------------------------- /cpa/fastgentleboostingworkermulticlass.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # 3 | # Worker script called from FastGentleBoosting.py. 4 | 5 | from sys import stdin, stdout, stderr, argv 6 | from numpy import * 7 | 8 | def train_weak_learner(labels, weights, values): 9 | ''' For a multiclass training set, with C classes and N examples, 10 | finds the optimal weak learner in O(M * N logN) time. 11 | Optimality is defined by Eq. 7 of Torralba et al., 'Sharing visual 12 | features...', 2007, IEEE PAMI. 13 | 14 | We differ from Torralba et al. in two ways: 15 | - we do not share a's and b's between classes 16 | - we always solve for the complete set of examples, regardless of label 17 | 18 | Labels should be 1 and -1, only. 19 | label_matrix and weights are NxC. 20 | values is Nx1 21 | ''' 22 | 23 | global order, s_values, s_labels, s_weights, s_weights_times_labels, num_a, den_a, a, b, sless0, sgrtr0, w_below_neg, w_below_pos, w_above_neg, w_above_pos, J 24 | 25 | # Sort labels and weights by values (AKA possible thresholds). By 26 | # default, argsort is not stable, so the results will vary 27 | # slightly with the number of workers. Add kind="mergesort" to 28 | # get a stable sort, which avoids this. 29 | order = argsort(values) 30 | s_values = values[order] 31 | s_labels = labels[order, :] 32 | s_weights = weights[order, :] 33 | 34 | # useful subfunction 35 | num_examples = labels.shape[0] 36 | def tilesum(a): 37 | return tile(sum(a, axis=0), (num_examples, 1)) 38 | 39 | # Equations 9 and 10 of Torralba et al. 40 | s_weights_times_labels = s_weights * s_labels 41 | num_a = (tilesum(s_weights_times_labels) - cumsum(s_weights_times_labels, axis=0)) 42 | den_a = (tilesum(s_weights) - cumsum(s_weights, axis=0)) 43 | den_a[den_a <= 0.0] = 1.0 # avoid div by zero 44 | a = num_a / den_a 45 | b = cumsum(s_weights_times_labels, axis=0) / cumsum(s_weights, axis=0) 46 | 47 | # We need, at each index, the total weights below and above, 48 | # separated by positive and negative label. Below includes the 49 | # current index 50 | sless0 = (s_labels < 0) 51 | sgrtr0 = (s_labels > 0) 52 | w_below_neg = cumsum(s_weights * sless0, axis=0) 53 | w_below_pos = cumsum(s_weights * sgrtr0, axis=0) 54 | w_above_neg = tilesum(s_weights * sless0) - w_below_neg 55 | w_above_pos = tilesum(s_weights * sgrtr0) - w_below_pos 56 | 57 | # Now evaluate the error at each threshold. 58 | # (see Equation 7, and note that we're assuming -1 and +1 for entries in the label matrix. 59 | J = w_below_neg * ((-1 - b)**2) + w_below_pos * ((1 - b)**2) + w_above_neg * ((-1 - a)**2) + w_above_pos * ((1 - a)**2) 60 | J = J.sum(axis=1) 61 | 62 | # Find index of least error 63 | idx = argmin(J) 64 | 65 | # make sure we're at the top of this thresh 66 | while (idx+1 < len(s_values)) and (s_values[idx] == s_values[idx + 1]): 67 | idx += 1 68 | 69 | # return the threshold at that index 70 | return s_values[idx], J[idx], a[idx, :].copy(), b[idx, :].copy() 71 | 72 | def train_classifier(labels, values, iterations): 73 | # make sure these are arrays (not matrices) 74 | labels = array(labels) 75 | values = array(values) 76 | 77 | num_examples = labels.shape[0] 78 | 79 | learners = [] 80 | weights = ones(labels.shape) 81 | output = zeros(labels.shape) 82 | for n in range(iterations): 83 | best_error = float(Infinity) 84 | 85 | for feature_idx in range(values.shape[1]): 86 | val, err, a, b = train_weak_learner(labels, weights, values[:, feature_idx]) 87 | if err < best_error: 88 | best_error = err 89 | best_idx = feature_idx 90 | best_val = val 91 | best_a = a 92 | best_b = b 93 | 94 | delta = values[:, best_idx] > best_val 95 | delta.shape = (len(delta), 1) 96 | feature_thresh_mask = tile(delta, (1, labels.shape[1])) 97 | output = output + feature_thresh_mask * tile(best_a, (num_examples, 1)) + (1 - feature_thresh_mask) * tile(best_b, (num_examples, 1)) 98 | weights = exp(- output * labels) 99 | weights = weights / sum(weights) 100 | err = sum((output * labels) <= 0) 101 | return 102 | 103 | def myfromfile(stream, type, sh): 104 | if len(sh) == 2: 105 | tot = sh[0] * sh[1] 106 | else: 107 | tot = sh[0] 108 | result = fromfile(stream, type, tot) 109 | result.shape = sh 110 | return result 111 | 112 | def doit(): 113 | testing = False 114 | n, ncols = myfromfile(stdin, int32, (2,)) 115 | num_classes = myfromfile(stdin, int32, (1,))[0] 116 | values = myfromfile(stdin, float32, (n, ncols)) 117 | label_matrix = myfromfile(stdin, int32, (n, num_classes)) 118 | 119 | while True: 120 | # It would be cleaner to tell the worker we're done by just 121 | # closing the stream, but numpy does strange things (prints 122 | # error message, signals MemoryError) when myfromfile cannot 123 | # read as many bytes as expected. 124 | if stdin.readline() == "done\n": 125 | return 126 | weights = myfromfile(stdin, float32, (n, num_classes)) 127 | 128 | best = float(Infinity) 129 | for column in range(ncols): 130 | colvals = values[:, column] 131 | # print >>stderr, "WORK", column, label_matrix, weights, colvals 132 | thresh, err, a, b = train_weak_learner(label_matrix, weights, colvals) 133 | if err < best: 134 | best = err 135 | bestvals = (err, column, thresh, a, b) 136 | 137 | err, column, thresh, a, b = bestvals 138 | array([err, column, thresh], float32).tofile(stdout) 139 | a.astype(float32).tofile(stdout) 140 | b.astype(float32).tofile(stdout) 141 | stdout.flush() 142 | 143 | 144 | 145 | if __name__ == '__main__': 146 | try: 147 | import dl 148 | h = dl.open('change_malloc_zone.dylib') 149 | h.call('setup') 150 | except: 151 | pass 152 | if len(argv) != 1: 153 | import cProfile 154 | cProfile.runctx("doit()", globals(), locals(), "worker.cprof") 155 | else: 156 | try: # Use binary I/O on Windows 157 | import msvcrt, os 158 | try: 159 | msvcrt.setmode(stdin.fileno(), os.O_BINARY) 160 | except: 161 | stderr.write("Couldn't deal with stdin\n") 162 | pass 163 | try: 164 | msvcrt.setmode(stdout.fileno(), os.O_BINARY) 165 | stderr.write("Couldn't deal with stdout\n") 166 | except: 167 | pass 168 | except ImportError: 169 | pass 170 | doit() 171 | try: 172 | h.call('teardown') 173 | except: 174 | pass 175 | -------------------------------------------------------------------------------- /cpa/helpmenu.py: -------------------------------------------------------------------------------- 1 | import wx 2 | import cpa 3 | import cpa.icons 4 | from cpa.updatechecker import check_update 5 | from cpa.util.version import display_version, __version__ 6 | 7 | 8 | def _on_check_update(self): 9 | check_update(self, force=True) 10 | 11 | def _on_about(self): 12 | ''' Shows a message box with the version number etc.''' 13 | shift = wx.GetKeyState(wx.WXK_SHIFT) 14 | ctrl = wx.GetKeyState(wx.WXK_CONTROL) 15 | 16 | if shift or ctrl: 17 | import logging 18 | import os 19 | import sys 20 | import javabridge 21 | logging.info("\n\nDEBUG - CPA Java State is as follows:") 22 | 23 | # Hold ctrl only: change CP_JAVA_HOME 24 | if ctrl and not shift: 25 | cd = wx.DirDialog(None, message="Choose new CP_JAVA_HOME", 26 | defaultPath=os.getcwd(), name="Set JAVA location") 27 | if cd.ShowModal() == wx.ID_OK: 28 | newdir = cd.GetPath() 29 | os.environ["CP_JAVA_HOME"] = newdir 30 | logging.info(f"Set CP_JAVA_HOME to {str(newdir)}") 31 | 32 | if 'CP_JAVA_HOME' in os.environ: 33 | logging.info(f"CP_JAVA_HOME is {os.environ['CP_JAVA_HOME']}") 34 | else: 35 | logging.info("CP_JAVA_HOME is not set") 36 | if 'JAVA_HOME' in os.environ: 37 | logging.info(f"JAVA_HOME is {os.environ['JAVA_HOME']}") 38 | else: 39 | logging.info("JAVA_HOME is not set") 40 | logging.info(f"Current working directory is {os.getcwd()}") 41 | logging.info(f"Python is running from {sys.prefix}") 42 | logging.info(f"Core Python install is at {sys.base_prefix}") 43 | logging.info(f"Javabridge java search returned {javabridge.locate.find_javahome()}") 44 | # Shift and ctrl/cmd held - test the VM. You'll need to restart CPA after since the VM can't be restarted. 45 | if shift and ctrl: 46 | try: 47 | logging.warning("Attempting to start Javabridge") 48 | javabridge.start_vm(run_headless=True) 49 | logging.warning("VM started successfully") 50 | javabridge.kill_vm() 51 | logging.warning("Shut down test vm. You'll need to RESTART CPA to use it again") 52 | except Exception as e: 53 | logging.info(f"Javabridge test failed") 54 | logging.info(e) 55 | 56 | message = ('CellProfiler Analyst was developed at The Broad Institute\n' 57 | 'Imaging Platform and is distributed under the\n' 58 | 'BSD 3-Clause License.') 59 | from wx.adv import AboutBox, AboutDialogInfo 60 | info = AboutDialogInfo() 61 | info.SetIcon(cpa.icons.get_cpa_icon()) 62 | info.SetName('CellProfiler Analyst (%s)'%(str(display_version) or 'unknown revision')) 63 | info.SetDescription(message) 64 | info.AddDeveloper('David Dao') 65 | info.AddDeveloper('Adam Fraser') 66 | info.AddDeveloper('Jane Hung') 67 | info.AddDeveloper('Thouis (Ray) Jones') 68 | info.AddDeveloper('Vebjorn Ljosa') 69 | info.AddDeveloper('David Stirling') 70 | info.SetWebSite('cellprofileranalyst.org') 71 | AboutBox(info) 72 | 73 | def make_help_menu(frame, main=False, manual_url="index.html"): 74 | help_version = __version__.rsplit('.', 1)[0] 75 | manual_url = f"https://cellprofiler-manual.s3.amazonaws.com/CellProfiler-Analyst-{help_version}/{manual_url}" 76 | helpMenu = wx.Menu() 77 | def on_manual(self): 78 | import webbrowser 79 | webbrowser.open(manual_url) 80 | 81 | frame.Bind(wx.EVT_MENU, on_manual, 82 | helpMenu.Append(-1, item='Online manual')) 83 | if main: 84 | frame.Bind(wx.EVT_MENU, _on_check_update, 85 | helpMenu.Append(-1, item='Check for updates', helpString='Check for new versions')) 86 | frame.Bind(wx.EVT_MENU, _on_about, 87 | helpMenu.Append(-1, item='About', helpString='About CellProfiler Analyst')) 88 | return helpMenu 89 | 90 | if __name__ == '__main__': 91 | app = wx.App() 92 | frame = wx.Frame(None, title='Test help menu') 93 | menu_bar = wx.MenuBar() 94 | menu_bar.Append(make_help_menu(frame), 'Help') 95 | frame.SetMenuBar(menu_bar) 96 | frame.Show() 97 | app.MainLoop() 98 | 99 | -------------------------------------------------------------------------------- /cpa/hypergeom.py: -------------------------------------------------------------------------------- 1 | # CellProfiler is distributed under the GNU General Public License, 2 | # but this file is licensed under the more permissive BSD license. 3 | # See the accompanying file LICENSE for details. 4 | 5 | from scipy.special import gamma, hyp2f1, gammaln 6 | from numpy import * 7 | import pdb 8 | 9 | def pochdivgamma(a, b, iterations): 10 | out = zeros(iterations, float64) 11 | out[0] = 1.0 / gamma(b) 12 | out[1:] = (a + arange(iterations-1).astype(float64)) / (b + arange(iterations-1).astype(float64)) 13 | return cumprod(out) 14 | 15 | def hyper3F2regularizedZ1(a1, a2, a3, b1, b2): 16 | '''the regularized hypergeometric function 3(F^~)2(a,b,z) with z=1. 17 | The terms are grouped under the assumption that the arguments will be: 18 | {a, 1-b, a+c} and {1+a, a+c+d} w/ a,b,c,d >= 0, in which case the 19 | groupings result in terms all <= 1 (after enough iterations)''' 20 | 21 | iterations = int(max(-2*a1, -2*a2, -2*a3, 100)) 22 | 23 | a1b1term = pochdivgamma(a1, b1, iterations) 24 | a3b2term = pochdivgamma(a3, b2, iterations) 25 | a2kterm = pochdivgamma(a2, 1, iterations) 26 | termprod = a1b1term * a3b2term * a2kterm 27 | 28 | pdb.set_trace() 29 | 30 | return sum(termprod), abs(termprod[-1]) 31 | 32 | 33 | def pochdivpoch(a, b, iterations): 34 | out = zeros(iterations, float64) 35 | out[0] = 1.0 36 | out[1:] = (a + arange(iterations-1).astype(float128)) / (b + arange(iterations-1).astype(float128)) 37 | return cumprod(out) 38 | 39 | 40 | def pochdivpochgen(a, b): 41 | 'generates 100 terms at a time of pochhammer(a)/pochhammer(b)' 42 | count = 0 43 | oldval = 0.0 44 | out = zeros(101, float64) 45 | out[0] = 1 46 | while True: 47 | out[1:] = (a + arange(count,count+100,dtype=float64)) / (b + arange(count,count+100,dtype=float64)) 48 | out = cumprod(out) 49 | yield out[1:] 50 | out[0] = out[-1] 51 | count += 100 52 | 53 | def hyper3F2Z1(a1, a2, a3, b1, b2, tol=1e-15): 54 | '''the hypergeometric function 3(F^~)2(a,b,z) with z=1. 55 | The terms are grouped under the assumption that the arguments will be: 56 | {a, 1-b, a+c} and {1+a, a+c+d} w/ a,b,c,d >= 0, in which case the 57 | groupings result in terms all < 1 (after enough iterations)''' 58 | 59 | a1b1terms = pochdivpochgen(a1, b1) 60 | a3b2terms = pochdivpochgen(a3, b2) 61 | a2kterms = pochdivpochgen(a2, 1) 62 | 63 | terms = [] 64 | while True: 65 | termprod = next(a1b1terms) * next(a3b2terms) * next(a2kterms) 66 | terms.append(termprod) 67 | if abs(termprod[-1]) < tol: 68 | break 69 | 70 | # sum in reverse, for better accuracy 71 | terms.reverse() 72 | # print 'L', len(terms) 73 | return 1.0+sum([sum(t[::-1]) for t in terms]), terms[0][-1] 74 | 75 | 76 | def hyp2f1mine(a, b, c): 77 | 'hyp2f1 from scipy gives nan if any of the arguments are too large' 78 | return exp(gammaln(c) + gammaln(c-a-b) - gammaln(c - a) - gammaln(c - b)) 79 | 80 | def hyper3F2aZ1(a1, a2, a3, b2, tol=1e-10): 81 | '''same has hyper3F2Z1 but with b1 = a1+1''' 82 | 83 | if (a2 > -2): 84 | # force a2 no higher than -2 85 | # use identity for hypergeom F: 86 | # (ai - 1) * F = (ai - aj - 1) * F(ai -1) + aj * F(ai-1, aj+1) 87 | # in this case, i = 2, j = 1 88 | toladjust = tol / max(1, abs((a2 - a1 - 1) / (a2 - 1))) 89 | temp = ((a2 - a1 -1) * hyper3F2aZ1(a1, a2 - 1, a3, b2, tol=toladjust) + a1 * hyp2f1mine(a2 - 1, a3, b2)) / (a2 - 1) 90 | return temp 91 | if (a2 < -10): 92 | # force a2 no lower than -10 93 | # use identity for hypergeom F: 94 | # (ai - aj) * F = ai * F(ai + 1) - aj * F(aj + 1) 95 | # in this case, i = 1, j = 2 96 | # no adjustment for tolerance because a1 > 0, a2 < 0 97 | 98 | a2new = arange(a2, -9) 99 | A = [a1 * hyp2f1mine(a2n, a3, b2) for a2n in a2new] 100 | B = a2new 101 | C = (a1 - a2new) 102 | # compute last entry 103 | B[-1] = a2new[-1] * hyper3F2aZ1(a1, a2new[-1]+1, a3, b2) 104 | for idx in arange(len(B)-1, 0, -1): 105 | B[idx-1] *= (A[idx] - B[idx]) / C[idx] 106 | 107 | # temp = (a1 * hyp2f1mine(a2, a3, b2) - a2 * hyper3F2aZ1(a1, a2 + 1, a3, b2)) / (a1 - a2) 108 | return (A[0] - B[0]) / C[0] 109 | else: 110 | return hyper3F2Z1(a1, a2, a3, a1+1, b2, tol=tol)[0] 111 | -------------------------------------------------------------------------------- /cpa/icons/__init__.py: -------------------------------------------------------------------------------- 1 | import wx 2 | import os.path 3 | import sys 4 | 5 | # Old code used to scan the icons directory and report everything into global variables on startup. 6 | # As of wx4 this is no longer valid, since the app has to launch first. 7 | # So now we'll call icons when needed and cache them in a dictionary. 8 | # We could convert to wx.Bitmap before storage, but there must be some reason the original 9 | # stored everything as wx.Image, right? 10 | 11 | icon_cache = {} 12 | 13 | def get_icon(name): 14 | if name in icon_cache: 15 | return icon_cache[name] 16 | else: 17 | dir = __path__[0] 18 | icon_cache[name] = wx.Image(os.path.join(dir, name + ".png")) 19 | return icon_cache[name] 20 | 21 | def get_cpa_icon(size=None): 22 | '''The CellProfiler Analyst icon as a wx.Icon''' 23 | icon = wx.Icon() 24 | if size == None and sys.platform.startswith('win'): 25 | icon.CopyFromBitmap(wx.Bitmap(get_icon("cpa_32"))) 26 | else: 27 | icon.CopyFromBitmap(wx.Bitmap(get_icon("cpa_128"))) 28 | return icon 29 | -------------------------------------------------------------------------------- /cpa/icons/boxplot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CellProfiler/CellProfiler-Analyst/8a7f924052867192b425e4b7f89137fadbbd93fa/cpa/icons/boxplot.png -------------------------------------------------------------------------------- /cpa/icons/brightness.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CellProfiler/CellProfiler-Analyst/8a7f924052867192b425e4b7f89137fadbbd93fa/cpa/icons/brightness.png -------------------------------------------------------------------------------- /cpa/icons/classifier.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CellProfiler/CellProfiler-Analyst/8a7f924052867192b425e4b7f89137fadbbd93fa/cpa/icons/classifier.png -------------------------------------------------------------------------------- /cpa/icons/cpa.icns: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CellProfiler/CellProfiler-Analyst/8a7f924052867192b425e4b7f89137fadbbd93fa/cpa/icons/cpa.icns -------------------------------------------------------------------------------- /cpa/icons/cpa.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CellProfiler/CellProfiler-Analyst/8a7f924052867192b425e4b7f89137fadbbd93fa/cpa/icons/cpa.ico -------------------------------------------------------------------------------- /cpa/icons/cpa_128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CellProfiler/CellProfiler-Analyst/8a7f924052867192b425e4b7f89137fadbbd93fa/cpa/icons/cpa_128.png -------------------------------------------------------------------------------- /cpa/icons/cpa_32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CellProfiler/CellProfiler-Analyst/8a7f924052867192b425e4b7f89137fadbbd93fa/cpa/icons/cpa_32.png -------------------------------------------------------------------------------- /cpa/icons/data_grid.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CellProfiler/CellProfiler-Analyst/8a7f924052867192b425e4b7f89137fadbbd93fa/cpa/icons/data_grid.png -------------------------------------------------------------------------------- /cpa/icons/density.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CellProfiler/CellProfiler-Analyst/8a7f924052867192b425e4b7f89137fadbbd93fa/cpa/icons/density.png -------------------------------------------------------------------------------- /cpa/icons/dimensionality.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CellProfiler/CellProfiler-Analyst/8a7f924052867192b425e4b7f89137fadbbd93fa/cpa/icons/dimensionality.png -------------------------------------------------------------------------------- /cpa/icons/filter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CellProfiler/CellProfiler-Analyst/8a7f924052867192b425e4b7f89137fadbbd93fa/cpa/icons/filter.png -------------------------------------------------------------------------------- /cpa/icons/filter.psd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CellProfiler/CellProfiler-Analyst/8a7f924052867192b425e4b7f89137fadbbd93fa/cpa/icons/filter.psd -------------------------------------------------------------------------------- /cpa/icons/filter_16.psd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CellProfiler/CellProfiler-Analyst/8a7f924052867192b425e4b7f89137fadbbd93fa/cpa/icons/filter_16.psd -------------------------------------------------------------------------------- /cpa/icons/filter_new.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CellProfiler/CellProfiler-Analyst/8a7f924052867192b425e4b7f89137fadbbd93fa/cpa/icons/filter_new.png -------------------------------------------------------------------------------- /cpa/icons/gate.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CellProfiler/CellProfiler-Analyst/8a7f924052867192b425e4b7f89137fadbbd93fa/cpa/icons/gate.png -------------------------------------------------------------------------------- /cpa/icons/gate.psd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CellProfiler/CellProfiler-Analyst/8a7f924052867192b425e4b7f89137fadbbd93fa/cpa/icons/gate.psd -------------------------------------------------------------------------------- /cpa/icons/gate_16.psd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CellProfiler/CellProfiler-Analyst/8a7f924052867192b425e4b7f89137fadbbd93fa/cpa/icons/gate_16.psd -------------------------------------------------------------------------------- /cpa/icons/gate_new.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CellProfiler/CellProfiler-Analyst/8a7f924052867192b425e4b7f89137fadbbd93fa/cpa/icons/gate_new.png -------------------------------------------------------------------------------- /cpa/icons/gate_tool.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CellProfiler/CellProfiler-Analyst/8a7f924052867192b425e4b7f89137fadbbd93fa/cpa/icons/gate_tool.png -------------------------------------------------------------------------------- /cpa/icons/gate_tool.psd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CellProfiler/CellProfiler-Analyst/8a7f924052867192b425e4b7f89137fadbbd93fa/cpa/icons/gate_tool.psd -------------------------------------------------------------------------------- /cpa/icons/histogram.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CellProfiler/CellProfiler-Analyst/8a7f924052867192b425e4b7f89137fadbbd93fa/cpa/icons/histogram.png -------------------------------------------------------------------------------- /cpa/icons/image_gallery.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CellProfiler/CellProfiler-Analyst/8a7f924052867192b425e4b7f89137fadbbd93fa/cpa/icons/image_gallery.png -------------------------------------------------------------------------------- /cpa/icons/image_viewer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CellProfiler/CellProfiler-Analyst/8a7f924052867192b425e4b7f89137fadbbd93fa/cpa/icons/image_viewer.png -------------------------------------------------------------------------------- /cpa/icons/lasso.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CellProfiler/CellProfiler-Analyst/8a7f924052867192b425e4b7f89137fadbbd93fa/cpa/icons/lasso.png -------------------------------------------------------------------------------- /cpa/icons/lasso_tool.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CellProfiler/CellProfiler-Analyst/8a7f924052867192b425e4b7f89137fadbbd93fa/cpa/icons/lasso_tool.png -------------------------------------------------------------------------------- /cpa/icons/normalize.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CellProfiler/CellProfiler-Analyst/8a7f924052867192b425e4b7f89137fadbbd93fa/cpa/icons/normalize.png -------------------------------------------------------------------------------- /cpa/icons/pixelclassifier.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CellProfiler/CellProfiler-Analyst/8a7f924052867192b425e4b7f89137fadbbd93fa/cpa/icons/pixelclassifier.png -------------------------------------------------------------------------------- /cpa/icons/platemapbrowser.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CellProfiler/CellProfiler-Analyst/8a7f924052867192b425e4b7f89137fadbbd93fa/cpa/icons/platemapbrowser.png -------------------------------------------------------------------------------- /cpa/icons/scatter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CellProfiler/CellProfiler-Analyst/8a7f924052867192b425e4b7f89137fadbbd93fa/cpa/icons/scatter.png -------------------------------------------------------------------------------- /cpa/icons/staticimage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CellProfiler/CellProfiler-Analyst/8a7f924052867192b425e4b7f89137fadbbd93fa/cpa/icons/staticimage.png -------------------------------------------------------------------------------- /cpa/icons/timelapse.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CellProfiler/CellProfiler-Analyst/8a7f924052867192b425e4b7f89137fadbbd93fa/cpa/icons/timelapse.png -------------------------------------------------------------------------------- /cpa/icons/timelapse.psd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CellProfiler/CellProfiler-Analyst/8a7f924052867192b425e4b7f89137fadbbd93fa/cpa/icons/timelapse.psd -------------------------------------------------------------------------------- /cpa/icons/zoom.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CellProfiler/CellProfiler-Analyst/8a7f924052867192b425e4b7f89137fadbbd93fa/cpa/icons/zoom.png -------------------------------------------------------------------------------- /cpa/imagelist.py: -------------------------------------------------------------------------------- 1 | 2 | import logging 3 | import wx 4 | import numpy as np 5 | from .properties import Properties 6 | from .dbconnect import * 7 | from . import imagetools 8 | 9 | p = Properties() 10 | db = DBConnect() 11 | 12 | class ImageListCtrl(wx.ListCtrl): 13 | def __init__(self, parent, imkeys): 14 | wx.ListCtrl.__init__(self, parent, -1, 15 | style=wx.LC_REPORT|wx.LC_VIRTUAL|wx.LC_HRULES|wx.LC_VRULES) 16 | 17 | self.set_key_list(imkeys) 18 | 19 | self.Bind(wx.EVT_LIST_ITEM_ACTIVATED, self.OnItemActivated) 20 | 21 | def set_key_list(self, imkeys): 22 | self.imkeys = imkeys 23 | 24 | if len(self.imkeys) > 0: 25 | columns_of_interest = well_key_columns(p.image_table) 26 | if len(columns_of_interest) > 0: 27 | columns_of_interest = ','+','.join(columns_of_interest) 28 | self.data = db.execute('SELECT %s%s FROM %s WHERE %s'%( 29 | UniqueImageClause(), 30 | columns_of_interest, 31 | p.image_table, 32 | GetWhereClauseForImages(imkeys))) 33 | self.cols = image_key_columns() + well_key_columns() 34 | else: 35 | self.data = np.array(self.imkeys) 36 | self.cols = image_key_columns() 37 | else: 38 | self.data = [] 39 | self.cols = [] 40 | 41 | self.data.sort() 42 | 43 | for i, col in enumerate(self.cols): 44 | self.InsertColumn(i, col) 45 | self.SetColumnWidth(i, 150) 46 | self.SetItemCount(len(imkeys)) 47 | 48 | def OnItemActivated(self, event): 49 | imkey = self.imkeys[event.m_itemIndex] 50 | f = imagetools.ShowImage(tuple(imkey), p.image_channel_colors, self.GrandParent or self.Parent) 51 | f.Raise() 52 | 53 | def OnGetItemText(self, row, col): 54 | return str(self.data[row][col]) 55 | 56 | 57 | class ImageListFrame(wx.Frame): 58 | def __init__(self, parent, imkeys, **kwargs): 59 | wx.Frame.__init__(self, parent, -1, **kwargs) 60 | 61 | sizer = wx.BoxSizer(wx.VERTICAL) 62 | self.imlist = ImageListCtrl(self, imkeys) 63 | sizer.Add(self.imlist, 1, wx.EXPAND) 64 | 65 | self.SetSizer(sizer) 66 | self.SetAutoLayout(True) 67 | 68 | 69 | 70 | if __name__ == "__main__": 71 | app = wx.App() 72 | logging.basicConfig(level=logging.DEBUG,) 73 | 74 | if not p.show_load_dialog(): 75 | print('Props file required') 76 | sys.exit() 77 | 78 | ilf = ImageListFrame(None, db.execute('SELECT %s from %s'%(UniqueImageClause(), p.image_table))) 79 | ilf.Show() 80 | 81 | app.MainLoop() 82 | -------------------------------------------------------------------------------- /cpa/imagepanel.py: -------------------------------------------------------------------------------- 1 | import wx 2 | from . import imagetools 3 | from .properties import Properties 4 | 5 | p = Properties() 6 | 7 | class ImagePanel(wx.Panel): 8 | ''' 9 | ImagePanels are wxPanels that display a wxBitmap and store multiple 10 | image channels which can be recombined to mix different bitmaps. 11 | ''' 12 | def __init__(self, images, channel_map, parent, 13 | scale=1.0, brightness=1.0, contrast=None, display_whole_image=False): 14 | """ 15 | images -- list of numpy arrays 16 | channel_map -- list of strings naming the color to map each channel 17 | onto, e.g., ['red', 'green', 'blue'] 18 | parent -- parent window to the wx.Panel 19 | scale -- factor to scale image by 20 | brightness -- factor to scale image pixel intensities by 21 | 22 | """ 23 | self.chMap = channel_map 24 | self.toggleChMap = channel_map[:] 25 | self.images = images 26 | 27 | # Displayed bitmap 28 | self.bitmap = imagetools.MergeToBitmap(images, 29 | chMap = channel_map, 30 | scale = scale, 31 | brightness = brightness, 32 | contrast = contrast, 33 | display_whole_image = display_whole_image) 34 | 35 | max_size = 1000 36 | sizex = min(max_size, self.bitmap.Size[0]) 37 | sizey = min(max_size, self.bitmap.Size[1]) 38 | wx.Panel.__init__(self, parent, wx.NewId(), size=(sizex, sizey)) 39 | 40 | self.scale = scale 41 | self.brightness = brightness 42 | self.contrast = contrast 43 | self.selected = False 44 | self.display_whole_image = display_whole_image 45 | 46 | self.Bind(wx.EVT_PAINT, self.OnPaint) 47 | 48 | def OnPaint(self, evt): 49 | self.SetClientSize((self.bitmap.Width, self.bitmap.Height)) 50 | dc = wx.PaintDC(self) 51 | dc.Clear() 52 | dc.DrawBitmap(self.bitmap, 0, 0) 53 | # Outline the whole image 54 | if self.selected: 55 | dc.SetPen(wx.Pen("WHITE",1)) 56 | dc.SetBrush(wx.Brush("WHITE", style=wx.TRANSPARENT)) 57 | dc.DrawRectangle(0,0,self.bitmap.Width,self.bitmap.Height) 58 | return dc 59 | 60 | def UpdateBitmap(self): 61 | self.bitmap = imagetools.MergeToBitmap(self.images, 62 | chMap = self.chMap, 63 | brightness = self.brightness, 64 | scale = self.scale, 65 | contrast = self.contrast, 66 | display_whole_image = self.display_whole_image) 67 | self.Refresh() 68 | self.Update() 69 | 70 | 71 | def MapChannels(self, chMap): 72 | ''' Recalculates the displayed bitmap for a new channel-color map. ''' 73 | self.chMap = chMap 74 | self.UpdateBitmap() 75 | 76 | def SetScale(self, scale): 77 | if scale != self.scale: 78 | self.scale = scale 79 | self.UpdateBitmap() 80 | self.SetClientSize((self.bitmap.Width, self.bitmap.Height)) 81 | 82 | def SetBrightness(self, brightness): 83 | if brightness != self.brightness: 84 | self.brightness = brightness 85 | self.UpdateBitmap() 86 | 87 | def SetContrastMode(self, mode): 88 | self.contrast = mode 89 | self.UpdateBitmap() 90 | 91 | 92 | -------------------------------------------------------------------------------- /cpa/imagetilesizer.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Special sizer for organizing image tiles. 3 | ''' 4 | 5 | import wx 6 | import math 7 | 8 | class ImageTileSizer(wx.Sizer): 9 | def __init__(self): 10 | wx.Sizer.__init__(self) 11 | 12 | def pitch(self): 13 | # get sizes of all tiles 14 | children = self.GetChildren() 15 | if len(children) == 0: 16 | return None 17 | else: 18 | maxi_w = 0 19 | maxi_h = 0 20 | for child in children: 21 | size = child.GetSize() 22 | add = 2 * child.GetBorder() 23 | maxi_w = max(maxi_w, size.GetWidth() + add) 24 | maxi_h = max(maxi_h, size.GetHeight() + add) 25 | return wx.Size(maxi_w, maxi_h) 26 | 27 | def CalcMin(self): 28 | n = len(self.GetChildren()) 29 | if n > 0: 30 | width = self.GetContainingWindow().GetClientSize().GetWidth() 31 | self.columns = max(1, width // self.pitch().x) 32 | self.rows = math.ceil(1.0 * n / self.columns) 33 | pitch = self.pitch() 34 | return wx.Size(self.columns * pitch.x, self.rows * pitch.y) 35 | else: 36 | return wx.Size(0,0) 37 | 38 | def RecalcSizes(self): 39 | self.CalcMin() 40 | origin = self.GetPosition() 41 | pitch = self.pitch() 42 | for k, item in enumerate(self.GetChildren()): 43 | i = k // self.columns 44 | j = k % self.columns 45 | pos = origin + wx.Point(j * pitch.x, i * pitch.y) 46 | item = self.GetChildren()[i * self.columns + j] 47 | border = item.GetBorder() 48 | item.SetDimension(pos+wx.Point(border, border), item.GetSize()) 49 | -------------------------------------------------------------------------------- /cpa/mysql_plugins/classifier_narrow.c: -------------------------------------------------------------------------------- 1 | /* 2 | * classifier_narrow.c 3 | * 4 | * Compile with: 5 | * gcc -Wall -fPIC -c `mysql_config --cflags` classifier_narrow.c 6 | * gcc -o classifier_narrow.so -shared classifier_narrow.o 7 | * 8 | * To add this function to mysql, compile it to classifier_narrow.so, 9 | * put it in a directory on the LD_LIBRARY_PATH for mysql, and execute 10 | * this statement within mysql: 11 | * 12 | * CREATE FUNCTION classifier_narrow RETURNS INTEGER SONAME 'classifier_narrow.so'; 13 | * 14 | */ 15 | 16 | #include 17 | #include 18 | #include 19 | 20 | #if defined(WIN32) || defined(MS_WINDOWS) || defined(WINDOWS) 21 | #else 22 | //typedef unsigned long long ulonglong; 23 | //typedef long long longlong; 24 | #endif /*__WIN__*/ 25 | 26 | 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include // To get strmov() 32 | 33 | my_bool classifier_narrow_init(UDF_INIT *initid, UDF_ARGS *args, char *message) 34 | { 35 | int num_stumps, num_classes, i; 36 | 37 | // Classifier function can't return null. 38 | initid->maybe_null = 0; 39 | 40 | if ((args->arg_count < 4) || (args->args[0] == NULL) || (args->arg_type[0] != INT_RESULT)) { 41 | strcpy(message, "Requires at least 6 arguments, the first of which is a constant integer."); 42 | return 1; // fail 43 | } 44 | 45 | num_stumps = *((longlong*) args->args[0]); 46 | if (num_stumps <= 0) { 47 | strcpy(message, "First argument must be positive."); 48 | return 1; // fail 49 | } 50 | 51 | num_classes = ((args->arg_count - 3) / num_stumps) - 2; 52 | 53 | if ((args->arg_count - 3) != (num_stumps * (num_classes + 2))) { 54 | strcpy(message, "Mismatch in argument number"); 55 | return 1; // fail 56 | } 57 | 58 | int *stumps = (int *)malloc(sizeof(int) * (num_stumps + 1)); 59 | stumps[0] = num_stumps; 60 | initid->ptr = (char *)stumps; 61 | if (!(initid->ptr)) { 62 | strcpy(message,"Couldn't allocate memory"); 63 | return 1; // fail 64 | } 65 | 66 | // set the argument types we want 67 | for (i = 1; i < args->arg_count; i++) 68 | args->arg_type[i] = REAL_RESULT; 69 | 70 | return 0; // success 71 | } 72 | 73 | void classifier_narrow_deinit(UDF_INIT *initid) 74 | { 75 | if (initid->ptr) 76 | free(initid->ptr); 77 | } 78 | 79 | void classifier_narrow_clear(UDF_INIT *initid, char *is_null, char *error) 80 | { 81 | int *stumps = (int *)(initid->ptr); 82 | int num_stumps = stumps[0]; 83 | memset(stumps + 1, 0, num_stumps * sizeof(int)); 84 | } 85 | 86 | #define get_arg(idx) ((args->args[idx] == NULL) ? 0.0 : *((double *) args->args[idx])) 87 | 88 | void classifier_narrow_add(UDF_INIT *initid, UDF_ARGS *args, 89 | char *is_null, char *error) 90 | { 91 | int num_stumps = *((longlong *)args->args[0]); 92 | int feature_id = *((longlong *)args->args[args->arg_count - 2]); 93 | double feature_value = get_arg(args->arg_count - 1); 94 | double threshold; 95 | int *stumps = (int *)(initid->ptr); 96 | int stump, i; 97 | 98 | /* Which feature is this row for? */ 99 | for (stump = 0; stump < num_stumps; stump++) { 100 | i = *((longlong *)args->args[stump + 1]); 101 | if (i == feature_id) 102 | break; 103 | } 104 | if (stump == num_stumps) 105 | return; /* This row is for a feature the classifier does not use. */ 106 | 107 | threshold = get_arg(1 + num_stumps + stump); 108 | stumps[stump + 1] = feature_value > threshold; 109 | } 110 | 111 | /* Used by older version of MySQL. */ 112 | void classifier_narrow_reset(UDF_INIT *initid, UDF_ARGS *args, 113 | char *is_null, char *error) 114 | { 115 | classifier_narrow_clear(initid, is_null, error); 116 | classifier_narrow_add(initid, args, is_null, error); 117 | } 118 | 119 | longlong classifier_narrow(UDF_INIT *initid, UDF_ARGS *args, char *is_null, 120 | char *error) 121 | { 122 | longlong class; 123 | double best_score; 124 | int num_stumps = *((longlong*) args->args[0]); 125 | int num_classes = ((args->arg_count - 1) / num_stumps) - 2; 126 | int *stumps = (int *) (initid->ptr); 127 | int offset, i, k; 128 | 129 | // weights start at this offset. 130 | offset = 1 + 2 * num_stumps; 131 | for (k = 0; k < num_classes; k++) { 132 | double temp_score = 0.0; 133 | for (i = 0; i < num_stumps; i++) { 134 | temp_score += get_arg(offset + i) * stumps[i + 1]; 135 | } 136 | if ((k == 0) || (temp_score > best_score)) { 137 | best_score = temp_score; 138 | class = k; 139 | } 140 | offset += num_stumps; 141 | } 142 | 143 | return class; 144 | } 145 | -------------------------------------------------------------------------------- /cpa/mysql_plugins/classify.c: -------------------------------------------------------------------------------- 1 | 2 | /* classify.c - */ 3 | 4 | // To add this function to mysql, compile it to classify.so, put it in a 5 | // directory on the LD_LIBRARY_PATH for mysql, and execute this statement 6 | // within mysql: 7 | // mysql> CREATE FUNCTION classifier RETURNS INTEGER SONAME 'classify.so'; 8 | 9 | 10 | 11 | #include 12 | #include 13 | 14 | #if defined(WIN32) || defined(MS_WINDOWS) || defined(WINDOWS) 15 | #else 16 | typedef unsigned long long ulonglong; 17 | typedef long long longlong; 18 | #endif /*__WIN__*/ 19 | 20 | 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include // To get strmov() 26 | 27 | my_bool classifier_init(UDF_INIT *initid, UDF_ARGS *args, char *message) 28 | { 29 | int num_stumps, num_classes, i; 30 | 31 | // Classifier function can't return null. 32 | initid->maybe_null = 0; 33 | 34 | if ((args->arg_count < 4) || (args->args[0] == NULL) || (args->arg_type[0] != INT_RESULT)) { 35 | strcpy(message, "Requires at least 4 arguments, the first of which is a constant integer."); 36 | return 1; // fail 37 | } 38 | 39 | num_stumps = *((longlong*) args->args[0]); 40 | if (num_stumps <= 0) { 41 | strcpy(message, "First argument must be positive."); 42 | return 1; // fail 43 | } 44 | 45 | num_classes = ((args->arg_count - 1) / num_stumps) - 2; 46 | 47 | if ((args->arg_count - 1) != (num_stumps * (num_classes + 2))) { 48 | strcpy(message, "Mismatch in argument number"); 49 | return 1; // fail 50 | } 51 | 52 | initid->ptr = (char *) malloc(sizeof (int) * num_stumps); 53 | if (!(initid->ptr)) { 54 | strcpy(message,"Couldn't allocate memory"); 55 | return 1; // fail 56 | } 57 | 58 | // set the argument types we want 59 | for (i = 1; i < args->arg_count; i++) 60 | args->arg_type[i] = REAL_RESULT; 61 | 62 | return 0; // success 63 | } 64 | 65 | void classifier_deinit(UDF_INIT *initid) 66 | { 67 | if (initid->ptr) 68 | free(initid->ptr); 69 | } 70 | 71 | longlong classifier(UDF_INIT *initid, UDF_ARGS *args, char *is_null, 72 | char *error) 73 | { 74 | longlong class; 75 | double best_score; 76 | int num_stumps = *((longlong*) args->args[0]); 77 | int num_classes = ((args->arg_count - 1) / num_stumps) - 2; 78 | int *stumps = (int *) (initid->ptr); 79 | int offset, i, k; 80 | 81 | #define get_arg(idx) ((args->args[idx] == NULL) ? 0.0 : *((double *) args->args[idx])) 82 | 83 | // evaluate stumps 84 | for (i = 0; i < num_stumps; i++) { 85 | stumps[i] = get_arg(i + 1) > get_arg(i + 1 + num_stumps); 86 | } 87 | 88 | // weights start at this offset. 89 | offset = 1 + 2 * num_stumps; 90 | for (k = 0; k < num_classes; k++) { 91 | double temp_score = 0.0; 92 | for (i = 0; i < num_stumps; i++) { 93 | temp_score += get_arg(offset + i) * stumps[i]; 94 | } 95 | if ((k == 0) || (temp_score > best_score)) { 96 | best_score = temp_score; 97 | class = k; 98 | } 99 | offset += num_stumps; 100 | } 101 | 102 | return class; 103 | } 104 | -------------------------------------------------------------------------------- /cpa/normalize.py: -------------------------------------------------------------------------------- 1 | from scipy.ndimage import median_filter, uniform_filter 2 | import numpy as np 3 | import logging 4 | 5 | 6 | G_EXPERIMENT = "Experiment" 7 | G_PLATE = "Plate" 8 | G_QUADRANT = "Plate Quadrant" 9 | G_WELL_NEIGHBORS = "Well Neighbors" 10 | G_CONSTANT = "Constant" 11 | 12 | M_MEDIAN = "Median" 13 | M_MEAN = "Mean" 14 | M_MODE = "Mode" 15 | M_NEGCTRL = "Negative Control" # DMSO Standardization 16 | M_ZSCORE = "Z score" 17 | 18 | W_SQUARE = "Square" 19 | W_MEANDER = "Linear (meander)" 20 | 21 | # Parameter names for do_normalization_step 22 | P_GROUPING = 'grouping' 23 | P_AGG_TYPE = 'aggregate_type' 24 | P_WIN_SIZE = 'win_size' 25 | P_WIN_TYPE = 'win_type' 26 | P_CONSTANT = 'constant' 27 | 28 | def do_normalization_step(input_data, grouping, aggregate_type, win_size, win_type, constant): 29 | '''Apply a single normalization step 30 | input_data -- a numpy array of raw data to normalize. This array MUST be in the same 31 | shape as your plate data if you are applying a spatially dependent 32 | grouping. 33 | returns a 2-tuple containing an array of normalized values and an array of 34 | the normalization factors 35 | ''' 36 | #assert input_data.ndim==2 or grouping in (G_CONSTANT, G_EXPERIMENT) 37 | 38 | if grouping == G_EXPERIMENT: 39 | output_data = do_normalization(input_data, aggregate_type) 40 | 41 | elif grouping == G_PLATE: 42 | output_data = do_normalization(input_data, aggregate_type) 43 | 44 | elif grouping == G_QUADRANT: 45 | all_quadrants = [ 46 | # upper left 47 | (np.arange(input_data.shape[0]) % 2 == 0, np.arange(input_data.shape[1]) % 2 == 0), 48 | # upper right 49 | (np.arange(input_data.shape[0]) % 2 == 0, np.arange(input_data.shape[1]) % 2 != 0), 50 | # lower left 51 | (np.arange(input_data.shape[0]) % 2 != 0, np.arange(input_data.shape[1]) % 2 == 0), 52 | # lower right 53 | (np.arange(input_data.shape[0]) % 2 != 0, np.arange(input_data.shape[1]) % 2 != 0) ] 54 | output_data = input_data.copy() 55 | for quad in all_quadrants: 56 | ixgrid = np.ix_(quad[0],quad[1]) 57 | output_data[ixgrid] = do_normalization(input_data[ixgrid], aggregate_type) 58 | 59 | elif grouping == G_WELL_NEIGHBORS: 60 | if win_type == W_SQUARE: 61 | output_data = square_filter_normalization(input_data, aggregate_type, win_size) 62 | elif win_type == W_MEANDER: 63 | output_data = linear_filter_normalization(input_data, aggregate_type, win_size) 64 | 65 | elif grouping == G_CONSTANT: 66 | output_data = do_normalization(input_data, constant) 67 | else: 68 | raise ValueError('Programming Error: Unknown normalization type supplied.') 69 | 70 | return output_data 71 | 72 | def square_filter_normalization(data, aggregate_type, win_size): 73 | ''' 74 | ''' 75 | # Filter locally, for staining variation 76 | if aggregate_type == M_MEDIAN: 77 | normalization_values = median_filter(data, (win_size, win_size)) 78 | elif aggregate_type == M_MEAN: 79 | normalization_values = uniform_filter(data, (win_size, win_size)) 80 | else: 81 | raise ValueError('Programming Error: Unknown window type supplied.') 82 | 83 | try: 84 | res = data / normalization_values 85 | except: 86 | logging.error("Division by zero, replace value with 0") 87 | res = 0 88 | 89 | 90 | def linear_filter_normalization(data, aggregate_type, win_size): 91 | ''' 92 | ''' 93 | # Filter linearly (assumes FormatPlateData reordered plate-data to account for meandering) 94 | if aggregate_type == M_MEDIAN: 95 | normalization_values = median_filter(data.flatten(), win_size).reshape(data.shape) 96 | elif aggregate_type == M_MEAN: 97 | normalization_values = uniform_filter(data.flatten(), win_size).reshape(data.shape) 98 | else: 99 | raise ValueError('Programming Error: Unknown window type supplied.') 100 | 101 | try: 102 | res = data / normalization_values 103 | except: 104 | logging.error("Division by zero, replace value with 0") 105 | res = 0 106 | 107 | return res 108 | 109 | def do_normalization(data, aggregate_type_or_const): 110 | ''' 111 | data -- meat and potatoes 112 | aggregate_type_or_const -- specify an aggregation type or a numeric constant 113 | to divide by 114 | ''' 115 | if aggregate_type_or_const == M_NEGCTRL: 116 | normalization_value = 1 # Keep data the same 117 | elif aggregate_type_or_const == M_MEDIAN: 118 | normalization_value = np.median(data.flatten()) 119 | elif aggregate_type_or_const == M_MEAN: 120 | normalization_value = np.mean(data.flatten()) 121 | elif aggregate_type_or_const == M_MODE: 122 | import scipy.ndimage 123 | # Use histogram function with values a bit removed from saturation 124 | robust_min = 0.02 * (np.max(data) - np.min(data)) + np.min(data) 125 | robust_max = 0.98 * (np.max(data) - np.min(data)) + np.min(data) 126 | nbins = 256 127 | h = scipy.ndimage.histogram(data.flatten(), robust_min, robust_max, nbins) 128 | index = np.argmax(h) 129 | normalization_value = np.min(data) + float(index)/float(nbins-1)*(np.max(data) - np.min(data)) 130 | elif type(aggregate_type_or_const) in (float, int): 131 | normalization_value = aggregate_type_or_const 132 | 133 | try: 134 | res = data / normalization_value 135 | except: 136 | logging.error("Division by zero, replace value with 0!") 137 | res = 0 138 | 139 | return res 140 | -------------------------------------------------------------------------------- /cpa/pilfix.py: -------------------------------------------------------------------------------- 1 | import logging 2 | import PIL.Image 3 | 4 | try: 5 | import PIL.Hdf5StubImagePlugin 6 | except: 7 | logging.info("No HDF5StubImagePlugin") 8 | try: 9 | import PIL.FitsStubImagePlugin 10 | except: 11 | logging.info("No PIL.FitsStubImagePlugin") 12 | try: 13 | import PIL.SunImagePlugin 14 | except: 15 | logging.info("No PIL.SunImagePlugin") 16 | try: 17 | import PIL.GbrImagePlugin 18 | except: 19 | logging.info("No PIL.GbrImagePlugin") 20 | try: 21 | import PIL.PngImagePlugin 22 | except: 23 | logging.info("No PIL.PngImagePlugin") 24 | try: 25 | import PIL.MicImagePlugin 26 | except: 27 | logging.info("No PIL.MicImagePlugin") 28 | try: 29 | import PIL.FpxImagePlugin 30 | except: 31 | logging.info("No PIL.FpxImagePlugin") 32 | try: 33 | import PIL.PcxImagePlugin 34 | except: 35 | logging.info("No PIL.PcxImagePlugin") 36 | try: 37 | import PIL.ImImagePlugin 38 | except: 39 | logging.info("No PIL.ImImagePlugin") 40 | try: 41 | import PIL.SpiderImagePlugin 42 | except: 43 | logging.info("No PIL.SpiderImagePlugin") 44 | try: 45 | import PIL.PsdImagePlugin 46 | except: 47 | logging.info("No PIL.PsdImagePlugin") 48 | try: 49 | import PIL.BufrStubImagePlugin 50 | except: 51 | logging.info("No PIL.BufrStubImagePlugin") 52 | try: 53 | import PIL.SgiImagePlugin 54 | except: 55 | logging.info("No PIL.SgiImagePlugin") 56 | try: 57 | import PIL.McIdasImagePlugin 58 | except: 59 | logging.info("No PIL.McIdasImagePlugin") 60 | try: 61 | import PIL.XpmImagePlugin 62 | except: 63 | logging.info("No PIL.XpmImagePlugin") 64 | try: 65 | import PIL.BmpImagePlugin 66 | except: 67 | logging.info("No PIL.BmpImagePlugin") 68 | try: 69 | import PIL.TgaImagePlugin 70 | except: 71 | logging.info("No PIL.TgaImagePlugin") 72 | try: 73 | import PIL.PalmImagePlugin 74 | except: 75 | logging.info("No PIL.PalmImagePlugin") 76 | try: 77 | import PIL.XVThumbImagePlugin 78 | except: 79 | logging.info("No PIL.XVThumbImagePlugin") 80 | try: 81 | import PIL.GribStubImagePlugin 82 | except: 83 | logging.info("No PIL.GribStubImagePlugin") 84 | try: 85 | import PIL.ArgImagePlugin 86 | except: 87 | logging.info("No PIL.ArgImagePlugin") 88 | try: 89 | import PIL.PdfImagePlugin 90 | except: 91 | logging.info("No PIL.PdfImagePlugin") 92 | try: 93 | import PIL.ImtImagePlugin 94 | except: 95 | logging.info("No PIL.ImtImagePlugin") 96 | try: 97 | import PIL.GifImagePlugin 98 | except: 99 | logging.info("No PIL.GifImagePlugin") 100 | try: 101 | import PIL.CurImagePlugin 102 | except: 103 | logging.info("No PIL.CurImagePlugin") 104 | try: 105 | import PIL.WmfImagePlugin 106 | except: 107 | logging.info("No PIL.WmfImagePlugin") 108 | try: 109 | import PIL.MpegImagePlugin 110 | except: 111 | logging.info("No PIL.MpegImagePlugin") 112 | try: 113 | import PIL.IcoImagePlugin 114 | except: 115 | logging.info("No PIL.IcoImagePlugin") 116 | try: 117 | import PIL.TiffImagePlugin 118 | except: 119 | logging.info("No PIL.TiffImagePlugin") 120 | try: 121 | import PIL.PpmImagePlugin 122 | except: 123 | logging.info("No PIL.PpmImagePlugin") 124 | try: 125 | import PIL.MspImagePlugin 126 | except: 127 | logging.info("No PIL.MspImagePlugin") 128 | try: 129 | import PIL.EpsImagePlugin 130 | except: 131 | logging.info("No PIL.EpsImagePlugin") 132 | try: 133 | import PIL.JpegImagePlugin 134 | except: 135 | logging.info("No PIL.JpegImagePlugin") 136 | try: 137 | import PIL.PixarImagePlugin 138 | except: 139 | logging.info("No PIL.PixarImagePlugin") 140 | try: 141 | import PIL.PcdImagePlugin 142 | except: 143 | logging.info("No PIL.PcdImagePlugin") 144 | try: 145 | import PIL.IptcImagePlugin 146 | except: 147 | logging.info("No PIL.IptcImagePlugin") 148 | try: 149 | import PIL.XbmImagePlugin 150 | except: 151 | logging.info("No PIL.XbmImagePlugin") 152 | try: 153 | import PIL.DcxImagePlugin 154 | except: 155 | logging.info("No PIL.DcxImagePlugin") 156 | try: 157 | import PIL.IcnsImagePlugin 158 | except: 159 | logging.info("No PIL.IcnsImagePlugin") 160 | try: 161 | import PIL.FliImagePlugin 162 | except: 163 | logging.info("No PIL.FliImagePlugin") 164 | -------------------------------------------------------------------------------- /cpa/querymaker.py: -------------------------------------------------------------------------------- 1 | 2 | import logging 3 | import wx 4 | import sys 5 | from .properties import Properties 6 | from . import tableviewer 7 | from . import dbconnect 8 | import numpy as np 9 | 10 | # TODO: Wrap queries in "SELECT * FROM () LIMIT 1000, offset" 11 | # and write a TableData subclass to feed rows to the TableViewer. 12 | class QueryMaker(wx.Frame): 13 | '''Super-simple interface for making queries directly to the database and 14 | displaying results using TableViewer. Results are pulled straight into 15 | memory, so this shouldn't be used to fetch large result sets. 16 | ''' 17 | def __init__(self, parent, size=(400,250), **kwargs): 18 | wx.Frame.__init__(self, parent, -1, size=size, title='Query Maker', **kwargs) 19 | panel = wx.Panel(self) 20 | self.query_textctrl = wx.TextCtrl(panel, -1, size=(-1,-1), style=wx.TE_MULTILINE) 21 | self.execute_btn = wx.Button(panel, -1, 'execute') 22 | 23 | sizer = wx.BoxSizer(wx.VERTICAL) 24 | panel.SetSizer(sizer) 25 | sizer.Add(self.query_textctrl, 1, wx.EXPAND|wx.TOP|wx.LEFT|wx.RIGHT, 10) 26 | button_sizer = wx.BoxSizer(wx.HORIZONTAL) 27 | sizer.Add(button_sizer, 0, wx.EXPAND) 28 | 29 | button_sizer.AddStretchSpacer() 30 | button_sizer.Add(self.execute_btn, 0, wx.ALL, 10) 31 | 32 | self.query_textctrl.Bind(wx.EVT_KEY_UP, self. on_enter) 33 | self.execute_btn.Bind(wx.EVT_BUTTON, self.on_execute) 34 | 35 | def on_enter(self, evt): 36 | '''Execute query on Cmd+Enter''' 37 | if evt.CmdDown() and evt.GetKeyCode() == wx.WXK_RETURN: 38 | self.on_execute() 39 | evt.Skip() 40 | 41 | def on_execute(self, evt=None): 42 | '''Run the query and show the results in a TableViewer''' 43 | db = dbconnect.DBConnect() 44 | q = self.query_textctrl.Value 45 | try: 46 | res = db.execute(q) 47 | if res is None or len(res) == 0: 48 | logging.info('Query successful. No Data to return.') 49 | return 50 | res = np.array(db.execute(q)) 51 | colnames = db.GetResultColumnNames() 52 | grid = tableviewer.TableViewer(self, title='query results') 53 | grid.table_from_array(res, colnames) 54 | grid.Show() 55 | logging.info('Query successful') 56 | except Exception as e: 57 | logging.error('Query failed:') 58 | logging.error(e) 59 | 60 | 61 | if __name__ == "__main__": 62 | app = wx.App() 63 | logging.basicConfig(stream=sys.stdout, level=logging.DEBUG) 64 | 65 | p = Properties() 66 | # Load a properties file if passed in args 67 | if len(sys.argv) > 1: 68 | propsFile = sys.argv[1] 69 | p.LoadFile(propsFile) 70 | else: 71 | if not p.show_load_dialog(): 72 | print('Query Maker requires a properties file. Exiting.') 73 | # necessary in case other modal dialogs are up 74 | wx.GetApp().Exit() 75 | sys.exit() 76 | 77 | QueryMaker(None).Show() 78 | 79 | app.MainLoop() 80 | 81 | -------------------------------------------------------------------------------- /cpa/scoredialog.py: -------------------------------------------------------------------------------- 1 | 2 | import wx 3 | 4 | class ScoreDialog(wx.Dialog): 5 | """ 6 | A dialog that prompts the user for group and filter, and whether or not 7 | to calculate/report enrichment values. 8 | """ 9 | def __init__(self, parent, groups, filters, enrichments=True): 10 | """Groups and filters are lists. Each item in the list is 11 | either a (key, value) pair or a non-tuple value (e.g., a 12 | string). In the latter case, str(value) is used as the key.""" 13 | wx.Dialog.__init__(self, parent, -1, "Score all cells") 14 | 15 | def key_value(item): 16 | if isinstance(item, tuple): 17 | return item 18 | else: 19 | return (item, str(item)) 20 | 21 | self.groups = list(map(key_value, groups)) 22 | self.filters = list(map(key_value, filters)) 23 | 24 | self.groups_lb = wx.ListBox(self, choices=[v for k,v in self.groups]) 25 | self.groups_lb.SetSelection(0) 26 | self.filters_lb = wx.ListBox(self, choices=[v for k,v in self.filters]) 27 | self.filters_lb.SetSelection(0) 28 | self._wants_enrichments = wx.CheckBox(self, -1, 'Report enrichments?') 29 | self._wants_enrichments.SetValue(enrichments) 30 | 31 | vbox = wx.BoxSizer(wx.VERTICAL) 32 | vbox.Add(wx.StaticText(self, -1, 'Grouping method:'), 0) 33 | vbox.Add(self.groups_lb, 1, wx.EXPAND) 34 | vbox.Add(wx.StaticText(self, -1, 'Filter:'), 0, wx.TOP, 5) 35 | vbox.Add(self.filters_lb, 1, wx.EXPAND) 36 | vbox.Add(self._wants_enrichments) 37 | vbox.Add(self.CreateButtonSizer(wx.OK | wx.CANCEL), 0, 38 | wx.TOP | wx.ALIGN_CENTER, 5) 39 | hbox = wx.BoxSizer(wx.HORIZONTAL) 40 | hbox.Add(vbox, 1, wx.EXPAND | wx.ALL, 10) 41 | self.SetSizer(hbox) 42 | self.Centre() 43 | 44 | @property 45 | def group(self): 46 | """Return the key of the selected group.""" 47 | return self.groups[self.groups_lb.GetSelections()[0]][0] 48 | 49 | @property 50 | def filter(self): 51 | """Return the key of the selected filter.""" 52 | return self.filters[self.filters_lb.GetSelections()[0]][0] 53 | 54 | @property 55 | def wants_enrichments(self): 56 | """Return whether the user checked the "Report enrichments?" box.""" 57 | return self._wants_enrichments.Value 58 | 59 | 60 | if __name__ == "__main__": 61 | app = wx.App() 62 | d = ScoreDialog(None, [str(a) for a in range(15)], 63 | [(None, 'None'), 'Untreated', 'HRG']) 64 | if d.ShowModal() == wx.ID_OK: 65 | print('a') 66 | print(("Group:", repr(d.group))) 67 | print(("Filter:", repr(d.filter))) 68 | print(((d.wants_enrichments and 'Wants' or 'Does not want') + ' enrichments')) 69 | d.Destroy() 70 | -------------------------------------------------------------------------------- /cpa/shell.py: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | ''' 3 | Load a properties file, then start a shell with certain local 4 | variables exposed. 5 | ''' 6 | 7 | 8 | import code 9 | import sys 10 | from optparse import OptionParser 11 | import cpa 12 | import cpa.properties 13 | import cpa.dbconnect 14 | 15 | parser = OptionParser("usage: %prog [options] [PROPERTIES-FILE [COMMAND]]") 16 | options, args = parser.parse_args() 17 | 18 | if len(args) > 0: 19 | cpa.properties.LoadFile(sys.argv[1]) 20 | 21 | variables = {'cpa': cpa} 22 | 23 | if len(args) == 2: 24 | interpreter = code.InteractiveInterpreter(locals=variables) 25 | interpreter.runsource(sys.argv[2]) 26 | else: 27 | code.interact(local=variables) 28 | -------------------------------------------------------------------------------- /cpa/singleton.py: -------------------------------------------------------------------------------- 1 | ''' 2 | This Singleton metaclass ensures that only one instance of a 3 | class can be created. Subsequent calls to make that class will 4 | return the original instance. In Python 3, specify metaclass=Singleton 5 | to use this functionality. 6 | 7 | If you absolutely must re-create a singleton, use the forget() method 8 | to delete the original instance. A new instance will then be created 9 | on the next class call. 10 | 11 | This version was put together to replace a more complex Python 2 singleton 12 | class that no longer works in Python 3. Good luck! 13 | ''' 14 | 15 | class Singleton(type): 16 | _instances = {} 17 | def __call__(cls, *args, **kwargs): 18 | if cls not in cls._instances: 19 | cls._instances[cls] = super(Singleton, cls).__call__(*args, **kwargs) 20 | return cls._instances[cls] 21 | 22 | def forget(cls): 23 | if cls in cls._instances: 24 | del cls._instances[cls] 25 | 26 | -------------------------------------------------------------------------------- /cpa/tests/32-bit-grayscale.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CellProfiler/CellProfiler-Analyst/8a7f924052867192b425e4b7f89137fadbbd93fa/cpa/tests/32-bit-grayscale.tif -------------------------------------------------------------------------------- /cpa/tests/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CellProfiler/CellProfiler-Analyst/8a7f924052867192b425e4b7f89137fadbbd93fa/cpa/tests/__init__.py -------------------------------------------------------------------------------- /cpa/tests/test.py: -------------------------------------------------------------------------------- 1 | import wx 2 | from matplotlib.backends.backend_wxagg import FigureCanvasWxAgg, NavigationToolbar2WxAgg 3 | from matplotlib.backends.backend_wx import _load_bitmap 4 | import matplotlib as mpl 5 | 6 | 7 | app = wx.App() 8 | f = wx.Frame(None) 9 | fig = mpl.figure.Figure() 10 | p = FigureCanvasWxAgg(f, -1, fig) 11 | 12 | toolbar = NavigationToolbar2WxAgg(p) 13 | toolbar.Hide() 14 | 15 | #toolbar constants 16 | TBFLAGS = (wx.TB_HORIZONTAL|wx.TB_TEXT) 17 | tsize = (24,24) 18 | tb = f.CreateToolBar(TBFLAGS) 19 | 20 | _NTB2_HOME = wx.NewId() 21 | _NTB2_BACK = wx.NewId() 22 | _NTB2_FORWARD = wx.NewId() 23 | _NTB2_PAN = wx.NewId() 24 | _NTB2_ZOOM = wx.NewId() 25 | _NTB2_SAVE = wx.NewId() 26 | _NTB2_SUBPLOT = wx.NewId() 27 | 28 | tb.AddSimpleTool(_NTB2_HOME, _load_bitmap('home.png'), 'Home', 'Reset original view') 29 | tb.AddSimpleTool(_NTB2_BACK, _load_bitmap('back.png'), 'Back', 'Back navigation view') 30 | tb.AddSimpleTool(_NTB2_FORWARD, _load_bitmap('forward.png'), 'Forward', 'Forward navigation view') 31 | 32 | tb.AddCheckTool(_NTB2_PAN, "", _load_bitmap('move.png'), shortHelp='Pan') 33 | tb.AddCheckTool(_NTB2_ZOOM, "", _load_bitmap('zoom_to_rect.png'), shortHelp='Zoom') 34 | 35 | tb.AddSeparator() 36 | tb.AddSimpleTool(_NTB2_SUBPLOT, _load_bitmap('subplots.png'), 'Configure subplots', 'Configure subplot parameters') 37 | tb.AddSimpleTool(_NTB2_SAVE, _load_bitmap('filesave.png'), 'Save', 'Save plot contents to file') 38 | 39 | f.Bind(wx.EVT_TOOL, toolbar.home, id=_NTB2_HOME) 40 | f.Bind(wx.EVT_TOOL, toolbar.forward, id=_NTB2_FORWARD) 41 | f.Bind(wx.EVT_TOOL, toolbar.back, id=_NTB2_BACK) 42 | f.Bind(wx.EVT_TOOL, toolbar.zoom, id=_NTB2_ZOOM) 43 | f.Bind(wx.EVT_TOOL, toolbar.pan, id=_NTB2_PAN) 44 | f.Bind(wx.EVT_TOOL, toolbar.configure_subplots, id=_NTB2_SUBPLOT) 45 | f.Bind(wx.EVT_TOOL, toolbar.save_figure, id=_NTB2_SAVE) 46 | 47 | tb.Realize() 48 | f.Show() 49 | f.Close() 50 | app.MainLoop() -------------------------------------------------------------------------------- /cpa/tests/test2.py: -------------------------------------------------------------------------------- 1 | 2 | # Fancy-pants method for getting a where clause that groups adjacent image keys 3 | # using "BETWEEN X AND Y" ... unfortunately this usually takes far more 4 | # characters than using "ImageNumber IN (X,Y,Z...)" since we don't run into 5 | # queries asking for consecutive image numbers very often (except when we do it 6 | # deliberately). It is also slower than the "IN" method unless the ImageNumbers 7 | # come in a smaller list of consecutive groups. 8 | # 9 | # ...still, this may be very useful since it is notably faster when ImageNumbers 10 | # are consecutive. 11 | 12 | def get_where_clause_for_images(keys, is_sorted=False): 13 | ''' 14 | takes a list of keys and returns a (hopefully) short where clause that 15 | includes those keys. 16 | ''' 17 | def in_sequence(k1,k2): 18 | if len(k1)>1: 19 | if k1[:-1] != k2[:-1]: 20 | return False 21 | return k1[-1]==(k2[-1]-1) 22 | 23 | def optimize_for_query(keys, is_sorted=False): 24 | if not is_sorted: 25 | keys.sort() 26 | groups = [] 27 | in_run = False 28 | for i in range(len(keys)): 29 | if i == len(keys)-1: 30 | if in_run: 31 | groups[-1] += [keys[i]] 32 | else: 33 | groups += [[keys[i]]] 34 | break 35 | if in_run: 36 | if in_sequence(keys[i], keys[i+1]): 37 | continue 38 | else: 39 | groups[-1] += [keys[i]] 40 | in_run = False 41 | else: 42 | if in_sequence(keys[i], keys[i+1]): 43 | in_run = True 44 | groups += [[keys[i]]] 45 | return groups 46 | 47 | groups = optimize_for_query(keys) 48 | wheres = [] 49 | for k in groups: 50 | if len(k)==1: 51 | wheres += ['%s=%s'%(col,value) for col, value in zip(object_key_columns(), k[0])] 52 | else: 53 | # expect 2 keys: the first and last of a contiguous run 54 | first, last = k 55 | if p.table_id: 56 | wheres += ['(%s=%s AND %s BETWEEN %s and %s)'% 57 | (p.table_id, first[0], p.image_id, first[1], last[1])] 58 | else: 59 | wheres += ['(%s BETWEEN %s and %s)'% 60 | (p.image_id, first[0], last[0])] 61 | return ' OR '.join(wheres) -------------------------------------------------------------------------------- /cpa/tests/test_datamodel.py: -------------------------------------------------------------------------------- 1 | from mock import patch 2 | import unittest 3 | import cpa.datamodel 4 | 5 | class PopulatePlateMapsTestCase(unittest.TestCase): 6 | 7 | def setUp(self): 8 | self.dm = cpa.datamodel.DataModel() 9 | self.p = cpa.datamodel.p 10 | 11 | @patch('cpa.datamodel.db') 12 | def test_well_format_A01(self, db): 13 | db.execute.return_value = [('A01',), ('P24',), ('b9',)] 14 | self.p.well_format = 'A01' 15 | self.p.plate_shape = (16, 24) 16 | self.dm.populate_plate_maps() 17 | 18 | @patch('cpa.datamodel.db') 19 | def test_well_format_123(self, db): 20 | db.execute.return_value = [('0',), ('01',), ('123',), ('12345',)] 21 | self.p.well_format = '123' 22 | self.p.plate_shape = (1, 20) 23 | self.dm.populate_plate_maps() 24 | 25 | def test_unknown_well_format(self): 26 | for value in [None, '', 'abc', 'AA1']: 27 | self.p.well_format = value 28 | self.assertRaises(ValueError, lambda: self.dm.populate_plate_maps()) 29 | 30 | @patch('cpa.datamodel.db') 31 | def test_A01_over_52_rows(self, db): 32 | # Need at least one well to trigger the code. 33 | db.execute.return_value = [('A01',),] 34 | self.p.well_format = 'A01' 35 | self.p.plate_shape = (53, 1) 36 | self.assertRaises(ValueError, lambda: self.dm.populate_plate_maps()) 37 | 38 | 39 | class GetWellPositionFromName(unittest.TestCase): 40 | def setUp(self): 41 | self.dm = cpa.datamodel.DataModel() 42 | self.set_plate_map() 43 | 44 | def set_plate_map(self): 45 | self.dm.plate_map = {'A01': (0, 0)} 46 | self.dm.rev_plate_map = {(0, 0): 'A01'} 47 | 48 | def clear_plate_map(self): 49 | self.dm.plate_map = {} 50 | self.dm.rev_plate_map = {} 51 | 52 | @patch.object(cpa.datamodel.DataModel, 'populate_plate_maps') 53 | def test_forward_missing(self, populate_plate_maps): 54 | populate_plate_maps.side_effect = self.set_plate_map 55 | self.clear_plate_map() 56 | row, col = self.dm.get_well_position_from_name('A01') 57 | populate_plate_maps.assert_called_with() 58 | self.assertEqual((row, col), (0, 0)) 59 | 60 | @patch.object(cpa.datamodel.DataModel, 'populate_plate_maps') 61 | def test_reverse_missing(self, populate_plate_maps): 62 | populate_plate_maps.side_effect = self.set_plate_map 63 | self.clear_plate_map() 64 | name = self.dm.get_well_name_from_position((0, 0)) 65 | populate_plate_maps.assert_called_with() 66 | self.assertEqual(name, 'A01') 67 | 68 | def test_forward_present(self): 69 | self.assertEqual(self.dm.get_well_position_from_name('A01'), 70 | (0, 0)) 71 | 72 | def test_reverse_present(self): 73 | self.assertEqual(self.dm.get_well_name_from_position((0, 0)), 74 | 'A01') 75 | 76 | def test_forward_absent(self): 77 | self.assertRaises(KeyError, lambda: self.dm.get_well_position_from_name('B01')) 78 | 79 | def test_reverse_absent(self): 80 | self.assertRaises(KeyError, lambda: self.dm.get_well_name_from_position((1, 0))) 81 | -------------------------------------------------------------------------------- /cpa/tests/test_dbconnect.py: -------------------------------------------------------------------------------- 1 | import threading 2 | from mock import patch, Mock 3 | import unittest 4 | import cpa.dbconnect 5 | 6 | 7 | class ExecuteTestCase(unittest.TestCase): 8 | 9 | def setUp(self): 10 | self.p = cpa.dbconnect.p 11 | self.db = cpa.dbconnect.DBConnect() 12 | cursor = Mock() 13 | connID = threading.currentThread().getName() 14 | self.db.connections[connID] = Mock() 15 | self.db.cursors[connID] = cursor 16 | 17 | def test_args_to_sqlite(self): 18 | self.p.db_type = 'SQLite' 19 | self.assertRaises(TypeError, lambda: self.db.execute('query', 'args')) 20 | 21 | 22 | class CheckColnameUserTestCase(unittest.TestCase): 23 | def setUp(self): 24 | self.db = cpa.dbconnect.DBConnect() 25 | self.p = cpa.dbconnect.p 26 | self.p.image_table = 'Per_Image' 27 | self.p.object_table = 'Per_Object' 28 | self.f = cpa.dbconnect._check_colname_user 29 | 30 | def test_not_user_image(self): 31 | self.assertRaises(ValueError, lambda: self.f(self.p, 'Per_Image', 'foo')) 32 | 33 | def test_user_image(self): 34 | self.f(self.p, 'Per_Image', 'User_foo') 35 | 36 | def test_not_user_object(self): 37 | self.assertRaises(ValueError, lambda: self.f(self.p, 'Per_Object', 'foo')) 38 | 39 | def test_user_object(self): 40 | self.f(self.p, 'Per_Object', 'usEr_foo') 41 | 42 | def test_not_user_other(self): 43 | self.f(self.p, 'MetadataTable', 'foo') 44 | 45 | 46 | class AppendColumnTestCase(unittest.TestCase): 47 | def setUp(self): 48 | self.db = cpa.dbconnect.DBConnect() 49 | self.p = cpa.dbconnect.p 50 | self.p.image_table = 'Per_Image' 51 | self.p.object_table = 'Per_Object' 52 | 53 | def test_blank_name(self): 54 | self.assertRaises(ValueError, lambda: self.db.AppendColumn('FooTable', '', 'TEXT')) 55 | 56 | def test_start_number(self): 57 | self.assertRaises(ValueError, lambda: self.db.AppendColumn('FooTable', '1s', 'TEXT')) 58 | 59 | def test_symbol(self): 60 | self.assertRaises(ValueError, lambda: self.db.AppendColumn('FooTable', 'foo$bar', 'TEXT')) 61 | 62 | 63 | class UpdateWellsTestCase(unittest.TestCase): 64 | def setUp(self): 65 | self.db = cpa.dbconnect.DBConnect() 66 | self.p = cpa.dbconnect.p 67 | self.p.image_table = 'Per_Image' 68 | self.p.object_table = 'Per_Object' 69 | self.p.well_id = 'Well' 70 | 71 | def test_double_quote(self): 72 | with patch.object(self.db, 'execute') as execute: 73 | self.assertRaises(ValueError, lambda: self.db.UpdateWells("Per_Image", "User_BarColumn", 'baz"quux', [('A01',)])) 74 | 75 | def test_single_quote(self): 76 | with patch.object(self.db, 'execute') as execute: 77 | self.assertRaises(ValueError, lambda: self.db.UpdateWells("Per_Image", "User_BarColumn", "baz'quux", [('A01',)])) 78 | 79 | def test_backtick(self): 80 | with patch.object(self.db, 'execute') as execute: 81 | self.assertRaises(ValueError, lambda: self.db.UpdateWells("Per_Image", "User_BarColumn", "baz`quux", [('A01',)])) 82 | 83 | def test_null(self): 84 | with patch.object(self.db, 'execute') as execute: 85 | self.db.UpdateWells("Per_Image", "User_BarColumn", None, [('A01',)]) 86 | execute.assert_called_with('UPDATE Per_Image SET User_BarColumn=NULL WHERE Well IN ("A01")') 87 | 88 | def test_string(self): 89 | with patch.object(self.db, 'execute') as execute: 90 | self.db.UpdateWells("Per_Image", "User_BarColumn", "baz", [('A01',)]) 91 | execute.assert_called_with('UPDATE Per_Image SET User_BarColumn="baz" WHERE Well IN ("A01")') 92 | 93 | 94 | 95 | -------------------------------------------------------------------------------- /cpa/tests/test_imagereader.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | import cpa.imagereader 3 | -------------------------------------------------------------------------------- /cpa/tests/test_multiclasssql.py: -------------------------------------------------------------------------------- 1 | import mock 2 | from unittest import TestCase 3 | import cpa.multiclasssql 4 | 5 | class WhereClausesTestCase(TestCase): 6 | def _where_clauses(self, imkeys): 7 | p = mock.Mock() 8 | p.table_id = None 9 | p.image_id = 'ImageNumber' 10 | p.object_table = 'Per_Object' 11 | dm = mock.Mock() 12 | filter_name = None 13 | dm.GetAllImageKeys = lambda x: imkeys 14 | return cpa.multiclasssql._where_clauses(p, dm, filter_name) 15 | 16 | def test_2(self): 17 | result = self._where_clauses([(2,), (1,)]) 18 | print(result) 19 | assert result == ['(1 = 1)'] 20 | 21 | def test_5(self): 22 | result = self._where_clauses([(5,), (4,), (3,), (2,), (1,)]) 23 | assert result == ['(Per_Object.ImageNumber <= 5)'] 24 | 25 | 26 | -------------------------------------------------------------------------------- /cpa/tests/test_properties.py: -------------------------------------------------------------------------------- 1 | import os.path 2 | import cpa 3 | 4 | # Issue #24 5 | # def test_old_filter(): 6 | # fn = os.path.join(os.path.dirname(__file__), 7 | # 'test_properties_old_filter.properties') 8 | # cpa.properties.LoadFile(fn) 9 | 10 | -------------------------------------------------------------------------------- /cpa/tests/test_pylab.py: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | import PIL.Image as Image 5 | import pylab 6 | import numpy as np 7 | 8 | 9 | pylab.figure() 10 | 11 | #im = Image.open("/Users/afraser/Pizzabarn.jpg") 12 | #ivals = np.array(im.getdata()) 13 | #ivals = ivals.reshape((im.size[1], im.size[0], 3)) 14 | #pylab.imshow(ivals[:,:,1], cmap=pylab.cm.gray, aspect='auto') 15 | #pylab.axis('tight') 16 | #pylab.axis('off') 17 | #pylab.subplots_adjust(0.,0.,1.,1.) 18 | 19 | a = np.ones(1000) 20 | a = a.reshape((100,10)) 21 | pylab.imshow(a) 22 | 23 | pylab.show() 24 | -------------------------------------------------------------------------------- /cpa/tests/test_sqltools.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | from mock import patch, Mock 3 | import threading 4 | import os.path 5 | import cpa 6 | 7 | 8 | class TestOldFilter(unittest.TestCase): 9 | def setUp(self): 10 | fn = os.path.join(os.path.dirname(__file__), 11 | 'test_sqltools_old_filter.properties') 12 | p = cpa.properties.Properties() 13 | p.load_file(fn) 14 | self.db = cpa.dbconnect.DBConnect() 15 | cursor = Mock() 16 | connID = threading.currentThread().getName() 17 | self.db.connections[connID] = Mock() 18 | self.db.cursors[connID] = cursor 19 | 20 | 21 | def test_get_tables(self): 22 | p = cpa.properties.Properties() 23 | filter = p._filters['MCF7wt'] 24 | with patch.object(cpa.db, 'execute') as execute: 25 | with patch.object(cpa.db, 'GetResultColumnNames') as GetResultColumnNames: 26 | execute.return_value = [(1, 'SIMPLE', 'Morphology_Per_Image', 'ALL', None, None, None, None, 107760, 'Using where')] 27 | GetResultColumnNames.return_value = ['id', 'select_type', 'table', 'type', 'possible_keys', 'key', 'key_len', 'ref', 'rows', 'Extra'] 28 | tables = filter.get_tables() 29 | self.assertEqual(tables, set(['Morphology_Per_Image'])) 30 | -------------------------------------------------------------------------------- /cpa/tests/testclassifier.py: -------------------------------------------------------------------------------- 1 | import cpa.dbconnect 2 | from cpa.datatable import DataGrid 3 | from cpa.datamodel import DataModel 4 | from cpa.imagecontrolpanel import ImageControlPanel 5 | from cpa.properties import Properties 6 | from cpa.scoredialog import ScoreDialog 7 | import cpa.sortbin 8 | from cpa.tilecollection import EVT_TILE_UPDATED 9 | from cpa.trainingset import TrainingSet 10 | from io import StringIO 11 | import cpa.fastgentleboostingmulticlass 12 | import cpa.imagetools 13 | import cpa.multiclasssql 14 | import cpa.polyafit 15 | import numpy 16 | import os 17 | import wx 18 | from cpa.classifier import * 19 | 20 | 21 | import time 22 | if __name__ == "__main__": 23 | app = wx.App() 24 | 25 | p = Properties() 26 | db = dbconnect.DBConnect() 27 | dm = DataModel() 28 | 29 | # props = '/Volumes/imaging_analysis/2007_10_19_Gilliland_LeukemiaScreens/Screen3_1Apr09_run3/2007_10_19_Gilliland_LeukemiaScreens_Validation_v2_AllBatches_DuplicatesFiltered_FullBarcode_testSinglePlate.properties' 30 | # ts = '/Volumes/imaging_analysis/2007_10_19_Gilliland_LeukemiaScreens/Screen3_1Apr09_run3/trainingvalidation3b.txt' 31 | props = '../Properties/nirht_area_test.properties' 32 | ts = '/Users/afraser/Desktop/MyTrainingSet.txt' 33 | p.LoadFile(props) 34 | classifier = Classifier(p) 35 | classifier.Show(True) 36 | classifier.LoadTrainingSet(ts) 37 | time.sleep(3) 38 | classifier.TrainClassifier() 39 | classifier.ScoreAll() 40 | 41 | app.MainLoop() -------------------------------------------------------------------------------- /cpa/tests/testimagereader.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | from cpa.imagereader import ImageReader 3 | from cpa.properties import Properties 4 | 5 | p = Properties() 6 | 7 | # fake-up some props 8 | p._filename = '../../CPAnalyst_test_data/test_images/' 9 | p.image_channel_colors = ['red','green','blue','none','none','none'] 10 | p.object_name = ['cell', 'cells'] 11 | p.image_names = ['', '', ''] 12 | p.image_id = 'ImageNumber' 13 | 14 | ir = ImageReader() 15 | 16 | class TestImageReader(unittest.TestCase): 17 | 18 | def test_tif1(self): 19 | # TIF RGB, 8-bit, PackBits encoding 20 | fds = ['color.tif'] 21 | images = ir.ReadImages(fds) 22 | assert len(images) == 3 23 | for im in images: 24 | assert 0. <= im.min() <= im.max() <= 1. 25 | assert im.shape == (512, 512) 26 | 27 | def test_tif2(self): 28 | # 2 RGB TIFS 29 | fds = ['color.tif','color.tif'] 30 | images = ir.ReadImages(fds) 31 | assert len(images) == 6 32 | for im in images: 33 | assert 0. <= im.min() <= im.max() <= 1. 34 | assert im.shape == (512, 512) 35 | 36 | def test_tif3(self): 37 | # Buzz buam TIF 8-bit uncompressed 38 | fds = ['01_POS002_D.TIF', 39 | '01_POS002_F.TIF', 40 | '01_POS002_R.TIF'] 41 | images = ir.ReadImages(fds) 42 | assert len(images) == 3 43 | for im in images: 44 | assert 0. <= im.min() <= im.max() <= 1. 45 | assert im.shape == (1006, 1000) 46 | 47 | def test_tif4(self): 48 | # TIF 8-bit PackBits encoding 49 | fds = ['AS_09125_050116030001_D03f00d0.tif', 50 | 'AS_09125_050116030001_D03f00d1.tif', 51 | 'AS_09125_050116030001_D03f00d2.tif',] 52 | images = ir.ReadImages(fds) 53 | assert len(images) == 3 54 | for im in images: 55 | assert 0. <= im.min() <= im.max() <= 1. 56 | assert im.shape == (512, 512) 57 | 58 | def test_tif5(self): 59 | # TIFs from Neurospheres project 60 | fds = ['PANDORA_100324070001_P14f00d0.TIF', 61 | 'PANDORA_100324070001_P14f00d1.TIF',] 62 | images = ir.ReadImages(fds) 63 | assert len(images) == 2 64 | for im in images: 65 | assert 0. <= im.min() <= im.max() <= 1. 66 | assert im.shape == (512, 512) 67 | 68 | def test_jpg1(self): 69 | # JPG 70 | fds = ['30-2A1b.jpg'] 71 | images = ir.ReadImages(fds) 72 | assert len(images) == 3 73 | for im in images: 74 | assert 0. <= im.min() <= im.max() <= 1. 75 | assert im.shape == (1200, 1600) 76 | 77 | def test_dib(self): 78 | # Cellomics dibs 79 | fds = ['AS_09125_050116030001_D03f00d0.DIB', 80 | 'AS_09125_050116030001_D03f00d1.DIB', 81 | 'AS_09125_050116030001_D03f00d2.DIB',] 82 | images = ir.ReadImages(fds) 83 | assert len(images) == 3 84 | for im in images: 85 | assert 0. <= im.min() <= im.max() <= 1. 86 | assert im.shape == (512, 512) 87 | 88 | def test_png(self): 89 | # PNG 90 | fds = ['AS_09125_050116000001_A01f00d0.png', 91 | 'AS_09125_050116000001_A01f00d1.png', 92 | 'AS_09125_050116000001_A01f00d2.png',] 93 | images = ir.ReadImages(fds) 94 | assert len(images) == 3 95 | for im in images: 96 | assert 0. <= im.min() <= im.max() <= 1. 97 | assert im.shape == (512, 512) 98 | 99 | def test_mixed(self): 100 | # READ different image types into same channel set 101 | fds = ['AS_09125_050116030001_D03f00d0.DIB', 102 | 'AS_09125_050116030001_D03f00d1.tif', 103 | 'AS_09125_050116000001_A01f00d2.png',] 104 | images = ir.ReadImages(fds) 105 | assert len(images) == 3 106 | for im in images: 107 | assert 0. <= im.min() <= im.max() <= 1. 108 | assert im.shape == (512, 512) 109 | 110 | if __name__ == "__main__": 111 | unittest.main() -------------------------------------------------------------------------------- /cpa/tests/threadingexample.py: -------------------------------------------------------------------------------- 1 | import time 2 | from threading import * 3 | import wx 4 | 5 | # Button definitions 6 | ID_START = wx.NewId() 7 | ID_STOP = wx.NewId() 8 | 9 | # Define notification event for thread completion 10 | EVT_RESULT_ID = wx.NewId() 11 | 12 | def EVT_RESULT(win, func): 13 | """Define Result Event.""" 14 | win.Connect(- 1, - 1, EVT_RESULT_ID, func) 15 | 16 | class ResultEvent(wx.PyEvent): 17 | """Simple event to carry arbitrary result data.""" 18 | def __init__(self, data): 19 | """Init Result Event.""" 20 | wx.PyEvent.__init__(self) 21 | self.SetEventType(EVT_RESULT_ID) 22 | self.data = data 23 | 24 | # Thread class that executes processing 25 | class WorkerThread(Thread): 26 | """Worker Thread Class.""" 27 | def __init__(self, notify_window): 28 | """Init Worker Thread Class.""" 29 | Thread.__init__(self) 30 | self._notify_window = notify_window 31 | self._want_abort = 0 32 | # This starts the thread running on creation, but you could 33 | # also make the GUI thread responsible for calling this 34 | self.start() 35 | 36 | def run(self): 37 | """Run Worker Thread.""" 38 | # This is the code executing in the new thread. Simulation of 39 | # a long process (well, 10s here) as a simple loop - you will 40 | # need to structure your processing so that you periodically 41 | # peek at the abort variable 42 | for i in range(10): 43 | time.sleep(1) 44 | if self._want_abort: 45 | # Use a result of None to acknowledge the abort (of 46 | # course you can use whatever you'd like or even 47 | # a separate event type) 48 | wx.PostEvent(self._notify_window, ResultEvent(None)) 49 | return 50 | # Here's where the result would be returned (this is an 51 | # example fixed result of the number 10, but it could be 52 | # any Python object) 53 | wx.PostEvent(self._notify_window, ResultEvent(10)) 54 | 55 | def abort(self): 56 | """abort worker thread.""" 57 | # Method for use by main thread to signal an abort 58 | self._want_abort = 1 59 | 60 | # GUI Frame class that spins off the worker thread 61 | class MainFrame(wx.Frame): 62 | """Class MainFrame.""" 63 | def __init__(self, parent, id): 64 | """Create the MainFrame.""" 65 | wx.Frame.__init__(self, parent, id, 'Thread Test') 66 | 67 | # Dumb sample frame with two buttons 68 | wx.Button(self, ID_START, 'Start', pos=(0, 0)) 69 | wx.Button(self, ID_STOP, 'Stop', pos=(0, 50)) 70 | self.status = wx.StaticText(self, - 1, '', pos=(0, 100)) 71 | 72 | self.Bind(wx.EVT_BUTTON, self.OnStart, id=ID_START) 73 | self.Bind(wx.EVT_BUTTON, self.OnStop, id=ID_STOP) 74 | 75 | # Set up event handler for any worker thread results 76 | EVT_RESULT(self, self.OnResult) 77 | 78 | # And indicate we don't have a worker thread yet 79 | self.worker = None 80 | 81 | def OnStart(self, event): 82 | """Start Computation.""" 83 | # Trigger the worker thread unless it's already busy 84 | if not self.worker: 85 | self.status.SetLabel('Starting computation') 86 | self.worker = WorkerThread(self) 87 | 88 | def OnStop(self, event): 89 | """Stop Computation.""" 90 | # Flag the worker thread to stop if running 91 | if self.worker: 92 | self.status.SetLabel('Trying to abort computation') 93 | self.worker.abort() 94 | 95 | def OnResult(self, event): 96 | """Show Result status.""" 97 | if event.data is None: 98 | # Thread aborted (using our convention of None return) 99 | self.status.SetLabel('Computation aborted') 100 | else: 101 | # Process results here 102 | self.status.SetLabel('Computation Result: %s' % event.data) 103 | # In either event, the worker is done 104 | self.worker = None 105 | 106 | class MainApp(wx.App): 107 | """Class Main App.""" 108 | def OnInit(self): 109 | """Init Main App.""" 110 | self.frame = MainFrame(None, - 1) 111 | self.frame.Show(True) 112 | self.SetTopWindow(self.frame) 113 | return True 114 | 115 | if __name__ == '__main__': 116 | app = MainApp(0) 117 | app.MainLoop() 118 | 119 | -------------------------------------------------------------------------------- /cpa/tsne.py: -------------------------------------------------------------------------------- 1 | 2 | # 3 | # tsne.py 4 | # 5 | # Implementation of t-SNE in Python. The implementation was tested on Python 2.5.1, and it requires a working 6 | # installation of NumPy. The implementation comes with an example on the MNIST dataset. In order to plot the 7 | # results of this example, a working installation of matplotlib is required. 8 | # The example can be run by executing: ipython tsne.py -pylab 9 | # 10 | # 11 | # Created by Laurens van der Maaten on 20-12-08. 12 | # Copyright (c) 2008 Tilburg University. All rights reserved. 13 | 14 | import numpy as np 15 | 16 | def Hbeta(D = np.array([]), beta = 1.0): 17 | """Compute the perplexity and the P-row for a specific value of the precision of a Gaussian distribution.""" 18 | 19 | # Compute P-row and corresponding perplexity 20 | P = np.exp(-D.copy() * beta); 21 | sumP = sum(P); 22 | H = np.log(sumP) + beta * np.sum(D * P) / sumP; 23 | P = P / sumP; 24 | return H, P; 25 | 26 | 27 | def x2p(X = np.array([]), tol = 1e-5, perplexity = 30.0): 28 | """Performs a binary search to get P-values in such a way that each conditional Gaussian has the same perplexity.""" 29 | 30 | # Initialize some variables 31 | print("Computing pairwise distances...") 32 | (n, d) = X.shape; 33 | sum_X = np.sum(np.square(X), 1); 34 | D = np.add(np.add(-2 * np.dot(X, X.T), sum_X).T, sum_X); 35 | P = np.zeros((n, n)); 36 | beta = np.ones((n, 1)); 37 | logU = np.log(perplexity); 38 | 39 | # Loop over all datapoints 40 | for i in range(n): 41 | 42 | # Print progress 43 | if i % 500 == 0: 44 | print(("Computing P-values for point ", i, " of ", n, "...")) 45 | 46 | # Compute the Gaussian kernel and entropy for the current precision 47 | betamin = -np.inf; 48 | betamax = np.inf; 49 | Di = D[i, np.concatenate((np.r_[0:i], np.r_[i+1:n]))]; 50 | (H, thisP) = Hbeta(Di, beta[i]); 51 | 52 | # Evaluate whether the perplexity is within tolerance 53 | Hdiff = H - logU; 54 | tries = 0; 55 | while np.abs(Hdiff) > tol and tries < 50: 56 | 57 | # If not, increase or decrease precision 58 | if Hdiff > 0: 59 | betamin = beta[i]; 60 | if betamax == np.inf or betamax == -np.inf: 61 | beta[i] = beta[i] * 2; 62 | else: 63 | beta[i] = (beta[i] + betamax) / 2; 64 | else: 65 | betamax = beta[i]; 66 | if betamin == np.inf or betamin == -np.inf: 67 | beta[i] = beta[i] / 2; 68 | else: 69 | beta[i] = (beta[i] + betamin) / 2; 70 | 71 | # Recompute the values 72 | (H, thisP) = Hbeta(Di, beta[i]); 73 | Hdiff = H - logU; 74 | tries = tries + 1; 75 | 76 | # Set the final row of P 77 | P[i, np.concatenate((np.r_[0:i], np.r_[i+1:n]))] = thisP; 78 | 79 | # Return final P-matrix 80 | print(("Mean value of sigma: ", np.mean(np.sqrt(1 / beta)))) 81 | return P; 82 | 83 | 84 | def pca(X = np.array([]), no_dims = 50): 85 | """Runs PCA on the NxD array X in order to reduce its dimensionality to no_dims dimensions.""" 86 | 87 | print("Preprocessing the data using PCA...") 88 | (n, d) = X.shape; 89 | X = X - np.tile(np.mean(X, 0), (n, 1)); 90 | (l, M) = np.linalg.eig(np.dot(X.T, X)); 91 | Y = np.dot(X, M[:,0:no_dims]); 92 | np.testing.assert_array_almost_equal(np.imag(Y), np.zeros(Y.shape)) 93 | return np.real(Y); 94 | 95 | 96 | def tsne(X = np.array([]), no_dims = 2, initial_dims = 50, perplexity = 30.0): 97 | """Runs t-SNE on the dataset in the NxD array X to reduce its dimensionality to no_dims dimensions. 98 | The syntaxis of the function is Y = tsne.tsne(X, no_dims, perplexity), where X is an NxD NumPy array.""" 99 | 100 | # Check inputs 101 | if X.dtype != "float64": 102 | print("Error: array X should have type float64."); 103 | return -1; 104 | #if no_dims.__class__ != "": # doesn't work yet! 105 | # print "Error: number of dimensions should be an integer."; 106 | # return -1; 107 | 108 | # Initialize variables 109 | X = pca(X, initial_dims); 110 | (n, d) = X.shape; 111 | max_iter = 1000; 112 | initial_momentum = 0.5; 113 | final_momentum = 0.8; 114 | eta = 500; 115 | min_gain = 0.01; 116 | Y = np.random.randn(n, no_dims); 117 | dY = np.zeros((n, no_dims)); 118 | iY = np.zeros((n, no_dims)); 119 | gains = np.ones((n, no_dims)); 120 | 121 | # Compute P-values 122 | P = x2p(X, 1e-5, perplexity); 123 | P = P + np.transpose(P); 124 | P = P / np.sum(P); 125 | P = P * 4; # early exaggeration 126 | P = np.maximum(P, 1e-12); 127 | 128 | # Run iterations 129 | for iter in range(max_iter): 130 | 131 | # Compute pairwise affinities 132 | sum_Y = np.sum(np.square(Y), 1); 133 | num = 1 / (1 + np.add(np.add(-2 * np.dot(Y, Y.T), sum_Y).T, sum_Y)); 134 | num[list(range(n)), list(range(n))] = 0; 135 | Q = num / np.sum(num); 136 | Q = np.maximum(Q, 1e-12); 137 | 138 | # Compute gradient 139 | PQ = P - Q; 140 | for i in range(n): 141 | dY[i,:] = np.sum(np.tile(PQ[:,i] * num[:,i], (no_dims, 1)).T * (Y[i,:] - Y), 0); 142 | 143 | # Perform the update 144 | if iter < 20: 145 | momentum = initial_momentum 146 | else: 147 | momentum = final_momentum 148 | gains = (gains + 0.2) * ((dY > 0) != (iY > 0)) + (gains * 0.8) * ((dY > 0) == (iY > 0)); 149 | gains[gains < min_gain] = min_gain; 150 | iY = momentum * iY - eta * (gains * dY); 151 | Y = Y + iY; 152 | Y = Y - np.tile(np.mean(Y, 0), (n, 1)); 153 | 154 | # Compute current value of cost function 155 | if (iter + 1) % 10 == 0: 156 | C = np.sum(P * np.log(P / Q)); 157 | print(("Iteration ", (iter + 1), ": error is ", C)) 158 | 159 | # Stop lying about P-values 160 | if iter == 100: 161 | P = P / 4; 162 | 163 | # Return solution 164 | return Y; 165 | 166 | 167 | if __name__ == "__main__": 168 | import pylab 169 | print("Run Y = tsne.tsne(X, no_dims, perplexity) to perform t-SNE on your dataset.") 170 | print("Running example on 2,500 MNIST digits...") 171 | X = np.loadtxt("mnist2500_X.txt"); 172 | labels = np.loadtxt("mnist2500_labels.txt"); 173 | Y = tsne(X, 2, 50, 20.0); 174 | pylab.scatter(Y[:,0], Y[:,1], 20, labels); 175 | -------------------------------------------------------------------------------- /cpa/updatechecker.py: -------------------------------------------------------------------------------- 1 | import datetime 2 | import logging 3 | import requests 4 | import wx 5 | 6 | from . import __version__ as current_version 7 | from .cpaprefs import get_check_update, get_check_update_bool, set_check_update 8 | 9 | 10 | def check_update(origin, force=False, event=True): 11 | if not force and not check_date(): 12 | return 13 | if event: 14 | parent = origin.GetEventObject().GetWindow() 15 | else: 16 | parent = origin 17 | try: 18 | response = requests.get("https://api.github.com/repos/cellprofiler/cellprofiler-analyst/releases/latest", timeout=0.25) 19 | except: 20 | response = False 21 | message = "CellProfiler-Analyst was unable to connect to GitHub to check for updates" 22 | if response: 23 | status = response.status_code 24 | response = response.json() 25 | if status == 200 and 'tag_name' in response: 26 | latest = response['tag_name'] 27 | latest = tuple(map(int, (latest.split(".")))) 28 | current = tuple(map(int, (current_version.split(".")))) 29 | if current < latest: 30 | body_text = response['body'] 31 | if len(body_text) > 1000: 32 | body_text = body_text[:1000] + "..." 33 | elif len(body_text) == 0: 34 | body_text = "No information available" 35 | logging.info(f"An update for CellProfiler-Analyst is available ({response['tag_name']})") 36 | show_message(parent, response['tag_name'], body_text) 37 | return 38 | else: 39 | message = "CellProfiler-Analyst is up-to-date" 40 | if get_check_update() != "Disabled": 41 | set_check_update(datetime.date.today().strftime("%Y%m%d")) 42 | elif status == 200: 43 | message = "Unable to read data from GitHub, API may have changed." 44 | else: 45 | message = "Invalid response from GitHub server, site may be down." 46 | if force: 47 | # User explicitly asked for a check, display a popup even with no available updates. 48 | dlg = wx.MessageDialog( 49 | parent, 50 | message, 51 | caption="Check for updates", 52 | style=wx.ICON_INFORMATION | wx.OK, 53 | ) 54 | dlg.ShowModal() 55 | else: 56 | logging.info(message) 57 | 58 | 59 | def show_message(parent, version, blurb): 60 | message = f"""A new CellProfiler-Analyst release is available:\n\nVersion {version}\n 61 | Would you like to visit the download page?""" 62 | dlg = wx.RichMessageDialog( 63 | parent, 64 | message, 65 | caption="CellProfiler-Analyst Update Available", 66 | style=wx.YES_NO | wx.CENTRE | wx.ICON_INFORMATION, 67 | ) 68 | dlg.ShowDetailedText(f"Release Notes:\n{blurb}") 69 | dlg.ShowCheckBox("Check for updates on startup", checked=get_check_update_bool()) 70 | response = dlg.ShowModal() 71 | if response == wx.ID_YES: 72 | wx.LaunchDefaultBrowser("https://cellprofileranalyst.org/releases") 73 | if not dlg.IsCheckBoxChecked(): 74 | set_check_update("Disabled") 75 | else: 76 | set_check_update(datetime.date.today().strftime("%Y%m%d")) 77 | 78 | 79 | def check_date(): 80 | last_checked = get_check_update() 81 | if last_checked == "Disabled": 82 | # Updating is disabled 83 | return False 84 | elif last_checked == "Never": 85 | return True 86 | today = datetime.date.today() 87 | last_checked = datetime.datetime.strptime(last_checked, "%Y%m%d").date() 88 | if (last_checked - today).days >= 7: 89 | return True 90 | else: 91 | return False -------------------------------------------------------------------------------- /cpa/util/frozen_version.py: -------------------------------------------------------------------------------- 1 | # MANUAL 2 | version_string = '2.2.1' -------------------------------------------------------------------------------- /cpa/util/version.py: -------------------------------------------------------------------------------- 1 | '''version.py - Version fetching and comparison. 2 | 3 | CellProfiler Analyst is distributed under the GNU General Public License, 4 | but this file is licensed under the more permissive BSD license. 5 | See the accompanying file LICENSE for details. 6 | 7 | Copyright (c) 2003-2009 Massachusetts Institute of Technology 8 | Copyright (c) 2009-2021 Broad Institute 9 | 10 | All rights reserved. 11 | 12 | Please see the AUTHORS file for credits. 13 | 14 | Website: http://www.cellprofileranalyst.org 15 | ''' 16 | 17 | 18 | import re 19 | import sys 20 | import os.path 21 | 22 | _cached_description = None 23 | 24 | __version__ = '3.0.4' # Version used by update checker, must be in format "N.N.N" 25 | _sub_version = '' # Use this to tag release candidates, betas, etc. 26 | 27 | display_version = __version__ + _sub_version 28 | 29 | def _get_description(): 30 | """Get description from git or file system. 31 | 32 | If we're not frozen and this is a git repository, try to get the 33 | description by running ``git describe``, then store it in 34 | javabridge/_description.py. Otherwise, try to load the description 35 | from that file. If both methods fail, quietly return None. 36 | 37 | """ 38 | global _cached_description 39 | git_description = None 40 | if (not hasattr(sys, 'frozen') and 41 | os.path.exists(os.path.join(os.path.dirname(__file__), '..', '..', 42 | '.git'))): 43 | import subprocess 44 | try: 45 | git_description = subprocess.Popen(['git', 'describe', '--long'], 46 | stdout=subprocess.PIPE).communicate()[0].strip() 47 | except: 48 | pass 49 | 50 | description_file = os.path.join(os.path.dirname(__file__), '..', 51 | '_description.py') 52 | if os.path.exists(description_file): 53 | with open(description_file) as f: 54 | cached_description_line = f.read().strip() 55 | try: 56 | # From http://stackoverflow.com/a/3619714/17498 57 | _cached_description = re.search(r"^__description__ = ['\"]([^'\"]*)['\"]", 58 | cached_description_line, re.M).group(1) 59 | except: 60 | raise RuntimeError("Unable to find description in %s" % description_file) 61 | else: 62 | _cached_description = None 63 | 64 | if git_description and git_description != _cached_description: 65 | with open(description_file, 'w') as f: 66 | print('__description__ = "%s"' % git_description, file=f) 67 | 68 | return git_description or _cached_description 69 | 70 | def _parse_description(description): 71 | if description is None: 72 | return None 73 | m = re.match('(.*)-(\d+)-g([0-9a-f]+)$', description) 74 | if m is None: 75 | return None 76 | else: 77 | return m.groups() 78 | 79 | def get_commit(_description=_get_description()): 80 | tag, additional, commit = _parse_description(_description) 81 | return commit 82 | 83 | if __name__ == '__main__': 84 | if len(sys.argv) == 2: 85 | description = sys.argv[1] 86 | elif len(sys.argv) == 1: 87 | description = _get_description() 88 | else: 89 | print("Usage: %s [DESCRIPTION]" % os.path.basename(sys.argv[0]), file=sys.stderr) 90 | sys.exit(64) # EX_USAGE 91 | print('Description:', description) 92 | print('Version:', __version__) 93 | print('Commit:', get_commit(description)) 94 | -------------------------------------------------------------------------------- /cpa/utils.py: -------------------------------------------------------------------------------- 1 | 2 | class Observable: 3 | '''Mixin for objects that need to be observed by other objects.''' 4 | _observers = None 5 | def addobserver(self, observer): 6 | if not self._observers: 7 | self._observers = [] 8 | self._observers.append(observer) 9 | 10 | def removeobserver(self, observer): 11 | if self._observers and observer in self._observers: 12 | self._observers.remove(observer) 13 | 14 | def notify(self, event): 15 | for o in self._observers or (): 16 | o(event) 17 | 18 | 19 | class ObservableDict(dict, Observable): 20 | def __setitem__(self, key, value): 21 | dict.__setitem__(self, key, value) 22 | self.notify((key, value)) 23 | 24 | def __delitem__(self, key): 25 | dict.__delitem__(self, key) 26 | self.notify((key, None)) 27 | 28 | def pop(self, key): 29 | v = dict.pop(self, key) 30 | self.notify((key, None)) 31 | return v 32 | 33 | def clear(self): 34 | dict.clear(self) 35 | self.notify(None) 36 | 37 | 38 | # AutoSave 39 | import threading 40 | from functools import wraps 41 | 42 | def delay(delay=0.): 43 | """ 44 | Decorator delaying the execution of a function for a while. 45 | """ 46 | def wrap(f): 47 | @wraps(f) 48 | def delayed(*args, **kwargs): 49 | timer = threading.Timer(delay, f, args=args, kwargs=kwargs) 50 | timer.start() 51 | return delayed 52 | return wrap -------------------------------------------------------------------------------- /distribution/macos/CellProfiler-Analyst.spec: -------------------------------------------------------------------------------- 1 | # -*- mode: python ; coding: utf-8 -*- 2 | 3 | import os 4 | import os.path 5 | 6 | import PyInstaller.compat 7 | import PyInstaller.utils.hooks 8 | 9 | binaries = [] 10 | 11 | block_cipher = None 12 | 13 | datas = [] 14 | 15 | datas += PyInstaller.utils.hooks.collect_data_files("bioformats") 16 | datas += PyInstaller.utils.hooks.collect_data_files("javabridge") 17 | 18 | datas += [ 19 | ("../../cpa/icons/*", "cpa/icons"), 20 | ] 21 | 22 | for subdir, dirs, files in os.walk(os.environ["JAVA_HOME"]): 23 | if 'Contents/' in subdir: 24 | if len(subdir.split('Contents/')) >1: 25 | _, subdir_split = subdir.split('Contents/') 26 | for file in files: 27 | datas += [(os.path.join(subdir, file), subdir_split)] 28 | 29 | hiddenimports = [] 30 | 31 | hiddenimports += PyInstaller.utils.hooks.collect_submodules('sklearn.utils') 32 | hiddenimports += ['cmath'] 33 | 34 | excludes = [] 35 | 36 | excludes += [ 37 | "PyQt5.QtGui", 38 | "PyQt5.QtCore", 39 | "PyQt4.QtGui", 40 | "PyQt4.QtCore", 41 | "PySide.QtGui", 42 | "PySide.QtCore", 43 | "PyQt5", 44 | "PyQt4", 45 | "PySide", 46 | "PySide2", 47 | "FixTk", 48 | "tcl", 49 | "tk", 50 | "_tkinter", 51 | "tkinter", 52 | "Tkinter" 53 | ] 54 | 55 | 56 | a = Analysis(['../../CellProfiler-Analyst.py'], 57 | pathex=['CellProfiler-Analyst'], 58 | binaries=binaries, 59 | datas=datas, 60 | excludes=excludes, 61 | hiddenimports=hiddenimports, 62 | hookspath=[], 63 | runtime_hooks=[], 64 | win_no_prefer_redirects=False, 65 | win_private_assemblies=False, 66 | cipher=block_cipher) 67 | 68 | libpng_pathname = PyInstaller.utils.hooks.get_homebrew_path("libpng") 69 | libpng_pathname = os.path.join(libpng_pathname, "lib", "libpng16.16.dylib") 70 | 71 | java_pathname = os.path.join(os.environ["JAVA_HOME"], "lib/libjava.dylib") 72 | a.binaries += [ 73 | ("libpng16.16.dylib", libpng_pathname, "BINARY"), 74 | ("libjava.dylib", java_pathname, "BINARY") 75 | ] 76 | 77 | exclude_binaries = [ 78 | ('libpng16.16.dylib', '/usr/local/lib/python3.8/site-packages/matplotlib/.dylibs/libpng16.16.dylib', 'BINARY'), 79 | ] 80 | 81 | a.binaries = [binary for binary in a.binaries if binary not in exclude_binaries] 82 | 83 | pyz = PYZ( 84 | a.pure, 85 | a.zipped_data, 86 | cipher=block_cipher 87 | ) 88 | 89 | exe = EXE( 90 | pyz, 91 | a.scripts, 92 | exclude_binaries=True, 93 | name="cpanalyst", 94 | debug=True, 95 | strip=False, 96 | upx=True, 97 | console=False 98 | ) 99 | 100 | coll = COLLECT( 101 | exe, 102 | a.binaries, 103 | a.zipfiles, 104 | a.datas, 105 | icon="../../cpa/icons/cpa.icns", 106 | name="CellProfiler-Analyst.app" 107 | ) 108 | 109 | app = BUNDLE( 110 | coll, 111 | name="CellProfiler-Analyst.app", 112 | icon="../../cpa/icons/cpa.icns", 113 | bundle_identifier=None 114 | ) -------------------------------------------------------------------------------- /distribution/macos/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | English 7 | CFBundleDisplayName 8 | CellProfiler-Analyst 9 | CFBundleExecutable 10 | MacOS/cpanalyst 11 | CFBundleIconFile 12 | cpa.icns 13 | CFBundleIdentifier 14 | org.cellprofiler.CellProfiler-Analyst 15 | CFBundleInfoDictionaryVersion 16 | 6.0 17 | CFBundleName 18 | CellProfiler-Analyst 19 | CFBundleVersion 20 | 4.0.0 21 | CFBundleShortVersionString 22 | 4.0.0 23 | LSApplicationCategoryType 24 | 25 | CFBundleDocumentTypes 26 | 27 | 28 | CFBundleTypeExtensions 29 | 30 | workspace 31 | 32 | CFBundleTypeIconFile 33 | cpa.icns 34 | CFBundleTypeName 35 | CellProfiler-Analyst Workspace 36 | CFBundleTypeRole 37 | Editor 38 | 39 | 40 | LSEnvironment 41 | 42 | JAVA_HOME 43 | ./Contents 44 | 45 | NSHighResolutionCapable 46 | 47 | 48 | 49 | -------------------------------------------------------------------------------- /distribution/macos/Makefile: -------------------------------------------------------------------------------- 1 | MAKEFLAGS += --warn-undefined-variables 2 | 3 | SHELL := bash 4 | 5 | .DEFAULT_GOAL := dist/CellProfiler-Analyst.app 6 | 7 | .DELETE_ON_ERROR: 8 | 9 | .SHELLFLAGS := -eu -o pipefail -c 10 | 11 | .SUFFIXES: 12 | 13 | CellProfiler-Analyst: 14 | git clone https://github.com/CellProfiler/CellProfiler-Analyst.git 15 | 16 | cd $@ 17 | 18 | .PHONY: dependencies 19 | dependencies: CellProfiler-Analyst 20 | pip3 install --editable CellProfiler-Analyst --upgrade 21 | 22 | dist/CellProfiler-Analyst.app: CellProfiler-Analyst dependencies Info.plist 23 | pyinstaller --noconfirm CellProfiler-Analyst.spec 24 | 25 | cp $(word 3, $^) $@/Contents 26 | 27 | cp entitlements.plist $@/Contents/MacOS 28 | 29 | .PHONY: clean 30 | clean: 31 | if [ -d CellProfiler-Analyst ]; then rm -rf CellProfiler-Analyst; fi 32 | 33 | if [ -d build ]; then rm -rf build; fi 34 | 35 | if [ -d dist ]; then rm -rf build; fi 36 | 37 | if [ CellProfiler.dmg ]; then rm -rf CellProfiler.dmg; fi 38 | -------------------------------------------------------------------------------- /distribution/macos/add-osx-certificate.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | KEY_CHAIN=build.keychain 4 | CERTIFICATE_P12=certificate.p12 5 | 6 | # Recreate the certificate from the secure environment variable 7 | echo $CERTIFICATE_OSX_APPLICATION | base64 --decode > $CERTIFICATE_P12 8 | 9 | #create a keychain 10 | security create-keychain -p actions $KEY_CHAIN 11 | 12 | # Make the keychain the default so identities are found 13 | security default-keychain -s $KEY_CHAIN 14 | 15 | # Unlock the keychain 16 | security unlock-keychain -p actions $KEY_CHAIN 17 | 18 | security import $CERTIFICATE_P12 -k $KEY_CHAIN -P $CERTIFICATE_PASSWORD -T /usr/bin/codesign; 19 | 20 | security set-key-partition-list -S apple-tool:,apple: -s -k actions $KEY_CHAIN 21 | 22 | # remove certs 23 | rm -fr *.p12 24 | 25 | 26 | -------------------------------------------------------------------------------- /distribution/macos/entitlements.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | com.apple.security.cs.allow-jit 6 | 7 | com.apple.security.cs.allow-unsigned-executable-memory 8 | 9 | com.apple.security.cs.disable-executable-page-protection 10 | 11 | com.apple.security.cs.allow-dyld-environment-variables 12 | 13 | com.apple.security.cs.disable-library-validation 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /distribution/macos/osx-codesign.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | cd ./dist/CellProfiler-Analyst.app/Contents/Resources 4 | sudo rm -r Home/legal/ 5 | sudo codesign --timestamp -s "Apple Development: alicelucas93@gmail.com (P6D4NCA4CT)" Home/lib/server/classes.jsa 6 | find . -type f | xargs -I file codesign --timestamp -f -s "Apple Development: alicelucas93@gmail.com (P6D4NCA4CT)" file 7 | cd ../MacOS 8 | find . -type f | xargs -I file sudo codesign --timestamp -f -s "Apple Development: alicelucas93@gmail.com (P6D4NCA4CT)" file 9 | codesign --timestamp -f -s "Apple Development: alicelucas93@gmail.com (P6D4NCA4CT)" _elementtree.cpython-38-darwin.so 10 | codesign --entitlements entitlements.plist --timestamp -o runtime -s "Apple Development: alicelucas93@gmail.com (P6D4NCA4CT)" ./cpanalyst 11 | cd .. 12 | codesign --timestamp -s "Apple Development: alicelucas93@gmail.com (P6D4NCA4CT)" Info.plist 13 | 14 | 15 | -------------------------------------------------------------------------------- /distribution/windows/CellProfiler-Analyst.iss: -------------------------------------------------------------------------------- 1 | ; Script generated by the Inno Script Studio Wizard. 2 | ; SEE THE DOCUMENTATION FOR DETAILS ON CREATING INNO SETUP SCRIPT FILES! 3 | 4 | #define MyAppName "CellProfiler-Analyst" 5 | #define MyAppPublisher "Broad Institute" 6 | #define MyAppURL "http:\\cellprofileranalyst.org" 7 | #define MyAppExeName "CellProfiler-Analyst.exe" 8 | 9 | [Setup] 10 | ; NOTE: The value of AppId uniquely identifies this application. 11 | ; Do not use the same AppId value in installers for other applications. 12 | ; (To generate a new GUID, click Tools | Generate GUID inside the IDE.) 13 | AppId={{9A310638-495F-4817-9AC1-6094DD90E821} 14 | AppName={#MyAppName} 15 | AppVersion={#MyAppVersion} 16 | ;AppVerName={#MyAppName} {#MyAppVersion} 17 | AppPublisher={#MyAppPublisher} 18 | AppPublisherURL={#MyAppURL} 19 | AppSupportURL={#MyAppURL} 20 | AppUpdatesURL={#MyAppURL} 21 | DefaultDirName={pf64}\{#MyAppName} 22 | DefaultGroupName={#MyAppName} 23 | LicenseFile=..\..\LICENSE 24 | OutputBaseFilename=CellProfiler-Analyst-Windows-{#MyAppVersion} 25 | Compression=lzma 26 | SolidCompression=yes 27 | DisableDirPage=no 28 | 29 | [Languages] 30 | Name: "english"; MessagesFile: "compiler:Default.isl" 31 | 32 | [Tasks] 33 | Name: "desktopicon"; Description: "{cm:CreateDesktopIcon}"; GroupDescription: "{cm:AdditionalIcons}"; Flags: unchecked 34 | 35 | [Files] 36 | Source: "D:\a\CellProfiler-Analyst\CellProfiler-Analyst\dist\CellProfiler-Analyst\CellProfiler-Analyst.exe"; DestDir: "{app}"; Flags: ignoreversion 37 | Source: "D:\a\CellProfiler-Analyst\CellProfiler-Analyst\dist\CellProfiler-Analyst\*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs createallsubdirs 38 | Source: "C:\hostedtoolcache\windows\jdk\14.0.1\x64\*"; DestDir: "{app}\java"; Flags: recursesubdirs 39 | ; NOTE: Don't use "Flags: ignoreversion" on any shared system files 40 | 41 | [Icons] 42 | Name: "{commonprograms}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}" 43 | Name: "{commondesktop}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"; Tasks: desktopicon 44 | 45 | [Run] 46 | Filename: "{app}\{#MyAppExeName}"; Description: "{cm:LaunchProgram,{#StringChange(MyAppName, '&', '&&')}}"; Flags: nowait postinstall skipifsilent 47 | -------------------------------------------------------------------------------- /distribution/windows/CellProfiler-Analyst.spec: -------------------------------------------------------------------------------- 1 | # -*- mode: python ; coding: utf-8 -*- 2 | 3 | import os 4 | import os.path 5 | 6 | import PyInstaller.compat 7 | import PyInstaller.utils.hooks 8 | 9 | binaries = [] 10 | 11 | block_cipher = None 12 | 13 | datas = [] 14 | 15 | datas += PyInstaller.utils.hooks.collect_data_files("bioformats") 16 | datas += PyInstaller.utils.hooks.collect_data_files("javabridge") 17 | 18 | datas += [ 19 | ("../../cpa/icons/*", "cpa/icons"), 20 | ] 21 | 22 | hiddenimports = [] 23 | 24 | hiddenimports += PyInstaller.utils.hooks.collect_submodules('sklearn.utils') 25 | 26 | a = Analysis(['../../CellProfiler-Analyst.py'], 27 | pathex=['CellProfiler-Analyst'], 28 | binaries=binaries, 29 | datas=datas, 30 | hiddenimports=hiddenimports, 31 | hookspath=[], 32 | runtime_hooks=[], 33 | excludes=[], 34 | win_no_prefer_redirects=False, 35 | win_private_assemblies=False, 36 | cipher=block_cipher, 37 | noarchive=False) 38 | pyz = PYZ(a.pure, a.zipped_data, 39 | cipher=block_cipher) 40 | exe = EXE(pyz, 41 | a.scripts, 42 | [], 43 | exclude_binaries=True, 44 | name='CellProfiler-Analyst', 45 | debug=False, 46 | bootloader_ignore_signals=False, 47 | strip=False, 48 | upx=True, 49 | icon='../../cpa/icons/cpa.ico', 50 | console=False ) 51 | coll = COLLECT(exe, 52 | a.binaries, 53 | a.zipfiles, 54 | a.datas, 55 | strip=False, 56 | upx=True, 57 | upx_exclude=[], 58 | name='CellProfiler-Analyst') 59 | -------------------------------------------------------------------------------- /docs/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2016, David Dao 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | 7 | * Redistributions of source code must retain the above copyright notice, this 8 | list of conditions and the following disclaimer. 9 | 10 | * Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions and the following disclaimer in the documentation 12 | and/or other materials provided with the distribution. 13 | 14 | * Neither the name of CPA-docs nor the names of its 15 | contributors may be used to endorse or promote products derived from 16 | this software without specific prior written permission. 17 | 18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 22 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 24 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 25 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 26 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | -------------------------------------------------------------------------------- /docs/Makefile: -------------------------------------------------------------------------------- 1 | # Makefile for Sphinx documentation 2 | # 3 | 4 | # You can set these variables from the command line. 5 | SPHINXOPTS = 6 | SPHINXBUILD = sphinx-build 7 | PAPER = 8 | BUILDDIR = build 9 | 10 | # Internal variables. 11 | PAPEROPT_a4 = -D latex_paper_size=a4 12 | PAPEROPT_letter = -D latex_paper_size=letter 13 | ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) source 14 | # the i18n builder cannot share the environment and doctrees with the others 15 | I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) source 16 | 17 | .PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext 18 | 19 | help: 20 | @echo "Please use \`make ' where is one of" 21 | @echo " html to make standalone HTML files" 22 | @echo " dirhtml to make HTML files named index.html in directories" 23 | @echo " singlehtml to make a single large HTML file" 24 | @echo " pickle to make pickle files" 25 | @echo " json to make JSON files" 26 | @echo " htmlhelp to make HTML files and a HTML help project" 27 | @echo " qthelp to make HTML files and a qthelp project" 28 | @echo " devhelp to make HTML files and a Devhelp project" 29 | @echo " epub to make an epub" 30 | @echo " latexmake to make LaTeX files, you can set PAPER=a4 or PAPER=letter" 31 | @echo " latexpdf to make LaTeX files and run them through pdflatex" 32 | @echo " text to make text files" 33 | @echo " man to make manual pages" 34 | @echo " texinfo to make Texinfo files" 35 | @echo " info to make Texinfo files and run them through makeinfo" 36 | @echo " gettext to make PO message catalogs" 37 | @echo " changes to make an overview of all changed/added/deprecated items" 38 | @echo " linkcheck to check all external links for integrity" 39 | @echo " doctest to run all doctests embedded in the documentation (if enabled)" 40 | 41 | clean: 42 | -rm -rf $(BUILDDIR)/* 43 | 44 | html: 45 | $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html 46 | @echo 47 | @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." 48 | 49 | dirhtml: 50 | $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml 51 | @echo 52 | @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." 53 | 54 | singlehtml: 55 | $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml 56 | @echo 57 | @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." 58 | 59 | pickle: 60 | $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle 61 | @echo 62 | @echo "Build finished; now you can process the pickle files." 63 | 64 | json: 65 | $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json 66 | @echo 67 | @echo "Build finished; now you can process the JSON files." 68 | 69 | htmlhelp: 70 | $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp 71 | @echo 72 | @echo "Build finished; now you can run HTML Help Workshop with the" \ 73 | ".hhp project file in $(BUILDDIR)/htmlhelp." 74 | 75 | qthelp: 76 | $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp 77 | @echo 78 | @echo "Build finished; now you can run "qcollectiongenerator" with the" \ 79 | ".qhcp project file in $(BUILDDIR)/qthelp, like this:" 80 | @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/SphinxRTDthemedemo.qhcp" 81 | @echo "To view the help file:" 82 | @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/SphinxRTDthemedemo.qhc" 83 | 84 | devhelp: 85 | $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp 86 | @echo 87 | @echo "Build finished." 88 | @echo "To view the help file:" 89 | @echo "# mkdir -p $$HOME/.local/share/devhelp/SphinxRTDthemedemo" 90 | @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/SphinxRTDthemedemo" 91 | @echo "# devhelp" 92 | 93 | epub: 94 | $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub 95 | @echo 96 | @echo "Build finished. The epub file is in $(BUILDDIR)/epub." 97 | 98 | latex: 99 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex 100 | @echo 101 | @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." 102 | @echo "Run \`make' in that directory to run these through (pdf)latex" \ 103 | "(use \`make latexpdf' here to do that automatically)." 104 | 105 | latexpdf: 106 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex 107 | @echo "Running LaTeX files through pdflatex..." 108 | $(MAKE) -C $(BUILDDIR)/latex all-pdf 109 | @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." 110 | 111 | text: 112 | $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text 113 | @echo 114 | @echo "Build finished. The text files are in $(BUILDDIR)/text." 115 | 116 | man: 117 | $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man 118 | @echo 119 | @echo "Build finished. The manual pages are in $(BUILDDIR)/man." 120 | 121 | texinfo: 122 | $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo 123 | @echo 124 | @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo." 125 | @echo "Run \`make' in that directory to run these through makeinfo" \ 126 | "(use \`make info' here to do that automatically)." 127 | 128 | info: 129 | $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo 130 | @echo "Running Texinfo files through makeinfo..." 131 | make -C $(BUILDDIR)/texinfo info 132 | @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo." 133 | 134 | gettext: 135 | $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale 136 | @echo 137 | @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale." 138 | 139 | changes: 140 | $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes 141 | @echo 142 | @echo "The overview file is in $(BUILDDIR)/changes." 143 | 144 | linkcheck: 145 | $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck 146 | @echo 147 | @echo "Link check complete; look for any errors in the above output " \ 148 | "or in $(BUILDDIR)/linkcheck/output.txt." 149 | 150 | doctest: 151 | $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest 152 | @echo "Testing of doctests in the sources finished, look at the " \ 153 | "results in $(BUILDDIR)/doctest/output.txt." 154 | -------------------------------------------------------------------------------- /docs/README.md: -------------------------------------------------------------------------------- 1 | # CPA-docs 2 | 3 | Manual for CellProfiler Analyst 3.0 4 | 5 | ## How to build 6 | 7 | ```bash 8 | 9 | pip install sphinx_rtd_theme 10 | make html 11 | cd build/html 12 | python -m SimpleHTTPServer . 13 | 14 | ``` 15 | 16 | -------------------------------------------------------------------------------- /docs/build/doctrees/0_introduction.doctree: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CellProfiler/CellProfiler-Analyst/8a7f924052867192b425e4b7f89137fadbbd93fa/docs/build/doctrees/0_introduction.doctree -------------------------------------------------------------------------------- /docs/build/doctrees/10_histogram_plot.doctree: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CellProfiler/CellProfiler-Analyst/8a7f924052867192b425e4b7f89137fadbbd93fa/docs/build/doctrees/10_histogram_plot.doctree -------------------------------------------------------------------------------- /docs/build/doctrees/11_density_plot.doctree: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CellProfiler/CellProfiler-Analyst/8a7f924052867192b425e4b7f89137fadbbd93fa/docs/build/doctrees/11_density_plot.doctree -------------------------------------------------------------------------------- /docs/build/doctrees/12_boxplot.doctree: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CellProfiler/CellProfiler-Analyst/8a7f924052867192b425e4b7f89137fadbbd93fa/docs/build/doctrees/12_boxplot.doctree -------------------------------------------------------------------------------- /docs/build/doctrees/13_workspaces.doctree: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CellProfiler/CellProfiler-Analyst/8a7f924052867192b425e4b7f89137fadbbd93fa/docs/build/doctrees/13_workspaces.doctree -------------------------------------------------------------------------------- /docs/build/doctrees/14_image_gallery.doctree: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CellProfiler/CellProfiler-Analyst/8a7f924052867192b425e4b7f89137fadbbd93fa/docs/build/doctrees/14_image_gallery.doctree -------------------------------------------------------------------------------- /docs/build/doctrees/15_normalization_tool.doctree: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CellProfiler/CellProfiler-Analyst/8a7f924052867192b425e4b7f89137fadbbd93fa/docs/build/doctrees/15_normalization_tool.doctree -------------------------------------------------------------------------------- /docs/build/doctrees/1_preliminary_requirements.doctree: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CellProfiler/CellProfiler-Analyst/8a7f924052867192b425e4b7f89137fadbbd93fa/docs/build/doctrees/1_preliminary_requirements.doctree -------------------------------------------------------------------------------- /docs/build/doctrees/2_installation.doctree: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CellProfiler/CellProfiler-Analyst/8a7f924052867192b425e4b7f89137fadbbd93fa/docs/build/doctrees/2_installation.doctree -------------------------------------------------------------------------------- /docs/build/doctrees/3_properties_file.doctree: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CellProfiler/CellProfiler-Analyst/8a7f924052867192b425e4b7f89137fadbbd93fa/docs/build/doctrees/3_properties_file.doctree -------------------------------------------------------------------------------- /docs/build/doctrees/4_cpa_interface.doctree: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CellProfiler/CellProfiler-Analyst/8a7f924052867192b425e4b7f89137fadbbd93fa/docs/build/doctrees/4_cpa_interface.doctree -------------------------------------------------------------------------------- /docs/build/doctrees/5_classifier.doctree: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CellProfiler/CellProfiler-Analyst/8a7f924052867192b425e4b7f89137fadbbd93fa/docs/build/doctrees/5_classifier.doctree -------------------------------------------------------------------------------- /docs/build/doctrees/6_table_viewer.doctree: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CellProfiler/CellProfiler-Analyst/8a7f924052867192b425e4b7f89137fadbbd93fa/docs/build/doctrees/6_table_viewer.doctree -------------------------------------------------------------------------------- /docs/build/doctrees/7_image_viewer.doctree: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CellProfiler/CellProfiler-Analyst/8a7f924052867192b425e4b7f89137fadbbd93fa/docs/build/doctrees/7_image_viewer.doctree -------------------------------------------------------------------------------- /docs/build/doctrees/8_plate_viewer.doctree: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CellProfiler/CellProfiler-Analyst/8a7f924052867192b425e4b7f89137fadbbd93fa/docs/build/doctrees/8_plate_viewer.doctree -------------------------------------------------------------------------------- /docs/build/doctrees/9_scatter_plot.doctree: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CellProfiler/CellProfiler-Analyst/8a7f924052867192b425e4b7f89137fadbbd93fa/docs/build/doctrees/9_scatter_plot.doctree -------------------------------------------------------------------------------- /docs/build/doctrees/environment.pickle: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CellProfiler/CellProfiler-Analyst/8a7f924052867192b425e4b7f89137fadbbd93fa/docs/build/doctrees/environment.pickle -------------------------------------------------------------------------------- /docs/build/doctrees/index.doctree: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CellProfiler/CellProfiler-Analyst/8a7f924052867192b425e4b7f89137fadbbd93fa/docs/build/doctrees/index.doctree -------------------------------------------------------------------------------- /docs/source/0_introduction.rst: -------------------------------------------------------------------------------- 1 | ============ 2 | Introduction 3 | ============ 4 | 5 | CellProfiler Analyst (CPA) provides tools for classifying biological images and exploring and visualizing multidimensional data (particularly from high-throughput experiments) that has been extracted from companion image analysis software CellProfiler. 6 | 7 | CellProfiler Analyst’s primary tools: 8 | 9 | * **Image Gallery** displays (full and cell) images with a variety of filter options and can be used interactively with other tools. 10 | 11 | * **Classifier** enables cell and field-of-view-level classification of multiple phenotypes using popular supervised machine learning models. 12 | 13 | * **Plate Viewer** displays data according to the spatial layout of the experiment, such as a multi-well plate or microarray. 14 | 15 | * **Scatter Plot**, **Histogram**, and **Density Plot** display numerical data. 16 | 17 | * **Table Viewer** displays numerical and text data in a spreadsheet format, where data points can be clicked to display images. 18 | 19 | * **Normalization Tool** creates a new datatable with normalized and feature-selected columns. 20 | 21 | The CellProfiler project is based at the Broad Institute Imaging Platform. It was started by `Anne E. Carpenter `_ and `Thouis (Ray) Jones `_ 22 | in the laboratories of David M. Sabatini and Polina Golland at the Whitehead Institute for Biomedical Research and MIT's CSAIL. CellProfiler Analyst is tested on MacOS 10.15, 11.2, Windows 7 and 10, and to a lesser extent Linux. Running the software from Linux currently requires use of the source code, which is beyond the scope of this document. 23 | 24 | CellProfiler Analyst is distributed under the BSD-3 Clause (see LICENSE.txt). 25 | -------------------------------------------------------------------------------- /docs/source/10_histogram_plot.rst: -------------------------------------------------------------------------------- 1 | ================= 2 | X. Histogram Plot 3 | ================= 4 | 5 | Launch **Histogram Plot** from the main CPA interface by clicking the button in the toolbar. This 6 | tool allows you to create histogram plots from the numeric columns in your tables. 7 | 8 | To use the **Histogram Plot**, simply select the table whose columns you would like to plot from 9 | the table dropdown. Then select a single measurement from that table in the x-axis dropdown 10 | (only numeric columns will be available). You can also enter the number of bins to use. The filter 11 | dropdown can be used to select filters defined in your properties file to limit the points being 12 | plotted. Finally, click the **Update Chart** button to view the plot. 13 | 14 | Once data is plotted, you can use the tools provided in the toolbar at the top of the window to 15 | explore the plot. Going backwards from right to left, the tools are as follows: 16 | 17 | - **Save**: Clicking this will give you choices for saving the plot as an image. 18 | 19 | * **Zoom-to-rect**: This tool may be toggled on and off. When it is on, you can use the mouse to click and drag a rectangle to zoom in on. The extents of the rectangle will become the new extents of the axes. Use the Back button (below) to zoom back out. 20 | 21 | - **Pan**: This tool may also be toggled. When on, you can use the mouse to pan the axes by clicking and dragging. 22 | 23 | * **Forward** and **Back**: These 2 buttons will redo and undo the zooming and panning actions 38 that you make 24 | 25 | - **Home**: This will reset the view to the way it was after Update Chart was pressed. 26 | 27 | .. figure:: static/10_01.jpg 28 | :align: center 29 | 30 | Using the Histogram Plot to view the distribution of the Nuclei_Intensity_DNA_IntegratedIntensity measurement, with the x-axis displayed in the log space. The distribution appears to be bimodal, each peak representing an accumulation of cells in different stages of mitosis. 31 | -------------------------------------------------------------------------------- /docs/source/11_density_plot.rst: -------------------------------------------------------------------------------- 1 | ================ 2 | XI. Density Plot 3 | ================ 4 | 5 | Launch **Density Plot** from the main CPA interface by clicking the button in the toolbar. This tool 6 | will allow you create density plots from the numeric columns in your tables. 7 | 8 | To use the **Density Plot**, simply select the table whose columns you would like to plot from the 9 | table dropdown. Then select the measurements you would like to plot from that table in the xaxis 10 | and y-axis dropdowns (only numeric columns will be available). To view an axis in the log 11 | scale, choose **log** from the x-scale or y-scale dropdown. You may also enter the grid size to use 12 | for binning the data. The grid size is similar to the bins input in the histogram plot except that it 13 | 39 14 | is applied along both dimensions, so a grid size of 50 would yield 50x50 points. The filter 15 | dropdown can be used to select filters defined in your properties file to limit the points being 16 | plotted. Finally, click the **Update Chart** button to view the plot. With the plot displayed, you can 17 | change the color map by selecting different maps from the color map dropdown. 18 | 19 | Once data is plotted, you can use the tools provided in the toolbar at the top of the window to 20 | explore the plot. Going backwards from right to left, the tools are as follows: 21 | 22 | .. figure:: static/11_01.jpg 23 | :align: center 24 | 25 | A density plot of Nuclei_Intensity_DNA_IntegratedIntensity versus Nuclei_AreaShape_Area with log axes, log color scale, and a grid size of 100. 26 | 27 | - **Save**: Clicking this will give you choices for saving the plot as an image. 28 | 29 | * **Zoom-to-rect**: This tool may be toggled on and off. When it is on, you can use the mouse to click and drag a rectangle to zoom in on. The extents of the rectangle will become the new extents of the axes. Use the Back button (below) to zoom back out. 30 | 31 | - **Pan**: This tool may also be toggled. When on, you can use the mouse to pan the axes by clicking and dragging. 32 | 33 | * **Forward** and **Back**: These 2 buttons will redo and undo the zooming and panning actions that you make 34 | 35 | - **Home**: This will reset the view to the way it was after Update Chart was pressed. 36 | 37 | .. note:: 38 | Update may take a long time for large databases. We are working to improve this performance in later releases. 39 | -------------------------------------------------------------------------------- /docs/source/12_boxplot.rst: -------------------------------------------------------------------------------- 1 | ============= 2 | XII. Box Plot 3 | ============= 4 | 5 | Launch **Box Plot** from the main CPA interface by clicking the button in the toolbar. This tool will 6 | allow you create box and whisker plots from the numeric columns in your tables. 7 | 8 | To use the **Box Plot**, simply select the table whose column(s) you would like to plot from the 9 | table dropdown. Then select the measurement you would like to plot from that table in the x-axis 10 | dropdown (only numeric columns will be available). To plot multiple measurements against the 11 | same y-axis, click the **Select Multiple** button to the right of the x-axis dropdown. You will be 12 | presented with a checklist of columns to include in the plot. The filter dropdown can be used to 13 | select filters defined in your properties file to limit the points being plotted. Finally, click the 14 | **Update Chart** button to view the plot. 15 | 16 | The bottom and top of the box represent the 25th and 75th percentile of the data, with the median 17 | value represented by a horizontal red line. The whiskers on the top and bottom extend to the 18 | most extreme data point within 1.5 times the upper and lower quartiles. Outliers are 19 | represented individually with “+” shapes. 20 | 21 | Once data is plotted, you can use the tools provided in the toolbar at the top of the window to 22 | explore the plot. Going backwards from right to left, the tools are as follows: 23 | 24 | * **Save**: Clicking this will give you choices for saving the plot as an image. 25 | 26 | - **Zoom-to-rect**: This tool may be toggled on and off. When it is on, you can use the mouse to click and drag a rectangle to zoom in on. The extents of the rectangle will become the new extents of the axes. Use the Back button (below) to zoom back out. 27 | 28 | * **Pan**: This tool may also be toggled. When on, you can use the mouse to pan the axes by clicking and dragging. 29 | 30 | - **Forward** and **Back**: These 2 buttons will redo and undo the zooming and panning actions that you make 31 | 32 | * **Home**: This will reset the view to the way it was after Update Chart was pressed. 33 | 34 | .. figure:: static/12_01.jpg 35 | :align: center 36 | 37 | A box plot of Nuclei_AreaShape_Area. 38 | -------------------------------------------------------------------------------- /docs/source/13_workspaces.rst: -------------------------------------------------------------------------------- 1 | ================ 2 | XIII. Workspaces 3 | ================ 4 | 5 | **Workspaces** in CPA are a way of saving the state of your plots so they can be reopened later 6 | and even applied as a template to new datasets. 7 | 8 | Suppose you are performing quality control on a biological screen in which new plates (or 9 | slides) are imaged every week. The way you process and perform quality control on each new 10 | plate is largely the same. For example, you first run a CellProfiler pipeline producing various QC 11 | measures such as focus scores and stain intensities. Then, in CPA, you want to create (for 12 | example) a DNA content histogram and a scatterplot of Measurement_X vs. Measurement_Y 13 | while filtering for your controls. You also display Measurement_Z in P**late Viewer** to look for 14 | wells that may be out of focus. All of these plots can be saved in a workspace file by CPA, and 15 | 42 16 | applied to new data later. 17 | 18 | To create a workspace, simply open and configure the plots that you wish to save. Then choose 19 | **File > Save workspace** from the CPA file menu. The file that you save will contain configuration 20 | details for all of the currently open plots (Note: Table Viewer and Classifier do not yet support 21 | saving configurations). These same plots can be reopened in CPA by choosing **File > Load 22 | workspace** from the CPA file menu when the same properties file is used. To apply the 23 | workspace to a new dataset, simply open CPA with a different properties file that points to your 24 | other data, then choose **File > Load workspace** from the CPA file menu. CPA will try to apply 25 | the same settings to all of the plots that were open while using your new data. 26 | 27 | **Warning**: If you save a histogram plot of per_image.Measurement_X in a workspace 28 | and try to open the workspace with a dataset that doesn’t have a Measurement_X 29 | column in it’s per_image table, CPA will simply use the first measurement in your 30 | per_image table instead. 31 | -------------------------------------------------------------------------------- /docs/source/14_image_gallery.rst: -------------------------------------------------------------------------------- 1 | ================== 2 | XIV. Image Gallery 3 | ================== 4 | Image Gallery provides a convenient gridview allowing an overview of images from the entire experiment. A variety of options are provided to filter images based on experiment-specific metadata, e.g., gene name, compound treatments, etc. Multiple filters can be combined to refine the search. Images can be displayed as a custom-sized thumbnail or in full resolution, and the color assigned to each channel in the image can be customized to highlight structures of interest. Individual segmented cells can be viewed for each image, and can be dragged and dropped into the Classifier window. 5 | 6 | Image Gallery consists of a menu bar, an area for the image gallery area, and an area for the objects of segmented image. In the menu bar, you can choose what image you want to fetch. You can choose a range of images based on image ID from the experiment or a filter, all images from the experiment or a filter, or an individual image based on image ID. Once the selection is made, click **Fetch** to load the relevant images. 7 | 8 | For each image loaded in the image gallery area, right-click to show the options. 9 | - Select **View full images of selected** or double-click an individual tile to show the object in the context of the image from which it was drawn. This launches the **Image Viewer** tool (section V). 10 | - **Select all/Deselect all** (``ctrl+A/ctrl+D``) selects/deselects all tiles in the bin so they can be dragged and dropped together. 11 | - **Invert selection** (``ctrl+I``) to invert your selection (that is, select all non-selected tiles in the current bin and deselect all selected tiles). 12 | - **Remove selected** (``Delete``) removes the selected tiles from the current bin. 13 | - **Fetch all objects from image** populates the objects of segmented image area below with all objects belonging to the selected image(s). 14 | 15 | Images loaded in the area for the objects of segmented image have the same right-click options except for **Fetch all objects from image**. Tiles in this area can be dragged and dropped into the Classifier. 16 | 17 | .. figure:: static/14_01.jpg 18 | :align: center 19 | 20 | Image Gallery -------------------------------------------------------------------------------- /docs/source/15_normalization_tool.rst: -------------------------------------------------------------------------------- 1 | ======================= 2 | XV. Normalization Tool 3 | ======================= 4 | 5 | .. figure:: static/15_01.jpg 6 | :align: center 7 | 8 | Normalization Tool -------------------------------------------------------------------------------- /docs/source/16_dimensionality_reduction.rst: -------------------------------------------------------------------------------- 1 | ============================= 2 | XVI. Dimensionality Reduction 3 | ============================= 4 | 5 | Click the **Reduction** button in the main CPA interface toolbar to launch the Dimensionality Reduction tool. This tool 6 | will allow you to perform several reduction methods and visualise the results as a scatter plot. 7 | 8 | .. figure:: static/16_01.jpg 9 | :align: center 10 | 11 | Dimensionality Reduction Tool 12 | 13 | Dimensionality reduction condenses large numbers of measurements into a more managable number of components, this can 14 | help to visualise results and identify clusters of objects and outliers. 15 | 16 | To use the **Dimensionality Reduction Plot**, select a reduction method from the available choices and click 17 | **Update Chart**. The different methods are explained further in the sections below. CPA will normalise measurements 18 | before applying these methods. 19 | 20 | The x- and y-axis dropdowns can be used to switch between display of different components on each axis. Click 21 | **Update Chart** after making a selection to display the data. 22 | 23 | Displaying "Scores" will show the positions of individual objects from your dataset. Hovering over a 24 | point will display a key for that object in the toolbar. A key of (4, 14) would mean Image #4, Object #14. Some 25 | reduction methods will have the option to display "Loadings", for which the average position of each original 26 | measurement column will be shown on the new axes. Hovering over a loading point will display the measurement name. 27 | 28 | Filters can be used to restrict which objects will be displayed on the resulting plot. Note that, due to the nature of 29 | these reduction methods, data from all objects from a dataset will be used to perform the initial reduction. 30 | 31 | In the toolbar, you'll also find the **lasso tool**. Activating this will allow you to draw a selection polygon onto 32 | the current plot. Any points within the polygon will be considered as selected. Right-clicking on a plot with an 33 | active selection will produce a popup menu with options to visualise the highlighted objects. If you have a Classifier 34 | tool open, you'll also see the option to *send the selected objects directly to the classifier*. 35 | 36 | Reduction Methods 37 | ***************** 38 | 39 | - **Principal Component Analysis (PCA)**: PCA attempts to generate a series of features which capture the variance of the original dataset. Measurements which vary in the same manner are collapsed towards a single new measurement, termed a *Principal Component*. On the resulting axis labels, CPA will also display the proportion of the original variance which is explained by each principal component. Components are sorted by their contribution to variance, so PC1 will always be the most significant feature. 40 | 41 | - **Singular Value Decomposition (SVD)**: SVD is very similar to PCA, but does not center the data before processing. This can be much faster and more memory efficient than PCA when working with very large datasets, but a trade-off is that the resulting components will not be ordered by significance (i.e. PC1 may not be the most important feature). 42 | 43 | - **Gaussian Random Projection (GRP)**: This method reduces the dimensionality of the dataset by projecting samples into fewer dimensions while preserving the pairwise distances between them. The random matrix used for projection is generated using a gaussian distribution. 44 | 45 | - **Sparse Random Projection (SRP)**: Similar to GRP, but uses a sparse matrix instead of a gaussian one. This can be more memory efficient with large datasets. 46 | 47 | - **Factor Analysis (FA)**: Like PCA, Factor Analysis generates a series of components which describe the variance of the dataset. However, with FA the variance in each direction within the input space can be modelled independently. 48 | 49 | - **Feature Agglomeration (FAgg)**: This method utilises hierarchical clustering to group together features that behave similarly. The generated clusters can then be treated like components 50 | 51 | - **t-Distributed Stochastic Neighbor Embedding (t-SNE)**: t-SNE helps to visualise high dimensional data by giving individual datapoints a coordinate on a 2D map, on which similar points are placed close together. The resulting clusters can help to visualise different object types within a dataset. 52 | 53 | -------------------------------------------------------------------------------- /docs/source/17_FAQ.rst: -------------------------------------------------------------------------------- 1 | ======================= 2 | XVII. FAQ 3 | ======================= 4 | 5 | Q1: I automatically correct images in my CP pipeline and save the corrected images to perform the analysis on them. However CPA opens the uncorrected images. I can't change the settings in the CPA properties file, and the path to the corrected images is not stored in the database (the corrected images are stored in the input folder but they have a different name). 6 | From https://forum.image.sc/t/path-to-aligned-images-in-cpa/16850 7 | 8 | A1: In the SaveImages module for the corrected images, check the box near the end of the settings that says "Record the file and path information to the saved image?" That setting is where the path gets input into the database and then into your properties file. -------------------------------------------------------------------------------- /docs/source/1_preliminary_requirements.rst: -------------------------------------------------------------------------------- 1 | ================================ 2 | I. Preliminary data requirements 3 | ================================ 4 | 5 | CPA requires access to the following data sources: 6 | 7 | - An image table and an object table containing measurements and metadata 8 | 9 | These may reside in a MySQL or SQLite database or in a set of comma-separated value (CSV) files. A MySQL database is recommended, though you may need to consult with your local information technology staff to set up a database server. See section II.B for more information. The tables must contain a few datacolumns needed by CellProfiler Analyst to access images and data properly, such as an Image ID column to link the per-image and per-object tables, file path and file name columns to specify where images are stored, and X, Y location columns to specify where each object resides within the image. These configuration details are specified in a properties file. Note: if image classification is specified in the properties file, an object table is not required. See section III. 10 | 11 | - The images that were analyzed to generate the above-mentioned Table Viewers 12 | 13 | These can be stored either locally or remotely and accessed via HTTP. The directory structure does not matter as long as the file paths stored in the image table point to the correct images. 14 | Throughout CPA, the term image is meant to include all image data associated with an analyzed field-of-view. An image in this sense usually includes several individual monochromatic images that show the different wavelengths (channels) as well as images that show outlines of identified objects. You can specify any number of image channels (including, for example, outlines of objects that resulted from image processing) by adding path and filename columns to the image table of your database for each channel. 15 | CPA currently requires image files to be monochromatic; several individual channels can be combined into a color image for viewing within the software. 16 | CPA currently supports the following image file types: BMP, CUR, DCX, Cellomics DIB, FLI, FLC, FPX, GBR, GD, GIF, ICO, IM, IMT, IPTC/NAA, JPG/JPEG, MCIDAS, MIC, MSP, PCD, PCX, PIXAR, PNG, PPM, PSD, SGI, SPIDER, TGA, TIF/TIFF, WAL, XBM, XPM, XV Thumbnails. 17 | 18 | .. note:: 19 | While designed for high-throughput, image-based biological experiments, CellProfiler Analyst is also useful for the exploration of other multi-dimensional data sets, particularly when data points are linked to images. 20 | 21 | I.A Example image table 22 | ======================= 23 | 24 | The image table requires one column for a unique image ID and a pair of columns for each channel represented in the images: one column for the image path, and one column for the image file name (which may include some part of the path to the image, such as the subdirectory that contains the file). These columns do not need to have specific names; you will indicate which column names correspond to image ID, image path, and image filename when configuring the properties file. The remaining columns can contain measurements and metadata about each image. 25 | 26 | .. note:: 27 | While MySQL and SQLite support diverse column names, CPA will not handle column names that contain commas. In general, we advise that you use only alphanumeric characters and underscores in the names of your table columns. 28 | 29 | An image table for an experiment involving cells imaged for GFP and Hoechst would have two channels and would look something like this: 30 | 31 | .. figure:: static/01_01.jpg 32 | :align: center 33 | 34 | I.B Example object table 35 | ========================= 36 | 37 | The object table requires four columns: a foreign key image ID column that corresponds to the image ID in the image table, a unique object ID column, a column for the object x-location, and a column for the object y-location. CPA expects the location columns to correspond to the x-y pixel coordinates of the objects’ centroids; the corresponding column names that are produced by CellProfiler depend on the name of the objects; for example, if nuclei were measured, the column names would be Nuclei_Location_Center_X and Nuclei_Location_Center_Y. Again, these columns do not need to have specific names; you indicate which column names correspond to these functionalities when configuring the properties file. Additional columns in this table typically contain measurements for each object, but are completely up to the user. 38 | 39 | .. note:: 40 | While MySQL and SQLite support diverse column names, CPA will not handle column names that contain commas. In general, we advise that you use only alphanumeric characters and underscores in the names of your table columns. 41 | 42 | An object table for an experiment involving cells imaged for GFP and Hoechst would have two channels and would look something like this: 43 | 44 | .. figure:: static/01_02.jpg 45 | :align: center 46 | -------------------------------------------------------------------------------- /docs/source/2_installation.rst: -------------------------------------------------------------------------------- 1 | ==================================== 2 | II. Installation and getting started 3 | ==================================== 4 | 5 | CPA releases 6 | ============ 7 | 8 | All CellProfiler-Analyst releases can be found `here `_ 9 | 10 | II.A Mac OS 11 | ============= 12 | 13 | Copy CellProfiler-Analyst.app to /Applications. 14 | 15 | II.B Windows 16 | ============== 17 | 18 | Run the setup.exe to install CPA and create shortcuts. 19 | 20 | II.C Using the example dataset 21 | ============================== 22 | 23 | Download the CPA example dataset from http://cellprofileranalyst.org/ or `this link `_ and unzip it to create the cpa_example directory. This directory contains: 24 | 25 | 1. example.properties - Configuration file for CPA (see section III). 26 | 2. MyTrainingSet.txt - Example training set file to be used in the Classifier (see section V). 27 | 3. images/ - Images from the screen used in the example. 28 | 4. per_image.csv - Comma Separated Values file for image data. This file was exported by CellProfiler’s ExportToDatabase module. 29 | 5. per_object.csv - Comma Separated Values file for object data. This file was exported by CellProfiler’s ExportToDatabase module. 30 | 6. example_SETUP.SQL - Used by CPA to create an internal database (SQLite). It can also be used to create a MySQL database. This file was exported by CellProfiler’s ExportToDatabase module. 31 | 32 | Run the CPAnalyst file created by the install process above. A dialog will appear asking you to select a properties file. Navigate to the cpa_example directory and select the example.properties file. You’re now ready to experiment with CellProfiler Analyst! 33 | -------------------------------------------------------------------------------- /docs/source/4_cpa_interface.rst: -------------------------------------------------------------------------------- 1 | ====================================== 2 | IV. The CellProfiler Analyst Interface 3 | ====================================== 4 | To run CPA, double-click the CPAnalyst.exe file on Windows or CPAnalyst.app on Mac OS. Once you have selected a properties file to load, the following small window will appear. 5 | 6 | .. figure:: static/04_01.jpg 7 | :align: center 8 | .. figure:: static/04_02.jpg 9 | :align: center 10 | 11 | CellProfiler Analyst main window. 12 | 13 | This window provides a toolbar at the top with icons to launch each of CPA’s tools. The currently available tools are Image Gallery, Classifier, Plate Viewer, Scatter Plot, Histogram, Density Plot and Table Viewer. These tools can also be launched from the Tools menu. More tools will be added to this suite in the future. 14 | 15 | Below the toolbar is a logging console that all the tools will use to provide feedback on status, warnings, etc. This console can be configured to display messages at 5 levels of verbosity chosen from the Logging menu. In order of increasing verbosity, these are: 16 | 17 | - Critical: Virtually no messages. Will only report critical errors. 18 | - Errors: Only reports error messages. 19 | - Warnings: Only reports warnings and error messages. 20 | - Info: Reports general status information as well as any warnings and errors. 21 | - Debug: Reports technical information such as SQL queries in addition to all other messages listed above. 22 | 23 | You can also optionally disable logging of image loading events by using the "Log image loading" toggle in the logging menu. 24 | 25 | You can save the log to a file by selecting File > Save Log, or copied by selecting the text and using Ctrl+C (or your operating system default copy command). 26 | 27 | You will also find menu items to save and load workspaces under the File menu. See Section XIII for more on workspaces in CPA and how they can help you analyze new data more quickly. 28 | 29 | 30 | 31 | SQL query tool 32 | -------------- 33 | 34 | The advanced menu provides a SQL query tool for writing SQL statements to query 35 | the DB 36 | 37 | .. figure:: static/04_03.jpg 38 | :align: center 39 | 40 | Querying for all unique genes in per_image table 41 | 42 | .. figure:: static/04_04.jpg 43 | :align: center 44 | 45 | Result of the query above for cpa_example dataset 46 | 47 | 48 | -------------------------------------------------------------------------------- /docs/source/6_table_viewer.rst: -------------------------------------------------------------------------------- 1 | ================ 2 | VI. Table Viewer 3 | ================ 4 | Certain tools, such as Classifier, produce a table that will be opened in the Table Viewer. As well, any CSV file or database table can be viewed by using this tool. 5 | 6 | .. figure:: static/06_01.jpg 7 | :align: center 8 | .. figure:: static/06_02.jpg 9 | :align: center 10 | 11 | Table Viewer produced by Classifier, grouped by well number and gene (only positive Enrichment Score column). 12 | 13 | Features available in the Table Viewer 14 | -------------------------------------- 15 | 16 | - **Sort**: Click on any column heading to sort the data based on that column. Click again to reverse the sort. To sort by more than one column (i.e., sort first by column X, then by column Y), click on the first heading of the first column you want to sort by, then hold shift and click on the next column heading. You can add any number of columns to a sorting in this way. Sorting order and direction is indicated in brackets at the end of the header name by a number and an arrow (^ or v). Clicking on any column header that is already part of a sorting will reverse the direction of the sort. Pressing shift+click on a column header that is already part of a sorting will remove that column from the sorting. 17 | - **Show images**: Double-click on a row header to show the image or images in that row’s group. Right-click to see a list of the image-keys in that row and click one to open it. 18 | - **View summary statistics**: Click anywhere within the table to select a column. A summary of statistical information about the selected column(s) is displayed in the status bar at the bottom of the window. You may select multiple columns by pressing ctrl+click (cmd+click on a Mac). 19 | - **Show/hide columns**: To select which columns are shown in the Table Viewer, select View > Show/hide columns and a dialog will appear with a list of columns. Check off the columns that you wish to show, and uncheck the column that you want hidden. 20 | - **Saving and loading CSV files**: CPA can read and write CSV (comma-separated value) files by selecting File > Load table from CSV or File > Save table to CSV. When saving a table it’s important to note that columns that were hidden (see above) will not be written to the CSV. 21 | - **Saving and Loading database tables**: Table Viewer can also load and save database tables. This means you can easily open a CSV file in Table Viewer and then store that table in your database for plotting and analysis in CPA. Conversely, you can load a database table into Table Viewer (such as your per-object table), and save it on your computer as a CSV. As with CSVs, saving and loading from the database can be done via File > Load table from database and File > Save table to database. Note, when saving a table to the database, you will be prompted whether to store the table permanently or "for this session only" – which means the table will be removed from the database when you close CPA. 22 | 23 | .. note:: 24 | When saving a table to the database, you will be prompted whether to store the table permanently or "for this session only" – which means the table will be removed from the database when you close CPA. 25 | -------------------------------------------------------------------------------- /docs/source/7_image_viewer.rst: -------------------------------------------------------------------------------- 1 | ================= 2 | VII. Image Viewer 3 | ================= 4 | 5 | Certain CPA tools, such as **Classifier**, display images in **Image Viewer**, and any image in the 6 | experiment can also be opened within CPA by choosing this tool from CPA’s **Tools** menu or by 7 | clicking the **Image Viewer** icon in the toolbar. 8 | 9 | .. figure:: static/07_01.jpg 10 | :align: center 11 | .. figure:: static/07_02.jpg 12 | :align: center 13 | 14 | The Image Viewer. 15 | 16 | When you open Image Viewer from CPA, it will prompt for the ID number of an image to show. If 17 | you also specified a ``table_id`` column in your properties file, then you will also be prompted for 18 | the table number. You can load additional images by selecting **File > Open Image (ctrl+O)**. 19 | 20 | If you specified ``plate_id`` and ``well_id`` in your properties file, then Image Viewer will display 21 | the plate and well in the title of the window along with the image-key, which is image 328 in the 22 | example above. 23 | 24 | The ``image_names`` that are specified in your properties file will appear in the menu bar. In the 25 | example above, the user has specified names for the **Actin**, **pH3**, and **DNA** channels. If you 26 | have not defined names for any channels, the menu bar will contain **channel-1**, **channel-2**, etc. 27 | 28 | Click on one of the channel names to see a dropdown list of available colors for each – clicking 29 | on a color will map that color onto the channel. If you specified ``image_channel_colors`` in 30 | your properties file, those colors specified there should appear under each channel menu by 31 | default. 32 | 33 | The Classifier menu provides an item that will let you classify the objects in the current image. 34 | This item is only enabled if Classifier is running and trained. For more 35 | on this feature see the **Score image** discussion in section III.C.6. 36 | 37 | - **Tip**: You can use keyboard shortcuts to toggle each channel on/off: Ctrl+1, +2, +3, … will toggle first, second, third, etc. color channels. 38 | 39 | Click **Show controls** (or press the space bar) to display the Image Viewer control panel, which 40 | controls brightness, contrast, and scale. This same control panel is available in Classifier by 41 | choosing **View > Image Controls** (see section III.C.1). 42 | 43 | .. figure:: static/07_03.jpg 44 | :align: center 45 | 46 | Image controls 47 | 48 | The upper slider controls brightness; the lower one rescales the size of the image or image tiles. 49 | The **Contrast Stretch** controls let you stretch the image contrast by rescaling the pixel 50 | intensities of each channel independently to fit the range 0-1 (where 0 is unsaturated and 1 is 51 | saturated). 52 | 53 | - **Linear** scales the image intensities linearly. For an image in the range 0-0.5, pixels at 0.5 intensity would be rescaled to 1.0, and pixels at 0.4 rescaled to 0.8; in short, all pixel intensities in the image would be doubled. 54 | 55 | - **Log** transform scales the image intensities logarithmically, which has the effect of scaling dimmer pixels by a greater factor than it scales brighter pixels. 56 | 57 | **Warning**: scaling in this way may yield misleading results. For example, if a channel of an 58 | image shows very little staining, the raw image may have intensities in a low, narrow range, 59 | e.g., from [0-0.01]. Stretching in this case would have the effect of raising the background 60 | intensity levels so that the image overall appears very bright. 61 | -------------------------------------------------------------------------------- /docs/source/8_plate_viewer.rst: -------------------------------------------------------------------------------- 1 | 2 | ================== 3 | VIII. Plate Viewer 4 | ================== 5 | 6 | Plate Viewer is a tool for browsing image-based data laid out on multi-well plates common to 7 | high-throughput biological screens. Supported formats are: 8 | 9 | - **96 well plate** — 8 rows x 12 columns 10 | - **384 well plate** — 16 rows x 24 columns 11 | - **1536 well plate** — 32 rows x 48 columns 12 | - **5600 spot microarray** — 40 rows x 140 columns 13 | 14 | To launch this tool click the Plate Viewer icon in the CPA toolbar or select **Tools > Plate Viewer** 15 | from the CPA menu bar. 16 | 17 | .. figure:: static/08_01.jpg 18 | :align: center 19 | 20 | Sample Plate Viewer for a single 96-well plate, viewing the mean positive enrichment score output by Classifier. We can see that well D07 is very highly enriched for our "positive" cell phenotype. 21 | 22 | .. note:: 23 | An **X** in one of the wells means there was no data in the database corresponding to that particular well. However, it may still contain images that can be viewed, as described below. 24 | 25 | In the colored plate display, right-clicking on a well will display a list of image-keys found in that 26 | well. Selecting one image-key will open that image in the **Image Viewer** (section V). Doubleclicking 27 | on a well will open all images from that well, each in its own Image Viewer. 28 | 29 | Above the plate is a menu that lets you specify the plate number to display. Holding the cursor 30 | over a particular well will display a tooltip showing the value pertaining to that well. 31 | 32 | The left-hand column contains many options for generating different views into your data. 33 | 34 | - **Data source**: Allows you to select a table for visualization. You cannot load a CSV directly into the Plate Viewer. You must open the CSV in Table Viewer first, save it to the database, and then open it in Plate Viewer. 35 | - **Measurement**: The column from the selected table that you would like to visualize. 36 | - **Aggregation Method**: Measurements must be aggregated to a single number for each well so that they can be represented by a color. Options are **mean**, **sum**, **median**, **standard deviation**, **cv%** (coefficient of variation), **minimum**, and **maximum**. If you’re viewing ``object_count`` from the image table, for example, you might select **sum** to visualize the sum of the object counts for all images that constitute a well. 37 | 38 | **Important**: Plate Viewer is agnostic with regard to the type of data it aggregates, so viewing columns from the image table will not cause the viewer to access any data from the object table. For example, a biological screen with 4 images (sites) per well may be analyzed in CellProfiler, and cell measurements may be aggregated to each image and output to the image table. One column grom the table, ``Image_Intensity_DNA_Mean_ Intensity``, could be visualized in Plate Viewer and aggregated from each image to each well by, say, the **maximum** option. This could be mistakenly thought to be reporting the maximum DNA intensity value of any cell from that well, when it is actually reporting the maximum of the mean per-image DNA intensity per-well. 39 | 40 | - **Color Map**: Each value computed by the Aggregation Method is mapped to a color via a color map. The currently selected color map is represented in a bar beneath the plate maps. More than 50 color maps are available. 41 | - **Well Shape**: Mostly for presentation purposes, you can select from different well shapes. Options are **square**, **rounded**, **circle**, and **image**. 42 | 43 | Important: The "*image*" feature is still under development. This will display a 44 | rescaled image from each well in the place of the well itself. This can take a very 45 | long time to refresh since full sized images must be loaded for every well in view. For 46 | it to be useful, viewing 1 plate at a time and maximizing the window is advised. Note: 47 | that the color map is irrelevant when using this view. 48 | 49 | - **Number of Plates**: Enter the number of plates you would like to view at once, and press the Enter or Return key. 50 | 51 | Here is a four-plate view of the same experiment shown in the previous example, in which the user has chosen to view the mean of the per-object measurement *Spindle_AreaShape_Area* in each well across 4 plates. 52 | 53 | .. figure:: static/08_y.jpg 54 | :align: center 55 | 56 | Viewing four 96-well plates at once in Plate Viewer. Here we are visualizing the mean Spindle_AreaShape_Area in each well. This makes it easy to visualize many thousands of object measurements in a meaningful way. 57 | 58 | .. figure:: static/08_z.jpg 59 | :align: center 60 | 61 | Viewing the sums of the per-object measurement tubulin_AreaShape_Area in each well of a single 384-well plate in Plate Viewer. Notice that while well C01 has the largest tubulin area (62406) in this plate, the color bar indicates that the largest value of this measurement in the experiment is 91617, which must be in some other plate. 62 | 63 | The color bar axis at the bottom of the window shows how the aggregated values of the selected measurement column map to colors: 64 | 65 | - The numbers at the far left and right of the axis represent the minimum and maximum values found in the entire experiment. 66 | - The value range of the current plate(s) extends to the point where the color bar stops and a thin black line begins. 67 | 68 | To assist in visualizing data, particularly when there are extreme outlier data points, you can 69 | **rescale** or **clip** the color bar by dragging the handles found at the far ends of the bar. 70 | 71 | - **Color rescaling**: This will rescale the full color map to fit within the minimum and maximum values at the handles. Values below the range are mapped to the minimum (leftmost) color, values above the range are mapped to the maximum (rightmost) color. 72 | 73 | - **Color clipping**: As with color rescaling, this will map values below the range to the minimum color, and values above the range to the maximum color. However, the full range of colors will not be rescaled to fit within the handles, it is cropped or “clipped.” 74 | 75 | To change the mode from rescaling to clipping, right click on the bar and select **Value 76 | bracketing: CLIP**, to change it back to rescaling, do the same and select **Value bracketing: 77 | RESCALE**. To set the sliders back at the global min and max, select **Reset sliders**. 78 | 79 | .. figure:: static/08_16.jpg 80 | :align: center 81 | 82 | Selecting Color Bar options. 83 | -------------------------------------------------------------------------------- /docs/source/9_scatter_plot.rst: -------------------------------------------------------------------------------- 1 | ================ 2 | IX. Scatter Plot 3 | ================ 4 | 5 | Launch **Scatter Plot** from the main CPA interface by clicking the button in the toolbar. This tool 6 | will allow you to create scatter plots from the numeric columns in your tables. 7 | 8 | .. figure:: static/09_01.jpg 9 | :align: center 10 | 11 | Using Scatter Plot to visualize the relationship between the Image_Intensity_DNA_Mean_intensity and the Image_Intensity_pH3_Mean_intensity image measurements. 12 | 13 | To use the **Scatter Plot**, simply select the table whose columns you would like to plot from the 14 | table dropdown. Then select measurements from that table in the x-axis and y-axis dropdowns 15 | (only numeric columns will be available). To view an axis in the log scale, choose **log** from the 16 | x-scale or y-scale dropdown. The filter dropdown can be used to select filters defined in your 17 | properties file to limit the points being plotted. Finally, click the **Update Chart** button to view the 18 | plot. 19 | 20 | .. note:: 21 | Update may take a long time or even fail for large databases. We are working to improve this performance in later releases. 22 | 23 | Once data is plotted, you can use the tools provided in the toolbar at the top of the window to 24 | 37 25 | explore the plot. Going backwards from right to left, the tools are as follows: 26 | 27 | - **Save**: Clicking this will give you choices for saving the plot as an image. 28 | 29 | * **Zoom-to-rect**: This tool may be toggled on and off. When it is on, you can use the mouse to click and drag a rectangle to zoom in on. The extents of the rectangle will become the new extents of the axes. Use the Back button (below) to zoom back out. 30 | 31 | - **Pan**: This tool may also be toggled. When on, you can use the mouse to pan the axes by clicking and dragging. 32 | 33 | * **Forward** and **Back**: These 2 buttons will redo and undo the zooming and panning actions that you make 34 | 35 | - **Home**: This will reset the view to the way it was after Update Chart was pressed 36 | 37 | **Selection**: 38 | When the pan and zoom tools are toggled off, the default action of the mouse is to draw a 39 | freeform selection. You can add to an existing selection by holding the shift key while drawing a 40 | new shape. Likewise, you can subtract from a selection by holding alt and drawing a selection 41 | around the points you wish to deselect. 42 | 43 | **Viewing Images**: 44 | You can view the images from a selection by right-clicking on the plot and selecting “Show 45 | images from selection” from the resultant popup menu. This will pop up a list of the selected 46 | image keys along with their plate and well information (if specified in your properties file). 47 | Double clicking on an image entry will launch that image in the **Image Viewer** tool. 48 | -------------------------------------------------------------------------------- /docs/source/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CellProfiler/CellProfiler-Analyst/8a7f924052867192b425e4b7f89137fadbbd93fa/docs/source/__init__.py -------------------------------------------------------------------------------- /docs/source/index.rst: -------------------------------------------------------------------------------- 1 | .. Sphinx RTD theme demo documentation master file, created by 2 | sphinx-quickstart on Sun Nov 3 11:56:36 2013. 3 | You can adapt this file completely to your liking, but it should at least 4 | contain the root `toctree` directive. 5 | 6 | ========== 7 | Manual 3.0 8 | ========== 9 | 10 | .. image:: https://i.imgur.com/uaEp2md.png 11 | 12 | Table of Contents: 13 | 14 | .. toctree:: 15 | :maxdepth: 1 16 | 17 | 0_introduction 18 | 1_preliminary_requirements 19 | 2_installation 20 | 3_properties_file 21 | 4_cpa_interface 22 | 5_classifier 23 | 6_table_viewer 24 | 7_image_viewer 25 | 8_plate_viewer 26 | 9_scatter_plot 27 | 10_histogram_plot 28 | 11_density_plot 29 | 12_boxplot 30 | 13_workspaces 31 | 14_image_gallery 32 | 15_normalization_tool 33 | 16_dimensionality_reduction 34 | 17_FAQ 35 | -------------------------------------------------------------------------------- /docs/source/manual.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CellProfiler/CellProfiler-Analyst/8a7f924052867192b425e4b7f89137fadbbd93fa/docs/source/manual.pdf -------------------------------------------------------------------------------- /docs/source/static/01_01.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CellProfiler/CellProfiler-Analyst/8a7f924052867192b425e4b7f89137fadbbd93fa/docs/source/static/01_01.jpg -------------------------------------------------------------------------------- /docs/source/static/01_02.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CellProfiler/CellProfiler-Analyst/8a7f924052867192b425e4b7f89137fadbbd93fa/docs/source/static/01_02.jpg -------------------------------------------------------------------------------- /docs/source/static/03_01.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CellProfiler/CellProfiler-Analyst/8a7f924052867192b425e4b7f89137fadbbd93fa/docs/source/static/03_01.jpg -------------------------------------------------------------------------------- /docs/source/static/03_02.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CellProfiler/CellProfiler-Analyst/8a7f924052867192b425e4b7f89137fadbbd93fa/docs/source/static/03_02.jpg -------------------------------------------------------------------------------- /docs/source/static/04_01.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CellProfiler/CellProfiler-Analyst/8a7f924052867192b425e4b7f89137fadbbd93fa/docs/source/static/04_01.jpg -------------------------------------------------------------------------------- /docs/source/static/04_02.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CellProfiler/CellProfiler-Analyst/8a7f924052867192b425e4b7f89137fadbbd93fa/docs/source/static/04_02.jpg -------------------------------------------------------------------------------- /docs/source/static/04_03.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CellProfiler/CellProfiler-Analyst/8a7f924052867192b425e4b7f89137fadbbd93fa/docs/source/static/04_03.jpg -------------------------------------------------------------------------------- /docs/source/static/04_04.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CellProfiler/CellProfiler-Analyst/8a7f924052867192b425e4b7f89137fadbbd93fa/docs/source/static/04_04.jpg -------------------------------------------------------------------------------- /docs/source/static/05_00.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CellProfiler/CellProfiler-Analyst/8a7f924052867192b425e4b7f89137fadbbd93fa/docs/source/static/05_00.jpg -------------------------------------------------------------------------------- /docs/source/static/05_01.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CellProfiler/CellProfiler-Analyst/8a7f924052867192b425e4b7f89137fadbbd93fa/docs/source/static/05_01.jpg -------------------------------------------------------------------------------- /docs/source/static/05_02.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CellProfiler/CellProfiler-Analyst/8a7f924052867192b425e4b7f89137fadbbd93fa/docs/source/static/05_02.jpg -------------------------------------------------------------------------------- /docs/source/static/05_03.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CellProfiler/CellProfiler-Analyst/8a7f924052867192b425e4b7f89137fadbbd93fa/docs/source/static/05_03.jpg -------------------------------------------------------------------------------- /docs/source/static/05_04.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CellProfiler/CellProfiler-Analyst/8a7f924052867192b425e4b7f89137fadbbd93fa/docs/source/static/05_04.jpg -------------------------------------------------------------------------------- /docs/source/static/05_04b.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CellProfiler/CellProfiler-Analyst/8a7f924052867192b425e4b7f89137fadbbd93fa/docs/source/static/05_04b.jpg -------------------------------------------------------------------------------- /docs/source/static/05_05.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CellProfiler/CellProfiler-Analyst/8a7f924052867192b425e4b7f89137fadbbd93fa/docs/source/static/05_05.jpg -------------------------------------------------------------------------------- /docs/source/static/05_06.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CellProfiler/CellProfiler-Analyst/8a7f924052867192b425e4b7f89137fadbbd93fa/docs/source/static/05_06.jpg -------------------------------------------------------------------------------- /docs/source/static/05_06b.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CellProfiler/CellProfiler-Analyst/8a7f924052867192b425e4b7f89137fadbbd93fa/docs/source/static/05_06b.jpg -------------------------------------------------------------------------------- /docs/source/static/05_07.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CellProfiler/CellProfiler-Analyst/8a7f924052867192b425e4b7f89137fadbbd93fa/docs/source/static/05_07.jpg -------------------------------------------------------------------------------- /docs/source/static/05_08.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CellProfiler/CellProfiler-Analyst/8a7f924052867192b425e4b7f89137fadbbd93fa/docs/source/static/05_08.jpg -------------------------------------------------------------------------------- /docs/source/static/05_09.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CellProfiler/CellProfiler-Analyst/8a7f924052867192b425e4b7f89137fadbbd93fa/docs/source/static/05_09.jpg -------------------------------------------------------------------------------- /docs/source/static/05_09a.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CellProfiler/CellProfiler-Analyst/8a7f924052867192b425e4b7f89137fadbbd93fa/docs/source/static/05_09a.jpg -------------------------------------------------------------------------------- /docs/source/static/05_09b.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CellProfiler/CellProfiler-Analyst/8a7f924052867192b425e4b7f89137fadbbd93fa/docs/source/static/05_09b.jpg -------------------------------------------------------------------------------- /docs/source/static/05_10.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CellProfiler/CellProfiler-Analyst/8a7f924052867192b425e4b7f89137fadbbd93fa/docs/source/static/05_10.jpg -------------------------------------------------------------------------------- /docs/source/static/05_11.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CellProfiler/CellProfiler-Analyst/8a7f924052867192b425e4b7f89137fadbbd93fa/docs/source/static/05_11.jpg -------------------------------------------------------------------------------- /docs/source/static/05_11b.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CellProfiler/CellProfiler-Analyst/8a7f924052867192b425e4b7f89137fadbbd93fa/docs/source/static/05_11b.jpg -------------------------------------------------------------------------------- /docs/source/static/05_12.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CellProfiler/CellProfiler-Analyst/8a7f924052867192b425e4b7f89137fadbbd93fa/docs/source/static/05_12.jpg -------------------------------------------------------------------------------- /docs/source/static/05_13.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CellProfiler/CellProfiler-Analyst/8a7f924052867192b425e4b7f89137fadbbd93fa/docs/source/static/05_13.jpg -------------------------------------------------------------------------------- /docs/source/static/05_14.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CellProfiler/CellProfiler-Analyst/8a7f924052867192b425e4b7f89137fadbbd93fa/docs/source/static/05_14.jpg -------------------------------------------------------------------------------- /docs/source/static/05_15.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CellProfiler/CellProfiler-Analyst/8a7f924052867192b425e4b7f89137fadbbd93fa/docs/source/static/05_15.jpg -------------------------------------------------------------------------------- /docs/source/static/05_16.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CellProfiler/CellProfiler-Analyst/8a7f924052867192b425e4b7f89137fadbbd93fa/docs/source/static/05_16.jpg -------------------------------------------------------------------------------- /docs/source/static/05_17.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CellProfiler/CellProfiler-Analyst/8a7f924052867192b425e4b7f89137fadbbd93fa/docs/source/static/05_17.jpg -------------------------------------------------------------------------------- /docs/source/static/05_18.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CellProfiler/CellProfiler-Analyst/8a7f924052867192b425e4b7f89137fadbbd93fa/docs/source/static/05_18.jpg -------------------------------------------------------------------------------- /docs/source/static/05_19.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CellProfiler/CellProfiler-Analyst/8a7f924052867192b425e4b7f89137fadbbd93fa/docs/source/static/05_19.jpg -------------------------------------------------------------------------------- /docs/source/static/05_20.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CellProfiler/CellProfiler-Analyst/8a7f924052867192b425e4b7f89137fadbbd93fa/docs/source/static/05_20.jpg -------------------------------------------------------------------------------- /docs/source/static/05_a.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CellProfiler/CellProfiler-Analyst/8a7f924052867192b425e4b7f89137fadbbd93fa/docs/source/static/05_a.jpg -------------------------------------------------------------------------------- /docs/source/static/05_b.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CellProfiler/CellProfiler-Analyst/8a7f924052867192b425e4b7f89137fadbbd93fa/docs/source/static/05_b.jpg -------------------------------------------------------------------------------- /docs/source/static/05_e.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CellProfiler/CellProfiler-Analyst/8a7f924052867192b425e4b7f89137fadbbd93fa/docs/source/static/05_e.jpg -------------------------------------------------------------------------------- /docs/source/static/05_f.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CellProfiler/CellProfiler-Analyst/8a7f924052867192b425e4b7f89137fadbbd93fa/docs/source/static/05_f.jpg -------------------------------------------------------------------------------- /docs/source/static/05_y.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CellProfiler/CellProfiler-Analyst/8a7f924052867192b425e4b7f89137fadbbd93fa/docs/source/static/05_y.jpg -------------------------------------------------------------------------------- /docs/source/static/05_z.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CellProfiler/CellProfiler-Analyst/8a7f924052867192b425e4b7f89137fadbbd93fa/docs/source/static/05_z.jpg -------------------------------------------------------------------------------- /docs/source/static/06_01.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CellProfiler/CellProfiler-Analyst/8a7f924052867192b425e4b7f89137fadbbd93fa/docs/source/static/06_01.jpg -------------------------------------------------------------------------------- /docs/source/static/06_02.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CellProfiler/CellProfiler-Analyst/8a7f924052867192b425e4b7f89137fadbbd93fa/docs/source/static/06_02.jpg -------------------------------------------------------------------------------- /docs/source/static/06_04.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CellProfiler/CellProfiler-Analyst/8a7f924052867192b425e4b7f89137fadbbd93fa/docs/source/static/06_04.jpg -------------------------------------------------------------------------------- /docs/source/static/07_01.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CellProfiler/CellProfiler-Analyst/8a7f924052867192b425e4b7f89137fadbbd93fa/docs/source/static/07_01.jpg -------------------------------------------------------------------------------- /docs/source/static/07_02.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CellProfiler/CellProfiler-Analyst/8a7f924052867192b425e4b7f89137fadbbd93fa/docs/source/static/07_02.jpg -------------------------------------------------------------------------------- /docs/source/static/07_03.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CellProfiler/CellProfiler-Analyst/8a7f924052867192b425e4b7f89137fadbbd93fa/docs/source/static/07_03.jpg -------------------------------------------------------------------------------- /docs/source/static/07_pic1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CellProfiler/CellProfiler-Analyst/8a7f924052867192b425e4b7f89137fadbbd93fa/docs/source/static/07_pic1.jpg -------------------------------------------------------------------------------- /docs/source/static/08_00.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CellProfiler/CellProfiler-Analyst/8a7f924052867192b425e4b7f89137fadbbd93fa/docs/source/static/08_00.jpg -------------------------------------------------------------------------------- /docs/source/static/08_001.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CellProfiler/CellProfiler-Analyst/8a7f924052867192b425e4b7f89137fadbbd93fa/docs/source/static/08_001.jpg -------------------------------------------------------------------------------- /docs/source/static/08_01.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CellProfiler/CellProfiler-Analyst/8a7f924052867192b425e4b7f89137fadbbd93fa/docs/source/static/08_01.jpg -------------------------------------------------------------------------------- /docs/source/static/08_02.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CellProfiler/CellProfiler-Analyst/8a7f924052867192b425e4b7f89137fadbbd93fa/docs/source/static/08_02.jpg -------------------------------------------------------------------------------- /docs/source/static/08_03.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CellProfiler/CellProfiler-Analyst/8a7f924052867192b425e4b7f89137fadbbd93fa/docs/source/static/08_03.jpg -------------------------------------------------------------------------------- /docs/source/static/08_04.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CellProfiler/CellProfiler-Analyst/8a7f924052867192b425e4b7f89137fadbbd93fa/docs/source/static/08_04.jpg -------------------------------------------------------------------------------- /docs/source/static/08_05.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CellProfiler/CellProfiler-Analyst/8a7f924052867192b425e4b7f89137fadbbd93fa/docs/source/static/08_05.jpg -------------------------------------------------------------------------------- /docs/source/static/08_06.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CellProfiler/CellProfiler-Analyst/8a7f924052867192b425e4b7f89137fadbbd93fa/docs/source/static/08_06.jpg -------------------------------------------------------------------------------- /docs/source/static/08_08.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CellProfiler/CellProfiler-Analyst/8a7f924052867192b425e4b7f89137fadbbd93fa/docs/source/static/08_08.jpg -------------------------------------------------------------------------------- /docs/source/static/08_09.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CellProfiler/CellProfiler-Analyst/8a7f924052867192b425e4b7f89137fadbbd93fa/docs/source/static/08_09.jpg -------------------------------------------------------------------------------- /docs/source/static/08_10.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CellProfiler/CellProfiler-Analyst/8a7f924052867192b425e4b7f89137fadbbd93fa/docs/source/static/08_10.jpg -------------------------------------------------------------------------------- /docs/source/static/08_11.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CellProfiler/CellProfiler-Analyst/8a7f924052867192b425e4b7f89137fadbbd93fa/docs/source/static/08_11.jpg -------------------------------------------------------------------------------- /docs/source/static/08_13.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CellProfiler/CellProfiler-Analyst/8a7f924052867192b425e4b7f89137fadbbd93fa/docs/source/static/08_13.jpg -------------------------------------------------------------------------------- /docs/source/static/08_14.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CellProfiler/CellProfiler-Analyst/8a7f924052867192b425e4b7f89137fadbbd93fa/docs/source/static/08_14.jpg -------------------------------------------------------------------------------- /docs/source/static/08_15.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CellProfiler/CellProfiler-Analyst/8a7f924052867192b425e4b7f89137fadbbd93fa/docs/source/static/08_15.jpg -------------------------------------------------------------------------------- /docs/source/static/08_16.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CellProfiler/CellProfiler-Analyst/8a7f924052867192b425e4b7f89137fadbbd93fa/docs/source/static/08_16.jpg -------------------------------------------------------------------------------- /docs/source/static/08_x.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CellProfiler/CellProfiler-Analyst/8a7f924052867192b425e4b7f89137fadbbd93fa/docs/source/static/08_x.jpg -------------------------------------------------------------------------------- /docs/source/static/08_y.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CellProfiler/CellProfiler-Analyst/8a7f924052867192b425e4b7f89137fadbbd93fa/docs/source/static/08_y.jpg -------------------------------------------------------------------------------- /docs/source/static/08_z.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CellProfiler/CellProfiler-Analyst/8a7f924052867192b425e4b7f89137fadbbd93fa/docs/source/static/08_z.jpg -------------------------------------------------------------------------------- /docs/source/static/09_01.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CellProfiler/CellProfiler-Analyst/8a7f924052867192b425e4b7f89137fadbbd93fa/docs/source/static/09_01.jpg -------------------------------------------------------------------------------- /docs/source/static/09_02.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CellProfiler/CellProfiler-Analyst/8a7f924052867192b425e4b7f89137fadbbd93fa/docs/source/static/09_02.jpg -------------------------------------------------------------------------------- /docs/source/static/09_z.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CellProfiler/CellProfiler-Analyst/8a7f924052867192b425e4b7f89137fadbbd93fa/docs/source/static/09_z.jpg -------------------------------------------------------------------------------- /docs/source/static/10_01.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CellProfiler/CellProfiler-Analyst/8a7f924052867192b425e4b7f89137fadbbd93fa/docs/source/static/10_01.jpg -------------------------------------------------------------------------------- /docs/source/static/11_01.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CellProfiler/CellProfiler-Analyst/8a7f924052867192b425e4b7f89137fadbbd93fa/docs/source/static/11_01.jpg -------------------------------------------------------------------------------- /docs/source/static/12_01.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CellProfiler/CellProfiler-Analyst/8a7f924052867192b425e4b7f89137fadbbd93fa/docs/source/static/12_01.jpg -------------------------------------------------------------------------------- /docs/source/static/14_01.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CellProfiler/CellProfiler-Analyst/8a7f924052867192b425e4b7f89137fadbbd93fa/docs/source/static/14_01.jpg -------------------------------------------------------------------------------- /docs/source/static/15_01.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CellProfiler/CellProfiler-Analyst/8a7f924052867192b425e4b7f89137fadbbd93fa/docs/source/static/15_01.jpg -------------------------------------------------------------------------------- /docs/source/static/16_01.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CellProfiler/CellProfiler-Analyst/8a7f924052867192b425e4b7f89137fadbbd93fa/docs/source/static/16_01.jpg -------------------------------------------------------------------------------- /docs/source/static/5_c.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CellProfiler/CellProfiler-Analyst/8a7f924052867192b425e4b7f89137fadbbd93fa/docs/source/static/5_c.jpg -------------------------------------------------------------------------------- /docs/source/static/5_d.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CellProfiler/CellProfiler-Analyst/8a7f924052867192b425e4b7f89137fadbbd93fa/docs/source/static/5_d.jpg -------------------------------------------------------------------------------- /manual/cpa_manual.doc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CellProfiler/CellProfiler-Analyst/8a7f924052867192b425e4b7f89137fadbbd93fa/manual/cpa_manual.doc -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | boto3 2 | botocore 3 | imagecodecs 4 | imageio 5 | joblib 6 | matplotlib 7 | mock 8 | mysqlclient 9 | numpy 10 | pandas 11 | Pillow 12 | progressbar 13 | python-bioformats 14 | python-javabridge 15 | pytz 16 | requests 17 | scikit-learn 18 | scipy 19 | seaborn 20 | verlib 21 | wxPython -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | import codecs 2 | import os 3 | import re 4 | 5 | import setuptools.dist 6 | 7 | import cpa.util.version 8 | 9 | 10 | def read(*directories): 11 | pathname = os.path.abspath(os.path.dirname(__file__)) 12 | 13 | return codecs.open(os.path.join(pathname, *directories), "r").read() 14 | 15 | 16 | def find_version(*pathnames): 17 | data = read(*pathnames) 18 | 19 | matched = re.search(r"^__version__ = ['\"]([^'\"]*)['\"]", data, re.M) 20 | 21 | if matched: 22 | return matched.group(1) 23 | 24 | raise RuntimeError("Unable to find version string.") 25 | 26 | 27 | def package_data(): 28 | resources = [] 29 | 30 | for root, _, filenames in os.walk(os.path.join("cellprofiler", "data")): 31 | resources += [ 32 | os.path.relpath(os.path.join(root, filename), "cellprofiler") 33 | for filename in filenames 34 | ] 35 | 36 | for root, _, filenames in os.walk(os.path.join("cellprofiler", "gui")): 37 | resources += [ 38 | os.path.relpath(os.path.join(root, filename), "cellprofiler") 39 | for filename in filenames 40 | if ".html" in filename 41 | ] 42 | 43 | return {"cellprofiler": resources} 44 | 45 | 46 | setuptools.setup( 47 | app=['CellProfiler-Analyst.py'], 48 | author="Broad Institute", 49 | author_email="imagingadmin@broadinstitute.org", 50 | classifiers=[ 51 | "Development Status :: 5 - Production/Stable", 52 | "Intended Audience :: Science/Research", 53 | "License :: OSI Approved :: BSD License", 54 | "Operating System :: OS Independent", 55 | "Programming Language :: Python :: 3", 56 | "Programming Language :: Python :: 3.8", 57 | "Topic :: Scientific/Engineering :: Bio-Informatics", 58 | "Topic :: Scientific/Engineering :: Image Recognition", 59 | "Topic :: Scientific/Engineering", 60 | ], 61 | # entry_points={"console_scripts": ["cellprofiler-analyst=CellProfiler-Analyst.__main__:main"]}, 62 | extras_require={ 63 | "build": ["pyinstaller"], 64 | }, 65 | install_requires=[ 66 | "boto3==1.17.15", 67 | "botocore==1.20.15", 68 | "imagecodecs>=2021.2.26", 69 | "imageio>=2.9.0", 70 | "joblib>=1.0.1", 71 | "matplotlib==3.3.4", 72 | "mock>=4.0.3", 73 | "mysqlclient>=2.0.3", 74 | "numpy>=1.20.1", 75 | "pandas>=1.2.2", 76 | "Pillow>=8.1.0", 77 | "progressbar>=2.5", 78 | "python-bioformats>=4.0.4", 79 | "python-javabridge>=4.0.3", 80 | "pytz>=2021.1", 81 | "requests>=2.25.1", 82 | "scikit-learn>=0.24.1", 83 | "scipy>=1.6.1", 84 | "seaborn>=0.11.1", 85 | "tifffile>=2021.3.31", 86 | "verlib==0.1", 87 | "wxPython==4.1.0", 88 | ], 89 | license="BSD", 90 | name="CellProfiler-Analyst", 91 | package_data=package_data(), 92 | include_package_data=True, 93 | packages=setuptools.find_packages(exclude=["tests*"]), 94 | python_requires=">=3.8", 95 | setup_requires=["pytest"], 96 | url="https://github.com/CellProfiler/CellProfiler-Analyst", 97 | version=cpa.util.version.__version__, 98 | windows=[{'script': 'CellProfiler-Analyst.py', 99 | 'icon_resources': [(1, '.\cpa\icons\cpa.ico')]}], 100 | 101 | ) 102 | --------------------------------------------------------------------------------