diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile new file mode 100644 index 0000000..ec93e9b --- /dev/null +++ b/.devcontainer/Dockerfile @@ -0,0 +1,22 @@ +# See here for image contents: https://github.com/microsoft/vscode-dev-containers/tree/v0.148.1/containers/python-3/.devcontainer/base.Dockerfile + +# [Choice] Python version: 3, 3.9, 3.8, 3.7, 3.6 +ARG VARIANT="3" +FROM mcr.microsoft.com/vscode/devcontainers/python:0-${VARIANT} + +# [Option] Install Node.js +ARG INSTALL_NODE="true" +ARG NODE_VERSION="lts/*" +RUN if [ "${INSTALL_NODE}" = "true" ]; then su vscode -c "source /usr/local/share/nvm/nvm.sh && nvm install ${NODE_VERSION} 2>&1"; fi + +# [Optional] If your pip requirements rarely change, uncomment this section to add them to the image. +# COPY requirements.txt /tmp/pip-tmp/ +# RUN pip3 --disable-pip-version-check --no-cache-dir install -r /tmp/pip-tmp/requirements.txt \ +# && rm -rf /tmp/pip-tmp + +# [Optional] Uncomment this section to install additional OS packages. +# RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \ +# && apt-get -y install --no-install-recommends + +# [Optional] Uncomment this line to install global node packages. +# RUN su vscode -c "source /usr/local/share/nvm/nvm.sh && npm install -g " 2>&1 \ No newline at end of file diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json new file mode 100644 index 0000000..4bc5e77 --- /dev/null +++ b/.devcontainer/devcontainer.json @@ -0,0 +1,44 @@ +{ + "name": "Python 3", + "build": { + "dockerfile": "Dockerfile", + "context": "..", + "args": { + // Update 'VARIANT' to pick a Python version: 3, 3.6, 3.7, 3.8, 3.9 + "VARIANT": "3", + // Options + "INSTALL_NODE": "false" + } + }, + + // Set *default* container specific settings.json values on container create. + "settings": { + "terminal.integrated.shell.linux": "/bin/bash", + "python.pythonPath": "/usr/local/bin/python", + "python.linting.enabled": true, + "python.linting.pylintEnabled": true, + "python.formatting.autopep8Path": "/usr/local/py-utils/bin/autopep8", + "python.formatting.blackPath": "/usr/local/py-utils/bin/black", + "python.formatting.yapfPath": "/usr/local/py-utils/bin/yapf", + "python.linting.banditPath": "/usr/local/py-utils/bin/bandit", + "python.linting.flake8Path": "/usr/local/py-utils/bin/flake8", + "python.linting.mypyPath": "/usr/local/py-utils/bin/mypy", + "python.linting.pycodestylePath": "/usr/local/py-utils/bin/pycodestyle", + "python.linting.pydocstylePath": "/usr/local/py-utils/bin/pydocstyle", + "python.linting.pylintPath": "/usr/local/py-utils/bin/pylint" + }, + + // Add the IDs of extensions you want installed when the container is created. + "extensions": [ + "ms-python.python" + ], + + // Use 'forwardPorts' to make a list of ports inside the container available locally. + // "forwardPorts": [], + + // Use 'postCreateCommand' to run commands after the container is created. + "postCreateCommand": "pip3 install --user -r requirements.txt", + + // Comment out connect as root instead. More info: https://aka.ms/vscode-remote/containers/non-root. + "remoteUser": "vscode" +} diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..3d2c432 --- /dev/null +++ b/.gitignore @@ -0,0 +1,203 @@ + +# Created by https://www.toptal.com/developers/gitignore/api/vscode,python,macos,vim +# Edit at https://www.toptal.com/developers/gitignore?templates=vscode,python,macos,vim + +### macOS ### +# General +.DS_Store +.AppleDouble +.LSOverride + +# Icon must end with two \r +Icon + + +# Thumbnails +._* + +# Files that might appear in the root of a volume +.DocumentRevisions-V100 +.fseventsd +.Spotlight-V100 +.TemporaryItems +.Trashes +.VolumeIcon.icns +.com.apple.timemachine.donotpresent + +# Directories potentially created on remote AFP share +.AppleDB +.AppleDesktop +Network Trash Folder +Temporary Items +.apdisk + +### Python ### +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +pip-wheel-metadata/ +share/python-wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.nox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +*.py,cover +.hypothesis/ +.pytest_cache/ +pytestdebug.log + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py +db.sqlite3 +db.sqlite3-journal + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ +doc/_build/ + +# PyBuilder +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# IPython +profile_default/ +ipython_config.py + +# pyenv +.python-version + +# pipenv +# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. +# However, in case of collaboration, if having platform-specific dependencies or dependencies +# having no cross-platform support, pipenv may install dependencies that don't work, or not +# install all needed dependencies. +#Pipfile.lock + +# PEP 582; used by e.g. github.com/David-OConnor/pyflow +__pypackages__/ + +# Celery stuff +celerybeat-schedule +celerybeat.pid + +# SageMath parsed files +*.sage.py + +# Environments +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ +pythonenv* + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ +.dmypy.json +dmypy.json + +# Pyre type checker +.pyre/ + +# pytype static type analyzer +.pytype/ + +# profiling data +.prof + +### Vim ### +# Swap +[._]*.s[a-v][a-z] +!*.svg # comment out if you don't need vector files +[._]*.sw[a-p] +[._]s[a-rt-v][a-z] +[._]ss[a-gi-z] +[._]sw[a-p] + +# Session +Session.vim +Sessionx.vim + +# Temporary +.netrwhist +*~ +# Auto-generated tag files +tags +# Persistent undo +[._]*.un~ + +### vscode ### +.vscode/* +!.vscode/settings.json +!.vscode/tasks.json +!.vscode/launch.json +!.vscode/extensions.json +*.code-workspace + +# End of https://www.toptal.com/developers/gitignore/api/vscode,python,macos,vim diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..17e15f2 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,15 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Python: Current File", + "type": "python", + "request": "launch", + "program": "${file}", + "console": "integratedTerminal" + } + ] +} \ No newline at end of file diff --git a/brain_average.csv b/brain_average.csv deleted file mode 100644 index d30573e..0000000 --- a/brain_average.csv +++ /dev/null @@ -1 +0,0 @@ -10.5,11.5,12.5,13.5,14.5,15.5,16.5,17.5,18.5,19.5,20.5,21.5,22.5,23.5,24.5,25.5,26.5,27.5,28.5,29.5 diff --git a/brain_sample.csv b/brain_sample.csv index 7b809c6..d0b9035 100644 --- a/brain_sample.csv +++ b/brain_sample.csv @@ -1,20 +1,20 @@ -1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20 -2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21 -3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22 -4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23 -5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24 -6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25 -7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26 -8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27 -9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28 -10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29 -11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30 -12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31 -13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32 -14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33 -15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34 -16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35 -17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36 -18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37 -19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38 -20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1 diff --git a/sagital_average/__init__.py b/sagital_average/__init__.py new file mode 100644 index 0000000..829850f --- /dev/null +++ b/sagital_average/__init__.py @@ -0,0 +1 @@ +from .sagital_brain import run_averages \ No newline at end of file diff --git a/sagital_average/brain_average.csv b/sagital_average/brain_average.csv new file mode 100644 index 0000000..af02e18 --- /dev/null +++ b/sagital_average/brain_average.csv @@ -0,0 +1 @@ +0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.0 diff --git a/sagital_average/brain_sample.csv b/sagital_average/brain_sample.csv new file mode 100644 index 0000000..d0b9035 --- /dev/null +++ b/sagital_average/brain_sample.csv @@ -0,0 +1,20 @@ +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1 diff --git a/sagital_average/command.py b/sagital_average/command.py new file mode 100644 index 0000000..29e6aa1 --- /dev/null +++ b/sagital_average/command.py @@ -0,0 +1,12 @@ +from argparse import ArgumentParser, ArgumentDefaultsHelpFormatter +import sagital_brain + +def process(): + parser = ArgumentParser(description="Calculates the average for each sagital-horizontal plane.", + formatter_class=ArgumentDefaultsHelpFormatter) + parser.add_argument('file_input', nargs='?', default="brain_sample.csv", + help="Input CSV file with the results from scikit-brain binning algorithm.") + parser.add_argument('--file_output', '-o', default="brain_average.csv", + help="Name of the output CSV file.") + arguments = parser.parse_args() + sagital_brain.run_averages(arguments.file_input, arguments.file_output) \ No newline at end of file diff --git a/sagital_average/requirements.txt b/sagital_average/requirements.txt new file mode 100644 index 0000000..296d654 --- /dev/null +++ b/sagital_average/requirements.txt @@ -0,0 +1 @@ +numpy \ No newline at end of file diff --git a/sagital_average/sagital_brain.py b/sagital_average/sagital_brain.py new file mode 100755 index 0000000..b33870c --- /dev/null +++ b/sagital_average/sagital_brain.py @@ -0,0 +1,21 @@ +import numpy as np + +def run_averages(file_input='brain_sample.csv', file_output='brain_average.csv'): + """ + Calculates the average through the coronal planes + The input file should has as many columns as coronal planes + The rows are intersections of the sagital/horizontal planes + + The result is the average for each sagital/horizontal plane (rows) + """ + # Open the file to analyse + planes = np.loadtxt(file_input, dtype=int, delimiter=',') + + # Calculates the averages through the sagital/horizontal planes + # and makes it as a row vector + averages = planes.mean(axis=1)[np.newaxis, :] + + # write it out on my file + np.savetxt(file_output, averages, fmt='%.1f', delimiter=',') + + diff --git a/sagital_average/tests/test_average.py b/sagital_average/tests/test_average.py new file mode 100644 index 0000000..a97c463 --- /dev/null +++ b/sagital_average/tests/test_average.py @@ -0,0 +1,22 @@ +#!/usr/bin/env python3 +import numpy as np +import subprocess +import sagital_average + +def test_average(): + # Make new output file + data_input = np.zeros((20, 20)) + data_input[-1, :] = 1 + np.savetxt("brain_sample.csv", data_input, fmt='%d', delimiter=',') + + # Run sagital brain file to generate output + sagital_average.run_averages() + + # Load output + loaded = np.loadtxt('brain_average.csv', delimiter=',') + + # Expected output + expected = np.array([0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.0]) + + # Check the values are identical + np.testing.assert_array_equal(loaded, expected) \ No newline at end of file diff --git a/sagital_brain.py b/sagital_brain.py deleted file mode 100644 index 9c5ed19..0000000 --- a/sagital_brain.py +++ /dev/null @@ -1,34 +0,0 @@ -from argparse import ArgumentParser, ArgumentDefaultsHelpFormatter - -import numpy as np - - -def run_averages(file_input='brain_sample.csv', file_output='brain_average.csv'): - """ - Calculates the average through the coronal planes - The input file should has as many columns as coronal planes - The rows are intersections of the sagital/horizontal planes - - The result is the average for each sagital/horizontal plane (rows) - """ - # Open the file to analyse - planes = np.loadtxt(file_input, dtype=int, delimiter=',') - - # Calculates the averages through the sagital/horizontal planes - # and makes it as a row vector - averages = planes.mean(axis=0)[np.newaxis, :] - - # write it out on my file - np.savetxt(file_output, averages, fmt='%.1f', delimiter=',') - - -if __name__ == "__main__": - parser = ArgumentParser(description="Calculates the average for each sagital-horizontal plane.", - formatter_class=ArgumentDefaultsHelpFormatter) - parser.add_argument('file_input', nargs='?', default="brain_sample.csv", - help="Input CSV file with the results from scikit-brain binning algorithm.") - parser.add_argument('--file_output', '-o', default="brain_average.csv", - help="Name of the output CSV file.") - arguments = parser.parse_args() - - run_averages(arguments.file_input, arguments.file_output) diff --git a/setup.py b/setup.py new file mode 100644 index 0000000..4f16d5a --- /dev/null +++ b/setup.py @@ -0,0 +1,12 @@ +from setuptools import setup, find_packages + +setup( + name="Sagital Brain", + version="0.1.0", + packages=find_packages(), + install_requires=['numpy', 'pytest'], + entry_points={ + 'console_scripts': [ + 'sagital_brain = sagital_brain.command:process' + ]} +) \ No newline at end of file