PyNutil 0.5.3__tar.gz → 0.6.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- pynutil-0.6.1/.gitattributes +2 -0
- pynutil-0.6.1/.github/workflows/benchmark.yml +35 -0
- pynutil-0.6.1/.github/workflows/build.yml +110 -0
- pynutil-0.6.1/.github/workflows/main.yml +21 -0
- pynutil-0.6.1/.github/workflows/publish-to-pypi.yml +30 -0
- pynutil-0.6.1/.github/workflows/tests.yml +33 -0
- pynutil-0.6.1/.gitignore +177 -0
- pynutil-0.6.1/MANIFEST.in +1 -0
- {pynutil-0.5.3 → pynutil-0.6.1}/PKG-INFO +38 -40
- pynutil-0.6.1/PyNutil/__init__.py +37 -0
- {pynutil-0.5.3 → pynutil-0.6.1}/PyNutil/config.py +3 -3
- {pynutil-0.5.3 → pynutil-0.6.1}/PyNutil/context.py +39 -18
- pynutil-0.6.1/PyNutil/image_series.py +91 -0
- pynutil-0.6.1/PyNutil/io/__init__.py +13 -0
- pynutil-0.6.1/PyNutil/io/atlas_loader.py +108 -0
- {pynutil-0.5.3 → pynutil-0.6.1}/PyNutil/io/colormap.py +0 -23
- pynutil-0.6.1/PyNutil/io/file_operations.py +177 -0
- {pynutil-0.5.3 → pynutil-0.6.1}/PyNutil/io/loaders.py +49 -143
- {pynutil-0.5.3 → pynutil-0.6.1}/PyNutil/io/meshview_writer.py +134 -123
- {pynutil-0.5.3 → pynutil-0.6.1}/PyNutil/io/nifti_writer.py +1 -5
- {pynutil-0.5.3 → pynutil-0.6.1}/PyNutil/io/reconstruct_dzi.py +3 -5
- {pynutil-0.5.3 → pynutil-0.6.1}/PyNutil/io/section_visualisation.py +48 -62
- pynutil-0.6.1/PyNutil/io/volume_nifti.py +136 -0
- pynutil-0.6.1/PyNutil/processing/__init__.py +17 -0
- pynutil-0.6.1/PyNutil/processing/adapters/__init__.py +26 -0
- {pynutil-0.5.3 → pynutil-0.6.1}/PyNutil/processing/adapters/anchoring.py +38 -27
- {pynutil-0.5.3 → pynutil-0.6.1}/PyNutil/processing/adapters/base.py +26 -1
- {pynutil-0.5.3 → pynutil-0.6.1}/PyNutil/processing/adapters/damage.py +26 -57
- {pynutil-0.5.3 → pynutil-0.6.1}/PyNutil/processing/adapters/deformation.py +55 -21
- {pynutil-0.5.3 → pynutil-0.6.1}/PyNutil/processing/adapters/registry.py +4 -5
- {pynutil-0.5.3 → pynutil-0.6.1}/PyNutil/processing/adapters/segmentation.py +57 -21
- {pynutil-0.5.3 → pynutil-0.6.1}/PyNutil/processing/adapters/visualign_deformations.py +67 -60
- pynutil-0.6.1/PyNutil/processing/analysis/data_analysis.py +279 -0
- {pynutil-0.5.3 → pynutil-0.6.1}/PyNutil/processing/analysis/region_counting.py +48 -72
- pynutil-0.6.1/PyNutil/processing/atlas_map.py +453 -0
- {pynutil-0.5.3 → pynutil-0.6.1}/PyNutil/processing/pipeline/__init__.py +4 -4
- pynutil-0.6.1/PyNutil/processing/pipeline/batch_processor.py +681 -0
- {pynutil-0.5.3 → pynutil-0.6.1}/PyNutil/processing/pipeline/connected_components.py +34 -42
- {pynutil-0.5.3 → pynutil-0.6.1}/PyNutil/processing/pipeline/section_processor.py +179 -219
- pynutil-0.6.1/PyNutil/processing/reorientation.py +143 -0
- {pynutil-0.5.3 → pynutil-0.6.1}/PyNutil/processing/section_volume.py +247 -149
- {pynutil-0.5.3 → pynutil-0.6.1}/PyNutil/processing/utils.py +17 -73
- pynutil-0.6.1/PyNutil/results/__init__.py +15 -0
- pynutil-0.6.1/PyNutil/results/atlas.py +17 -0
- pynutil-0.6.1/PyNutil/results/extraction.py +128 -0
- pynutil-0.6.1/PyNutil/results/section.py +61 -0
- pynutil-0.6.1/PyNutil/results/volume.py +27 -0
- {pynutil-0.5.3 → pynutil-0.6.1}/PyNutil.egg-info/PKG-INFO +38 -40
- {pynutil-0.5.3 → pynutil-0.6.1}/PyNutil.egg-info/SOURCES.txt +48 -6
- {pynutil-0.5.3 → pynutil-0.6.1}/PyNutil.egg-info/requires.txt +4 -0
- {pynutil-0.5.3 → pynutil-0.6.1}/README.md +24 -31
- pynutil-0.6.1/benchmarks/benchmark.py +408 -0
- pynutil-0.6.1/benchmarks/profile_detailed.py +52 -0
- pynutil-0.6.1/demos/basic_example.py +33 -0
- pynutil-0.6.1/demos/basic_example_custom_atlas.py +39 -0
- pynutil-0.6.1/demos/basic_example_intensity.py +32 -0
- pynutil-0.6.1/demos/brainglobe_coordinate_example.py +26 -0
- pynutil-0.6.1/demos/brainglobe_registration_usage.py +29 -0
- pynutil-0.6.1/demos/coordinate_example.py +33 -0
- pynutil-0.6.1/demos/plot_cells_in_brainrender.py +27 -0
- pynutil-0.6.1/docs/assets/MeshView.mp4 +0 -0
- pynutil-0.6.1/docs/assets/PyNutil_fig1.png +0 -0
- pynutil-0.6.1/docs/assets/Siibra.mp4 +0 -0
- pynutil-0.6.1/gui/Logo_PyNutil.ico +0 -0
- pynutil-0.6.1/gui/Logo_PyNutil.png +0 -0
- pynutil-0.6.1/gui/PyNutilGUI.py +771 -0
- pynutil-0.6.1/gui/gui_smoke_test.py +34 -0
- pynutil-0.6.1/gui/log_manager.py +65 -0
- pynutil-0.6.1/gui/settings_manager.py +76 -0
- pynutil-0.6.1/gui/ui_components.py +230 -0
- pynutil-0.6.1/gui/validation.py +67 -0
- pynutil-0.6.1/gui/workers.py +186 -0
- pynutil-0.6.1/misc/PyNutil_test.json +285 -0
- pynutil-0.6.1/misc/PyNutil_test.waln +1 -0
- pynutil-0.6.1/misc/Tiling_script.py +24 -0
- pynutil-0.6.1/misc/create_test_data.py +64 -0
- pynutil-0.6.1/misc/download_and_pack_atlases_allen.py +43 -0
- pynutil-0.6.1/misc/download_and_pack_atlases_waxholm.py +69 -0
- pynutil-0.6.1/misc/implement_allen_downsampling.py +46 -0
- pynutil-0.6.1/misc/make_white_images.py +8 -0
- pynutil-0.6.1/misc/reformat_label_files.py +153 -0
- pynutil-0.6.1/misc/reorient_allen_volume.py +15 -0
- pynutil-0.6.1/misc/waln_to_json.py +47 -0
- pynutil-0.6.1/pyproject.toml +44 -0
- pynutil-0.5.3/PyNutil/__init__.py +0 -1
- pynutil-0.5.3/PyNutil/io/__init__.py +0 -63
- pynutil-0.5.3/PyNutil/io/atlas_loader.py +0 -87
- pynutil-0.5.3/PyNutil/io/file_operations.py +0 -221
- pynutil-0.5.3/PyNutil/io/propagation.py +0 -133
- pynutil-0.5.3/PyNutil/io/volume_nifti.py +0 -91
- pynutil-0.5.3/PyNutil/main.py +0 -720
- pynutil-0.5.3/PyNutil/processing/__init__.py +0 -94
- pynutil-0.5.3/PyNutil/processing/adapters/__init__.py +0 -98
- pynutil-0.5.3/PyNutil/processing/analysis/data_analysis.py +0 -354
- pynutil-0.5.3/PyNutil/processing/atlas_map.py +0 -440
- pynutil-0.5.3/PyNutil/processing/pipeline/batch_processor.py +0 -546
- pynutil-0.5.3/PyNutil/processing/transforms.py +0 -221
- pynutil-0.5.3/PyNutil/results.py +0 -127
- pynutil-0.5.3/setup.py +0 -32
- pynutil-0.5.3/tests/test_helpers.py +0 -23
- {pynutil-0.5.3 → pynutil-0.6.1}/LICENSE +0 -0
- {pynutil-0.5.3 → pynutil-0.6.1}/PyNutil/logging_utils.py +0 -0
- {pynutil-0.5.3 → pynutil-0.6.1}/PyNutil/processing/analysis/__init__.py +0 -0
- {pynutil-0.5.3 → pynutil-0.6.1}/PyNutil/processing/analysis/aggregator.py +0 -0
- {pynutil-0.5.3 → pynutil-0.6.1}/PyNutil.egg-info/dependency_links.txt +0 -0
- {pynutil-0.5.3 → pynutil-0.6.1}/PyNutil.egg-info/top_level.txt +0 -0
- {pynutil-0.5.3 → pynutil-0.6.1}/setup.cfg +0 -0
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
name: Benchmark
|
|
2
|
+
|
|
3
|
+
on: [push, pull_request]
|
|
4
|
+
|
|
5
|
+
jobs:
|
|
6
|
+
benchmark:
|
|
7
|
+
runs-on: ubuntu-latest
|
|
8
|
+
|
|
9
|
+
steps:
|
|
10
|
+
- name: Checkout code
|
|
11
|
+
uses: actions/checkout@v4
|
|
12
|
+
|
|
13
|
+
- name: Set up Python
|
|
14
|
+
uses: actions/setup-python@v5
|
|
15
|
+
with:
|
|
16
|
+
python-version: '3.12'
|
|
17
|
+
|
|
18
|
+
- name: Install dependencies
|
|
19
|
+
run: |
|
|
20
|
+
python -m pip install --upgrade pip
|
|
21
|
+
pip install .
|
|
22
|
+
|
|
23
|
+
- name: Run benchmark
|
|
24
|
+
run: python benchmarks/benchmark.py 2>&1
|
|
25
|
+
|
|
26
|
+
- name: Write job summary
|
|
27
|
+
run: cat benchmarks/results.md >> "$GITHUB_STEP_SUMMARY"
|
|
28
|
+
|
|
29
|
+
- name: Upload benchmark results
|
|
30
|
+
uses: actions/upload-artifact@v4
|
|
31
|
+
with:
|
|
32
|
+
name: benchmark-results
|
|
33
|
+
path: |
|
|
34
|
+
benchmarks/results.md
|
|
35
|
+
benchmarks/results.json
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
name: Build Application
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
release:
|
|
5
|
+
types: [published] # Only trigger on published releases
|
|
6
|
+
workflow_dispatch: # Allow manual triggering
|
|
7
|
+
|
|
8
|
+
# Add global permissions
|
|
9
|
+
permissions:
|
|
10
|
+
contents: write
|
|
11
|
+
|
|
12
|
+
jobs:
|
|
13
|
+
build-windows:
|
|
14
|
+
runs-on: windows-latest
|
|
15
|
+
steps:
|
|
16
|
+
- uses: actions/checkout@v3
|
|
17
|
+
|
|
18
|
+
- name: Set up Python 3.10
|
|
19
|
+
uses: actions/setup-python@v4
|
|
20
|
+
with:
|
|
21
|
+
python-version: '3.10'
|
|
22
|
+
|
|
23
|
+
- name: Install dependencies
|
|
24
|
+
run: |
|
|
25
|
+
python -m pip install --upgrade pip
|
|
26
|
+
pip install pyinstaller
|
|
27
|
+
pip install ".[gui]"
|
|
28
|
+
- name: Build with PyInstaller
|
|
29
|
+
run: |
|
|
30
|
+
pyinstaller --windowed --icon=gui/Logo_PyNutil.ico --name PyNutil gui/PyNutilGUI.py
|
|
31
|
+
|
|
32
|
+
- name: Create Windows ZIP archive
|
|
33
|
+
run: |
|
|
34
|
+
cd dist
|
|
35
|
+
powershell Compress-Archive -Path PyNutil -DestinationPath PyNutil-Windows.zip
|
|
36
|
+
|
|
37
|
+
- name: Upload Windows artifact
|
|
38
|
+
uses: actions/upload-artifact@v4
|
|
39
|
+
with:
|
|
40
|
+
name: PyNutil-Windows
|
|
41
|
+
path: dist/PyNutil-Windows.zip
|
|
42
|
+
retention-days: 5
|
|
43
|
+
|
|
44
|
+
build-macos:
|
|
45
|
+
runs-on: macos-latest
|
|
46
|
+
steps:
|
|
47
|
+
- uses: actions/checkout@v3
|
|
48
|
+
|
|
49
|
+
- name: Set up Python 3.10
|
|
50
|
+
uses: actions/setup-python@v4
|
|
51
|
+
with:
|
|
52
|
+
python-version: '3.10'
|
|
53
|
+
|
|
54
|
+
- name: Install dependencies
|
|
55
|
+
run: |
|
|
56
|
+
python -m pip install --upgrade pip
|
|
57
|
+
pip install pyinstaller
|
|
58
|
+
pip install dmgbuild
|
|
59
|
+
pip install ".[gui]"
|
|
60
|
+
- name: Build with PyInstaller
|
|
61
|
+
run: |
|
|
62
|
+
# Build without specifying an icon for macOS to avoid format issues
|
|
63
|
+
pyinstaller --windowed --osx-bundle-identifier com.pynutil.app --name PyNutil gui/PyNutilGUI.py
|
|
64
|
+
|
|
65
|
+
- name: Create DMG
|
|
66
|
+
run: |
|
|
67
|
+
pip install dmgbuild
|
|
68
|
+
cat > dmg_settings.py << EOF
|
|
69
|
+
app = 'dist/PyNutil.app'
|
|
70
|
+
appname = 'PyNutil'
|
|
71
|
+
format = 'UDBZ'
|
|
72
|
+
size = '500M'
|
|
73
|
+
files = [app]
|
|
74
|
+
symlinks = {'Applications': '/Applications'}
|
|
75
|
+
# Remove badge_icon to avoid icon format issues
|
|
76
|
+
icon_locations = {
|
|
77
|
+
appname + '.app': (140, 120),
|
|
78
|
+
'Applications': (360, 120)
|
|
79
|
+
}
|
|
80
|
+
background = 'builtin-arrow'
|
|
81
|
+
EOF
|
|
82
|
+
dmgbuild -s dmg_settings.py "PyNutil" "dist/PyNutil-macOS.dmg" || true
|
|
83
|
+
|
|
84
|
+
- name: Upload DMG artifact
|
|
85
|
+
uses: actions/upload-artifact@v4
|
|
86
|
+
with:
|
|
87
|
+
name: PyNutil-macOS
|
|
88
|
+
path: dist/PyNutil-macOS.dmg
|
|
89
|
+
retention-days: 5
|
|
90
|
+
|
|
91
|
+
create-release:
|
|
92
|
+
needs: [build-windows, build-macos]
|
|
93
|
+
runs-on: ubuntu-latest
|
|
94
|
+
permissions:
|
|
95
|
+
contents: write
|
|
96
|
+
steps:
|
|
97
|
+
- name: Download all artifacts
|
|
98
|
+
uses: actions/download-artifact@v4
|
|
99
|
+
|
|
100
|
+
- name: List downloaded artifacts
|
|
101
|
+
run: |
|
|
102
|
+
find . -type f | sort
|
|
103
|
+
|
|
104
|
+
- name: Attach Artifacts to Release
|
|
105
|
+
uses: softprops/action-gh-release@v1
|
|
106
|
+
with:
|
|
107
|
+
files: |
|
|
108
|
+
PyNutil-Windows/PyNutil-Windows.zip
|
|
109
|
+
PyNutil-macOS/PyNutil-macOS.dmg
|
|
110
|
+
token: ${{ github.token }}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
name: Mirror to Ebrains
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [ main ]
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
jobs:
|
|
9
|
+
# set the job name
|
|
10
|
+
to_ebrains:
|
|
11
|
+
runs-on: ubuntu-latest
|
|
12
|
+
steps:
|
|
13
|
+
|
|
14
|
+
- name: syncmain
|
|
15
|
+
uses: wei/git-sync@v3
|
|
16
|
+
|
|
17
|
+
with:
|
|
18
|
+
source_repo: "Neural-Systems-at-UIO/PyNutil"
|
|
19
|
+
source_branch: "main"
|
|
20
|
+
destination_repo: "https://ghpusher:${{ secrets.EBRAINS_GITLAB_ACCESS_TOKEN }}@gitlab.ebrains.eu/polarbean/PyNutil.git"
|
|
21
|
+
destination_branch: "main"
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
name: Publish to PyPI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
release:
|
|
5
|
+
types: [created]
|
|
6
|
+
|
|
7
|
+
jobs:
|
|
8
|
+
deploy:
|
|
9
|
+
runs-on: ubuntu-latest
|
|
10
|
+
permissions:
|
|
11
|
+
id-token: write # Required for trusted publisher authentication
|
|
12
|
+
contents: read # Required for checkout
|
|
13
|
+
steps:
|
|
14
|
+
- uses: actions/checkout@v3
|
|
15
|
+
with:
|
|
16
|
+
fetch-depth: 0
|
|
17
|
+
- name: Set up Python
|
|
18
|
+
uses: actions/setup-python@v4
|
|
19
|
+
with:
|
|
20
|
+
python-version: '3.x'
|
|
21
|
+
- name: Install dependencies
|
|
22
|
+
run: |
|
|
23
|
+
python -m pip install --upgrade pip
|
|
24
|
+
pip install build
|
|
25
|
+
- name: Build package
|
|
26
|
+
run: python -m build
|
|
27
|
+
- name: Publish package
|
|
28
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
|
29
|
+
with:
|
|
30
|
+
verbose: true
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
name: Run Tests
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches:
|
|
6
|
+
- main
|
|
7
|
+
pull_request:
|
|
8
|
+
|
|
9
|
+
jobs:
|
|
10
|
+
test:
|
|
11
|
+
runs-on: ubuntu-latest
|
|
12
|
+
|
|
13
|
+
steps:
|
|
14
|
+
- name: Checkout code
|
|
15
|
+
uses: actions/checkout@v2
|
|
16
|
+
|
|
17
|
+
- name: Set up Python
|
|
18
|
+
uses: actions/setup-python@v2
|
|
19
|
+
with:
|
|
20
|
+
python-version: '3.x' # Specify your Python version
|
|
21
|
+
|
|
22
|
+
- name: Install dependencies
|
|
23
|
+
run: |
|
|
24
|
+
python -m pip install --upgrade pip
|
|
25
|
+
pip install .
|
|
26
|
+
|
|
27
|
+
- name: Download atlas
|
|
28
|
+
run: |
|
|
29
|
+
brainglobe install -a allen_mouse_25um
|
|
30
|
+
|
|
31
|
+
- name: Run tests
|
|
32
|
+
run: |
|
|
33
|
+
python -m unittest discover -s tests -v
|
pynutil-0.6.1/.gitignore
ADDED
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
dmg.py
|
|
2
|
+
# dev environment
|
|
3
|
+
.vscode
|
|
4
|
+
.claude
|
|
5
|
+
.complexipy_cache
|
|
6
|
+
.# Byte-compiled / optimized / DLL files
|
|
7
|
+
__pycache__/
|
|
8
|
+
*.py[cod]
|
|
9
|
+
*$py.class
|
|
10
|
+
demo_data/*
|
|
11
|
+
# C extensions
|
|
12
|
+
*.so
|
|
13
|
+
# WSL zone identifiers
|
|
14
|
+
*:Zone.Identifier*
|
|
15
|
+
*:encryptable*
|
|
16
|
+
# Distribution / packaging
|
|
17
|
+
.Python
|
|
18
|
+
build/
|
|
19
|
+
develop-eggs/
|
|
20
|
+
dist/
|
|
21
|
+
downloads/
|
|
22
|
+
eggs/
|
|
23
|
+
.eggs/
|
|
24
|
+
lib/
|
|
25
|
+
lib64/
|
|
26
|
+
parts/
|
|
27
|
+
sdist/
|
|
28
|
+
var/
|
|
29
|
+
wheels/
|
|
30
|
+
share/python-wheels/
|
|
31
|
+
*.egg-info/
|
|
32
|
+
.installed.cfg
|
|
33
|
+
*.egg
|
|
34
|
+
MANIFEST
|
|
35
|
+
|
|
36
|
+
# PyInstaller
|
|
37
|
+
# Usually these files are written by a python script from a template
|
|
38
|
+
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
|
39
|
+
*.manifest
|
|
40
|
+
*.spec
|
|
41
|
+
|
|
42
|
+
# Installer logs
|
|
43
|
+
pip-log.txt
|
|
44
|
+
pip-delete-this-directory.txt
|
|
45
|
+
|
|
46
|
+
# Unit test / coverage reports
|
|
47
|
+
htmlcov/
|
|
48
|
+
.tox/
|
|
49
|
+
.nox/
|
|
50
|
+
.coverage
|
|
51
|
+
.coverage.*
|
|
52
|
+
.cache
|
|
53
|
+
nosetests.xml
|
|
54
|
+
coverage.xml
|
|
55
|
+
*.cover
|
|
56
|
+
*.py,cover
|
|
57
|
+
.hypothesis/
|
|
58
|
+
.pytest_cache/
|
|
59
|
+
cover/
|
|
60
|
+
|
|
61
|
+
# Translations
|
|
62
|
+
*.mo
|
|
63
|
+
*.pot
|
|
64
|
+
|
|
65
|
+
# Django stuff:
|
|
66
|
+
*.log
|
|
67
|
+
local_settings.py
|
|
68
|
+
db.sqlite3
|
|
69
|
+
db.sqlite3-journal
|
|
70
|
+
|
|
71
|
+
# Flask stuff:
|
|
72
|
+
instance/
|
|
73
|
+
.webassets-cache
|
|
74
|
+
|
|
75
|
+
# Scrapy stuff:
|
|
76
|
+
.scrapy
|
|
77
|
+
|
|
78
|
+
# Sphinx documentation
|
|
79
|
+
docs/_build/
|
|
80
|
+
|
|
81
|
+
# PyBuilder
|
|
82
|
+
.pybuilder/
|
|
83
|
+
target/
|
|
84
|
+
|
|
85
|
+
# Jupyter Notebook
|
|
86
|
+
.ipynb_checkpoints
|
|
87
|
+
|
|
88
|
+
# IPython
|
|
89
|
+
profile_default/
|
|
90
|
+
ipython_config.py
|
|
91
|
+
|
|
92
|
+
# pyenv
|
|
93
|
+
# For a library or package, you might want to ignore these files since the code is
|
|
94
|
+
# intended to run in multiple environments; otherwise, check them in:
|
|
95
|
+
# .python-version
|
|
96
|
+
|
|
97
|
+
# pipenv
|
|
98
|
+
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
|
|
99
|
+
# However, in case of collaboration, if having platform-specific dependencies or dependencies
|
|
100
|
+
# having no cross-platform support, pipenv may install dependencies that don't work, or not
|
|
101
|
+
# install all needed dependencies.
|
|
102
|
+
#Pipfile.lock
|
|
103
|
+
|
|
104
|
+
# poetry
|
|
105
|
+
# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
|
|
106
|
+
# This is especially recommended for binary packages to ensure reproducibility, and is more
|
|
107
|
+
# commonly ignored for libraries.
|
|
108
|
+
# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
|
|
109
|
+
#poetry.lock
|
|
110
|
+
|
|
111
|
+
# pdm
|
|
112
|
+
# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
|
|
113
|
+
#pdm.lock
|
|
114
|
+
# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
|
|
115
|
+
# in version control.
|
|
116
|
+
# https://pdm.fming.dev/#use-with-ide
|
|
117
|
+
.pdm.toml
|
|
118
|
+
|
|
119
|
+
# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
|
|
120
|
+
__pypackages__/
|
|
121
|
+
|
|
122
|
+
# Celery stuff
|
|
123
|
+
celerybeat-schedule
|
|
124
|
+
celerybeat.pid
|
|
125
|
+
|
|
126
|
+
# SageMath parsed files
|
|
127
|
+
*.sage.py
|
|
128
|
+
|
|
129
|
+
# Environments
|
|
130
|
+
.env
|
|
131
|
+
.venv
|
|
132
|
+
env/
|
|
133
|
+
venv/
|
|
134
|
+
ENV/
|
|
135
|
+
env.bak/
|
|
136
|
+
venv.bak/
|
|
137
|
+
|
|
138
|
+
# Spyder project settings
|
|
139
|
+
.spyderproject
|
|
140
|
+
.spyproject
|
|
141
|
+
|
|
142
|
+
# Rope project settings
|
|
143
|
+
.ropeproject
|
|
144
|
+
|
|
145
|
+
# mkdocs documentation
|
|
146
|
+
/site
|
|
147
|
+
|
|
148
|
+
# mypy
|
|
149
|
+
.mypy_cache/
|
|
150
|
+
.dmypy.json
|
|
151
|
+
dmypy.json
|
|
152
|
+
|
|
153
|
+
# Pyre type checker
|
|
154
|
+
.pyre/
|
|
155
|
+
|
|
156
|
+
# pytype static type analyzer
|
|
157
|
+
.pytype/
|
|
158
|
+
|
|
159
|
+
# Cython debug symbols
|
|
160
|
+
cython_debug/
|
|
161
|
+
|
|
162
|
+
# PyCharm
|
|
163
|
+
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
|
|
164
|
+
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
|
|
165
|
+
# and can be added to the global gitignore or merged into this file. For a more nuclear
|
|
166
|
+
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
|
|
167
|
+
#.idea/
|
|
168
|
+
|
|
169
|
+
|
|
170
|
+
#inputs
|
|
171
|
+
|
|
172
|
+
#outputs
|
|
173
|
+
test_result/
|
|
174
|
+
|
|
175
|
+
# Benchmark generated data
|
|
176
|
+
benchmarks/results.json
|
|
177
|
+
benchmarks/results.md
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
prune tests
|
|
@@ -1,9 +1,17 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: PyNutil
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.6.1
|
|
4
4
|
Summary: a package to quantify atlas registered brain data
|
|
5
|
-
|
|
6
|
-
|
|
5
|
+
License-Expression: MIT
|
|
6
|
+
Project-URL: Homepage, https://github.com/Neural-Systems-at-UIO/PyNutil
|
|
7
|
+
Classifier: Development Status :: 4 - Beta
|
|
8
|
+
Classifier: Intended Audience :: Science/Research
|
|
9
|
+
Classifier: Operating System :: OS Independent
|
|
10
|
+
Classifier: Programming Language :: Python :: 3
|
|
11
|
+
Classifier: Topic :: Scientific/Engineering
|
|
12
|
+
Classifier: Topic :: Scientific/Engineering :: Bio-Informatics
|
|
13
|
+
Classifier: Topic :: Scientific/Engineering :: Image Processing
|
|
14
|
+
Requires-Python: >=3.8
|
|
7
15
|
Description-Content-Type: text/markdown
|
|
8
16
|
License-File: LICENSE
|
|
9
17
|
Requires-Dist: numpy
|
|
@@ -16,17 +24,16 @@ Requires-Dist: scipy
|
|
|
16
24
|
Requires-Dist: nibabel
|
|
17
25
|
Requires-Dist: orjson
|
|
18
26
|
Requires-Dist: tqdm
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
Dynamic: license
|
|
27
|
+
Requires-Dist: tifffile
|
|
28
|
+
Provides-Extra: gui
|
|
29
|
+
Requires-Dist: PyQt6; extra == "gui"
|
|
23
30
|
Dynamic: license-file
|
|
24
|
-
Dynamic: requires-dist
|
|
25
|
-
Dynamic: summary
|
|
26
31
|
|
|
27
32
|
# PyNutil
|
|
28
33
|
|
|
29
|
-
|
|
34
|
+
> [!WARNING]
|
|
35
|
+
> PyNutil is still under development and the API is subject to change.
|
|
36
|
+
|
|
30
37
|
|
|
31
38
|
PyNutil is a Python library for brain-wide quantification and spatial analysis of features in serial section images from the brain. It aims to replicate the Quantifier feature of the Nutil software (RRID: SCR_017183).
|
|
32
39
|
|
|
@@ -71,37 +78,31 @@ As input, PyNutil requires:
|
|
|
71
78
|
3. A segmentation file for each brain section with the features to be quantified displayed with a unique RGB colour code (it currently accepts many image formats: png, jpg, jpeg, etc).
|
|
72
79
|
|
|
73
80
|
```python
|
|
74
|
-
from
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
segmentation_folder='../tests/test_data/non_linear_allen_mouse/segmentations/',
|
|
89
|
-
alignment_json='../tests/test_data/non_linear_allen_mouse/alignment.json',
|
|
90
|
-
colour=[0, 0, 0],
|
|
91
|
-
atlas_name='allen_mouse_25um'
|
|
92
|
-
#If you would like to use cellpose segmentations add:
|
|
93
|
-
#segmentation_format = 'cellpose'
|
|
81
|
+
from brainglobe_atlasapi import BrainGlobeAtlas
|
|
82
|
+
import PyNutil as pnt
|
|
83
|
+
|
|
84
|
+
# Load an atlas (BrainGlobe) and alignment
|
|
85
|
+
atlas = BrainGlobeAtlas("allen_mouse_25um")
|
|
86
|
+
alignment = pnt.read_alignment("path/to/alignment.json")
|
|
87
|
+
|
|
88
|
+
# Extract coordinates from segmentations
|
|
89
|
+
coords = pnt.seg_to_coords(
|
|
90
|
+
"path/to/segmentations/",
|
|
91
|
+
alignment,
|
|
92
|
+
atlas,
|
|
93
|
+
pixel_id=[0, 0, 0],
|
|
94
|
+
# For cellpose segmentations: segmentation_format="cellpose"
|
|
94
95
|
)
|
|
95
96
|
|
|
96
|
-
#
|
|
97
|
-
pnt.
|
|
98
|
-
|
|
99
|
-
pnt.get_coordinates(object_cutoff=0)
|
|
100
|
-
|
|
101
|
-
pnt.quantify_coordinates()
|
|
97
|
+
# Quantify by atlas region
|
|
98
|
+
label_df = pnt.quantify_coords(coords, atlas)
|
|
102
99
|
|
|
103
|
-
|
|
100
|
+
# Save results
|
|
101
|
+
pnt.save_analysis("path/to/output", coords, atlas, label_df=label_df)
|
|
104
102
|
```
|
|
103
|
+
|
|
104
|
+
For custom atlases (not from BrainGlobe), use `pnt.load_custom_atlas()` instead.
|
|
105
|
+
See `demos/basic_example.py` and `demos/basic_example_custom_atlas.py` for complete examples.
|
|
105
106
|
PyNutil generates a series of reports in the folder which you specify.
|
|
106
107
|
|
|
107
108
|
## Per-Hemisphere Quantification
|
|
@@ -155,9 +156,6 @@ PyNutil is developed at the Neural Systems Laboratory at the Institute of Basic
|
|
|
155
156
|
# Contributors
|
|
156
157
|
Harry Carey, Sharon C Yates, Gergely Csucs, Arda Balkir, Ingvild Bjerke, Rembrandt Bakker, Nicolaas Groeneboom, Maja A Puchades, Jan G Bjaalie.
|
|
157
158
|
|
|
158
|
-
# Licence
|
|
159
|
-
GNU General Public License v3
|
|
160
|
-
|
|
161
159
|
# Related articles
|
|
162
160
|
Yates SC, Groeneboom NE, Coello C, et al. & Bjaalie JG (2019) QUINT: Workflow for Quantification and Spatial Analysis of Features in Histological Images From Rodent Brain. Front. Neuroinform. 13:75. https://doi.org/10.3389/fninf.2019.00075
|
|
163
161
|
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
from .results import AtlasData, ExtractionResult, PointSetResult, VolumeResult
|
|
2
|
+
from .processing.adapters.base import RegistrationData
|
|
3
|
+
from .processing.adapters import read_alignment
|
|
4
|
+
from .io.atlas_loader import load_custom_atlas
|
|
5
|
+
from .image_series import Section, ImageSeries
|
|
6
|
+
from .processing.pipeline.batch_processor import (
|
|
7
|
+
read_segmentation_dir,
|
|
8
|
+
read_image_dir,
|
|
9
|
+
seg_to_coords,
|
|
10
|
+
image_to_coords,
|
|
11
|
+
xy_to_coords,
|
|
12
|
+
)
|
|
13
|
+
from .processing.analysis.data_analysis import quantify_coords
|
|
14
|
+
from .io.file_operations import save_analysis
|
|
15
|
+
from .processing.section_volume import interpolate_volume
|
|
16
|
+
from .io.volume_nifti import save_volumes
|
|
17
|
+
|
|
18
|
+
__all__ = [
|
|
19
|
+
"AtlasData",
|
|
20
|
+
"ExtractionResult",
|
|
21
|
+
"PointSetResult",
|
|
22
|
+
"RegistrationData",
|
|
23
|
+
"read_alignment",
|
|
24
|
+
"load_custom_atlas",
|
|
25
|
+
"Section",
|
|
26
|
+
"ImageSeries",
|
|
27
|
+
"read_segmentation_dir",
|
|
28
|
+
"read_image_dir",
|
|
29
|
+
"seg_to_coords",
|
|
30
|
+
"image_to_coords",
|
|
31
|
+
"xy_to_coords",
|
|
32
|
+
"quantify_coords",
|
|
33
|
+
"save_analysis",
|
|
34
|
+
"VolumeResult",
|
|
35
|
+
"interpolate_volume",
|
|
36
|
+
"save_volumes",
|
|
37
|
+
]
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
-
import json
|
|
4
3
|
from dataclasses import dataclass
|
|
5
4
|
from typing import Any, Dict, Optional
|
|
6
5
|
|
|
6
|
+
from .io.loaders import load_json_file
|
|
7
|
+
|
|
7
8
|
|
|
8
9
|
@dataclass
|
|
9
10
|
class PyNutilConfig:
|
|
@@ -25,8 +26,7 @@ class PyNutilConfig:
|
|
|
25
26
|
|
|
26
27
|
@classmethod
|
|
27
28
|
def from_settings_file(cls, settings_file: str) -> "PyNutilConfig":
|
|
28
|
-
|
|
29
|
-
settings = json.load(f)
|
|
29
|
+
settings = load_json_file(settings_file)
|
|
30
30
|
return cls.from_settings_dict(settings)
|
|
31
31
|
|
|
32
32
|
@classmethod
|
|
@@ -7,13 +7,15 @@ processing layers.
|
|
|
7
7
|
from __future__ import annotations
|
|
8
8
|
|
|
9
9
|
from dataclasses import dataclass
|
|
10
|
-
from typing import
|
|
10
|
+
from typing import TYPE_CHECKING, Optional
|
|
11
11
|
|
|
12
12
|
import numpy as np
|
|
13
13
|
import pandas as pd
|
|
14
14
|
|
|
15
15
|
from .processing.adapters.base import SliceInfo
|
|
16
|
-
|
|
16
|
+
|
|
17
|
+
if TYPE_CHECKING:
|
|
18
|
+
from .processing.adapters.segmentation import SegmentationAdapter
|
|
17
19
|
|
|
18
20
|
|
|
19
21
|
@dataclass(frozen=True)
|
|
@@ -30,16 +32,10 @@ class PipelineContext:
|
|
|
30
32
|
3-D hemisphere mask (same shape as *atlas_volume*).
|
|
31
33
|
segmentation_adapter : SegmentationAdapter
|
|
32
34
|
Pre-resolved adapter for the current segmentation format.
|
|
33
|
-
non_linear : bool
|
|
34
|
-
Whether to apply non-linear deformation.
|
|
35
35
|
object_cutoff : int
|
|
36
36
|
Minimum connected-component area (binary pipeline).
|
|
37
|
-
use_flat : bool
|
|
38
|
-
If True, load flat-file atlas maps instead of slicing the volume.
|
|
39
37
|
pixel_id : object
|
|
40
38
|
Pixel colour to match, or ``"auto"`` for auto-detection.
|
|
41
|
-
apply_damage_mask : bool
|
|
42
|
-
Apply the damage / exclusion mask when available.
|
|
43
39
|
intensity_channel : str or None
|
|
44
40
|
Channel name for the intensity pipeline (``None`` in binary mode).
|
|
45
41
|
min_intensity : int or None
|
|
@@ -52,16 +48,41 @@ class PipelineContext:
|
|
|
52
48
|
atlas_volume: Optional[np.ndarray]
|
|
53
49
|
hemi_map: Optional[np.ndarray]
|
|
54
50
|
segmentation_adapter: SegmentationAdapter
|
|
55
|
-
non_linear: bool
|
|
56
51
|
object_cutoff: int
|
|
57
|
-
use_flat: bool
|
|
58
52
|
pixel_id: object
|
|
59
|
-
apply_damage_mask: bool
|
|
60
|
-
flat_label_path: Optional[str] = None
|
|
61
53
|
intensity_channel: Optional[str] = None
|
|
62
54
|
min_intensity: Optional[int] = None
|
|
63
55
|
max_intensity: Optional[int] = None
|
|
64
56
|
|
|
57
|
+
@classmethod
|
|
58
|
+
def from_format(
|
|
59
|
+
cls,
|
|
60
|
+
*,
|
|
61
|
+
segmentation_format: str,
|
|
62
|
+
atlas_labels,
|
|
63
|
+
atlas_volume,
|
|
64
|
+
hemi_map,
|
|
65
|
+
object_cutoff: int,
|
|
66
|
+
pixel_id,
|
|
67
|
+
intensity_channel=None,
|
|
68
|
+
min_intensity=None,
|
|
69
|
+
max_intensity=None,
|
|
70
|
+
) -> "PipelineContext":
|
|
71
|
+
"""Construct a PipelineContext, resolving *segmentation_format* to an adapter."""
|
|
72
|
+
from .processing.adapters.segmentation import SegmentationAdapterRegistry
|
|
73
|
+
|
|
74
|
+
return cls(
|
|
75
|
+
atlas_labels=atlas_labels,
|
|
76
|
+
atlas_volume=atlas_volume,
|
|
77
|
+
hemi_map=hemi_map,
|
|
78
|
+
segmentation_adapter=SegmentationAdapterRegistry.get(segmentation_format),
|
|
79
|
+
object_cutoff=object_cutoff,
|
|
80
|
+
pixel_id=pixel_id,
|
|
81
|
+
intensity_channel=intensity_channel,
|
|
82
|
+
min_intensity=min_intensity,
|
|
83
|
+
max_intensity=max_intensity,
|
|
84
|
+
)
|
|
85
|
+
|
|
65
86
|
|
|
66
87
|
@dataclass(frozen=True)
|
|
67
88
|
class SectionContext:
|
|
@@ -73,13 +94,13 @@ class SectionContext:
|
|
|
73
94
|
Numeric section identifier matching the alignment JSON.
|
|
74
95
|
slice_info : SliceInfo
|
|
75
96
|
Registration data for this section (anchoring, deformation, damage …).
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
97
|
+
image : np.ndarray
|
|
98
|
+
Pre-loaded image array for this section.
|
|
99
|
+
filename : str
|
|
100
|
+
Source filename, used for output tracking (empty string if unknown).
|
|
80
101
|
"""
|
|
81
102
|
|
|
82
103
|
section_number: int
|
|
83
104
|
slice_info: SliceInfo
|
|
84
|
-
|
|
85
|
-
|
|
105
|
+
image: np.ndarray
|
|
106
|
+
filename: str = ""
|