diff --git a/.github/workflows/continuous-integration.yml b/.github/workflows/continuous-integration.yml new file mode 100644 index 0000000..03ab330 --- /dev/null +++ b/.github/workflows/continuous-integration.yml @@ -0,0 +1,129 @@ +name: Continuous Integration + +on: [push, pull_request] + +jobs: + unix-build: + name: Unix Build + strategy: + matrix: + os: [ubuntu-18.04] + python-version: [3.6] + runs-on: ${{ matrix.os }} + steps: + - uses: actions/checkout@v1 + - name: Environment Variables + run: | + CI_PYTHON_VERSION=${{ matrix.python-version }} + CI_PACKAGE=colour_datasets + CI_SHA=${{ github.sha }} + CI_SLACK_WEBHOOK=${{ secrets.SLACK_WEBHOOK }} + CI_SLACK_SUCCESS_NOTIFICATION="payload={\"attachments\": [{\"color\": \"#4CAF50\", \"author_name\": \"Python ${{ matrix.python-version }} build on ${{ matrix.os }}\", \"text\": \"Build for commit *${CI_SHA:0:7}* succeeded!\", \"title\": \"${{ github.repository }}@${{ github.ref }}\", \"title_link\": \"https://github.com/${{ github.repository }}/commit/${{ github.sha }}/checks\", \"footer\": \"Triggered by ${{ github.actor }}\"}], \"username\":\"Github Actions @ ${{ github.repository }}\", \"channel\":\"#continuous-integration\", \"icon_url\":\"https://github.githubassets.com/images/modules/logos_page/GitHub-Mark.png\"}" + CI_SLACK_FAILURE_NOTIFICATION="${CI_SLACK_SUCCESS_NOTIFICATION/4CAF50/F44336}" + CI_SLACK_FAILURE_NOTIFICATION="${CI_SLACK_FAILURE_NOTIFICATION/succeeded/failed}" + COVERALLS_REPO_TOKEN=${{ secrets.COVERALLS_REPO_TOKEN }} + echo ::set-env name=CI_PYTHON_VERSION::$CI_PYTHON_VERSION + echo ::set-env name=CI_PACKAGE::$CI_PACKAGE + echo ::set-env name=CI_SHA::$CI_SHA + echo ::set-env name=CI_SLACK_WEBHOOK::$CI_SLACK_WEBHOOK + echo ::set-env name=CI_SLACK_SUCCESS_NOTIFICATION::$CI_SLACK_SUCCESS_NOTIFICATION + echo ::set-env name=CI_SLACK_FAILURE_NOTIFICATION::$CI_SLACK_FAILURE_NOTIFICATION + echo ::set-env name=COVERALLS_REPO_TOKEN::$COVERALLS_REPO_TOKEN + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v1 + with: + python-version: ${{ matrix.python-version }} + - name: Install Poetry + run: | + curl -L https://raw.githubusercontent.com/sdispater/poetry/master/get-poetry.py -o get-poetry.py + python get-poetry.py --preview + PATH=$HOME/.poetry/bin:$PATH + echo ::set-env name=PATH::$PATH + - name: Install Package Dependencies + run: | + poetry install + poetry env use $CI_PYTHON_VERSION + - name: Lint with flake8 + run: | + source $(poetry env info -p)/bin/activate + flake8 $CI_PACKAGE --count --show-source --statistics + - name: Test with nosetests + run: | + source $(poetry env info -p)/bin/activate + python -W ignore -m nose --nocapture --with-doctest --doctest-options=+ELLIPSIS --with-coverage --cover-package=$CI_PACKAGE $CI_PACKAGE + - name: Upload Coverage to coveralls.io + if: matrix.python-version == '3.6' || matrix.python-version == '3.7' + run: | + source $(poetry env info -p)/bin/activate + if [ -z "$COVERALLS_REPO_TOKEN" ]; then echo \"COVERALLS_REPO_TOKEN\" secret is undefined!; else coveralls; fi + - name: Notify Slack + if: always() + run: | + if [ "${{ job.status }}" == "Success" ]; then CI_SLACK_NOTIFICATION="$CI_SLACK_SUCCESS_NOTIFICATION"; else CI_SLACK_NOTIFICATION="$CI_SLACK_FAILURE_NOTIFICATION"; fi + if [ -z "$CI_SLACK_WEBHOOK" ]; then echo \"SLACK_WEBHOOK\" secret is undefined!; else curl -k -d "$CI_SLACK_NOTIFICATION" -X POST $CI_SLACK_WEBHOOK; fi + windows-build: + name: Windows Build + strategy: + matrix: + os: [windows-2019] + python-version: [3.6] + runs-on: ${{ matrix.os }} + steps: + - uses: actions/checkout@v1 + - name: Environment Variables + run: | + set CI_PYTHON_VERSION=${{ matrix.python-version }} + set CI_PACKAGE=colour_datasets + set CI_SHA=${{ github.sha }} + set CI_SLACK_WEBHOOK=${{ secrets.SLACK_WEBHOOK }} + set CI_SLACK_SUCCESS_NOTIFICATION="payload={\"attachments\": [{\"color\": \"#4CAF50\", \"author_name\": \"Python ${{ matrix.python-version }} build on ${{ matrix.os }}\", \"text\": \"Build for commit *"%CI_SHA:~0,7%"* succeeded!\", \"title\": \"${{ github.repository }}@${{ github.ref }}\", \"title_link\": \"https://github.com/${{ github.repository }}/commit/${{ github.sha }}/checks\", \"footer\": \"Triggered by ${{ github.actor }}\"}], \"username\":\"Github Actions @ ${{ github.repository }}\", \"channel\":\"#continuous-integration\", \"icon_url\":\"https://github.githubassets.com/images/modules/logos_page/GitHub-Mark.png\"}" + set CI_SLACK_FAILURE_NOTIFICATION=%CI_SLACK_SUCCESS_NOTIFICATION:4CAF50=F44336% + set CI_SLACK_FAILURE_NOTIFICATION=%CI_SLACK_FAILURE_NOTIFICATION:succeeded=failed% + set COVERALLS_REPO_TOKEN=${{ secrets.COVERALLS_REPO_TOKEN }} + echo ::set-env name=CI_PYTHON_VERSION::%CI_PYTHON_VERSION% + echo ::set-env name=CI_PACKAGE::%CI_PACKAGE% + echo ::set-env name=CI_SHA::%CI_SHA% + echo ::set-env name=CI_SLACK_WEBHOOK::%CI_SLACK_WEBHOOK% + echo ::set-env name=CI_SLACK_SUCCESS_NOTIFICATION::%CI_SLACK_SUCCESS_NOTIFICATION% + echo ::set-env name=CI_SLACK_FAILURE_NOTIFICATION::%CI_SLACK_FAILURE_NOTIFICATION% + echo ::set-env name=COVERALLS_REPO_TOKEN::%COVERALLS_REPO_TOKEN% + shell: cmd + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v1 + with: + python-version: ${{ matrix.python-version }} + - name: Install Poetry + run: | + curl -L https://raw.githubusercontent.com/sdispater/poetry/master/get-poetry.py -o get-poetry.py + python get-poetry.py --preview + set PATH=%USERPROFILE%\.poetry\bin;%PATH% + echo ::set-env name=PATH::%PATH% + shell: cmd + - name: Install Package Dependencies + run: | + call poetry install + FOR /F %%a IN ('poetry env info -p') DO SET CI_VIRTUAL_ENVIRONMENT=%%a + echo ::set-env name=CI_VIRTUAL_ENVIRONMENT::%CI_VIRTUAL_ENVIRONMENT% + shell: cmd + - name: Lint with flake8 + run: | + call %CI_VIRTUAL_ENVIRONMENT%\scripts\activate + flake8 %CI_PACKAGE% --count --show-source --statistics + shell: cmd + - name: Test with nosetests + run: | + call %CI_VIRTUAL_ENVIRONMENT%\scripts\activate + python -W ignore -m nose --nocapture --with-doctest --doctest-options=+ELLIPSIS --with-coverage --cover-package=%CI_PACKAGE% %CI_PACKAGE% + shell: cmd + - name: Upload Coverage to coveralls.io + if: matrix.python-version == '3.6' || matrix.python-version == '3.7' + run: | + call %CI_VIRTUAL_ENVIRONMENT%\scripts\activate + IF "%COVERALLS_REPO_TOKEN%"=="" (echo "COVERALLS_REPO_TOKEN" secret is undefined!) ELSE (coveralls) + shell: cmd + - name: Notify Slack + if: always() + run: | + IF "${{ job.status }}"=="Success" (set CI_SLACK_NOTIFICATION=%CI_SLACK_SUCCESS_NOTIFICATION%) ELSE (set CI_SLACK_NOTIFICATION=%CI_SLACK_FAILURE_NOTIFICATION%) + IF "%CI_SLACK_WEBHOOK%"=="" (echo "SLACK_WEBHOOK" secret is undefined!) ELSE (curl -k -d %CI_SLACK_NOTIFICATION% -X POST %CI_SLACK_WEBHOOK%) + shell: cmd diff --git a/.gitignore b/.gitignore index 04236b6..d1f97b4 100644 --- a/.gitignore +++ b/.gitignore @@ -8,5 +8,7 @@ __pycache__ build dist docs/_build +docs/generated references zenodo +poetry.lock diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 0000000..95ecce1 --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,10 @@ +repos: +- repo: https://gitlab.com/pycqa/flake8 + rev: 3.7.8 + hooks: + - id: flake8 + exclude: examples +- repo: https://github.com/pre-commit/mirrors-yapf + rev: v0.23.0 + hooks: + - id: yapf diff --git a/.readthedocs.yml b/.readthedocs.yml new file mode 100644 index 0000000..bbb41c1 --- /dev/null +++ b/.readthedocs.yml @@ -0,0 +1,8 @@ +build: + image: latest + +python: + version: 3.6 + pip_install: true + extra_requirements: + - read-the-docs diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index e65f980..0000000 --- a/.travis.yml +++ /dev/null @@ -1,49 +0,0 @@ -sudo: true -language: python - -matrix: - fast_finish: true - include: - - python: 3.6 - env: - - PYTHON_VERSION="3.6" - - python: 2.7 - env: - - PYTHON_VERSION="2.7" - -notifications: - slack: colour-science:Y6lPPcN7y53Js94geqUpqsAP - -addons: - apt: - sources: - - ubuntu-toolchain-r-test - packages: - - libboost-all-dev - - libopenexr-dev - - libilmbase-dev - -before_install: - - wget http://repo.continuum.io/miniconda/Miniconda-latest-Linux-x86_64.sh -O miniconda.sh - - chmod +x miniconda.sh - - ./miniconda.sh -b -p /home/travis/miniconda - - export PATH=/home/travis/miniconda/bin:$PATH - - conda update --yes --quiet conda - - "export DISPLAY=:99.0" - - "sh -e /etc/init.d/xvfb start" - - PACKAGES="python=${PYTHON_VERSION}" - - PACKAGES="${PACKAGES} numpy"; if [ ${NUMPY_VERSION} ]; then PACKAGES="${PACKAGES}=${NUMPY_VERSION}"; fi - - PACKAGES="${PACKAGES} scipy"; if [ ${SCIPY_VERSION} ]; then PACKAGES="${PACKAGES}=${SCIPY_VERSION}"; fi - - cd /home/travis/build/colour-science/colour-datasets - -install: - - conda create --yes --quiet -n colour-datasets-test ${PACKAGES} pip setuptools nose - - source activate colour-datasets-test - - pip install colour-science coverage coveralls flake8 mock==1.0.1 tqdm - -script: - - flake8 colour_datasets - - nosetests --nocapture --with-doctest --doctest-options=+ELLIPSIS,+NORMALIZE_WHITESPACE --with-coverage --cover-package=colour_datasets colour_datasets - -after_success: - - coveralls diff --git a/BIBLIOGRAPHY.bib b/BIBLIOGRAPHY.bib index fa68485..4168c74 100644 --- a/BIBLIOGRAPHY.bib +++ b/BIBLIOGRAPHY.bib @@ -1,3 +1,124 @@ +@phdthesis{Asano2015, + author = {Asano, Yuta}, + school = {R.I.T.}, + title = {{Individual Colorimetric Observers for Personalized + Color Imaging}}, + year = 2015, +} +@article{Breneman1987b, + abstract = {While each of his or her two eyes was independently + adapted to a different illuminant in viewing a complex visual + field, each of a number of observers matched a series of test + colors seen by one eye with a juxtaposed variable stimulus seen by + the other eye. The 2 degrees test and matching stimuli were + located centrally in the complex adapting field, which subtended + an angle of 31 degrees X 24 degrees. In making the matches, the + observer viewed the test and matching stimuli for a series of + brief intervals (approximately 1 sec) while viewing the complex + adapting field with normal eye movements. Nine experiments were + performed with different pairs of illuminants and different + illuminances ranging from that of an average living room to that + of a scene illuminated with hazy sunlight. In three other + experiments each of the observer's two eyes was adapted to a + different illuminance of D55. The amount of adaptation was more + nearly complete at high levels of illuminance than at low levels, + and the proportional amount of adaptation was less for the "blue" + receptors. When adaptation coefficients were determined from the + actual adaptation differences (e.g., from corresponding + tristimulus values for matching neutrals) rather than from the + adapting illuminants, a linear von Kries transformation based on + experimentally determined visual primaries gave corresponding + chromaticities that were in good agreement with the results + obtained in each of the chromatic-adaptation experiments, except + at the lowest illuminances. The results of the experiments in + which each eye was adapted to different levels of the same + illuminant indicated again that adaptation to the different levels + was incomplete, the proportional amount of adaptation being less + at low illuminances and for the "blue" receptors. This caused a + change in chromatic adaptation with the level of illuminance even + when the chromaticities of the adapting lights were equal. The + results of these experiments also indicated that higher purities + are needed in order to produce the same absolute color appearances + at low levels of illuminance.}, + author = {Breneman, Edwin J.}, + doi = {10.1364/JOSAA.4.001115}, + issn = {1084-7529}, + journal = {Journal of the Optical Society of America A}, + month = jun, + number = 6, + pages = 1115, + pmid = 3598755, + title = {{Corresponding chromaticities for different states + of adaptation to complex visual fields}}, + url = {https://www.osapublishing.org/abstract.cfm?URI=josaa-4-6-1115 + http://www.opticsinfobase.org/josaa/fulltext.cfm?uri=josaa-4-6-1115\&id=2783}, + volume = 4, + year = 1987, +} +@misc{Dyer2017, + author = {Dyer, Scott and Forsythe, Alexander and Irons, + Jonathon and Mansencal, Thomas and Zhu, Miaoqi}, + title = {{RAW to ACES Utility Data}}, + year = 2017, +} +@inproceedings{Ebner1998, + author = {Ebner, Fritz and Fairchild, Mark D.}, + booktitle = {Proc. SPIE 3300, Color Imaging: Device-Independent + Color, Color Hardcopy, and Graphic Arts III, (2 January 1998)}, + doi = {10.1117/12.298269}, + editor = {Beretta, Giordano B. and Eschbach, Reiner}, + month = jan, + pages = {107--117}, + title = {{Finding constant hue surfaces in color space}}, + url = {http://proceedings.spiedigitallibrary.org/proceeding.aspx?articleid=936964}, + year = 1998, +} +@misc{Haanpaloa, + author = {Haanpalo, Jouni and {University of Kuopio}}, + doi = {10.5281/zenodo.3269922}, + title = {{Paper Spectra}}, + url = {http://www.uef.fi/web/spectral/paper-spectra}, +} +@misc{Haanpalo, + author = {Haanpalo, Jouni and {University of Kuopio}}, + doi = {10.5281/zenodo.3269916}, + title = {{Munsell Colors Glossy (Spectrofotometer Measured)}}, + url = {http://www.uef.fi/web/spectral/munsell-colors-glossy-spectrofotometer-measured}, +} +@misc{Hauta-Kasaria, + author = {Hauta-Kasari, Markku and {University of Kuopio}}, + doi = {10.5281/zenodo.3269914}, + title = {{Munsell Colors Matt (AOTF Measured)}}, + url = {http://www.uef.fi/web/spectral/munsell-colors-matt-aotf-measured-}, +} +@misc{Hauta-Kasari, + author = {Hauta-Kasari, Markku and {University of Kuopio}}, + doi = {10.5281/zenodo.3269912}, + title = {{Munsell Colors Matt (Spectrofotometer Measured)}}, + url = {http://www.uef.fi/web/spectral/munsell-colors-matt-spectrofotometer-measured}, +} +@misc{Hiltunen, + author = {Hiltunen, Jouni and {University of Kuopio}}, + doi = {10.5281/zenodo.3269924}, + title = {{Lumber Spectra}}, + url = {http://www.uef.fi/web/spectral/lumber-spectra}, +} +@article{Hung1995, + author = {Hung, Po-Chieh and Berns, Roy S.}, + doi = {10.1002/col.5080200506}, + issn = 03612317, + journal = {Color Research \& Application}, + keywords = {color appearance spaces,experiments to evaluate + color space hue linearity,perceived hue}, + month = oct, + number = 5, + pages = {285--295}, + title = {{Determination of constant Hue Loci for a CRT gamut + and their predictions using color appearance spaces}}, + url = {http://doi.wiley.com/10.1002/col.5080200506}, + volume = 20, + year = 1995, +} @inproceedings{Jiang2013, abstract = {Camera spectral sensitivity functions relate scene radiance with captured RGB triplets. They are important for many @@ -36,11 +157,71 @@ @misc{Labsphere2019 title = {{Labsphere SRS-99-020}}, year = 2019, } +@article{Luo1999, + abstract = {Predicting the binding mode of flexible polypeptides + to proteins is an important task that falls outside the domain of + applicability of most small molecule and protein−protein docking + tools. Here, we test the small molecule flexible ligand docking + program Glide on a set of 19 non-$\alpha$-helical peptides and + systematically improve pose prediction accuracy by enhancing Glide + sampling for flexible polypeptides. In addition, scoring of the + poses was improved by post-processing with physics-based implicit + solvent MM- GBSA calculations. Using the best RMSD among the top + 10 scoring poses as a metric, the success rate (RMSD ≤ 2.0 {\AA} + for the interface backbone atoms) increased from 21% with default + Glide SP settings to 58% with the enhanced peptide sampling and + scoring protocol in the case of redocking to the native protein + structure. This approaches the accuracy of the recently developed + Rosetta FlexPepDock method (63% success for these 19 peptides) + while being over 100 times faster. Cross-docking was performed for + a subset of cases where an unbound receptor structure was + available, and in that case, 40% of peptides were docked + successfully. We analyze the results and find that the optimized + polypeptide protocol is most accurate for extended peptides of + limited size and number of formal charges, defining a domain of + applicability for this approach.}, + author = {Luo, M. Ronnier and Rhodes, Peter A.}, + doi = {10.1002/(SICI)1520-6378(199908)24:4<295::AID-COL10>3.0.CO;2-K}, + issn = {0361-2317}, + journal = {Color Research \& Application}, + month = aug, + number = 4, + pages = {295--296}, + title = {{Corresponding-colour datasets}}, + url = {http://doi.wiley.com/10.1002/%28SICI%291520-6378%28199908%2924%3A4%3C295%3A%3AAID-COL10%3E3.0.CO%3B2-K}, + volume = 24, + year = 1999, +} +@misc{Marszalec, + author = {Marszalec, Elzbieta and {University of Kuopio}}, + doi = {10.5281/zenodo.3269926}, + title = {{Agfa IT8.7/2 Set}}, + url = {http://www.uef.fi/web/spectral/agfa-it8.7/2-set}, +} +@misc{OpenpyxlDevelopers2019, + author = {{Openpyxl Developers}}, + title = {openpyxl}, + url = {https://bitbucket.org/openpyxl/openpyxl/}, + year = 2019, +} +@misc{Orava, + author = {Orava, Joni and {University of Kuopio}}, + doi = {10.5281/zenodo.3269918}, + title = {{Munsell Colors Glossy (All) (Spectrofotometer + Measured)}}, + url = {http://www.uef.fi/web/spectral/munsell-colors-glossy-all-spectrofotometer-measured}, +} +@misc{Silvennoinen, + author = {Silvennoinen, Raimo and {University of Kuopio}}, + doi = {10.5281/zenodo.3269920}, + title = {{Forest Colors}}, + url = {http://www.uef.fi/web/spectral/forest-colors}, +} @misc{X-Rite2016, author = {X-Rite}, title = {{New Color Specifications for ColorChecker SG and Classic Charts}}, url = {https://xritephoto.com/ph_product_overview.aspx?ID=938\&Action=Support\&SupportID=5884}, - urldate = {2019/06/14}, + urldate = {2019-06-14}, year = 2016, } diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 0000000..20c11a6 --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1,51 @@ +# Code of Conduct + +## Our Pledge + +In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, sex characteristics, gender identity and expression, level of experience, education, socio-economic status, nationality, personal appearance, race, religion, or sexual identity and orientation. + +## Our Standards + +Examples of behavior that contributes to creating a positive environment include: + +* Using welcoming and inclusive language +* Being respectful of differing viewpoints and experiences +* Gracefully accepting constructive criticism +* Focusing on what is best for the community +* Showing empathy towards other community members + +Examples of unacceptable behavior by participants include: + +* The use of sexualized language or imagery and unwelcome sexual attention or advances +* Trolling, insulting/derogatory comments, and personal or political attacks +* Public or private harassment +* Publishing others’ private information, such as a physical or electronic address, without explicit permission +* Other conduct which could reasonably be considered inappropriate in a professional setting + +## Our Responsibilities + + +Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior. + +Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. + +## Scope + +This Code of Conduct applies within all project spaces, and it also applies when an individual is representing the project or its community in public spaces. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers. + +## Enforcement + + +Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting Thomas Mansencal and Michael Mauderer via email at thomas.mansencal@gmail.com and michael@mauderer.me respectively. All complaints will be reviewed and investigated and will result in a response that is deemed necessary and appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately. + +Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project’s leadership. + +## Attribution + +This Code of Conduct is adapted from the Contributor Covenant, version 1.4, available at [https://www.contributor-covenant.org/version/1/4/code-of-conduct.html][homepage]. + +For answers to common questions about this code of conduct, see [https://www.contributor-covenant.org/faq][faq]. + + +[homepage]: https://www.contributor-covenant.org/version/1/4/code-of-conduct.html +[faq]: https://www.contributor-covenant.org/faq \ No newline at end of file diff --git a/CONTRIBUTORS.rst b/CONTRIBUTORS.rst index 7a14faa..fab8f02 100644 --- a/CONTRIBUTORS.rst +++ b/CONTRIBUTORS.rst @@ -12,6 +12,6 @@ About ----- | **Colour - Datasets** by Colour Developers -| Copyright © 2019 – Colour Developers – `colour-science@googlegroups.com `_ +| Copyright © 2019 – Colour Developers – `colour-science@googlegroups.com `__ | This software is released under terms of New BSD License: https://opensource.org/licenses/BSD-3-Clause -| `https://github.com/colour-science/colour-datasets `_ +| `https://github.com/colour-science/colour-datasets `__ diff --git a/LICENSE b/LICENSE index 1b9e425..e4f528f 100644 --- a/LICENSE +++ b/LICENSE @@ -21,4 +21,7 @@ DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \ No newline at end of file +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +Copyright for portions of project openpyxl are held by Openpyxl Developers, +2010 as part of project openpyxl distributed under the MIT Licence. diff --git a/README.rst b/README.rst index c596d44..ed6619d 100644 --- a/README.rst +++ b/README.rst @@ -3,10 +3,10 @@ Colour - Datasets .. start-badges -|travis| |coveralls| |codacy| |version| +|actions| |coveralls| |codacy| |version| -.. |travis| image:: https://img.shields.io/travis/colour-science/colour-datasets/develop.svg?style=flat-square - :target: https://travis-ci.org/colour-science/colour-datasets +.. |actions| image:: https://github.com/colour-science/colour-datasets/workflows/Continuous%20Integration/badge.svg + :target: https://github.com/colour-science/colour-datasets/actions :alt: Develop Build Status .. |coveralls| image:: http://img.shields.io/coveralls/colour-science/colour-datasets/develop.svg?style=flat-square :target: https://coveralls.io/r/colour-science/colour-datasets @@ -15,20 +15,20 @@ Colour - Datasets :target: https://www.codacy.com/app/colour-science/colour-datasets :alt: Code Grade .. |version| image:: https://img.shields.io/pypi/v/colour-datasets.svg?style=flat-square - :target: https://pypi.python.org/pypi/colour-datasets + :target: https://pypi.org/project/colour-datasets :alt: Package Version .. end-badges Colour science datasets for use with -`Colour `_ or any Python package -manipulating colours. The datasets are hosted in `Zenodo `_ +`Colour `__ or any Python package +manipulating colours. The datasets are hosted in `Zenodo `__ under the -`Colour Science - Datasets `_ +`Colour Science - Datasets `__ community. It is open source and freely available under the -`New BSD License `_ terms. +`New BSD License `__ terms. .. contents:: **Table of Contents** :backlinks: none @@ -39,6 +39,35 @@ It is open source and freely available under the Features -------- +**Colour - Datasets** was created to overcome issues encountered frequently +when trying to access or use colour science datasets: + +- No straightforward ingestion path for dataset content. +- No simple loading mechanism for dataset content. +- Unavailability of the dataset, e.g. download url is down, dataset + content is passed directly from hand to hand. +- No information regarding the definitive origination of the dataset. + +**Colour - Datasets** offers all the above: it allows users to ingest and load +colour science datasets with a single function call. The datasets information +is hosted on `Zenodo `__ +where the record for a dataset typically contain: + +- An *urls.txt* file describing the urls to source the dataset files from. +- A copy of those files in the eventuality where the source files are not + available or the content has changed without notice. +- Information about the authors, content and licensing. + +When no explicit licensing information is available, the dataset adopts the +**Other (Not Open)** licensing scheme, implying that assessing usage conditions +is at the sole discretion of the users. + +Online +------ + +**Colour - Datasets** can be used online with +`Google Colab `__. + Installation ------------ @@ -47,28 +76,21 @@ Primary Dependencies **Colour - Datasets** requires various dependencies in order to run: -- `Python 2.7 `_ or - `Python 3.7 `_ -- `Colour Science `_ -- `tqdm `_ +- `Python >=2.7 `__ or + `Python >=3.5 `__ +- `Colour Science `__ +- `tqdm `__ +- `xlrd `__ Pypi ^^^^ Once the dependencies satisfied, **Colour - Datasets** can be installed from -the `Python Package Index `_ by +the `Python Package Index `__ by issuing this command in a shell:: pip install colour-datasets -The tests suite dependencies are installed as follows:: - - pip install 'colour-datasets[tests]' - -The documentation building dependencies are installed as follows:: - - pip install 'colour-datasets[docs]' - The overall development dependencies are installed as follows:: pip install 'colour-datasets[development]' @@ -79,33 +101,107 @@ Usage API ^^^ -The main reference for `Colour - Datasets `_ -is the `Colour - Datasets Manual `_. +The main reference for `Colour - Datasets `__ +is the `Colour - Datasets Manual `__. Examples ^^^^^^^^ -Various usage examples are available from the -`examples directory `_. +Most of the objects are available from the ``colour_datasets`` namespace: + +.. code-block:: python + + >>> import colour_datasets + +The available datasets are listed with the ``colour_datasets.datasets()`` +definition: + +.. code-block:: python + + >>> print(colour_datasets.datasets()) + +:: + + colour-science-datasets + ======================= + + Datasets : 16 + Synced : 1 + URL : https://zenodo.org/communities/colour-science-datasets/ + + Datasets + -------- + + [ ] 3269926 : Agfa IT8.7/2 Set + [ ] 3245883 : Camera Spectral Sensitivity Database + [ ] 3367463 : Constant Hue Loci Data + [ ] 3362536 : Constant Perceived-Hue Data + [ ] 3270903 : Corresponding-Colour Datasets + [ ] 3269920 : Forest Colors + [x] 3245875 : Labsphere SRS-99-020 + [ ] 3269924 : Lumber Spectra + [ ] 3269918 : Munsell Colors Glossy (All) (Spectrofotometer Measured) + [ ] 3269916 : Munsell Colors Glossy (Spectrofotometer Measured) + [ ] 3269914 : Munsell Colors Matt (AOTF Measured) + [ ] 3269912 : Munsell Colors Matt (Spectrofotometer Measured) + [ ] 3245895 : New Color Specifications for ColorChecker SG and Classic Charts + [ ] 3252742 : Observer Function Database + [ ] 3269922 : Paper Spectra + [ ] 3372171 : RAW to ACES Utility Data + +A ticked checkbox means that the particular dataset has been synced locally. +A dataset is loaded by using its unique number: *3245895*: + +.. code-block:: python + + >>> print(colour_datasets.load('3245895').keys()) + +:: + + Pulling "New Color Specifications for ColorChecker SG and Classic Charts" record content... + Downloading "urls.txt" file: 8.19kB [00:01, 5.05kB/s] + Downloading "ColorChecker24_After_Nov2014.zip" file: 8.19kB [00:01, 6.52kB/s] + Downloading "ColorChecker24_Before_Nov2014.zip" file: 8.19kB [00:01, 7.66kB/s] + Downloading "ColorCheckerSG_After_Nov2014.zip" file: 8.19kB [00:01, 7.62kB/s] + Downloading "ColorCheckerSG_Before_Nov2014.zip" file: 8.19kB [00:00, 9.39kB/s] + Unpacking "/Users/kelsolaar/.colour-science/colour-datasets/3245895/dataset/ColorCheckerSG_Before_Nov2014.zip" archive... + Unpacking "/Users/kelsolaar/.colour-science/colour-datasets/3245895/dataset/ColorCheckerSG_After_Nov2014.zip" archive... + Unpacking "/Users/kelsolaar/.colour-science/colour-datasets/3245895/dataset/ColorChecker24_After_Nov2014.zip" archive... + Unpacking "/Users/kelsolaar/.colour-science/colour-datasets/3245895/dataset/ColorChecker24_Before_Nov2014.zip" archive... + odict_keys(['ColorChecker24 - After November 2014', 'ColorChecker24 - Before November 2014', 'ColorCheckerSG - After November 2014', 'ColorCheckerSG - Before November 2014']) + +Alternatively, a dataset can be loaded by using its full title: +*New Color Specifications for ColorChecker SG and Classic Charts* + +.. code-block:: python + + >>> print(colour_datasets.load('3245895').keys()) + odict_keys(['ColorChecker24 - After November 2014', 'ColorChecker24 - Before November 2014', 'ColorCheckerSG - After November 2014', 'ColorCheckerSG - Before November 2014']) Contributing ------------ -If you would like to contribute to `Colour - Datasets `_, -please refer to the following `Contributing `_ -guide for `Colour `_. +If you would like to contribute to `Colour - Datasets `__, +please refer to the following `Contributing `__ +guide for `Colour `__. Bibliography ------------ The bibliography is available in the repository in -`BibTeX `_ +`BibTeX `__ format. +Code of Conduct +--------------- + +The *Code of Conduct*, adapted from the `Contributor Covenant 1.4 `__, +is available on the `Code of Conduct `__ page. + About ----- | **Colour - Datasets** by Colour Developers -| Copyright © 2019 – Colour Developers – `colour-science@googlegroups.com `_ +| Copyright © 2019 – Colour Developers – `colour-science@googlegroups.com `__ | This software is released under terms of New BSD License: https://opensource.org/licenses/BSD-3-Clause -| `https://github.com/colour-science/colour-datasets `_ +| `https://github.com/colour-science/colour-datasets `__ diff --git a/TODO.rst b/TODO.rst index 7db2a4b..6e2d986 100644 --- a/TODO.rst +++ b/TODO.rst @@ -10,6 +10,6 @@ About ----- | **Colour - Datasets** by Colour Developers -| Copyright © 2019 – Colour Developers – `colour-science@googlegroups.com `_ +| Copyright © 2019 – Colour Developers – `colour-science@googlegroups.com `__ | This software is released under terms of New BSD License: https://opensource.org/licenses/BSD-3-Clause -| `https://github.com/colour-science/colour-datasets `_ +| `https://github.com/colour-science/colour-datasets `__ diff --git a/colour_datasets/__init__.py b/colour_datasets/__init__.py index 29f280a..5c3e41b 100644 --- a/colour_datasets/__init__.py +++ b/colour_datasets/__init__.py @@ -24,7 +24,9 @@ import colour -from .records import datasets, sandbox +from .records import Configuration +from .records import Community, Record, datasets +from .records import sandbox from .loaders import load __author__ = 'Colour Developers' @@ -34,7 +36,9 @@ __email__ = 'colour-science@googlegroups.com' __status__ = 'Production' -__all__ = ['datasets', 'sandbox'] +__all__ = ['Configuration'] +__all__ += ['Community', 'Record', 'datasets'] +__all__ += ['sandbox'] __all__ += ['load'] __application_name__ = 'Colour - Datasets' diff --git a/colour_datasets/examples/examples_load.py b/colour_datasets/examples/examples_load.py index fba326e..dfaf36d 100644 --- a/colour_datasets/examples/examples_load.py +++ b/colour_datasets/examples/examples_load.py @@ -12,7 +12,7 @@ 'has been synced locally.') print(colour_datasets.datasets()) -message_box('A dataset is loaded by using its unique number: "295257"') +message_box('A dataset is loaded by using its unique number: "3245895"') print(colour_datasets.load('3245895')) message_box('Or alternatively its full title: "New Color Specifications ' diff --git a/colour_datasets/loaders/__init__.py b/colour_datasets/loaders/__init__.py index df32df6..dc7e17c 100644 --- a/colour_datasets/loaders/__init__.py +++ b/colour_datasets/loaders/__init__.py @@ -2,23 +2,42 @@ from __future__ import absolute_import +import six +import sys + from colour.utilities import CaseInsensitiveMapping, warning from colour_datasets.records import datasets from .abstract import AbstractDatasetLoader +from .asano2015 import Asano2015DatasetLoader, build_Asano2015 +from .dyer2017 import Dyer2017DatasetLoader, build_Dyer2017 +from .ebner1998 import Ebner1998DatasetLoader, build_Ebner1998 +from .hung1995 import Hung1995DatasetLoader, build_Hung1995 from .jiang2013 import Jiang2013DatasetLoader, build_Jiang2013 from .labsphere2019 import Labsphere2019DatasetLoader, build_Labsphere2019 +from .luo1999 import Luo1999DatasetLoader, build_Luo1999 from .xrite2016 import XRite2016DatasetLoader, build_XRite2016 __all__ = ['AbstractDatasetLoader'] +__all__ += ['Asano2015DatasetLoader', 'build_Asano2015'] +__all__ += ['Dyer2017DatasetLoader', 'build_Dyer2017'] +__all__ += ['Ebner1998DatasetLoader', 'build_Ebner1998'] +__all__ += ['Hung1995DatasetLoader', 'build_Hung1995'] +__all__ += ['Jiang2013DatasetLoader', 'build_Jiang2013'] __all__ += ['Jiang2013DatasetLoader', 'build_Jiang2013'] __all__ += ['Labsphere2019DatasetLoader', 'build_Labsphere2019'] +__all__ += ['Luo1999DatasetLoader', 'build_Luo1999'] __all__ += ['XRite2016DatasetLoader', 'build_XRite2016'] DATASET_LOADERS = CaseInsensitiveMapping({ + Asano2015DatasetLoader.ID: build_Asano2015, + Dyer2017DatasetLoader.ID: build_Dyer2017, + Ebner1998DatasetLoader.ID: build_Ebner1998, + Hung1995DatasetLoader.ID: build_Hung1995, Jiang2013DatasetLoader.ID: build_Jiang2013, Labsphere2019DatasetLoader.ID: build_Labsphere2019, + Luo1999DatasetLoader.ID: build_Luo1999, XRite2016DatasetLoader.ID: build_XRite2016, }) DATASET_LOADERS.__doc__ = """ @@ -27,6 +46,23 @@ DATASET_LOADERS : CaseInsensitiveMapping """ +from .kuopio import KUOPIO_UNIVERSITY_DATASET_LOADERS # noqa + +DATASET_LOADERS.update(KUOPIO_UNIVERSITY_DATASET_LOADERS) + +from . import kuopio # noqa + +_module = sys.modules['colour_datasets.loaders'] + +for _export in kuopio.__all__: + if _export.endswith('DatasetLoader') or _export.startswith('build'): + + setattr(_module, _export, getattr(kuopio, _export)) + + __all__ += [_export] + +del _module, _export + _HAS_TITLE_KEYS = False """ Whether the :attr:`colour_datasets.loaders.DATASET_LOADERS` attribute has @@ -45,7 +81,7 @@ def load(dataset): Parameters ---------- - dataset : unicode + dataset : unicode or int Dataset id, i.e. the *Zenodo* record number or title. Returns @@ -65,14 +101,18 @@ def load(dataset): if not _HAS_TITLE_KEYS: for key in list(DATASET_LOADERS.keys())[:]: - title = datasets()[key].title + dataset_loader = datasets().get(key) + if not dataset_loader: + continue + + title = dataset_loader.title if title in DATASET_LOADERS: warning('"{0}" key is already defined in the dataset loaders!'. format(title)) DATASET_LOADERS[title] = DATASET_LOADERS[key] _HAS_TITLE_KEYS = True - return DATASET_LOADERS[dataset]().data + return DATASET_LOADERS[six.text_type(dataset)]().content __all__ += ['DATASET_LOADERS', 'load'] diff --git a/colour_datasets/loaders/abstract.py b/colour_datasets/loaders/abstract.py index 3867a33..1d13aa3 100644 --- a/colour_datasets/loaders/abstract.py +++ b/colour_datasets/loaders/abstract.py @@ -41,7 +41,7 @@ class AbstractDatasetLoader: ID record id - data + content Methods ------- @@ -63,7 +63,7 @@ class AbstractDatasetLoader: def __init__(self, record): self._record = record - self._data = None + self._content = None @property def record(self): @@ -102,22 +102,22 @@ def id(self): return self.__class__.ID @property - def data(self): + def content(self): """ - Getter and setter property for the dataset data. + Getter and setter property for the dataset content. Parameters ---------- value : object - Value to set the dataset data with. + Value to set the dataset content with. Returns ------- unicode - Dataset data. + Dataset content. """ - return self._data + return self._content @abstractmethod def load(self): diff --git a/colour_datasets/loaders/asano2015.py b/colour_datasets/loaders/asano2015.py new file mode 100644 index 0000000..1b61ad3 --- /dev/null +++ b/colour_datasets/loaders/asano2015.py @@ -0,0 +1,310 @@ +# -*- coding: utf-8 -*- +""" +Observer Function Database - Asano (2015) +========================================= + +Defines the objects implementing support for *Asano (2015)* +*Observer Function Database* dataset loading: + +- :class:`colour_datasets.loaders.Asano2015DatasetLoader` +- :func:`colour_datasets.loaders.build_Asano2015` + +References +---------- +- :cite:`Asano2015` : Asano, Y. (2015). Individual Colorimetric Observers for + Personalized Color Imaging. R.I.T. +""" + +from __future__ import division, unicode_literals + +import numpy as np +import os +import xlrd +from collections import OrderedDict, namedtuple + +from colour import SpectralShape +from colour.colorimetry import (XYZ_ColourMatchingFunctions, + LMS_ConeFundamentals) +from colour.utilities import as_float_array, tstack + +from colour_datasets.records import datasets +from colour_datasets.loaders import AbstractDatasetLoader +from colour_datasets.utilities import cell_range_values, index_to_column + +__author__ = 'Colour Developers' +__copyright__ = 'Copyright (C) 2019 - Colour Developers' +__license__ = 'New BSD License - https://opensource.org/licenses/BSD-3-Clause' +__maintainer__ = 'Colour Developers' +__email__ = 'colour-science@googlegroups.com' +__status__ = 'Production' + +__all__ = [ + 'Asano2015_Specification', 'Asano2015DatasetLoader', 'build_Asano2015' +] + + +class Asano2015_Specification( + namedtuple( + 'Asano2015_Specification', + ('XYZ_2', 'XYZ_10', 'LMS_2', 'LMS_10', 'parameters', 'others'))): + """ + Defines the *Asano (2015)* specification for an observer. + + Parameters + ---------- + XYZ_2 : XYZ_ColourMatchingFunctions + *CIE XYZ* 2 degree colour matching functions. + XYZ_10 : XYZ_ColourMatchingFunctions + *CIE XYZ* 10 degree colour matching functions. + LMS_2 : LMS_ConeFundamentals + *LMS* 2 degree cone fundamentals. + LMS_10 : LMS_ConeFundamentals + *LMS* 10 degree cone fundamentals. + parameters : array_like + Observer parameters. + others : array_like + Other information. + + References + ---------- + :cite:`Asano2015` + """ + + def __new__(cls, XYZ_2, XYZ_10, LMS_2, LMS_10, parameters, others=None): + """ + Returns a new instance of the + :class:`colour_datasets.loaders.asano2015.Asano2015_Specification` + class. + """ + + return super(Asano2015_Specification, cls).__new__( + cls, XYZ_2, XYZ_10, LMS_2, LMS_10, parameters, others) + + +class Asano2015DatasetLoader(AbstractDatasetLoader): + """ + Defines the *Asano (2015)* *Observer Function Database* dataset loader. + + Attributes + ---------- + ID + + Methods + ------- + load + parse_workbook_Asano2015 + + References + ---------- + :cite:`Asano2015` + """ + + ID = '3252742' + """ + Dataset record id, i.e. the *Zenodo* record number. + + ID : unicode + """ + + def __init__(self): + super(Asano2015DatasetLoader, + self).__init__(datasets()[Asano2015DatasetLoader.ID]) + + def load(self): + """ + Syncs, parses, converts and returns the *Asano (2015)* + *Observer Function Database* dataset content. + + Returns + ------- + OrderedDict + *Asano (2015)* *Observer Function Database* dataset content. + + Examples + -------- + >>> from colour_datasets.utilities import suppress_stdout + >>> dataset = Asano2015DatasetLoader() + >>> with suppress_stdout(): + ... dataset.load() + >>> len(dataset.content.keys()) + 2 + """ + + super(Asano2015DatasetLoader, self).sync() + + self._content = OrderedDict([ + ('Categorical Observers', OrderedDict()), + ('Colour Normal Observers', OrderedDict()), + ]) + + # Categorical Observers + workbook_path = os.path.join(self.record.repository, 'dataset', + 'Data_10CatObs.xls') + + observers = (1, 10) + template = 'Asano 2015 {0} Categorical Observer No. {1} {2}' + for index, observer in self.parse_workbook_Asano2015( + workbook_path, template, observers).items(): + self._content['Categorical Observers'][index] = ( + Asano2015_Specification( + observer['XYZ_2'], + observer['XYZ_10'], + observer['LMS_2'], + observer['LMS_10'], + observer['parameters'], + )) + + # Colour Normal Observers + workbook_path = os.path.join(self.record.repository, 'dataset', + 'Data_151Obs.xls') + + observers = (1, 151) + + # Other Information + column_in, column_out = (index_to_column(observers[0] - 1), + index_to_column(observers[1])) + workbook = xlrd.open_workbook(workbook_path) + values = cell_range_values( + workbook.sheet_by_index(5), '{0}2:{1}9'.format( + column_in, column_out)) + values.extend( + cell_range_values( + workbook.sheet_by_index(5), '{0}12:{1}16'.format( + column_in, column_out))) + values = np.transpose(values) + header, values = values[0], values[1:] + + template = 'Asano 2015 {0} Colour Normal Observer No. {1} {2}' + for i, (index, observer) in enumerate( + self.parse_workbook_Asano2015(workbook_path, template, + observers).items()): + self._content['Colour Normal Observers'][index] = ( + Asano2015_Specification( + observer['XYZ_2'], + observer['XYZ_10'], + observer['LMS_2'], + observer['LMS_10'], + observer['parameters'], + OrderedDict(zip(header, values[i])), + )) + + return self._content + + @staticmethod + def parse_workbook_Asano2015(workbook, template, observers=(1, 10)): + """ + Parses given *Asano (2015)* *Observer Function Database* workbook. + + Parameters + ---------- + workbook : unicode + *Asano (2015)* *Observer Function Database* workbook path. + template : unicode + Template used to create the *CMFS* names. + observers : tuple, optional + Observers range. + + Returns + ------- + OrderedDict + *Asano (2015)* *Observer Function Database* workbook observer data. + """ + + workbook = xlrd.open_workbook(workbook) + + # "CIE XYZ" and "LMS" CMFS. + column_in, column_out = (index_to_column(observers[0] + 1), + index_to_column(observers[1] + 1)) + + shape = SpectralShape(390, 780, 5) + wavelengths = shape.range() + data = OrderedDict() + + for i, cmfs in enumerate([(XYZ_ColourMatchingFunctions, 'XYZ'), + (LMS_ConeFundamentals, 'LMS')]): + + for j, degree in enumerate([(2, '2$^\\circ$'), (10, + '10$^\\circ$')]): + + sheet = workbook.sheet_by_index(j + (i * 2)) + + x = np.transpose( + cell_range_values( + sheet, '{0}3:{1}81'.format(column_in, column_out))) + y = np.transpose( + cell_range_values( + sheet, '{0}82:{1}160'.format(column_in, column_out))) + z = np.transpose( + cell_range_values( + sheet, '{0}161:{1}239'.format(column_in, column_out))) + + for k in range(observers[1]): + observer = k + 1 + rgb = tstack([x[k], y[k], z[k]]) + if data.get(observer) is None: + data[observer] = OrderedDict() + + key = '{0}_{1}'.format(cmfs[1], degree[0]) + data[observer][key] = cmfs[0]( + rgb, + domain=wavelengths, + name=template.format(degree[0], observer, cmfs[1]), + strict_name=template.format(degree[0], observer, + cmfs[1])) + + # Parameters + column_in, column_out = (index_to_column(observers[0] - 1), + index_to_column(observers[1])) + + values = np.transpose( + cell_range_values( + workbook.sheet_by_index(4), '{0}2:{1}10'.format( + column_in, column_out))) + header, values = values[0], values[1:] + + for i in range(observers[1]): + observer = i + 1 + data[observer]['parameters'] = OrderedDict( + zip(header, as_float_array(values[i]))) + + return data + + +_ASANO2015_DATASET_LOADER = None +""" +Singleton instance of the *Asano (2015)* *Observer Function Database* dataset +loader. + +_ASANO2015_DATASET_LOADER : Asano2015DatasetLoader +""" + + +def build_Asano2015(load=True): + """ + Singleton factory that the builds *Asano (2015)* + *Observer Function Database* dataset loader. + + Parameters + ---------- + load : bool, optional + Whether to load the dataset upon instantiation. + + Returns + ------- + Asano2015DatasetLoader + Singleton instance of the *Asano (2015)* + *Observer Function Database* dataset loader. + + References + ---------- + :cite:`Asano2015` + """ + + global _ASANO2015_DATASET_LOADER + + if _ASANO2015_DATASET_LOADER is None: + _ASANO2015_DATASET_LOADER = Asano2015DatasetLoader() + if load: + _ASANO2015_DATASET_LOADER.load() + + return _ASANO2015_DATASET_LOADER diff --git a/colour_datasets/loaders/dyer2017.py b/colour_datasets/loaders/dyer2017.py new file mode 100644 index 0000000..c40618c --- /dev/null +++ b/colour_datasets/loaders/dyer2017.py @@ -0,0 +1,991 @@ +# -*- coding: utf-8 -*- +""" +RAW to ACES Utility Data - Dyer et al. (2017) +============================================= + +Defines the objects implementing support for +*Dyer, Forsythe, Irons, Mansencal and Zhu (2017)* +*RAW to ACES Utility Data* dataset loading: + +- :class:`colour_datasets.loaders.Dyer2017DatasetLoader` +- :func:`colour_datasets.loaders.build_Dyer2017` + +References +---------- +- :cite:`Dyer2017` : Dyer, S., Forsythe, A., Irons, J., Mansencal, T., & Zhu, + M. (2017). RAW to ACES Utility Data. +""" + +from __future__ import division, unicode_literals + +import json +import glob +import os +from collections import OrderedDict + +from colour import MultiSpectralDistributions, SpectralDistribution +from colour.continuous import MultiSignals, Signal +from colour.utilities import is_numeric, is_string + +from colour_datasets.records import datasets +from colour_datasets.loaders import AbstractDatasetLoader + +__author__ = 'Colour Developers' +__copyright__ = 'Copyright (C) 2019 - Colour Developers' +__license__ = 'New BSD License - https://opensource.org/licenses/BSD-3-Clause' +__maintainer__ = 'Colour Developers' +__email__ = 'colour-science@googlegroups.com' +__status__ = 'Production' + +__all__ = [ + 'AMPAS_SpectralDataHeader', 'AMPAS_SpectralDataMixin', + 'SpectralDistribution_AMPAS', 'Dyer2017DatasetLoader', 'build_Dyer2017' +] + + +class AMPAS_SpectralDataHeader(object): + """ + Defines the header object for an *A.M.P.A.S* spectral data. + + Parameters + ---------- + schema_version : unicode, optional + Version of the *A.M.P.A.S* spectral data schema. + catalog_number : unicode, optional + Manufacturer's product catalog number. + description : unicode, optional + Description of the spectral data in the spectral data JSON file. + document_creator : unicode, optional + Creator of the spectral data JSON file, which may be a + test lab, a research group, a standard body, a company or an + individual. + unique_identifier : unicode, optional + Description of the equipment used to measure the spectral data. + measurement_equipment : unicode, optional + Description of the equipment used to measure the spectral data. + laboratory : unicode, optional + Testing laboratory name that performed the spectral data measurements. + document_creation_date : unicode, optional + Spectral data JSON file creation date using the + *JSON DateTime Data Type*, *YYYY-MM-DDThh:mm:ss*. + comments : unicode, optional + Additional information relating to the tested and reported data. + license : unicode, optional + License under which the data is distributed. + + Attributes + ---------- + schema_version + catalog_number + description + document_creator + unique_identifier + measurement_equipment + laboratory + document_creation_date + comments + license + """ + + def __init__(self, + schema_version=None, + catalog_number=None, + description=None, + document_creator=None, + unique_identifier=None, + measurement_equipment=None, + laboratory=None, + document_creation_date=None, + comments=None, + license=None, + **kwargs): + + self._schema_version = None + self.schema_version = schema_version + self._catalog_number = None + self.catalog_number = catalog_number + self._description = None + self.description = description + self._document_creator = None + self.document_creator = document_creator + self._unique_identifier = None + self.unique_identifier = unique_identifier + self._measurement_equipment = None + self.measurement_equipment = measurement_equipment + self._laboratory = None + self.laboratory = laboratory + self._document_creation_date = None + self.document_creation_date = document_creation_date + self._comments = None + self.comments = comments + self._license = None + self.license = license + + # TODO: Re-instate "manufacturer", "model", "illuminant" and "type" + # attributes according to outcome of + # https://github.com/ampas/rawtoaces/issues/114. Those attributes are + # currently stored in "self._kwargs". + self._kwargs = kwargs + + @property + def schema_version(self): + """ + Getter and setter property for the schema version. + + Parameters + ---------- + value : unicode + Value to set the schema version with. + + Returns + ------- + unicode + Schema version. + """ + + return self._schema_version + + @schema_version.setter + def schema_version(self, value): + """ + Setter for the **self.schema_version** property. + """ + + if value is not None: + assert is_string(value), ( + '"{0}" attribute: "{1}" is not a "string" like object!'.format( + 'schema_version', value)) + self._schema_version = value + + @property + def catalog_number(self): + """ + Getter and setter property for the catalog number. + + Parameters + ---------- + value : unicode + Value to set the catalog number with. + + Returns + ------- + unicode + Catalog number. + """ + + return self._catalog_number + + @catalog_number.setter + def catalog_number(self, value): + """ + Setter for the **self.catalog_number** property. + """ + + if value is not None: + assert is_string(value), ( + '"{0}" attribute: "{1}" is not a "string" like object!'.format( + 'catalog_number', value)) + self._catalog_number = value + + @property + def description(self): + """ + Getter and setter property for the description. + + Parameters + ---------- + value : unicode + Value to set the description with. + + Returns + ------- + unicode + Description. + """ + + return self._description + + @description.setter + def description(self, value): + """ + Setter for the **self.description** property. + """ + + if value is not None: + assert is_string(value), ( + '"{0}" attribute: "{1}" is not a "string" like object!'.format( + 'description', value)) + self._description = value + + @property + def document_creator(self): + """ + Getter and setter property for the document creator. + + Parameters + ---------- + value : unicode + Value to set the document creator with. + + Returns + ------- + unicode + Document creator. + """ + + return self._document_creator + + @document_creator.setter + def document_creator(self, value): + """ + Setter for the **self.document_creator** property. + """ + + if value is not None: + assert is_string(value), ( + '"{0}" attribute: "{1}" is not a "string" like object!'.format( + 'document_creator', value)) + self._document_creator = value + + @property + def unique_identifier(self): + """ + Getter and setter property for the unique identifier. + + Parameters + ---------- + value : unicode + Value to set the unique identifier with. + + Returns + ------- + unicode + Unique identifier. + """ + + return self._unique_identifier + + @unique_identifier.setter + def unique_identifier(self, value): + """ + Setter for the **self.unique_identifier** property. + """ + + if value is not None: + assert is_string(value), ( + '"{0}" attribute: "{1}" is not a "string" like object!'.format( + 'unique_identifier', value)) + self._unique_identifier = value + + @property + def measurement_equipment(self): + """ + Getter and setter property for the measurement equipment. + + Parameters + ---------- + value : unicode + Value to set the measurement equipment with. + + Returns + ------- + unicode + Measurement equipment. + """ + + return self._measurement_equipment + + @measurement_equipment.setter + def measurement_equipment(self, value): + """ + Setter for the **self.measurement_equipment** property. + """ + + if value is not None: + assert is_string(value), ( + '"{0}" attribute: "{1}" is not a "string" like object!'.format( + 'measurement_equipment', value)) + self._measurement_equipment = value + + @property + def laboratory(self): + """ + Getter and setter property for the laboratory. + + Parameters + ---------- + value : unicode + Value to set the laboratory with. + + Returns + ------- + unicode + Laboratory. + """ + + return self._laboratory + + @laboratory.setter + def laboratory(self, value): + """ + Setter for the **self.measurement_equipment** property. + """ + + if value is not None: + assert is_string(value), ( + '"{0}" attribute: "{1}" is not a "string" like object!'.format( + 'laboratory', value)) + self._laboratory = value + + @property + def document_creation_date(self): + """ + Getter and setter property for the document creation date. + + Parameters + ---------- + value : unicode + Value to set the document creation date with. + + Returns + ------- + unicode + Document creation date. + """ + + return self._document_creation_date + + @document_creation_date.setter + def document_creation_date(self, value): + """ + Setter for the **self.document_creation_date** property. + """ + + if value is not None: + assert is_string(value), ( + '"{0}" attribute: "{1}" is not a "string" like object!'.format( + 'document_creation_date', value)) + self._document_creation_date = value + + @property + def comments(self): + """ + Getter and setter property for the comments. + + Parameters + ---------- + value : unicode + Value to set the comments with. + + Returns + ------- + unicode + Comments. + """ + + return self._comments + + @comments.setter + def comments(self, value): + """ + Setter for the **self.comments** property. + """ + + if value is not None: + assert is_string(value), ( + '"{0}" attribute: "{1}" is not a "string" like object!'.format( + 'comments', value)) + self._comments = value + + @property + def license(self): + """ + Getter and setter property for the license. + + Parameters + ---------- + value : unicode + Value to set the license with. + + Returns + ------- + unicode + Comments. + """ + + return self._license + + @license.setter + def license(self, value): + """ + Setter for the **self.license** property. + """ + + if value is not None: + assert is_string(value), ( + '"{0}" attribute: "{1}" is not a "string" like object!'.format( + 'license', value)) + self._license = value + + +class AMPAS_SpectralDataMixin(object): + """ + Defines a mixin for *A.M.P.A.S* spectral data. + + Parameters + ---------- + path : unicode, optional + Spectral data JSON file path. + header : AMPAS_SpectralDataHeader, optional + *A.M.P.A.S.* spectral distribution header. + units : unicode, optional + **{'flux', 'absorptance', 'transmittance', 'reflectance', 'intensity', + 'irradiance', 'radiance', 'exitance', 'R-Factor', 'T-Factor', + 'relative', 'other'}**, + Quantity of measurement for each element of the spectral data. + reflection_geometry : unicode, optional + **{'di:8', 'de:8', '8:di', '8:de', 'd:d', 'd:0', '45a:0', '45c:0', + '0:45a', '45x:0', '0:45x', 'other'}**, + Spectral reflectance factors geometric conditions. + transmission_geometry : unicode, optional + **{'0:0', 'di:0', 'de:0', '0:di', '0:de', 'd:d', 'other'}**, + Spectral transmittance factors geometric conditions. + bandwidth_FWHM : numeric, optional + Spectroradiometer full-width half-maximum bandwidth in nanometers. + bandwidth_corrected : bool, optional + Specifies if bandwidth correction has been applied to the measured + data. + + Notes + ----- + *Reflection Geometry* + + - di:8: Diffuse / eight-degree, specular component included. + - de:8: Diffuse / eight-degree, specular component excluded. + - 8:di: Eight-degree / diffuse, specular component included. + - 8:de: Eight-degree / diffuse, specular component excluded. + - d:d: Diffuse / diffuse. + - d:0: Alternative diffuse. + - 45a:0: Forty-five degree annular / normal. + - 45c:0: Forty-five degree circumferential / normal. + - 0:45a: Normal / forty-five degree annular. + - 45x:0: Forty-five degree directional / normal. + - 0:45x: Normal / forty-five degree directional. + - other: User-specified in comments. + + *Transmission Geometry* + + - 0:0: Normal / normal. + - di:0: Diffuse / normal, regular component included. + - de:0: Diffuse / normal, regular component excluded. + - 0:di: Normal / diffuse, regular component included. + - 0:de: Normal / diffuse, regular component excluded. + - d:d: Diffuse / diffuse. + - other: User-specified in comments. + + Attributes + ---------- + path + header + units + reflection_geometry + transmission_geometry + bandwidth_FWHM + bandwidth_corrected + + Methods + ------- + read + + References + ---------- + :cite:`IESComputerCommittee2014a` + """ + + def __init__(self, + path=None, + header=None, + units=None, + reflection_geometry=None, + transmission_geometry=None, + bandwidth_FWHM=None, + bandwidth_corrected=None): + super(AMPAS_SpectralDataMixin, self).__init__() + + self._path = None + self.path = path + self._header = None + self.header = (header + if header is not None else AMPAS_SpectralDataHeader()) + self._units = None + self.units = units + self._reflection_geometry = None + self.reflection_geometry = reflection_geometry + self._transmission_geometry = None + self.transmission_geometry = transmission_geometry + self._bandwidth_FWHM = None + self.bandwidth_FWHM = bandwidth_FWHM + self._bandwidth_corrected = None + self.bandwidth_corrected = bandwidth_corrected + + @property + def path(self): + """ + Getter and setter property for the path. + + Parameters + ---------- + value : unicode + Value to set the path with. + + Returns + ------- + unicode + Path. + """ + + return self._path + + @path.setter + def path(self, value): + """ + Setter for the **self.path** property. + """ + + if value is not None: + assert is_string(value), ( + '"{0}" attribute: "{1}" is not a "string" like object!'.format( + 'path', value)) + self._path = value + + @property + def header(self): + """ + Getter and setter property for the header. + + Parameters + ---------- + value : AMPAS_SpectralDataHeader + Value to set the header with. + + Returns + ------- + AMPAS_SpectralDataHeader + Header. + """ + + return self._header + + @header.setter + def header(self, value): + """ + Setter for the **self.header** property. + """ + + if value is not None: + assert isinstance(value, AMPAS_SpectralDataHeader), ( + '"{0}" attribute: "{1}" is not a "AMPAS_SpectralDataHeader" ' + 'instance!'.format('header', value)) + self._header = value + + @property + def units(self): + """ + Getter and setter property for the units. + + Parameters + ---------- + value : unicode + Value to set the units with. + + Returns + ------- + unicode + Spectral quantity. + """ + + return self._units + + @units.setter + def units(self, value): + """ + Setter for the **self.units** property. + """ + + if value is not None: + assert is_string(value), ( + '"{0}" attribute: "{1}" is not a "string" like object!'.format( + 'units', value)) + self._units = value + + @property + def reflection_geometry(self): + """ + Getter and setter property for the reflection geometry. + + Parameters + ---------- + value : unicode + Value to set the reflection geometry with. + + Returns + ------- + unicode + Reflection geometry. + """ + + return self._reflection_geometry + + @reflection_geometry.setter + def reflection_geometry(self, value): + """ + Setter for the **self.reflection_geometry** property. + """ + + if value is not None: + assert is_string(value), ( + '"{0}" attribute: "{1}" is not a "string" like object!'.format( + 'reflection_geometry', value)) + self._reflection_geometry = value + + @property + def transmission_geometry(self): + """ + Getter and setter property for the transmission geometry. + + Parameters + ---------- + value : unicode + Value to set the transmission geometry with. + + Returns + ------- + unicode + Transmission geometry. + """ + + return self._transmission_geometry + + @transmission_geometry.setter + def transmission_geometry(self, value): + """ + Setter for the **self.transmission_geometry** property. + """ + + if value is not None: + assert is_string(value), ( + '"{0}" attribute: "{1}" is not a "string" like object!'.format( + 'transmission_geometry', value)) + self._transmission_geometry = value + + @property + def bandwidth_FWHM(self): + """ + Getter and setter property for the full-width half-maximum bandwidth. + + Parameters + ---------- + value : numeric + Value to set the full-width half-maximum bandwidth with. + + Returns + ------- + numeric + Full-width half-maximum bandwidth. + """ + + return self._bandwidth_FWHM + + @bandwidth_FWHM.setter + def bandwidth_FWHM(self, value): + """ + Setter for the **self.bandwidth_FWHM** property. + """ + + if value is not None: + assert is_numeric(value), ( + '"{0}" attribute: "{1}" is not a "numeric"!'.format( + 'bandwidth_FWHM', value)) + + self._bandwidth_FWHM = value + + @property + def bandwidth_corrected(self): + """ + Getter and setter property for whether bandwidth correction has been + applied to the measured data. + + Parameters + ---------- + value : bool + Whether bandwidth correction has been applied to the measured data. + + Returns + ------- + bool + Whether bandwidth correction has been applied to the measured data. + """ + + return self._bandwidth_corrected + + @bandwidth_corrected.setter + def bandwidth_corrected(self, value): + """ + Setter for the **self.bandwidth_corrected** property. + """ + + if value is not None: + assert isinstance(value, bool), ( + '"{0}" attribute: "{1}" is not a "bool" instance!'.format( + 'bandwidth_corrected', value)) + + self._bandwidth_corrected = value + + def read(self): + """ + Reads and parses the spectral data JSON file path. + + Returns + ------- + bool + Definition success. + """ + + with open(self._path, 'r') as json_file: + content = json.load(json_file) + + self._header = AMPAS_SpectralDataHeader(**content['header']) + for attribute in ('units', 'reflection_geometry', + 'transmission_geometry', 'bandwidth_FWHM', + 'bandwidth_corrected'): + setattr(self, '_{0}'.format(attribute), + content['spectral_data'][attribute]) + + index = content['spectral_data']['index']['main'] + data = content['spectral_data']['data']['main'] + + if len(index) == 1: + self.domain, self.range = Signal.signal_unpack_data( + {k: v[0] + for k, v in data.items()}) + else: + self.signals = MultiSignals.multi_signals_unpack_data( + data, labels=index) + + # TODO: Re-instate "manufacturer", "model", "illuminant" and "type" + # attributes according to outcome of + # https://github.com/ampas/rawtoaces/issues/114. + if ('manufacturer' in self._header._kwargs and + 'model' in self._header._kwargs): + self.name = '{0} {1}'.format(self._header._kwargs['manufacturer'], + self._header._kwargs['model']) + elif 'illuminant' in self._header._kwargs: + self.name = self._header._kwargs['illuminant'] + elif 'type' in self._header._kwargs: + self.name = self._header._kwargs['type'] + + return self + + +class SpectralDistribution_AMPAS(AMPAS_SpectralDataMixin, + SpectralDistribution): + """ + Defines an *A.M.P.A.S* spectral distribution. + + This class can read *A.M.P.A.S* spectral data JSON files. + + Parameters + ---------- + path : unicode, optional + Spectral data JSON file path. + header : AMPAS_SpectralDataHeader, optional + *A.M.P.A.S.* spectral distribution header. + units : unicode, optional + **{'flux', 'absorptance', 'transmittance', 'reflectance', 'intensity', + 'irradiance', 'radiance', 'exitance', 'R-Factor', 'T-Factor', + 'relative', 'other'}**, + Quantity of measurement for each element of the spectral data. + reflection_geometry : unicode, optional + **{'di:8', 'de:8', '8:di', '8:de', 'd:d', 'd:0', '45a:0', '45c:0', + '0:45a', '45x:0', '0:45x', 'other'}**, + Spectral reflectance factors geometric conditions. + transmission_geometry : unicode, optional + **{'0:0', 'di:0', 'de:0', '0:di', '0:de', 'd:d', 'other'}**, + Spectral transmittance factors geometric conditions. + bandwidth_FWHM : numeric, optional + Spectroradiometer full-width half-maximum bandwidth in nanometers. + bandwidth_corrected : bool, optional + Specifies if bandwidth correction has been applied to the measured + data. + + References + ---------- + :cite:`IESComputerCommittee2014a` + """ + + def __init__(self, + path=None, + header=None, + units=None, + reflection_geometry=None, + transmission_geometry=None, + bandwidth_FWHM=None, + bandwidth_corrected=None): + super(SpectralDistribution_AMPAS, self).__init__( + path, header, units, reflection_geometry, transmission_geometry, + bandwidth_FWHM, bandwidth_corrected) + + +class MultiSpectralDistributions_AMPAS(AMPAS_SpectralDataMixin, + MultiSpectralDistributions): + """ + Defines the *A.M.P.A.S* multi-spectral distributions. + + This class can read *A.M.P.A.S* spectral data JSON files. + + Parameters + ---------- + path : unicode, optional + Spectral data JSON file path. + header : AMPAS_SpectralDataHeader, optional + *A.M.P.A.S.* spectral distribution header. + units : unicode, optional + **{'flux', 'absorptance', 'transmittance', 'reflectance', 'intensity', + 'irradiance', 'radiance', 'exitance', 'R-Factor', 'T-Factor', + 'relative', 'other'}**, + Quantity of measurement for each element of the spectral data. + reflection_geometry : unicode, optional + **{'di:8', 'de:8', '8:di', '8:de', 'd:d', 'd:0', '45a:0', '45c:0', + '0:45a', '45x:0', '0:45x', 'other'}**, + Spectral reflectance factors geometric conditions. + transmission_geometry : unicode, optional + **{'0:0', 'di:0', 'de:0', '0:di', '0:de', 'd:d', 'other'}**, + Spectral transmittance factors geometric conditions. + bandwidth_FWHM : numeric, optional + Spectroradiometer full-width half-maximum bandwidth in nanometers. + bandwidth_corrected : bool, optional + Specifies if bandwidth correction has been applied to the measured + data. + + References + ---------- + :cite:`IESComputerCommittee2014a` + """ + + def __init__(self, + path=None, + header=None, + units=None, + reflection_geometry=None, + transmission_geometry=None, + bandwidth_FWHM=None, + bandwidth_corrected=None): + super(MultiSpectralDistributions_AMPAS, self).__init__( + path, header, units, reflection_geometry, transmission_geometry, + bandwidth_FWHM, bandwidth_corrected) + + +class Dyer2017DatasetLoader(AbstractDatasetLoader): + """ + Defines the *Dyer et al. (2017)* *RAW to ACES Utility Data* dataset + loader. + + Attributes + ---------- + ID + + Methods + ------- + load + + References + ---------- + :cite:`Dyer2017` + """ + + ID = '3372171' + """ + Dataset record id, i.e. the *Zenodo* record number. + + ID : unicode + """ + + def __init__(self): + super(Dyer2017DatasetLoader, + self).__init__(datasets()[Dyer2017DatasetLoader.ID]) + + def load(self): + """ + Syncs, parses, converts and returns the *Dyer et al. (2017)* + *RAW to ACES Utility Data* dataset content. + + Returns + ------- + OrderedDict + *Dyer et al. (2017)* *RAW to ACES Utility Data* dataset content. + + Examples + -------- + >>> from colour_datasets.utilities import suppress_stdout + >>> dataset = Dyer2017DatasetLoader() + >>> with suppress_stdout(): + ... dataset.load() + >>> len(dataset.content.keys()) + 4 + """ + + super(Dyer2017DatasetLoader, self).sync() + + self._content = OrderedDict() + + for directory in ('camera', 'cmf', 'illuminant', 'training'): + self._content[directory] = OrderedDict() + factory = (SpectralDistribution_AMPAS if directory == 'illuminant' + else MultiSpectralDistributions_AMPAS) + glob_pattern = os.path.join(self.record.repository, 'dataset', + 'data', directory, '*.json') + for path in glob.glob(glob_pattern): + msds = factory(path).read() + self._content[directory][msds.name] = msds + + return self._content + + +_DYER2017_DATASET_LOADER = None +""" +Singleton instance of the *Dyer et al. (2017)* *RAW to ACES Utility Data* +dataset loader. + +_DYER2017_DATASET_LOADER : Dyer2017DatasetLoader +""" + + +def build_Dyer2017(load=True): + """ + Singleton factory that builds the *Dyer et al. (2017)* + *RAW to ACES Utility Data* dataset loader. + + Parameters + ---------- + load : bool, optional + Whether to load the dataset upon instantiation. + + Returns + ------- + Dyer2017DatasetLoader + Singleton instance of the *Dyer et al. (2017)* + *RAW to ACES Utility Data* dataset loader. + + References + ---------- + :cite:`Dyer2017` + """ + + global _DYER2017_DATASET_LOADER + + if _DYER2017_DATASET_LOADER is None: + _DYER2017_DATASET_LOADER = Dyer2017DatasetLoader() + if load: + _DYER2017_DATASET_LOADER.load() + + return _DYER2017_DATASET_LOADER diff --git a/colour_datasets/loaders/ebner1998.py b/colour_datasets/loaders/ebner1998.py new file mode 100644 index 0000000..3219303 --- /dev/null +++ b/colour_datasets/loaders/ebner1998.py @@ -0,0 +1,196 @@ +# -*- coding: utf-8 -*- +""" +Constant Perceived-Hue Data - Ebner and Fairchild (1998) +======================================================== + +Defines the objects implementing support for *Ebner and Fairchild (1998)* +*Constant Perceived-Hue Data* dataset loading: + +- :class:`colour_datasets.loaders.Ebner1998DatasetLoader` +- :func:`colour_datasets.loaders.build_Ebner1998` + +References +---------- +- :cite:`Ebner1998` : Ebner, F., & Fairchild, M. D. (1998). Finding constant + hue surfaces in color space. In G. B. Beretta & R. Eschbach (Eds.), Proc. + SPIE 3300, Color Imaging: Device-Independent Color, Color Hardcopy, and + Graphic Arts III, (2 January 1998) (pp. 107–117). doi:10.1117/12.298269 +""" + +from __future__ import division, unicode_literals + +import codecs +import numpy as np +import os +from collections import OrderedDict, namedtuple + +from colour.utilities import as_float_array + +from colour_datasets.records import datasets +from colour_datasets.loaders import AbstractDatasetLoader + +__author__ = 'Colour Developers' +__copyright__ = 'Copyright (C) 2019 - Colour Developers' +__license__ = 'New BSD License - https://opensource.org/licenses/BSD-3-Clause' +__maintainer__ = 'Colour Developers' +__email__ = 'colour-science@googlegroups.com' +__status__ = 'Production' + +__all__ = [ + 'ConstantPerceivedHueColourMatchesEbner1998', 'Ebner1998DatasetLoader', + 'build_Ebner1998' +] + + +class ConstantPerceivedHueColourMatchesEbner1998( + namedtuple('ConstantPerceivedHueColourMatchesEbner1998', + ('name', 'XYZ_r', 'XYZ_cr', 'XYZ_ct', 'metadata'))): + """ + Defines *Ebner and Fairchild (1998)* *Constant Perceived-Hue Data* + colour matches data for a given hue angle. + + Parameters + ---------- + name : unicode + *Ebner and Fairchild (1998)* *Constant Perceived-Hue Data* hue angle or + name. + XYZ_r : array_like + *CIE XYZ* tristimulus values of the reference illuminant. + XYZ_cr : array_like + *CIE XYZ* tristimulus values of the reference colour under the + reference illuminant. + XYZ_ct : array_like + *CIE XYZ* tristimulus values of the colour matches under the reference + illuminant. + metadata : dict + Dataset metadata. + """ + + +class Ebner1998DatasetLoader(AbstractDatasetLoader): + """ + Defines the *Ebner and Fairchild (1998)* *Constant Perceived-Hue Data* + dataset loader. + + Attributes + ---------- + ID + + Methods + ------- + load + + References + ---------- + :cite:`Ebner1998` + """ + + ID = '3362536' + """ + Dataset record id, i.e. the *Zenodo* record number. + + ID : unicode + """ + + def __init__(self): + super(Ebner1998DatasetLoader, + self).__init__(datasets()[Ebner1998DatasetLoader.ID]) + + def load(self): + """ + Syncs, parses, converts and returns the *Ebner and Fairchild (1998)* + *Constant Perceived-Hue Data* dataset content. + + Returns + ------- + OrderedDict + *Ebner and Fairchild (1998)* Constant Perceived-Hue Data* dataset + content. + + Examples + -------- + >>> from colour_datasets.utilities import suppress_stdout + >>> dataset = Ebner1998DatasetLoader() + >>> with suppress_stdout(): + ... dataset.load() + >>> len(dataset.content.keys()) + 1 + """ + + super(Ebner1998DatasetLoader, self).sync() + + self._content = OrderedDict([('Constant Perceived-Hue Data', + OrderedDict())]) + + datafile_path = os.path.join(self.record.repository, 'dataset', + 'Ebner_Constant_Hue_Data.txt') + + def _parse_float_values(data): + """ + Parses float values from given data. + """ + + data = [float(x) / 100 for x in data.split('\t') if x] + + values = as_float_array(data).reshape(-1, 3) + + return np.squeeze(values) + + with codecs.open(datafile_path, encoding='utf-8') as database_file: + lines = filter( + None, (line.strip() for line in database_file.readlines())) + + for line in lines: + if line.startswith('White Point'): + XYZ_r = _parse_float_values(line.split(':')[-1]) + elif line.startswith('reference hue'): + line = line.replace('reference hue ', '') + hue, data = line.split('\t', 1) + hue, data = int(hue), _parse_float_values(data) + + self._content['Constant Perceived-Hue Data'][hue] = ( + ConstantPerceivedHueColourMatchesEbner1998( + 'Reference Hue Angle - {0}'.format(hue), XYZ_r, + data[0], data[1:], {'h': hue})) + + return self._content + + +_EBNER1998_DATASET_LOADER = None +""" +Singleton instance of the *Ebner and Fairchild (1998)* +*Constant Perceived-Hue Data* dataset loader. + +_EBNER1998_DATASET_LOADER : Ebner1998DatasetLoader +""" + + +def build_Ebner1998(load=True): + """ + Singleton factory that builds the *Ebner and Fairchild (1998)* + *Constant Perceived-Hue Data* dataset loader. + + Parameters + ---------- + load : bool, optional + Whether to load the dataset upon instantiation. + + Returns + ------- + Ebner1998DatasetLoader + Singleton instance of the *Ebner and Fairchild (1998)* + *Constant Perceived-Hue Data* dataset loader. + + References + ---------- + :cite:`Ebner1998` + """ + + global _EBNER1998_DATASET_LOADER + + if _EBNER1998_DATASET_LOADER is None: + _EBNER1998_DATASET_LOADER = Ebner1998DatasetLoader() + if load: + _EBNER1998_DATASET_LOADER.load() + + return _EBNER1998_DATASET_LOADER diff --git a/colour_datasets/loaders/hung1995.py b/colour_datasets/loaders/hung1995.py new file mode 100644 index 0000000..55ed8e4 --- /dev/null +++ b/colour_datasets/loaders/hung1995.py @@ -0,0 +1,222 @@ +# -*- coding: utf-8 -*- +""" +Constant Hue Loci Data - Hung and Berns (1995) +============================================== + +Defines the objects implementing support for *Hung and Berns (1995)* +*Constant Hue Loci Data* dataset loading: + +- :class:`colour_datasets.loaders.Hung1995DatasetLoader` +- :func:`colour_datasets.loaders.build_Hung1995` + +References +---------- +- :cite:`Hung1995` : Hung, P.-C., & Berns, R. S. (1995). Determination of + constant Hue Loci for a CRT gamut and their predictions using color + appearance spaces. Color Research & Application, 20(5), 285–295. + doi:10.1002/col.5080200506 +""" + +from __future__ import division, unicode_literals + +import numpy as np +import os +from collections import OrderedDict, namedtuple + +from colour import ILLUMINANTS, xy_to_XYZ, xyY_to_XYZ + +from colour_datasets.records import datasets +from colour_datasets.loaders import AbstractDatasetLoader + +__author__ = 'Colour Developers' +__copyright__ = 'Copyright (C) 2019 - Colour Developers' +__license__ = 'New BSD License - https://opensource.org/licenses/BSD-3-Clause' +__maintainer__ = 'Colour Developers' +__email__ = 'colour-science@googlegroups.com' +__status__ = 'Production' + +__all__ = [ + 'ConstantPerceivedHueColourMatchesHung1995', 'Hung1995DatasetLoader', + 'build_Hung1995' +] + + +class ConstantPerceivedHueColourMatchesHung1995( + namedtuple('ConstantPerceivedHueColourMatchesHung1995', + ('name', 'XYZ_r', 'XYZ_cr', 'XYZ_ct', 'metadata'))): + """ + Defines *Hung and Berns (1995)* *Constant Hue Loci Data* + colour matches data for a given hue angle. + + Parameters + ---------- + name : unicode + *Hung and Berns (1995)* *Constant Hue Loci Data* hue angle or + name. + XYZ_r : array_like + *CIE XYZ* tristimulus values of the reference illuminant. + XYZ_cr : array_like + *CIE XYZ* tristimulus values of the reference colour under the + reference illuminant. + XYZ_ct : array_like + *CIE XYZ* tristimulus values of the colour matches under the reference + illuminant. + metadata : dict + Dataset metadata. + """ + + +class Hung1995DatasetLoader(AbstractDatasetLoader): + """ + Defines the *Hung and Berns (1995)* *Constant Hue Loci Data* + dataset loader. + + Attributes + ---------- + ID + + Methods + ------- + load + + References + ---------- + :cite:`Hung1995` + """ + + ID = '3367463' + """ + Dataset record id, i.e. the *Zenodo* record number. + + ID : unicode + """ + + def __init__(self): + super(Hung1995DatasetLoader, + self).__init__(datasets()[Hung1995DatasetLoader.ID]) + + def load(self): + """ + Syncs, parses, converts and returns the *Hung and Berns (1995)* + *Constant Hue Loci Data* dataset content. + + Returns + ------- + OrderedDict + *Hung and Berns (1995)* *Constant Hue Loci Data* dataset content. + + Examples + -------- + >>> from colour_datasets.utilities import suppress_stdout + >>> dataset = Hung1995DatasetLoader() + >>> with suppress_stdout(): + ... dataset.load() + >>> len(dataset.content.keys()) + 6 + """ + + super(Hung1995DatasetLoader, self).sync() + + self._content = OrderedDict() + + filenames = OrderedDict([ + ('Table I.csv', 'Reference colors.'), + ('Table II.csv', 'Intra- and interobserver variances for each ' + 'reference hue expressed in circumferential ' + 'hue-angle difference.'), + ('Table III.csv', 'Weight-averaged constant hue loci for the CL ' + 'experiment.'), + ('Table IV.csv', 'Weight-averaged constant hue loci for the VL ' + 'experiment.'), + ]) + + for filename in filenames: + datafile_path = os.path.join(self.record.repository, 'dataset', + filename) + + self._content[filename.split('.')[0]] = np.genfromtxt( + datafile_path, + delimiter=',', + names=True, + dtype=None, + encoding='utf-8') + + hues = [ + 'Red', 'Red-yellow', 'Yellow', 'Yellow-green', 'Green', + 'Green-cyan', 'Cyan', 'Cyan-blue', 'Blue', 'Blue-magenta', + 'Magenta', 'Magenta-red' + ] + + XYZ_r = xy_to_XYZ( + ILLUMINANTS['CIE 1931 2 Degree Standard Observer']['C']) + + for table, experiment in [('Table III', 'CL'), ('Table IV', 'VL')]: + key = 'Constant Hue Loci Data - {0}'.format(experiment) + self._content[key] = OrderedDict() + for hue in hues: + for sample_r in self._content['Table I']: + sample_r = sample_r.tolist() + if sample_r[0] == hue: + XYZ_cr = xyY_to_XYZ(sample_r[1:4]) / 100 + break + + XYZ_ct = [] + metadata = { + 'Color name': [], + 'C*uv': [], + } + for sample_t in self._content[table]: + sample_t = sample_t.tolist() + if not sample_t[0] == hue: + continue + + XYZ_ct.append(sample_t[2:]) + metadata['Color name'].append(sample_t[0]) + metadata['C*uv'].append(sample_t[1]) + + self._content[key][hue] = ( + ConstantPerceivedHueColourMatchesHung1995( + hue, XYZ_r, XYZ_cr, + np.vstack(XYZ_ct) / 100, metadata)) + + return self._content + + +_HUNG1995_DATASET_LOADER = None +""" +Singleton instance of the *Hung and Berns (1995)* +*Constant Hue Loci Data* dataset loader. + +_HUNG1995_DATASET_LOADER : Hung1995DatasetLoader +""" + + +def build_Hung1995(load=True): + """ + Singleton factory that builds the *Hung and Berns (1995)* + *Constant Hue Loci Data* dataset loader. + + Parameters + ---------- + load : bool, optional + Whether to load the dataset upon instantiation. + + Returns + ------- + Hung1995DatasetLoader + Singleton instance of the *Hung and Berns (1995)* + *Constant Hue Loci Data* dataset loader. + + References + ---------- + :cite:`Hung1995` + """ + + global _HUNG1995_DATASET_LOADER + + if _HUNG1995_DATASET_LOADER is None: + _HUNG1995_DATASET_LOADER = Hung1995DatasetLoader() + if load: + _HUNG1995_DATASET_LOADER.load() + + return _HUNG1995_DATASET_LOADER diff --git a/colour_datasets/loaders/jiang2013.py b/colour_datasets/loaders/jiang2013.py index 3bf70a8..b2d7ebe 100644 --- a/colour_datasets/loaders/jiang2013.py +++ b/colour_datasets/loaders/jiang2013.py @@ -74,18 +74,22 @@ def __init__(self): def load(self): """ - Syncs, parses, converts and returns the dataset content. + Syncs, parses, converts and returns the *Jiang et al. (2013)* + *Camera Spectral Sensitivity Database* dataset content. Returns ------- OrderedDict - Dataset content as an :class:`OrderedDict` of cameras and their - spectral sensitivities. + *Jiang et al. (2013)* *Camera Spectral Sensitivity Database* + dataset content. Examples -------- + >>> from colour_datasets.utilities import suppress_stdout >>> dataset = Jiang2013DatasetLoader() - >>> len(dataset.load().keys()) + >>> with suppress_stdout(): + ... dataset.load() + >>> len(dataset.content.keys()) 28 """ @@ -93,7 +97,7 @@ def load(self): shape = SpectralShape(400, 720, 10) - self._data = OrderedDict() + self._content = OrderedDict() database_path = os.path.join(self.record.repository, 'dataset', 'camspec_database.txt') with codecs.open(database_path, encoding='utf-8') as database_file: @@ -103,19 +107,19 @@ def load(self): for line in lines: if re.match('[a-zA-Z]+', line): camera = line - self._data[camera] = [] + self._content[camera] = [] continue - self._data[camera].extend( + self._content[camera].extend( [float(value) for value in line.split('\t')]) - for camera, values in self._data.items(): - self._data[camera] = RGB_SpectralSensitivities( + for camera, values in self._content.items(): + self._content[camera] = RGB_SpectralSensitivities( np.transpose(as_float_array(values).reshape([3, 33])), shape.range(), name=camera) - return self._data + return self._content _JIANG2013_DATASET_LOADER = None diff --git a/colour_datasets/loaders/kuopio.py b/colour_datasets/loaders/kuopio.py new file mode 100644 index 0000000..82d782e --- /dev/null +++ b/colour_datasets/loaders/kuopio.py @@ -0,0 +1,468 @@ +# -*- coding: utf-8 -*- +""" +University of Kuopio +==================== + +Defines the objects implementing support for the *University of Kuopio* +datasets loading: + +- :class:`colour_datasets.loaders.KuopioUniversityDatasetLoader` +- :func:`colour_datasets.loaders.build_KuopioUniversity` + +Notes +---- +- The various *University of Kuopio* datasets loading classes are built at + module import time. + +References +---------- +- :cite:`Hauta-Kasari` : Hauta-Kasari, M., & University of Kuopio. (n.d.). + Munsell Colors Matt (Spectrofotometer Measured). doi:10.5281/zenodo.3269912 +- :cite:`Hauta-Kasaria` : Hauta-Kasari, M., & University of Kuopio. (n.d.). + Munsell Colors Matt (AOTF Measured). doi:10.5281/zenodo.3269914 +- :cite:`Haanpalo` : Haanpalo, J., & University of Kuopio. (n.d.). Munsell + Colors Glossy (Spectrofotometer Measured). doi:10.5281/zenodo.3269916 +- :cite:`Orava` : Orava, J., & University of Kuopio. (n.d.). Munsell Colors + Glossy (All) (Spectrofotometer Measured). doi:10.5281/zenodo.3269918 +- :cite:`Silvennoinen` : Silvennoinen, R., & University of Kuopio. (n.d.). + Forest Colors. doi:10.5281/zenodo.3269920 +- :cite:`Haanpaloa` : Haanpalo, J., & University of Kuopio. (n.d.). Paper + Spectra. doi:10.5281/zenodo.3269922 +- :cite:`Hiltunen` : Hiltunen, J., & University of Kuopio. (n.d.). Lumber + Spectra. doi:10.5281/zenodo.3269924 +- :cite:`Marszalec` : Marszalec, E., & University of Kuopio. (n.d.). Agfa + IT8.7/2 Set. doi:10.5281/zenodo.3269926 +""" + +from __future__ import division, unicode_literals + +import functools +import numpy as np +import os +import re +import scipy.io +import six +import sys +from collections import OrderedDict, namedtuple + +from colour import SpectralDistribution, SpectralShape + +from colour_datasets import datasets +from colour_datasets.loaders import AbstractDatasetLoader + +__author__ = 'Colour Developers' +__copyright__ = 'Copyright (C) 2019 - Colour Developers' +__license__ = 'New BSD License - https://opensource.org/licenses/BSD-3-Clause' +__maintainer__ = 'Colour Developers' +__email__ = 'colour-science@googlegroups.com' +__status__ = 'Production' + +__all__ = [ + 'KuopioUniversityMatFileMetadata', + 'read_sds_from_mat_file_KuopioUniversity', 'KuopioUniversityDatasetLoader', + 'build_KuopioUniversity', 'KUOPIO_UNIVERSITY_DATASETS_DATA', + 'KUOPIO_UNIVERSITY_DATASET_LOADERS' +] + + +class KuopioUniversityMatFileMetadata( + namedtuple('KuopioUniversityMatFileMetadata', + ('key', 'shape', 'transpose', 'identifiers'))): + """ + Metadata storage for an *University of Kuopio* dataset spectral + distributions. + + Parameters + ---------- + key : unicode + *Matlab* *.mat* file key to extract the data from. + shape : SpectralShape + Spectral distributions shape. + transpose : bool + Whether to transpose the data. + identifiers : array_like + Identifiers for the spectral distributions. + """ + + +def read_sds_from_mat_file_KuopioUniversity(mat_file, metadata): + """ + Reads the spectral distributions from given *University of Kuopio* + *Matlab* *.mat* file. + + Parameters + ---------- + mat_file : unicode + *Matlab* *.mat* file. + metadata : KuopioUniversityMatFileMetadata + Metadata required to read the spectral distributions in the *Matlab* + *.mat* file. + + Returns + ------- + OrderedDict + Spectral distributions from the *Matlab* *.mat* file. + """ + + matlab_data = scipy.io.loadmat(mat_file) + + sds = OrderedDict() + table = matlab_data[metadata.key] + wavelengths = metadata.shape.range() + + if metadata.transpose: + table = np.transpose(table) + + for i, data in enumerate(table): + identifier = six.text_type(i + 1 if metadata.identifiers is None else + matlab_data[metadata.identifiers][ + i].strip()) + + if identifier in sds: + identifier = '{0} ({1})'.format(identifier, i) + + sds[identifier] = SpectralDistribution( + dict(zip(wavelengths, data)), name=identifier) + + return sds + + +class KuopioUniversityDatasetLoader(AbstractDatasetLoader): + """ + Defines the base class for a *University of Kuopio* dataset loader. + + Attributes + ---------- + ID + METADATA + + Methods + ------- + load + """ + + ID = None + """ + Dataset record id, i.e. the *Zenodo* record number. + + ID : unicode + """ + + METADATA = None + """ + Mapping of paths and + :class:`colour_datasets.loaders.kuopio.KuopioUniversityMatFileMetadata` + class instances. + + METADATA : dict + """ + + def __init__(self): + super(KuopioUniversityDatasetLoader, + self).__init__(datasets()[self.ID]) + + def load(self): + """ + Syncs, parses, converts and returns the *University of Kuopio* dataset + content. + + Returns + ------- + OrderedDict + *University of Kuopio* dataset content. + """ + + super(KuopioUniversityDatasetLoader, self).sync() + + self._content = OrderedDict() + + for path, metadata in self.METADATA.items(): + mat_path = os.path.join(self.record.repository, 'dataset', *path) + + self._content[ + metadata.key] = read_sds_from_mat_file_KuopioUniversity( + mat_path, metadata) + + return self._content + + +def _build_dataset_loader_class_KuopioUniversity(id_, title, citation_key, + metadata): + """ + Class factory building *University of Kuopio* dataset loaders. + + Parameters + ---------- + id_ : unicode + Dataset record id, i.e. the *Zenodo* record number. + title : unicode + *University of Kuopio* dataset loader title. + citation_key : unicode + *University of Kuopio* dataset citation key. + metadata : dict + Mapping of paths and + :class:`colour_datasets.loaders.kuopio.KuopioUniversityMatFileMetadata` + class instances. + + Returns + ------- + object + *University of Kuopio* dataset loader class. + """ + + class_docstring = """ + Defines the *University of Kuopio* *{0}* dataset loader. + + Attributes + ---------- + ID + METADATA + + Methods + ------- + load + + References + ---------- + :cite:`{1}`""" [1:].format(title, citation_key) + + load_method_docstring = """ + Syncs, parses, converts and returns the *University of Kuopio* *{0}* + dataset content. + + Returns + ------- + OrderedDict + *University of Kuopio* *{0}* dataset content. """ [1:].format( + title) + + module = sys.modules['colour_datasets.loaders.kuopio'] + + prefix = re.sub('\\.|\\(|\\)|/|\\s', '', title) + class_attribute = '{0}DatasetLoader'.format(prefix) + dataset_loader_class = type( + str(class_attribute), (KuopioUniversityDatasetLoader, ), { + 'ID': id_, + 'METADATA': metadata + }) + + dataset_loader_class.__doc__ = class_docstring + try: + dataset_loader_class.load.__doc__ = load_method_docstring + except AttributeError: + pass + + setattr(module, class_attribute, dataset_loader_class) + + return dataset_loader_class + + +def build_KuopioUniversity(dataset_loader_class, load=True): + """ + Singleton factory that builds a *University of Kuopio* dataset loader. + + Parameters + ---------- + dataset_loader_class : object + *University of Kuopio* dataset loader class. + load : bool, optional + Whether to load the dataset upon instantiation. + + Returns + ------- + KuopioUniversityDatasetLoader + Singleton instance of a *University of Kuopio* dataset loader. + """ + + module = sys.modules['colour_datasets.loaders.kuopio'] + + prefix = dataset_loader_class.__name__.replace('DatasetLoader', '') + prefix = re.sub('([A-Z]+)', r'_\1', prefix).replace('__', '_').upper() + dataset_loader_attribute = '_{0}_DATASET_LOADER'.format(prefix) + + if not hasattr(module, dataset_loader_attribute): + setattr(module, dataset_loader_attribute, dataset_loader_class()) + if load: + getattr(module, dataset_loader_attribute).load() + + return getattr(module, dataset_loader_attribute) + + +# TODO: Implement support for *Natural Colors*: +# https://sandbox.zenodo.org/record/315640 +# http://www.uef.fi/web/spectral/natural-colors +KUOPIO_UNIVERSITY_DATASETS_DATA = { + '3269912': [ + 'Munsell Colors Matt (Spectrofotometer Measured)', 'Hauta-Kasari', { + ('munsell380_800_1_mat', 'munsell380_800_1.mat'): + KuopioUniversityMatFileMetadata('munsell', + SpectralShape(380, 800, 1), + True, 'S') + } + ], + '3269914': [ + 'Munsell Colors Matt (AOTF Measured)', 'Hauta-Kasaria', { + ('munsell400_700_5_mat', 'munsell400_700_5.mat'): + KuopioUniversityMatFileMetadata('munsell', + SpectralShape(400, 700, 5), + True, 'S') + } + ], + '3269916': [ + 'Munsell Colors Glossy (Spectrofotometer Measured)', 'Haanpalo', { + ('munsell400_700_10_mat', 'munsell400_700_10.mat'): + KuopioUniversityMatFileMetadata('munsell', + SpectralShape(400, 700, 10), + True, 'S') + } + ], + '3269918': [ + 'Munsell Colors Glossy (All) (Spectrofotometer Measured)', 'Orava', { + ('munsell380_780_1_glossy_mat', 'munsell380_780_1_glossy.mat'): + KuopioUniversityMatFileMetadata('X', SpectralShape( + 380, 780, 1), True, None) + } + ], + '3269920': [ + 'Forest Colors', 'Silvennoinen', { + ('forest_matlab', 'birch.mat'): + KuopioUniversityMatFileMetadata('birch', + SpectralShape(380, 850, 5), + True, None), + ('forest_matlab', 'pine.mat'): + KuopioUniversityMatFileMetadata('pine', + SpectralShape(380, 850, 5), + True, None), + ('forest_matlab', 'spruce.mat'): + KuopioUniversityMatFileMetadata('spruce', + SpectralShape(380, 850, 5), + True, None) + } + ], + '3269922': [ + 'Paper Spectra', 'Haanpaloa', { + ('paper_matlab', 'cardboardsce.mat'): + KuopioUniversityMatFileMetadata('cardboardsce', + SpectralShape(400, 700, 10), + True, None), + ('paper_matlab', 'cardboardsci.mat'): + KuopioUniversityMatFileMetadata('cardboardsci', + SpectralShape(400, 700, 10), + True, None), + ('paper_matlab', 'mirrorsci.mat'): + KuopioUniversityMatFileMetadata('mirrorsci', + SpectralShape(400, 700, 10), + True, None), + ('paper_matlab', 'newsprintsce.mat'): + KuopioUniversityMatFileMetadata('newsprintsce', + SpectralShape(400, 700, 10), + True, None), + ('paper_matlab', 'newsprintsci.mat'): + KuopioUniversityMatFileMetadata('newsprintsci', + SpectralShape(400, 700, 10), + True, None), + ('paper_matlab', 'papersce.mat'): + KuopioUniversityMatFileMetadata('papersce', + SpectralShape(400, 700, 10), + True, None), + ('paper_matlab', 'papersci.mat'): + KuopioUniversityMatFileMetadata('papersci', + SpectralShape(400, 700, 10), + True, None), + } + ], + '3269924': [ + 'Lumber Spectra', 'Hiltunen', { + ('lumber_matlab', 'aspenWb.mat'): + KuopioUniversityMatFileMetadata('aspenWb', + SpectralShape(380, 2700, 1), + True, None), + ('lumber_matlab', 'aspenWp.mat'): + KuopioUniversityMatFileMetadata('aspenWp', + SpectralShape(380, 2700, 1), + True, None), + ('lumber_matlab', 'birchWb.mat'): + KuopioUniversityMatFileMetadata('birchWb', + SpectralShape(380, 2700, 1), + True, None), + ('lumber_matlab', 'birchWp.mat'): + KuopioUniversityMatFileMetadata('birchWp', + SpectralShape(380, 2700, 1), + True, None), + ('lumber_matlab', 'pineWb.mat'): + KuopioUniversityMatFileMetadata('pineWb', + SpectralShape(380, 2700, 1), + True, None), + ('lumber_matlab', 'pineWp.mat'): + KuopioUniversityMatFileMetadata('pineWp', + SpectralShape(380, 2700, 1), + True, None), + ('lumber_matlab', 'spruceWb.mat'): + KuopioUniversityMatFileMetadata('spruceWb', + SpectralShape(380, 2700, 1), + True, None), + ('lumber_matlab', 'spruceWp.mat'): + KuopioUniversityMatFileMetadata('spruceWp', + SpectralShape(380, 2700, 1), + True, None) + } + ], + '3269926': [ + 'Agfa IT8.7/2 Set', 'Marszalec', { + ('agfait872_mat', 'agfait872.mat'): + KuopioUniversityMatFileMetadata('agfa', + SpectralShape(400, 700, 10), + True, None) + } + ], +} + +_singleton_factory_docstring_template = """ + Singleton factory that the builds *University of Kuopio* *{1}* dataset + loader. + + Parameters + ---------- + load : bool, optional + Whether to load the dataset upon instantiation. + + Returns + ------- + {0} + Singleton instance of the *University of Kuopio* *{1}* dataset loader. + + References + ---------- + :cite:`{2}`""" [1:] + +KUOPIO_UNIVERSITY_DATASET_LOADERS = {} +""" +*University of Kuopio* dataset loaders. + +References +---------- +:cite:`Hauta-Kasari`, :cite:`Hauta-Kasaria`, :cite:`Haanpalo`, :cite:`Orava`, +:cite:`Silvennoinen`, :cite:`Haanpaloa`, :cite:`Hiltunen`, :cite:`Marszalec` + +KUOPIO_UNIVERSITY_DATASET_LOADERS : dict +""" + +for _id, _data in KUOPIO_UNIVERSITY_DATASETS_DATA.items(): + _module = sys.modules['colour_datasets.loaders.kuopio'] + _dataset_loader_class = _build_dataset_loader_class_KuopioUniversity( + _id, *_data) + _partial_function = functools.partial(build_KuopioUniversity, + _dataset_loader_class) + _partial_function.__doc__ = _singleton_factory_docstring_template.format( + _dataset_loader_class.__name__, *_data[:-1]) + + _build_function_name = 'build_{0}'.format( + _dataset_loader_class.__name__.replace('DatasetLoader', '')) + + setattr(_module, _build_function_name, _partial_function) + + KUOPIO_UNIVERSITY_DATASET_LOADERS[_id] = _partial_function + + __all__ += [_dataset_loader_class.__name__, _build_function_name] + +del _id, _data, _module, _partial_function, _build_function_name diff --git a/colour_datasets/loaders/labsphere2019.py b/colour_datasets/loaders/labsphere2019.py index 60bfd30..1f6a579 100644 --- a/colour_datasets/loaders/labsphere2019.py +++ b/colour_datasets/loaders/labsphere2019.py @@ -67,19 +67,21 @@ def __init__(self): def load(self): """ - Syncs, parses, converts and returns the dataset content. + Syncs, parses, converts and returns the *Labsphere (2019)* + *Labsphere SRS-99-020* dataset content. Returns ------- OrderedDict - Dataset content as an :class:`OrderedDict` of - *Spectralon SRS-99-020* diffuse reflectance standard and its - spectral distribution. + *Labsphere (2019)* *Labsphere SRS-99-020* dataset content. Examples -------- + >>> from colour_datasets.utilities import suppress_stdout >>> dataset = Labsphere2019DatasetLoader() - >>> len(dataset.load().keys()) + >>> with suppress_stdout(): + ... dataset.load() + >>> len(dataset.content.keys()) 1 """ @@ -89,13 +91,13 @@ def load(self): 'SRS-99-020.txt') values = tsplit(np.loadtxt(sd_path, delimiter='\t', skiprows=2)) - self._data = OrderedDict([ + self._content = OrderedDict([ ('Labsphere SRS-99-020', SpectralDistribution( values[1], values[0], name='Labsphere SRS-99-020')), ]) - return self._data + return self._content _LABSPHERE2019_DATASET_LOADER = None diff --git a/colour_datasets/loaders/luo1999.py b/colour_datasets/loaders/luo1999.py new file mode 100644 index 0000000..ae79f30 --- /dev/null +++ b/colour_datasets/loaders/luo1999.py @@ -0,0 +1,448 @@ +# -*- coding: utf-8 -*- +""" +Corresponding-Colour Datasets - Luo and Rhodes (1999) +===================================================== + +Defines the objects implementing support for *Luo and Rhodes (1999)* +*Corresponding-Colour Datasets* dataset loading: + +- :class:`colour_datasets.loaders.Luo1999DatasetLoader` +- :func:`colour_datasets.loaders.build_Luo1999` + +References +---------- +- :cite:`Breneman1987b` : Breneman, E. J. (1987). Corresponding + chromaticities for different states of adaptation to complex visual fields. + Journal of the Optical Society of America A, 4(6), 1115. + doi:10.1364/JOSAA.4.001115 +- :cite:`Luo1999` : Luo, M. R., & Rhodes, P. A. (1999). Corresponding-colour + datasets. Color Research & Application, 24(4), 295–296. + doi:10.1002/(SICI)1520-6378(199908)24:4<295::AID-COL10>3.0.CO;2-K +- :cite:`McCann1976` : McCann, J. J., McKee, S. P., & Taylor, T. H. (1976). + Quantitative studies in retinex theory a comparison between theoretical + predictions and observer responses to the “color mondrian” experiments. + Vision Research, 16(5), 445-IN3. doi:10.1016/0042-6989(76)90020-1 +""" + +from __future__ import division, unicode_literals + +import codecs +import numpy as np +import os +from collections import OrderedDict, namedtuple +from colour.utilities import as_float_array + +from colour_datasets.records import datasets +from colour_datasets.loaders import AbstractDatasetLoader + +__author__ = 'Colour Developers' +__copyright__ = 'Copyright (C) 2019 - Colour Developers' +__license__ = 'New BSD License - https://opensource.org/licenses/BSD-3-Clause' +__maintainer__ = 'Colour Developers' +__email__ = 'colour-science@googlegroups.com' +__status__ = 'Production' + +__all__ = [ + 'CorrespondingColourDatasetLuo1999', 'Luo1999DatasetLoader', + 'build_Luo1999' +] + + +class CorrespondingColourDatasetLuo1999( + namedtuple('CorrespondingColourDatasetLuo1999', + ('name', 'XYZ_r', 'XYZ_t', 'XYZ_cr', 'XYZ_ct', 'Y_r', 'Y_t', + 'B_r', 'B_t', 'metadata'))): + """ + Defines a *Luo and Rhodes (1999)* *Corresponding-Colour Datasets* dataset. + + Parameters + ---------- + name : unicode + *Luo and Rhodes (1999)* *Corresponding-Colour Datasets* dataset name. + XYZ_r : array_like + *CIE XYZ* tristimulus values of the reference illuminant. + XYZ_t : array_like + *CIE XYZ* tristimulus values of the test illuminant. + XYZ_cr : array_like + Corresponding *CIE XYZ* tristimulus values under the reference + illuminant. + XYZ_ct : array_like + Corresponding *CIE XYZ* tristimulus values under the test illuminant. + Y_r : numeric + Reference white luminance :math:`Y_r` in :math:`cd/m^2`. + Y_t : numeric + Test white luminance :math:`Y_t` in :math:`cd/m^2`. + B_r : numeric + Luminance factor :math:`B_r` of reference achromatic background as + percentage. + B_t : numeric + Luminance factor :math:`B_t` of test achromatic background as + percentage. + metadata : dict + Dataset metadata. + """ + + +class Luo1999DatasetLoader(AbstractDatasetLoader): + """ + Defines the *Luo and Rhodes (1999)* + *Corresponding-Colour Datasets* dataset + loader. + + Attributes + ---------- + ID + + Methods + ------- + load + + References + ---------- + :cite:`Breneman1987b`, :cite:`Luo1999`, :cite:`McCann1976` + """ + + ID = '3270903' + """ + Dataset record id, i.e. the *Zenodo* record number. + + ID : unicode + """ + + def __init__(self): + super(Luo1999DatasetLoader, + self).__init__(datasets()[Luo1999DatasetLoader.ID]) + + def load(self): + """ + Syncs, parses, converts and returns the *Luo and Rhodes (1999)* + *Corresponding-Colour Datasets* dataset content. + + Returns + ------- + OrderedDict + *Luo and Rhodes (1999)* *Corresponding-Colour Datasets* dataset + content. + + Notes + ----- + - *Brene.p6.dat* has only 11 samples while *Breneman (1987)* has 12 + results. + - The illuminance in :math:`Lux` for *Breneman (1987)* datasets given + by *Luo and Rhodes (1999)* is in domain [50, 3870] while + *Breneman (1987)* reports luminance in :math:`cd/m^2` in domain + [15, 11100], i.e. [47, 34871.69] in :math:`Lux`. The metadata has + been corrected accordingly. + - The illuminance values, i.e. 14 and 40, for + *McCann, McKee and Taylor (1976)* datasets given by + *Luo and Rhodes (1999)* were not found in :cite:`McCann1976`. The + values in use are the average of both. + + Examples + -------- + >>> from colour_datasets.utilities import suppress_stdout + >>> dataset = Luo1999DatasetLoader() + >>> with suppress_stdout(): + ... dataset.load() + >>> len(dataset.content.keys()) + 37 + """ + + super(Luo1999DatasetLoader, self).sync() + + metadata_headers = ( + 'No. of Phases', + 'No. of Samples', + 'Illuminant Test', + 'Illuminant Ref.', + 'Illuminance (lux)', + 'Background (Y%)', + 'Sample Size', + 'Medium', + 'Experimental Method', + ) + + corresponding_colour_datasets = OrderedDict([ + ('CSAJ-C', [('CSAJ.da.dat', ), ( + 1, + 87, + 'D65', + 'A', + np.tile(1000, [1, 2]), + np.tile(20, [1, 2]), + 'S', + 'Refl.', + 'Haploscopic', + )]), + ('CSAJ-Hunt', [( + 'CSAJ.10.dat', + 'CSAJ.50.dat', + 'CSAJ.1000.dat', + 'CSAJ.3000.dat', + ), ( + 4, + 20, + 'D65', + 'D65', + np.repeat([10, 50, 1000, 3000], 2, -1).reshape(-1, 2), + np.tile(20, [4, 2]), + 'S', + 'Refl.', + 'Haploscopic', + )]), + ('CSAJ-Stevens', [( + 'Steve.10.dat', + 'Steve.50.dat', + 'Steve.1000.dat', + 'Steve.3000.dat', + ), ( + 4, + 19, + 'D65', + 'D65', + np.repeat([10, 50, 1000, 3000], 2, -1).reshape(-1, 2), + np.tile(20, [4, 2]), + 'S', + 'Refl.', + 'Haploscopic', + )]), + ('Helson', [('helson.ca.dat', ), ( + 1, + 59, + 'D65', + 'A', + np.tile(1000, [1, 2]), + np.tile(20, [1, 2]), + 'S', + 'Refl.', + 'Memory', + )]), + ('Lam & Rigg', [('lam.da.dat', ), ( + 1, + 58, + 'D65', + 'A', + np.tile(1000, [1, 2]), + np.tile(20, [1, 2]), + 'L', + 'Refl.', + 'Memory', + )]), + ('Lutchi (A)', [('lutchi.da.dat', ), ( + 1, + 43, + 'D65', + 'A', + np.tile(1000, [1, 2]), + np.tile(20, [1, 2]), + 'S', + 'Refl.', + 'Magnitude', + )]), + ('Lutchi (D50)', [('lutchi.dd.dat', ), ( + 1, + 44, + 'D65', + 'D50', + np.tile(1000, [1, 2]), + np.tile(20, [1, 2]), + 'S', + 'Refl.', + 'Magnitude', + )]), + ('Lutchi (WF)', [('lutchi.dw.dat', ), ( + 1, + 41, + 'D65', + 'WF', + np.tile(1000, [1, 2]), + np.tile(20, [1, 2]), + 'S', + 'Refl.', + 'Magnitude', + )]), + ('Kuo & Luo (A)', [('Kuo.da.dat', ), ( + 1, + 40, + 'D65', + 'A', + np.tile(1000, [1, 2]), + np.tile(20, [1, 2]), + 'L', + 'Refl.', + 'Magnitude', + )]), + ('Kuo & Luo (TL84)', [('Kuo.dt.dat', ), ( + 1, + 41, + 'D65', + 'TL84', + np.tile(1000, [1, 2]), + np.tile(20, [1, 2]), + 'S', + 'Refl.', + 'Magnitude', + )]), + ('Breneman-C', [( + 'Brene.p1.dat', + 'Brene.p2.dat', + 'Brene.p3.dat', + 'Brene.p4.dat', + 'Brene.p6.dat', + 'Brene.p8.dat', + 'Brene.p9.dat', + 'Brene.p11.dat', + 'Brene.p12.dat', + ), ( + 9, + 107, + 'D65, 55', + 'A, P, G', + np.repeat([1500, 1500, 75, 75, 11100, 350, 15, 1560, 75], 2, + -1).reshape(-1, 2), + np.tile(30, [9, 2]), + 'S', + 'Trans.', + 'Magnitude', + )]), + ('Breneman-L', [( + 'Brene.p5.dat', + 'Brene.p7.dat', + 'Brene.p10.dat', + ), ( + 3, + 36, + 'D55', + 'D55', + np.array([[130, 2120], [850, 11100], [15, 270]]), + np.tile(30, [3, 2]), + 'S', + 'Trans.', + 'Haploscopic', + )]), + ('Braun & Fairchild', [( + 'RIT.1.dat', + 'RIT.2.dat', + 'RIT.3.dat', + 'RIT.4.dat', + ), ( + 4, + 66, + 'D65', + 'D30, 65, 95', + np.tile(129, [4, 2]), + np.tile(20, [4, 2]), + 'S', + 'Mon., Refl.', + 'Matching', + )]), + ('McCann', [( + 'mcan.b.dat', + 'mcan.g.dat', + 'mcan.grey.dat', + 'mcan.r.dat', + 'mcan.y.dat', + ), ( + 5, + 85, + 'D65', + 'R, Y, G, B', + np.tile((14 + 40) / 2, [5, 2]), + np.tile(30, [5, 2]), + 'S', + 'Refl.', + 'Haploscopic', + )]), + ]) + + self._content = OrderedDict() + for key, (filenames, + metadata) in corresponding_colour_datasets.items(): + for i, filename in enumerate(filenames): + path = os.path.join(self.record.repository, 'dataset', + filename) + + XYZ_r = XYZ_t = None + XYZ_cr, XYZ_ct = [], [] + with codecs.open(path, encoding='utf-8') as dat_file: + lines = filter( + None, (line.strip() for line in dat_file.readlines())) + for j, line in enumerate(lines): + values = line.split() + if j == 0: + XYZ_r = list(map(float, values[:3])) + XYZ_t = list(map(float, values[3:])) + elif len(values) == 1: + continue + else: + XYZ_cr.append(list(map(float, values[:3]))) + XYZ_ct.append(list(map(float, values[3:]))) + + name = '{0} - {1}'.format(key, filename.split('.')[1]) + dataset_metadata = OrderedDict(zip(metadata_headers, metadata)) + + Y_r = dataset_metadata['Illuminance (lux)'][i][0] + Y_t = dataset_metadata['Illuminance (lux)'][i][1] + + B_r = dataset_metadata['Background (Y%)'][i][0] + B_t = dataset_metadata['Background (Y%)'][i][1] + + dataset_metadata['Illuminance (lux)'] = ( + dataset_metadata['Illuminance (lux)'][i]) + dataset_metadata['Background (Y%)'] = ( + dataset_metadata['Background (Y%)'][i]) + + self._content[name] = CorrespondingColourDatasetLuo1999( + name, + as_float_array(XYZ_r) / 100, + as_float_array(XYZ_t) / 100, + as_float_array(XYZ_cr) / 100, + as_float_array(XYZ_ct) / 100, + Y_r * np.pi, + Y_t * np.pi, + B_r, + B_t, + dataset_metadata, + ) + + return self._content + + +_LUO1999_DATASET_LOADER = None +""" +Singleton instance of the *Luo and Rhodes (1999)* +*Corresponding-Colour Datasets* dataset loader. + +_LUO1999_DATASET_LOADER : Luo1999DatasetLoader +""" + + +def build_Luo1999(load=True): + """ + Singleton factory that the builds *Luo and Rhodes (1999)* + *Corresponding-Colour Datasets* dataset loader. + + Parameters + ---------- + load : bool, optional + Whether to load the dataset upon instantiation. + + Returns + ------- + Luo1999DatasetLoader + Singleton instance of the *Luo and Rhodes (1999)* + *Corresponding-Colour Datasets* dataset loader. + + References + ---------- + :cite:`Breneman1987b`, :cite:`Luo1999`, :cite:`McCann1976` + """ + + global _LUO1999_DATASET_LOADER + + if _LUO1999_DATASET_LOADER is None: + _LUO1999_DATASET_LOADER = Luo1999DatasetLoader() + if load: + _LUO1999_DATASET_LOADER.load() + + return _LUO1999_DATASET_LOADER diff --git a/colour_datasets/loaders/tests/resources/Kuopio_Typical.mat b/colour_datasets/loaders/tests/resources/Kuopio_Typical.mat new file mode 100644 index 0000000..67094c2 Binary files /dev/null and b/colour_datasets/loaders/tests/resources/Kuopio_Typical.mat differ diff --git a/colour_datasets/loaders/tests/test_abstract.py b/colour_datasets/loaders/tests/test_abstract.py index 163a835..2dbc6ac 100644 --- a/colour_datasets/loaders/tests/test_abstract.py +++ b/colour_datasets/loaders/tests/test_abstract.py @@ -30,7 +30,7 @@ def test_required_attributes(self): Tests presence of required attributes. """ - required_attributes = ('ID', 'record', 'id', 'data') + required_attributes = ('ID', 'record', 'id', 'content') for attribute in required_attributes: self.assertIn(attribute, dir(AbstractDatasetLoader)) diff --git a/colour_datasets/loaders/tests/test_asano2015.py b/colour_datasets/loaders/tests/test_asano2015.py new file mode 100644 index 0000000..161f0bf --- /dev/null +++ b/colour_datasets/loaders/tests/test_asano2015.py @@ -0,0 +1,139 @@ +# -*- coding: utf-8 -*- +""" +Defines unit tests for :mod:`colour_datasets.loaders.asano2015` module. +""" + +from __future__ import division, unicode_literals + +import numpy as np +import unittest + +from colour import SpectralShape + +from colour_datasets.loaders import Asano2015DatasetLoader, build_Asano2015 + +__author__ = 'Colour Developers' +__copyright__ = 'Copyright (C) 2019 - Colour Developers' +__license__ = 'New BSD License - https://opensource.org/licenses/BSD-3-Clause' +__maintainer__ = 'Colour Developers' +__email__ = 'colour-science@googlegroups.com' +__status__ = 'Production' + +__all__ = ['TestAsano2015DatasetLoader', 'TestBuildAsano2015'] + + +class TestAsano2015DatasetLoader(unittest.TestCase): + """ + Defines :class:`colour_datasets.loaders.asano2015.Asano2015DatasetLoader` + class unit tests methods. + """ + + def test_required_attributes(self): + """ + Tests presence of required attributes. + """ + + required_attributes = ('ID', ) + + for attribute in required_attributes: + self.assertIn(attribute, dir(Asano2015DatasetLoader)) + + def test_required_methods(self): + """ + Tests presence of required methods. + """ + + required_methods = ('load', 'parse_workbook_Asano2015') + + for method in required_methods: + self.assertIn(method, dir(Asano2015DatasetLoader)) + + def test_load(self): + """ + Tests :func:`colour_datasets.loaders.asano2015.Asano2015DatasetLoader.\ +load` method. + """ + + dataset = Asano2015DatasetLoader() + self.assertEqual( + sorted(dataset.load().keys()), + ['Categorical Observers', 'Colour Normal Observers']) + + self.assertEqual( + dataset.content['Categorical Observers'][1].XYZ_2.shape, + SpectralShape(390, 780, 5)) + + np.testing.assert_almost_equal( + dataset.content['Categorical Observers'][1].XYZ_2[390], + np.array([ + 0.003774670254076, + 0.000033807427536, + 0.017705556255144, + ]), + decimal=7) + + np.testing.assert_almost_equal( + dataset.content['Categorical Observers'][10].LMS_10[780], + np.array([ + 0.000101460310461, + 9.67131698024335e-06, + 0.000000000000000, + ]), + decimal=7) + + self.assertAlmostEqual( + dataset.content['Categorical Observers'] + [5].parameters['Shift in S [nm]'], + 0.233255808, + places=7) + + self.assertEqual( + dataset.content['Colour Normal Observers'][1].XYZ_2.shape, + SpectralShape(390, 780, 5)) + + np.testing.assert_almost_equal( + dataset.content['Colour Normal Observers'][1].XYZ_2[390], + np.array([ + 0.001627436785620, + 0.000021871064674, + 0.007492391403616, + ]), + decimal=7) + + np.testing.assert_almost_equal( + dataset.content['Colour Normal Observers'][10].LMS_10[780], + np.array([ + 0.000092440377130, + 6.93870146211108e-06, + 0.000000000000000, + ]), + decimal=7) + + self.assertAlmostEqual( + dataset.content['Colour Normal Observers'] + [5].parameters['Shift in S [nm]'], + 0.000649602695013, + places=7) + + self.assertEqual( + dataset.content['Colour Normal Observers'][151].others['Location'], + 'Darmstadt') + + +class TestBuildAsano2015(unittest.TestCase): + """ + Defines :func:`colour_datasets.loaders.asano2015.build_Asano2015` + definition unit tests methods. + """ + + def test_build_Asano2015(self): + """ + Tests :func:`colour_datasets.loaders.asano2015.build_Asano2015` + definition. + """ + + self.assertIs(build_Asano2015(), build_Asano2015()) + + +if __name__ == '__main__': + unittest.main() diff --git a/colour_datasets/loaders/tests/test_dyer2017.py b/colour_datasets/loaders/tests/test_dyer2017.py new file mode 100644 index 0000000..eaaab8d --- /dev/null +++ b/colour_datasets/loaders/tests/test_dyer2017.py @@ -0,0 +1,167 @@ +# -*- coding: utf-8 -*- +""" +Defines unit tests for :mod:`colour_datasets.loaders.dyer2017` module. +""" + +from __future__ import division, unicode_literals + +import numpy as np +import unittest + +from colour_datasets.loaders import Dyer2017DatasetLoader, build_Dyer2017 + +__author__ = 'Colour Developers' +__copyright__ = 'Copyright (C) 2019 - Colour Developers' +__license__ = 'New BSD License - https://opensource.org/licenses/BSD-3-Clause' +__maintainer__ = 'Colour Developers' +__email__ = 'colour-science@googlegroups.com' +__status__ = 'Production' + +__all__ = ['TestDyer2017DatasetLoader', 'TestBuildDyer2017'] + + +class TestDyer2017DatasetLoader(unittest.TestCase): + """ + Defines :class:`colour_datasets.loaders.dyer2017.Dyer2017DatasetLoader` + class unit tests methods. + """ + + def test_required_attributes(self): + """ + Tests presence of required attributes. + """ + + required_attributes = ('ID', ) + + for attribute in required_attributes: + self.assertIn(attribute, dir(Dyer2017DatasetLoader)) + + def test_required_methods(self): + """ + Tests presence of required methods. + """ + + required_methods = ('load', ) + + for method in required_methods: + self.assertIn(method, dir(Dyer2017DatasetLoader)) + + def test_load(self): + """ + Tests :func:`colour_datasets.loaders.dyer2017.Dyer2017DatasetLoader.\ +load` method. + """ + + dataset = Dyer2017DatasetLoader() + self.assertListEqual( + sorted(dataset.load().keys()), + ['camera', 'cmf', 'illuminant', 'training']) + + np.testing.assert_almost_equal( + dataset.load()['camera']['canon eos 5d mark ii'][555], + np.array([ + 0.165200000000000, + 0.802800000000000, + 0.028300000000000, + ]), + decimal=7) + np.testing.assert_almost_equal( + dataset.load()['cmf']['cie-1931'][555], + np.array([ + 0.512050100000000, + 1.000000000000000, + 0.005749999000000, + ]), + decimal=7) + np.testing.assert_almost_equal( + dataset.load()['illuminant']['iso7589'][555], + np.array([0.485000000000000]), + decimal=7) + np.testing.assert_almost_equal( + dataset.load()['training']['190-patch'][555], + np.array([ + 0.016543747000000, 0.089454049000000, 0.775860114000000, + 0.199500000000000, 0.589294177000000, 0.426983879000000, + 0.299315241000000, 0.195307174000000, 0.113005514000000, + 0.065695622000000, 0.030550537000000, 0.185923210000000, + 0.138998782000000, 0.253323493000000, 0.116890395000000, + 0.059878320000000, 0.386424591000000, 0.242522104000000, + 0.042793898000000, 0.039108407000000, 0.340616303000000, + 0.109391839000000, 0.024575114000000, 0.013437553000000, + 0.165550372000000, 0.044162979000000, 0.038362653000000, + 0.050943800000000, 0.060706606000000, 0.017150009000000, + 0.030958883000000, 0.294163695000000, 0.094815764000000, + 0.013631268000000, 0.011556292000000, 0.102712966000000, + 0.014063110000000, 0.088584881000000, 0.019506551000000, + 0.049543471000000, 0.216543615000000, 0.148685793000000, + 0.426425448000000, 0.066590491000000, 0.185951857000000, + 0.161431933000000, 0.046959872000000, 0.337386898000000, + 0.044950244000000, 0.186142255000000, 0.217803413000000, + 0.176242473000000, 0.180234723000000, 0.573066803000000, + 0.396281106000000, 0.130612404000000, 0.489232284000000, + 0.086611731000000, 0.482820917000000, 0.285489705000000, + 0.390752390000000, 0.553103082000000, 0.761045838000000, + 0.448310405000000, 0.751459057000000, 0.296973364000000, + 0.845515046000000, 0.600851468000000, 0.790979892000000, + 0.116890676000000, 0.471334928000000, 0.796627165000000, + 0.318975867000000, 0.365398300000000, 0.663541772000000, + 0.243604910000000, 0.817055901000000, 0.746637464000000, + 0.142703616000000, 0.060728679000000, 0.244645070000000, + 0.525056690000000, 0.125884506000000, 0.159583709000000, + 0.333025306000000, 0.099145922000000, 0.115960832000000, + 0.142817663000000, 0.105357260000000, 0.154603755000000, + 0.136542750000000, 0.235944300000000, 0.322853029000000, + 0.636786365000000, 0.478067566000000, 0.357385246000000, + 0.233766382000000, 0.313229098000000, 0.470989753000000, + 0.219620176000000, 0.087619811000000, 0.181083141000000, + 0.237307524000000, 0.134183724000000, 0.052929690000000, + 0.335421880000000, 0.355101839000000, 0.051487691000000, + 0.225285679000000, 0.208450311000000, 0.137336941000000, + 0.069794973000000, 0.311496347000000, 0.655141187000000, + 0.092340917000000, 0.446097178000000, 0.595113151000000, + 0.051742762000000, 0.308310085000000, 0.218221361000000, + 0.459776672000000, 0.483055996000000, 0.209489271000000, + 0.270752508000000, 0.581475704000000, 0.150634167000000, + 0.162358582000000, 0.576733107000000, 0.327650514000000, + 0.341401404000000, 0.153771821000000, 0.402136399000000, + 0.079694635000000, 0.068407983000000, 0.534616880000000, + 0.183116936000000, 0.171525933000000, 0.037855717000000, + 0.168182056000000, 0.559997393000000, 0.144518923000000, + 0.108677750000000, 0.075848465000000, 0.106230967000000, + 0.271748990000000, 0.108267178000000, 0.363043033000000, + 0.041006456000000, 0.031950058000000, 0.173380906000000, + 0.359966187000000, 0.044712750000000, 0.100602091000000, + 0.175245406000000, 0.061063126000000, 0.258613296000000, + 0.026866789000000, 0.197704679000000, 0.543435154000000, + 0.113192419000000, 0.267300817000000, 0.135820481000000, + 0.154000795000000, 0.045469997000000, 0.408044588000000, + 0.011999794000000, 0.047949059000000, 0.052502489000000, + 0.065332167000000, 0.151156617000000, 0.132535937000000, + 0.037475628000000, 0.138033009000000, 0.210685187000000, + 0.265259355000000, 0.523381186000000, 0.105874515000000, + 0.164640208000000, 0.109354860000000, 0.437779019000000, + 0.024237616000000, 0.144939306000000, 0.297763330000000, + 0.178469229000000, 0.312304014000000, 0.327352013000000, + 0.026469427000000, 0.431901773000000, 0.015418874000000, + 0.158126080000000 + ]), + decimal=7) + + +class TestBuildDyer2017(unittest.TestCase): + """ + Defines :func:`colour_datasets.loaders.dyer2017.build_Dyer2017` + definition unit tests methods. + """ + + def test_build_Dyer2017(self): + """ + Tests :func:`colour_datasets.loaders.dyer2017.build_Dyer2017` + definition. + """ + + self.assertIs(build_Dyer2017(), build_Dyer2017()) + + +if __name__ == '__main__': + unittest.main() diff --git a/colour_datasets/loaders/tests/test_ebner1998.py b/colour_datasets/loaders/tests/test_ebner1998.py new file mode 100644 index 0000000..5af3d2b --- /dev/null +++ b/colour_datasets/loaders/tests/test_ebner1998.py @@ -0,0 +1,124 @@ +# -*- coding: utf-8 -*- +""" +Defines unit tests for :mod:`colour_datasets.loaders.ebner1998` module. +""" + +from __future__ import division, unicode_literals + +import numpy as np +import unittest + +from colour_datasets.loaders import Ebner1998DatasetLoader, build_Ebner1998 + +__author__ = 'Colour Developers' +__copyright__ = 'Copyright (C) 2019 - Colour Developers' +__license__ = 'New BSD License - https://opensource.org/licenses/BSD-3-Clause' +__maintainer__ = 'Colour Developers' +__email__ = 'colour-science@googlegroups.com' +__status__ = 'Production' + +__all__ = ['TestEbner1998DatasetLoader', 'TestBuildEbner1998'] + + +class TestEbner1998DatasetLoader(unittest.TestCase): + """ + Defines :class:`colour_datasets.loaders.ebner1998.Ebner1998DatasetLoader` + class unit tests methods. + """ + + def test_required_attributes(self): + """ + Tests presence of required attributes. + """ + + required_attributes = ('ID', ) + + for attribute in required_attributes: + self.assertIn(attribute, dir(Ebner1998DatasetLoader)) + + def test_required_methods(self): + """ + Tests presence of required methods. + """ + + required_methods = ('load', ) + + for method in required_methods: + self.assertIn(method, dir(Ebner1998DatasetLoader)) + + def test_load(self): + """ + Tests :func:`colour_datasets.loaders.ebner1998.Ebner1998DatasetLoader.\ +load` method. + """ + + dataset = Ebner1998DatasetLoader() + self.assertListEqual( + sorted(dataset.load().keys()), ['Constant Perceived-Hue Data']) + + self.assertListEqual( + sorted(dataset.load()['Constant Perceived-Hue Data'].keys()), [ + 0, 24, 48, 72, 96, 120, 144, 168, 192, 216, 240, 264, 288, 312, + 336 + ]) + + np.testing.assert_almost_equal( + dataset.load()['Constant Perceived-Hue Data'][96].XYZ_r, + np.array([ + 0.950100000000000, + 1.000000000000000, + 1.088100000000000, + ]), + decimal=7) + np.testing.assert_almost_equal( + dataset.load()['Constant Perceived-Hue Data'][96].XYZ_cr, + np.array([ + 0.518400000000000, + 0.566800000000000, + 0.211200000000000, + ]), + decimal=7) + np.testing.assert_almost_equal( + dataset.load()['Constant Perceived-Hue Data'][96].XYZ_ct, + np.array([ + [0.028909000000000, 0.029891000000000, 0.010142000000000], + [0.059861000000000, 0.062359000000000, 0.028395000000000], + [0.061870000000000, 0.062359000000000, 0.010384000000000], + [0.108221000000000, 0.112510000000000, 0.017582000000000], + [0.138453000000000, 0.145417000000000, 0.084043000000000], + [0.140725000000000, 0.145417000000000, 0.037708000000000], + [0.174718000000000, 0.184187000000000, 0.027642000000000], + [0.266956000000000, 0.281233000000000, 0.186195000000000], + [0.267106000000000, 0.281233000000000, 0.102615000000000], + [0.265222000000000, 0.281233000000000, 0.048764000000000], + [0.378172000000000, 0.407494000000000, 0.060499000000000], + [0.452991000000000, 0.482781000000000, 0.349471000000000], + [0.448363000000000, 0.482781000000000, 0.217887000000000], + [0.444752000000000, 0.482781000000000, 0.124260000000000], + [0.512315000000000, 0.566813000000000, 0.085942000000000], + [0.709748000000000, 0.763034000000000, 0.589282000000000], + [0.701174000000000, 0.763034000000000, 0.398412000000000], + [0.698154000000000, 0.763034000000000, 0.253302000000000], + [0.705383000000000, 0.763034000000000, 0.148054000000000], + [0.704427000000000, 0.763034000000000, 0.112490000000000], + ]), + decimal=7) + + +class TestBuildEbner1998(unittest.TestCase): + """ + Defines :func:`colour_datasets.loaders.ebner1998.build_Ebner1998` + definition unit tests methods. + """ + + def test_build_Ebner1998(self): + """ + Tests :func:`colour_datasets.loaders.ebner1998.build_Ebner1998` + definition. + """ + + self.assertIs(build_Ebner1998(), build_Ebner1998()) + + +if __name__ == '__main__': + unittest.main() diff --git a/colour_datasets/loaders/tests/test_hung1995.py b/colour_datasets/loaders/tests/test_hung1995.py new file mode 100644 index 0000000..5f149e9 --- /dev/null +++ b/colour_datasets/loaders/tests/test_hung1995.py @@ -0,0 +1,110 @@ +# -*- coding: utf-8 -*- +""" +Defines unit tests for :mod:`colour_datasets.loaders.hung1995` module. +""" + +from __future__ import division, unicode_literals + +import numpy as np +import unittest + +from colour_datasets.loaders import Hung1995DatasetLoader, build_Hung1995 + +__author__ = 'Colour Developers' +__copyright__ = 'Copyright (C) 2019 - Colour Developers' +__license__ = 'New BSD License - https://opensource.org/licenses/BSD-3-Clause' +__maintainer__ = 'Colour Developers' +__email__ = 'colour-science@googlegroups.com' +__status__ = 'Production' + +__all__ = ['TestHung1995DatasetLoader', 'TestBuildHung1995'] + + +class TestHung1995DatasetLoader(unittest.TestCase): + """ + Defines :class:`colour_datasets.loaders.hung1995.Hung1995DatasetLoader` + class unit tests methods. + """ + + def test_required_attributes(self): + """ + Tests presence of required attributes. + """ + + required_attributes = ('ID', ) + + for attribute in required_attributes: + self.assertIn(attribute, dir(Hung1995DatasetLoader)) + + def test_required_methods(self): + """ + Tests presence of required methods. + """ + + required_methods = ('load', ) + + for method in required_methods: + self.assertIn(method, dir(Hung1995DatasetLoader)) + + def test_load(self): + """ + Tests :func:`colour_datasets.loaders.hung1995.Hung1995DatasetLoader.\ +load` method. + """ + + dataset = Hung1995DatasetLoader() + self.assertListEqual( + list(dataset.load().keys()), [ + 'Table I', 'Table II', 'Table III', 'Table IV', + 'Constant Hue Loci Data - CL', 'Constant Hue Loci Data - VL' + ]) + self.assertListEqual( + list(dataset.load()['Constant Hue Loci Data - CL'].keys()), [ + 'Red', 'Red-yellow', 'Yellow', 'Yellow-green', 'Green', + 'Green-cyan', 'Cyan', 'Cyan-blue', 'Blue', 'Blue-magenta', + 'Magenta', 'Magenta-red' + ]) + + np.testing.assert_almost_equal( + dataset.load()['Constant Hue Loci Data - CL']['Cyan'].XYZ_r, + np.array([ + 0.980705971659919, + 1.000000000000000, + 1.182249493927126, + ]), + decimal=7) + np.testing.assert_almost_equal( + dataset.load()['Constant Hue Loci Data - CL']['Cyan'].XYZ_cr, + np.array([ + 0.495450736980020, + 0.722700000000000, + 1.149029086144775, + ]), + decimal=7) + np.testing.assert_almost_equal( + dataset.load()['Constant Hue Loci Data - CL']['Cyan'].XYZ_ct, + np.array( + [[0.655100000000000, 0.722700000000000, 0.916200000000000], [ + 0.603500000000000, 0.722700000000000, 0.995100000000000 + ], [0.553100000000000, 0.722700000000000, 1.084400000000000], + [0.495500000000000, 0.722700000000000, 1.149100000000000]]), + decimal=7) + + +class TestBuildHung1995(unittest.TestCase): + """ + Defines :func:`colour_datasets.loaders.hung1995.build_Hung1995` + definition unit tests methods. + """ + + def test_build_Hung1995(self): + """ + Tests :func:`colour_datasets.loaders.hung1995.build_Hung1995` + definition. + """ + + self.assertIs(build_Hung1995(), build_Hung1995()) + + +if __name__ == '__main__': + unittest.main() diff --git a/colour_datasets/loaders/tests/test_jiang2013.py b/colour_datasets/loaders/tests/test_jiang2013.py index db6cc46..f648532 100644 --- a/colour_datasets/loaders/tests/test_jiang2013.py +++ b/colour_datasets/loaders/tests/test_jiang2013.py @@ -65,7 +65,7 @@ def test_load(self): 'Phase One', 'Point Grey Grasshopper 50S5C', 'Point Grey Grasshopper2 14S5C', 'SONY NEX-5N' ]) - self.assertEqual(dataset.data['Canon 1DMarkIII'].shape, + self.assertEqual(dataset.content['Canon 1DMarkIII'].shape, SpectralShape(400, 720, 10)) diff --git a/colour_datasets/loaders/tests/test_kuopio.py b/colour_datasets/loaders/tests/test_kuopio.py new file mode 100644 index 0000000..d439939 --- /dev/null +++ b/colour_datasets/loaders/tests/test_kuopio.py @@ -0,0 +1,3568 @@ +# -*- coding: utf-8 -*- +""" +Defines unit tests for :mod:`colour_datasets.loaders.kuopio` module. +""" + +from __future__ import division, unicode_literals + +import numpy as np +import os +import unittest + +from colour import SpectralShape + +from colour_datasets.loaders.kuopio import ( + KuopioUniversityMatFileMetadata, read_sds_from_mat_file_KuopioUniversity) +from colour_datasets.loaders.kuopio import ( + MunsellColorsMattSpectrofotometerMeasuredDatasetLoader, + MunsellColorsMattAOTFMeasuredDatasetLoader, + MunsellColorsGlossySpectrofotometerMeasuredDatasetLoader, + MunsellColorsGlossyAllSpectrofotometerMeasuredDatasetLoader, + ForestColorsDatasetLoader, PaperSpectraDatasetLoader, + LumberSpectraDatasetLoader, AgfaIT872SetDatasetLoader) + +__author__ = 'Colour Developers' +__copyright__ = 'Copyright (C) 2019 - Colour Developers' +__license__ = 'New BSD License - https://opensource.org/licenses/BSD-3-Clause' +__maintainer__ = 'Colour Developers' +__email__ = 'colour-science@googlegroups.com' +__status__ = 'Production' + +__all__ = [] + + +class TestReadSdsFromMatFileKuopioUniversity(unittest.TestCase): + """ + Defines :func:`colour_datasets.loaders.kuopio.\ +read_sds_from_mat_file_KuopioUniversity` definition unit tests methods. + """ + + def test_read_sds_from_mat_file_KuopioUniversity(self): + """ + Tests :func:`colour_datasets.loaders.kuopio.\ +read_sds_from_mat_file_KuopioUniversity` definition. + """ + + mat_file = os.path.join( + os.path.dirname(__file__), 'resources', 'Kuopio_Typical.mat') + metadata = KuopioUniversityMatFileMetadata('munsell', + SpectralShape(400, 700, 10), + True, 'S') + + sds = read_sds_from_mat_file_KuopioUniversity(mat_file, metadata) + self.assertEqual(len(sds), 32) + + np.testing.assert_array_almost_equal( + sds['5R 6/8 (3)'].values, + np.array([ + 17.870000000000000, + 19.840000000000000, + 19.530000000000000, + 18.730000000000000, + 18.230000000000000, + 17.630000000000000, + 17.040000000000000, + 16.660000000000000, + 15.700000000000000, + 14.080000000000000, + 12.810000000000000, + 12.650000000000000, + 12.110000000000000, + 10.840000000000000, + 10.890000000000000, + 14.260000000000000, + 23.080000000000000, + 33.950000000000000, + 43.500000000000000, + 49.790000000000000, + 52.340000000000000, + 53.170000000000000, + 53.300000000000000, + 53.100000000000000, + 52.960000000000000, + 52.840000000000000, + 52.700000000000000, + 52.480000000000000, + 52.120000000000000, + 51.940000000000000, + 51.890000000000000, + ]), + decimal=7) + + +class KuopioUniversityDatasetLoader(unittest.TestCase): + """ + Defines :class:`colour_datasets.loaders.kuopio.\ +KuopioUniversityDatasetLoader` class unit tests methods. + """ + + def test_required_attributes(self): + """ + Tests presence of required attributes. + """ + + required_attributes = ('ID', 'METADATA') + + for dataset_loader in ( + MunsellColorsMattSpectrofotometerMeasuredDatasetLoader, + MunsellColorsMattAOTFMeasuredDatasetLoader, + MunsellColorsGlossySpectrofotometerMeasuredDatasetLoader, + MunsellColorsGlossyAllSpectrofotometerMeasuredDatasetLoader, + ForestColorsDatasetLoader, PaperSpectraDatasetLoader, + LumberSpectraDatasetLoader, AgfaIT872SetDatasetLoader): + for attribute in required_attributes: + self.assertIn(attribute, dir(dataset_loader)) + + def test_required_methods(self): + """ + Tests presence of required methods. + """ + + required_methods = ('load', ) + + for dataset_loader in ( + MunsellColorsMattSpectrofotometerMeasuredDatasetLoader, + MunsellColorsMattAOTFMeasuredDatasetLoader, + MunsellColorsGlossySpectrofotometerMeasuredDatasetLoader, + MunsellColorsGlossyAllSpectrofotometerMeasuredDatasetLoader, + ForestColorsDatasetLoader, PaperSpectraDatasetLoader, + LumberSpectraDatasetLoader, AgfaIT872SetDatasetLoader): + for method in required_methods: + self.assertIn(method, dir(dataset_loader)) + + def test_load(self): + """ + Tests :func:`colour_datasets.loaders.kuopio.\ +KuopioUniversityDatasetLoader.load` method. + """ + + dataset_loaders = { + MunsellColorsMattSpectrofotometerMeasuredDatasetLoader(): ( + 'munsell', 1269, '2.5R 5/2', + np.array([ + 0.105600000000000, + 0.114100000000000, + 0.117000000000000, + 0.119000000000000, + 0.121900000000000, + 0.124600000000000, + 0.127100000000000, + 0.135200000000000, + 0.137100000000000, + 0.141900000000000, + 0.151300000000000, + 0.155800000000000, + 0.154900000000000, + 0.162200000000000, + 0.166000000000000, + 0.168700000000000, + 0.173300000000000, + 0.174400000000000, + 0.173900000000000, + 0.179700000000000, + 0.182200000000000, + 0.183900000000000, + 0.185500000000000, + 0.184600000000000, + 0.184800000000000, + 0.187700000000000, + 0.184600000000000, + 0.183700000000000, + 0.187600000000000, + 0.186500000000000, + 0.183200000000000, + 0.185800000000000, + 0.184400000000000, + 0.181300000000000, + 0.183800000000000, + 0.181800000000000, + 0.179500000000000, + 0.181900000000000, + 0.180200000000000, + 0.178600000000000, + 0.179600000000000, + 0.176300000000000, + 0.176300000000000, + 0.178100000000000, + 0.175100000000000, + 0.174000000000000, + 0.176300000000000, + 0.173400000000000, + 0.173800000000000, + 0.175500000000000, + 0.171100000000000, + 0.170600000000000, + 0.174300000000000, + 0.171800000000000, + 0.170600000000000, + 0.172800000000000, + 0.172300000000000, + 0.171200000000000, + 0.170900000000000, + 0.169300000000000, + 0.172000000000000, + 0.175300000000000, + 0.171500000000000, + 0.169500000000000, + 0.170800000000000, + 0.167100000000000, + 0.167700000000000, + 0.170100000000000, + 0.165600000000000, + 0.164800000000000, + 0.167500000000000, + 0.164600000000000, + 0.162500000000000, + 0.165500000000000, + 0.162500000000000, + 0.163400000000000, + 0.163600000000000, + 0.161500000000000, + 0.162400000000000, + 0.164500000000000, + 0.162200000000000, + 0.163900000000000, + 0.164900000000000, + 0.162200000000000, + 0.163600000000000, + 0.166100000000000, + 0.162900000000000, + 0.164700000000000, + 0.167400000000000, + 0.164800000000000, + 0.165200000000000, + 0.165400000000000, + 0.164400000000000, + 0.166300000000000, + 0.167600000000000, + 0.163800000000000, + 0.164400000000000, + 0.163600000000000, + 0.162100000000000, + 0.163800000000000, + 0.162900000000000, + 0.158600000000000, + 0.160300000000000, + 0.159100000000000, + 0.155300000000000, + 0.157200000000000, + 0.159000000000000, + 0.154100000000000, + 0.154500000000000, + 0.154600000000000, + 0.151100000000000, + 0.153700000000000, + 0.155000000000000, + 0.151200000000000, + 0.151100000000000, + 0.151300000000000, + 0.149300000000000, + 0.152000000000000, + 0.150700000000000, + 0.148400000000000, + 0.151300000000000, + 0.152600000000000, + 0.149000000000000, + 0.152200000000000, + 0.152700000000000, + 0.149700000000000, + 0.150800000000000, + 0.151100000000000, + 0.148300000000000, + 0.152100000000000, + 0.153100000000000, + 0.150900000000000, + 0.151100000000000, + 0.149300000000000, + 0.148500000000000, + 0.150900000000000, + 0.148300000000000, + 0.145300000000000, + 0.148100000000000, + 0.147000000000000, + 0.144900000000000, + 0.146600000000000, + 0.145300000000000, + 0.143100000000000, + 0.146300000000000, + 0.144400000000000, + 0.141000000000000, + 0.141200000000000, + 0.143700000000000, + 0.142000000000000, + 0.142900000000000, + 0.142400000000000, + 0.142700000000000, + 0.145400000000000, + 0.142900000000000, + 0.141300000000000, + 0.144500000000000, + 0.143700000000000, + 0.143400000000000, + 0.148600000000000, + 0.147500000000000, + 0.147000000000000, + 0.151300000000000, + 0.153100000000000, + 0.150800000000000, + 0.155800000000000, + 0.156400000000000, + 0.158100000000000, + 0.162700000000000, + 0.164600000000000, + 0.165200000000000, + 0.171900000000000, + 0.171900000000000, + 0.173600000000000, + 0.176300000000000, + 0.176800000000000, + 0.178200000000000, + 0.183400000000000, + 0.179800000000000, + 0.177500000000000, + 0.180400000000000, + 0.184800000000000, + 0.191700000000000, + 0.194900000000000, + 0.195100000000000, + 0.193100000000000, + 0.196400000000000, + 0.196700000000000, + 0.195900000000000, + 0.201000000000000, + 0.200100000000000, + 0.197400000000000, + 0.201200000000000, + 0.200500000000000, + 0.198200000000000, + 0.203900000000000, + 0.204700000000000, + 0.201900000000000, + 0.204000000000000, + 0.203800000000000, + 0.202000000000000, + 0.206200000000000, + 0.206600000000000, + 0.204200000000000, + 0.205500000000000, + 0.204700000000000, + 0.205100000000000, + 0.208300000000000, + 0.206300000000000, + 0.204100000000000, + 0.208100000000000, + 0.206600000000000, + 0.203300000000000, + 0.206400000000000, + 0.206400000000000, + 0.203900000000000, + 0.206100000000000, + 0.205400000000000, + 0.202700000000000, + 0.204600000000000, + 0.205300000000000, + 0.204700000000000, + 0.205800000000000, + 0.204600000000000, + 0.204000000000000, + 0.206900000000000, + 0.203500000000000, + 0.202900000000000, + 0.207000000000000, + 0.206200000000000, + 0.203400000000000, + 0.206500000000000, + 0.205500000000000, + 0.204300000000000, + 0.207100000000000, + 0.205100000000000, + 0.202300000000000, + 0.205000000000000, + 0.204100000000000, + 0.203900000000000, + 0.205800000000000, + 0.203500000000000, + 0.203800000000000, + 0.205800000000000, + 0.203200000000000, + 0.201200000000000, + 0.203700000000000, + 0.200600000000000, + 0.201400000000000, + 0.206300000000000, + 0.203100000000000, + 0.201000000000000, + 0.203600000000000, + 0.200500000000000, + 0.199300000000000, + 0.202700000000000, + 0.202300000000000, + 0.201700000000000, + 0.202900000000000, + 0.199900000000000, + 0.199200000000000, + 0.202500000000000, + 0.200400000000000, + 0.199500000000000, + 0.199800000000000, + 0.196400000000000, + 0.197200000000000, + 0.200500000000000, + 0.196800000000000, + 0.196700000000000, + 0.200100000000000, + 0.197800000000000, + 0.195700000000000, + 0.198500000000000, + 0.196500000000000, + 0.197100000000000, + 0.198400000000000, + 0.195900000000000, + 0.196400000000000, + 0.200200000000000, + 0.198300000000000, + 0.199400000000000, + 0.198500000000000, + 0.193700000000000, + 0.195300000000000, + 0.198400000000000, + 0.193300000000000, + 0.193800000000000, + 0.197200000000000, + 0.193900000000000, + 0.194700000000000, + 0.197300000000000, + 0.195000000000000, + 0.197700000000000, + 0.200700000000000, + 0.197100000000000, + 0.196300000000000, + 0.197700000000000, + 0.196800000000000, + 0.197300000000000, + 0.198000000000000, + 0.193900000000000, + 0.195300000000000, + 0.196100000000000, + 0.192900000000000, + 0.195100000000000, + 0.196100000000000, + 0.188600000000000, + 0.187100000000000, + 0.192700000000000, + 0.195800000000000, + 0.194800000000000, + 0.196100000000000, + 0.192200000000000, + 0.195100000000000, + 0.196500000000000, + 0.192600000000000, + 0.195000000000000, + 0.195500000000000, + 0.193100000000000, + 0.193200000000000, + 0.194200000000000, + 0.191800000000000, + 0.194500000000000, + 0.193600000000000, + 0.191100000000000, + 0.193100000000000, + 0.192800000000000, + 0.190600000000000, + 0.193600000000000, + 0.192400000000000, + 0.189900000000000, + 0.192900000000000, + 0.193900000000000, + 0.191700000000000, + 0.194700000000000, + 0.195900000000000, + 0.192400000000000, + 0.192900000000000, + 0.193100000000000, + 0.192200000000000, + 0.195700000000000, + 0.195500000000000, + 0.192200000000000, + 0.195100000000000, + 0.193600000000000, + 0.192300000000000, + 0.196200000000000, + 0.196100000000000, + 0.193800000000000, + 0.198400000000000, + 0.196900000000000, + 0.192900000000000, + 0.196300000000000, + 0.196800000000000, + 0.194800000000000, + 0.195600000000000, + 0.194600000000000, + 0.193700000000000, + 0.196900000000000, + 0.196100000000000, + 0.194800000000000, + 0.196700000000000, + 0.193900000000000, + 0.193400000000000, + 0.197000000000000, + 0.193000000000000, + 0.192200000000000, + 0.196000000000000, + 0.193800000000000, + 0.191800000000000, + 0.194000000000000, + 0.193500000000000, + 0.191000000000000, + 0.192300000000000, + 0.190700000000000, + 0.189500000000000, + 0.191700000000000, + 0.189900000000000, + 0.191200000000000, + 0.192400000000000, + 0.189600000000000, + 0.189500000000000, + 0.193200000000000, + 0.191200000000000, + 0.188600000000000, + 0.192800000000000, + 0.191700000000000, + 0.190800000000000, + 0.194300000000000, + 0.191600000000000, + 0.190400000000000, + 0.192700000000000, + 0.191000000000000, + 0.189300000000000, + 0.192200000000000, + 0.190200000000000, + 0.190100000000000, + 0.192900000000000, + 0.191300000000000, + 0.192900000000000, + 0.196700000000000, + 0.191600000000000, + 0.192400000000000, + 0.195900000000000, + 0.189600000000000, + 0.188700000000000, + 0.192400000000000, + 0.193200000000000, + 0.193000000000000, + 0.193400000000000, + 0.190200000000000, + 0.192200000000000, + 0.193100000000000, + 0.190000000000000, + 0.191000000000000, + 0.192500000000000, + 0.190200000000000, + 0.191300000000000, + 0.192700000000000, + 0.190000000000000, + ])), + MunsellColorsMattAOTFMeasuredDatasetLoader(): ( + 'munsell', 1250, '10bV50C01.NM5', + np.array([ + 0.363525390625000, + 0.486328125000000, + 0.262451171875000, + 0.270263671875000, + 0.278076171875000, + 0.293945312500000, + 0.272705078125000, + 0.253417968750000, + 0.272216796875000, + 0.255859375000000, + 0.260498046875000, + 0.253906250000000, + 0.256591796875000, + 0.248535156250000, + 0.245849609375000, + 0.243408203125000, + 0.247802734375000, + 0.240234375000000, + 0.247314453125000, + 0.243164062500000, + 0.237548828125000, + 0.238525390625000, + 0.230957031250000, + 0.227050781250000, + 0.231689453125000, + 0.232421875000000, + 0.228027343750000, + 0.223876953125000, + 0.224853515625000, + 0.219726562500000, + 0.220703125000000, + 0.218994140625000, + 0.216552734375000, + 0.217529296875000, + 0.217041015625000, + 0.213134765625000, + 0.212402343750000, + 0.204833984375000, + 0.210205078125000, + 0.205810546875000, + 0.201416015625000, + 0.202392578125000, + 0.200439453125000, + 0.198730468750000, + 0.197998046875000, + 0.193359375000000, + 0.192871093750000, + 0.193115234375000, + 0.192626953125000, + 0.188476562500000, + 0.189208984375000, + 0.185058593750000, + 0.185546875000000, + 0.186035156250000, + 0.183349609375000, + 0.183105468750000, + 0.181884765625000, + 0.178222656250000, + 0.175292968750000, + 0.169921875000000, + 0.175048828125000, + ])), + MunsellColorsGlossySpectrofotometerMeasuredDatasetLoader(): ( + 'munsell', 32, '5R 5/6', + np.array([ + 12.660000000000000, + 13.540000000000000, + 12.990000000000000, + 12.260000000000000, + 11.910000000000000, + 11.580000000000000, + 11.360000000000000, + 11.430000000000000, + 10.910000000000000, + 9.8000000000000000, + 9.1100000000000000, + 9.1400000000000000, + 8.5200000000000000, + 7.4800000000000000, + 8.1600000000000000, + 11.190000000000000, + 15.190000000000000, + 18.460000000000000, + 23.560000000000000, + 29.770000000000000, + 33.250000000000000, + 34.400000000000000, + 34.540000000000000, + 34.350000000000000, + 34.200000000000000, + 34.050000000000000, + 33.800000000000000, + 33.560000000000000, + 33.290000000000000, + 33.080000000000000, + 32.910000000000000, + ])), + MunsellColorsGlossyAllSpectrofotometerMeasuredDatasetLoader(): ( + 'X', 1600, '5', + np.array([ + 0.0832583349355893, + 0.0841964216140708, + 0.0854254747054747, + 0.0864870564212114, + 0.0885143682165685, + 0.0905455902475432, + 0.0915811880405238, + 0.0935670213290593, + 0.0953374607500153, + 0.0969212265220306, + 0.0988861173336562, + 0.1011019151764140, + 0.1027070137118110, + 0.1045144157706090, + 0.1066298320094840, + 0.1078871227364190, + 0.1097310323760100, + 0.1114069239380190, + 0.1121451511457540, + 0.1134318032825190, + 0.1141553695955370, + 0.1148042526315790, + 0.1151973800818870, + 0.1163717178232080, + 0.1153836989247310, + 0.1163973344056990, + 0.1164192531233960, + 0.1176007052049480, + 0.1185813542341110, + 0.1188167084135430, + 0.1188947903717930, + 0.1194576529747440, + 0.1206333985004790, + 0.1203924436437340, + 0.1212710711071110, + 0.1208673887423540, + 0.1215377256924970, + 0.1218716508912110, + 0.1213794497567520, + 0.1217316822846940, + 0.1216057200200700, + 0.1220691362725450, + 0.1223934228755990, + 0.1226491662040630, + 0.1222738901730910, + 0.1235775559991130, + 0.1240115273049840, + 0.1245753981184280, + 0.1249519072803720, + 0.1251793875497570, + 0.1253437823548850, + 0.1259486272019440, + 0.1259670591996470, + 0.1261504072273180, + 0.1270547857142860, + 0.1275530353200880, + 0.1278131387343720, + 0.1280998512642540, + 0.1287212301001870, + 0.1289580095830810, + 0.1290085828891700, + 0.1304132516826660, + 0.1309290648193960, + 0.1315601250826540, + 0.1320659696068720, + 0.1328932240677590, + 0.1336453489265910, + 0.1340303717553890, + 0.1347657294298580, + 0.1352923279986800, + 0.1360370366290280, + 0.1365566273001920, + 0.1375466104152930, + 0.1380393871162610, + 0.1391758261775510, + 0.1393372198783630, + 0.1403947401936650, + 0.1410517545489320, + 0.1420981132075470, + 0.1424267063197030, + 0.1431591745373150, + 0.1439438302804960, + 0.1449724509333040, + 0.1457406097108570, + 0.1466319866826770, + 0.1477144227624550, + 0.1491561375701750, + 0.1499657283479590, + 0.1508730084930310, + 0.1524472420812020, + 0.1538901500326160, + 0.1551999854276550, + 0.1564189116238570, + 0.1575284381833020, + 0.1588692308277620, + 0.1593696495517520, + 0.1605326245110820, + 0.1618569582133350, + 0.1624176661422450, + 0.1634395257586450, + 0.1635596262494570, + 0.1647163760720880, + 0.1653961094581390, + 0.1659311061379690, + 0.1668263889643190, + 0.1664016268098260, + 0.1663602603460430, + 0.1672364293227780, + 0.1676109344315600, + 0.1680388326738580, + 0.1677260481471460, + 0.1674615913396480, + 0.1674423665261110, + 0.1669457804244260, + 0.1667212939521800, + 0.1666681862479700, + 0.1661996093893670, + 0.1660631997190860, + 0.1650462213562810, + 0.1644598642563330, + 0.1639480785837650, + 0.1629394804605160, + 0.1618968264677260, + 0.1607553251918300, + 0.1599774502784840, + 0.1592006389084410, + 0.1577751116168180, + 0.1567381133546260, + 0.1558041359727410, + 0.1546063862270590, + 0.1532839006439740, + 0.1522304826541110, + 0.1510174361195320, + 0.1495370270065490, + 0.1482986794128800, + 0.1471751082251080, + 0.1459533303020460, + 0.1448406104887160, + 0.1432260271395360, + 0.1420294881655200, + 0.1407796123863140, + 0.1394713345247770, + 0.1383847867252320, + 0.1367663760554230, + 0.1353930054621170, + 0.1340665548764000, + 0.1326094541324100, + 0.1314476955556760, + 0.1300619568392020, + 0.1286112691620170, + 0.1270600768689440, + 0.1256763453237410, + 0.1247108740387740, + 0.1233902828348500, + 0.1219225162024490, + 0.1203756671729230, + 0.1193858886718750, + 0.1187244485879990, + 0.1172117915401300, + 0.1163088532870850, + 0.1148534423920700, + 0.1134792034486500, + 0.1125721330001090, + 0.1113368023192800, + 0.1101989148244470, + 0.1091195956961200, + 0.1083813403562120, + 0.1071390462089160, + 0.1061137185040440, + 0.1049129130387580, + 0.1043954382535030, + 0.1031281954323000, + 0.1021073306429620, + 0.1010716444082520, + 0.1004949793702500, + 0.0995802646626368, + 0.0984846824799607, + 0.0976298555319497, + 0.0964366697093181, + 0.0959713445121951, + 0.0946097380316976, + 0.0940169040274674, + 0.0931408770974068, + 0.0925075464007411, + 0.0919924512854102, + 0.0911384338532010, + 0.0904112434318108, + 0.0898916765781003, + 0.0889631941324027, + 0.0886735681284474, + 0.0881560421558456, + 0.0874990131233596, + 0.0870141730990311, + 0.0865602858079677, + 0.0866091052286152, + 0.0860980602739726, + 0.0854415269900361, + 0.0852274163424125, + 0.0846683259332347, + 0.0846999037966362, + 0.0846302515481997, + 0.0837975875576037, + 0.0838024112149533, + 0.0835321230735480, + 0.0829661160327131, + 0.0827144267149202, + 0.0827143225629190, + 0.0820904100032906, + 0.0820583758300862, + 0.0819189005552196, + 0.0810632600471517, + 0.0810455174001206, + 0.0807908284431793, + 0.0804156337410190, + 0.0805326402629417, + 0.0800952396585686, + 0.0796956921896410, + 0.0793305183644425, + 0.0789345770872087, + 0.0784959303128253, + 0.0783585716629300, + 0.0780296335618316, + 0.0776355686360401, + 0.0777728303000492, + 0.0771084880319877, + 0.0769203308138898, + 0.0765511326039387, + 0.0762573573616277, + 0.0762127566381391, + 0.0760990485894276, + 0.0759584208223972, + 0.0755359285636025, + 0.0756633663670248, + 0.0752572122010094, + 0.0758166600909639, + 0.0750690017513135, + 0.0752405613919895, + 0.0750479940841367, + 0.0752528940517383, + 0.0749732792022792, + 0.0751002570131788, + 0.0750104604924056, + 0.0749880663745893, + 0.0752553795596451, + 0.0753496369021501, + 0.0753240486895493, + 0.0749273240054870, + 0.0755281749629548, + 0.0757077530932087, + 0.0758634115061267, + 0.0756506801228609, + 0.0760071605101143, + 0.0762060860026327, + 0.0759151579640193, + 0.0760791654510557, + 0.0761815485996705, + 0.0765150256522692, + 0.0762693840004381, + 0.0764163189645717, + 0.0764907408057002, + 0.0768342669584245, + 0.0771621960440524, + 0.0770743948220065, + 0.0770292538916904, + 0.0771631784423267, + 0.0774133684557129, + 0.0772509793050447, + 0.0776359754048861, + 0.0776684550740538, + 0.0775999245903436, + 0.0775543019880607, + 0.0775452066523959, + 0.0779931107448912, + 0.0779379115287394, + 0.0777371116127967, + 0.0777113861657265, + 0.0783069040254470, + 0.0777791275336913, + 0.0778322734546252, + 0.0782278086575343, + 0.0781885667306111, + 0.0779885797133166, + 0.0778922203584937, + 0.0777887903693571, + 0.0781322884794139, + 0.0778500300990532, + 0.0783473231527094, + 0.0781106787355065, + 0.0774791683038638, + 0.0774638428430621, + 0.0776397440804944, + 0.0778363414820891, + 0.0773739737159128, + 0.0771565329105620, + 0.0774208283325135, + 0.0773433725061492, + 0.0769061458287716, + 0.0768768537704918, + 0.0767942762841530, + 0.0766405641193834, + 0.0768223210852969, + 0.0756511902310809, + 0.0760848653489134, + 0.0758909124746839, + 0.0757557372797899, + 0.0755393640350877, + 0.0755921310541311, + 0.0759533260309984, + 0.0755523312534209, + 0.0758025853417513, + 0.0754538890712176, + 0.0759966492343413, + 0.0756392191463549, + 0.0760002427745665, + 0.0759172330727733, + 0.0760517874821252, + 0.0761247379087473, + 0.0767259722054381, + 0.0763790106863501, + 0.0764716400109619, + 0.0764261489525063, + 0.0764849258345667, + 0.0770762127916552, + 0.0770786163439449, + 0.0777177075901432, + 0.0779242324199406, + 0.0779871221093106, + 0.0782395180299033, + 0.0780202550409318, + 0.0784945261194030, + 0.0789988898659046, + 0.0787182916666667, + 0.0795837732500822, + 0.0803447880449685, + 0.0798549101363562, + 0.0801640755957272, + 0.0806020982436883, + 0.0807538561632564, + 0.0815723849317322, + 0.0814840643355108, + 0.0818510493352379, + 0.0819726217696014, + 0.0822825937877291, + 0.0826006385614824, + 0.0832230251162791, + 0.0832401884518462, + 0.0837584412217095, + 0.0840583776960650, + 0.0838307027945206, + 0.0846559244351832, + 0.0854320944276695, + 0.0859695935852373, + 0.0860562020024205, + 0.0868489965268207, + 0.0869247383567663, + 0.0877802062760588, + 0.0889851523971662, + 0.0886742533164529, + 0.0894202225519288, + 0.0903602252401458, + 0.0913718090645038, + 0.0926356862097440, + 0.0927020975529644, + 0.0934591620557682, + 0.0942531088738516, + 0.0957034433521885, + 0.0966463331682351, + 0.0970120648886445, + 0.0982979563203177, + 0.0993772702256467, + 0.1001024339091560, + 0.1006514627853130, + 0.1021924514103130, + 0.1032385466651990, + 0.1042875362287090, + 0.1054265632733870, + 0.1065878370941110, + 0.1078802324765710, + 0.1085841372602890, + 0.1096687124910860, + 0.1103224411182040, + 0.1116595158900050, + 0.1135477486645740, + 0.1144331781621860, + 0.1143250851485150, + 0.1156502670851920, + 0.1175013129411760, + 0.1179270310695630, + 0.1182087558274100, + 0.1191784615553600, + 0.1209157444943570, + 0.1216799742574260, + 0.1230600100148570, + 0.1251525243466300, + 0.1264191929573590, + 0.1278286560939470, + 0.1295155392232370, + 0.1325001371944510, + 0.1325402033842440, + 0.1334973586771410, + 0.1362069264544460, + ])), + ForestColorsDatasetLoader(): ('pine', 370, '5', + np.array([ + 0.010262410000000, + 0.009839101400000, + 0.012529907000000, + 0.011030105000000, + 0.010073634000000, + 0.011320871000000, + 0.011616203000000, + 0.013212691000000, + 0.012491421000000, + 0.011912613000000, + 0.013115942000000, + 0.013417573000000, + 0.013631902000000, + 0.013967374000000, + 0.014361868000000, + 0.014427279000000, + 0.014636329000000, + 0.014908329000000, + 0.014993297000000, + 0.015136227000000, + 0.015386547000000, + 0.015711171000000, + 0.015828966000000, + 0.016981529000000, + 0.018321589000000, + 0.019439448000000, + 0.021571993000000, + 0.023876195000000, + 0.025659029000000, + 0.026894433000000, + 0.028889134000000, + 0.030469200000000, + 0.030692223000000, + 0.031212534000000, + 0.030800426000000, + 0.029837495000000, + 0.029041031000000, + 0.027807930000000, + 0.027085866000000, + 0.026870222000000, + 0.026034403000000, + 0.025490563000000, + 0.025915747000000, + 0.025255465000000, + 0.024883133000000, + 0.024609150000000, + 0.023686946000000, + 0.023991298000000, + 0.023958765000000, + 0.023967050000000, + 0.023539582000000, + 0.022725872000000, + 0.022347244000000, + 0.022138569000000, + 0.021979660000000, + 0.020823906000000, + 0.021076211000000, + 0.021165034000000, + 0.022165784000000, + 0.025146573000000, + 0.029714434000000, + 0.039837663000000, + 0.052246223000000, + 0.067425578000000, + 0.083176671000000, + 0.097080232000000, + 0.111191460000000, + 0.122961630000000, + 0.134962030000000, + 0.143059710000000, + 0.149133660000000, + 0.155173970000000, + 0.155457870000000, + 0.159591120000000, + 0.164270350000000, + 0.165211360000000, + 0.167401470000000, + 0.167736380000000, + 0.169301000000000, + 0.170914620000000, + 0.171809910000000, + 0.172325160000000, + 0.174672460000000, + 0.176431510000000, + 0.174736990000000, + 0.177491730000000, + 0.176703620000000, + 0.177523560000000, + 0.182620180000000, + 0.182529490000000, + 0.183265810000000, + 0.183518600000000, + 0.186661620000000, + ])), + PaperSpectraDatasetLoader(): ('newsprintsce', 36, '5', + np.array([ + 28.430000000000000, + 37.390000000000000, + 44.860000000000000, + 48.860000000000000, + 51.120000000000000, + 52.330000000000000, + 53.140000000000000, + 53.930000000000000, + 54.620000000000000, + 55.090000000000000, + 54.890000000000000, + 53.670000000000000, + 51.830000000000000, + 50.610000000000000, + 48.660000000000000, + 45.180000000000000, + 43.640000000000000, + 48.450000000000000, + 58.400000000000000, + 67.180000000000000, + 69.940000000000000, + 69.630000000000000, + 69.300000000000000, + 69.340000000000000, + 69.370000000000000, + 69.190000000000000, + 68.880000000000000, + 68.610000000000000, + 68.290000000000000, + 68.250000000000000, + 68.230000000000000, + ])), + LumberSpectraDatasetLoader(): ('birchWp', 12, '5', + np.array([ + 0.044233333000000, + 0.045133333000000, + 0.045233333000000, + 0.046333333000000, + 0.046833333000000, + 0.047633333000000, + 0.048733333000000, + 0.049633333000000, + 0.049933333000000, + 0.051733333000000, + 0.052733333000000, + 0.053133333000000, + 0.053833333000000, + 0.054633333000000, + 0.055433333000000, + 0.056333333000000, + 0.056833333000000, + 0.058033333000000, + 0.058433333000000, + 0.059633333000000, + 0.059933333000000, + 0.060433333000000, + 0.061033333000000, + 0.063233333000000, + 0.063833333000000, + 0.064133333000000, + 0.064133333000000, + 0.065533333000000, + 0.066533333000000, + 0.067033333000000, + 0.067833333000000, + 0.068233333000000, + 0.068633333000000, + 0.069933333000000, + 0.070033333000000, + 0.071533333000000, + 0.071933333000000, + 0.072433333000000, + 0.072933333000000, + 0.073833333000000, + 0.074433333000000, + 0.074933333000000, + 0.075833333000000, + 0.076233333000000, + 0.076833333000000, + 0.077233333000000, + 0.077933333000000, + 0.078133333000000, + 0.078133333000000, + 0.079933333000000, + 0.080333333000000, + 0.080833333000000, + 0.081333333000000, + 0.081633333000000, + 0.082433333000000, + 0.083733333000000, + 0.083833333000000, + 0.084233333000000, + 0.085033333000000, + 0.085733333000000, + 0.085733333000000, + 0.086333333000000, + 0.086733333000000, + 0.087433333000000, + 0.088133333000000, + 0.089033333000000, + 0.089433333000000, + 0.089733333000000, + 0.090033333000000, + 0.090333333000000, + 0.090833333000000, + 0.091533333000000, + 0.092233333000000, + 0.092633333000000, + 0.092833333000000, + 0.093333333000000, + 0.094133333000000, + 0.094833333000000, + 0.095133333000000, + 0.095833333000000, + 0.096233333000000, + 0.097133333000000, + 0.096833333000000, + 0.097733333000000, + 0.098133333000000, + 0.098933333000000, + 0.099233333000000, + 0.099633333000000, + 0.100333330000000, + 0.101433330000000, + 0.101933330000000, + 0.102533330000000, + 0.102933330000000, + 0.103633330000000, + 0.103533330000000, + 0.104533330000000, + 0.104833330000000, + 0.105833330000000, + 0.106133330000000, + 0.106933330000000, + 0.106733330000000, + 0.107733330000000, + 0.108033330000000, + 0.108133330000000, + 0.108533330000000, + 0.109633330000000, + 0.109833330000000, + 0.110533330000000, + 0.111133330000000, + 0.111633330000000, + 0.111533330000000, + 0.111833330000000, + 0.113033330000000, + 0.112833330000000, + 0.113333330000000, + 0.114033330000000, + 0.114333330000000, + 0.115233330000000, + 0.116033330000000, + 0.116433330000000, + 0.116933330000000, + 0.117333330000000, + 0.117733330000000, + 0.118633330000000, + 0.118933330000000, + 0.119633330000000, + 0.119833330000000, + 0.120733330000000, + 0.121233330000000, + 0.121833330000000, + 0.122333330000000, + 0.123133330000000, + 0.123633330000000, + 0.124133330000000, + 0.124433330000000, + 0.125233330000000, + 0.125533330000000, + 0.126033330000000, + 0.126633330000000, + 0.127033330000000, + 0.127533330000000, + 0.128033330000000, + 0.128033330000000, + 0.128833330000000, + 0.129233330000000, + 0.129433330000000, + 0.130233330000000, + 0.130833330000000, + 0.130933330000000, + 0.131833330000000, + 0.132033330000000, + 0.132433330000000, + 0.133233330000000, + 0.134233330000000, + 0.134133330000000, + 0.134533330000000, + 0.135033330000000, + 0.135433330000000, + 0.136133330000000, + 0.136033330000000, + 0.136933330000000, + 0.137733330000000, + 0.138333330000000, + 0.138533330000000, + 0.139133330000000, + 0.139633330000000, + 0.139933330000000, + 0.140133330000000, + 0.140633330000000, + 0.141433330000000, + 0.141633330000000, + 0.142433330000000, + 0.142733330000000, + 0.143933330000000, + 0.143633330000000, + 0.144233330000000, + 0.144533330000000, + 0.145333330000000, + 0.145233330000000, + 0.145933330000000, + 0.146233330000000, + 0.147133330000000, + 0.147233330000000, + 0.147533330000000, + 0.148133330000000, + 0.148733330000000, + 0.148933330000000, + 0.149533330000000, + 0.149933330000000, + 0.150733330000000, + 0.151333330000000, + 0.151633330000000, + 0.152133330000000, + 0.152033330000000, + 0.152233330000000, + 0.152333330000000, + 0.153233330000000, + 0.153833330000000, + 0.154433330000000, + 0.154333330000000, + 0.154633330000000, + 0.155433330000000, + 0.155433330000000, + 0.155333330000000, + 0.155833330000000, + 0.156833330000000, + 0.157433330000000, + 0.158033330000000, + 0.158533330000000, + 0.158933330000000, + 0.158833330000000, + 0.158533330000000, + 0.158533330000000, + 0.160633330000000, + 0.161133330000000, + 0.160933330000000, + 0.161633330000000, + 0.162033330000000, + 0.162333330000000, + 0.163033330000000, + 0.163333330000000, + 0.163433330000000, + 0.163833330000000, + 0.163933330000000, + 0.164333330000000, + 0.165433330000000, + 0.165733330000000, + 0.166033330000000, + 0.166333330000000, + 0.166433330000000, + 0.166533330000000, + 0.167833330000000, + 0.167933330000000, + 0.167733330000000, + 0.168233330000000, + 0.168333330000000, + 0.168533330000000, + 0.169333330000000, + 0.169533330000000, + 0.170333330000000, + 0.170033330000000, + 0.171033330000000, + 0.170433330000000, + 0.171233330000000, + 0.171533330000000, + 0.172233330000000, + 0.172133330000000, + 0.172233330000000, + 0.172733330000000, + 0.173533330000000, + 0.174033330000000, + 0.174133330000000, + 0.175033330000000, + 0.175433330000000, + 0.175733330000000, + 0.176133330000000, + 0.175733330000000, + 0.175833330000000, + 0.175733330000000, + 0.176833330000000, + 0.176733330000000, + 0.177033330000000, + 0.176933330000000, + 0.177233330000000, + 0.178233330000000, + 0.178933330000000, + 0.178533330000000, + 0.180033330000000, + 0.180233330000000, + 0.180633330000000, + 0.180633330000000, + 0.181433330000000, + 0.180433330000000, + 0.180833330000000, + 0.181233330000000, + 0.181033330000000, + 0.181233330000000, + 0.182333330000000, + 0.181833330000000, + 0.182133330000000, + 0.183333330000000, + 0.182333330000000, + 0.182633330000000, + 0.183533330000000, + 0.183833330000000, + 0.183933330000000, + 0.183433330000000, + 0.184733330000000, + 0.184633330000000, + 0.185033330000000, + 0.185433330000000, + 0.186033330000000, + 0.185833330000000, + 0.186833330000000, + 0.185733330000000, + 0.186433330000000, + 0.187033330000000, + 0.187333330000000, + 0.187433330000000, + 0.187833330000000, + 0.187433330000000, + 0.186333330000000, + 0.186933330000000, + 0.188433330000000, + 0.188433330000000, + 0.188833330000000, + 0.189333330000000, + 0.190133330000000, + 0.189633330000000, + 0.190433330000000, + 0.190133330000000, + 0.190733330000000, + 0.190033330000000, + 0.189933330000000, + 0.190433330000000, + 0.190433330000000, + 0.190933330000000, + 0.191633330000000, + 0.191833330000000, + 0.191933330000000, + 0.191733330000000, + 0.191233330000000, + 0.192333330000000, + 0.192833330000000, + 0.193233330000000, + 0.193633330000000, + 0.193633330000000, + 0.193033330000000, + 0.192933330000000, + 0.192833330000000, + 0.193533330000000, + 0.193433330000000, + 0.193733330000000, + 0.193833330000000, + 0.194333330000000, + 0.194033330000000, + 0.195133330000000, + 0.195033330000000, + 0.194933330000000, + 0.196233330000000, + 0.197033330000000, + 0.196833330000000, + 0.197333330000000, + 0.195533330000000, + 0.195733330000000, + 0.197233330000000, + 0.198333330000000, + 0.196433330000000, + 0.197233330000000, + 0.196833330000000, + 0.197433330000000, + 0.197033330000000, + 0.196833330000000, + 0.198433330000000, + 0.198233330000000, + 0.198233330000000, + 0.198533330000000, + 0.198233330000000, + 0.197833330000000, + 0.199133330000000, + 0.199233330000000, + 0.199333330000000, + 0.199433330000000, + 0.200133330000000, + 0.200133330000000, + 0.200533330000000, + 0.199433330000000, + 0.200633330000000, + 0.200633330000000, + 0.200233330000000, + 0.199833330000000, + 0.200133330000000, + 0.201433330000000, + 0.202233330000000, + 0.201333330000000, + 0.201233330000000, + 0.201433330000000, + 0.201833330000000, + 0.201533330000000, + 0.203233330000000, + 0.202333330000000, + 0.201433330000000, + 0.203333330000000, + 0.202733330000000, + 0.202533330000000, + 0.202633330000000, + 0.203533330000000, + 0.203433330000000, + 0.202633330000000, + 0.203133330000000, + 0.203233330000000, + 0.204533330000000, + 0.204533330000000, + 0.203533330000000, + 0.203133330000000, + 0.202633330000000, + 0.203133330000000, + 0.204433330000000, + 0.205033330000000, + 0.205533330000000, + 0.204733330000000, + 0.206333330000000, + 0.205633330000000, + 0.207733330000000, + 0.207133330000000, + 0.207233330000000, + 0.206933330000000, + 0.206833330000000, + 0.209133330000000, + 0.207533330000000, + 0.207733330000000, + 0.208333330000000, + 0.208333330000000, + 0.206133330000000, + 0.207433330000000, + 0.209033330000000, + 0.209233330000000, + 0.208633330000000, + 0.207733330000000, + 0.210233330000000, + 0.209633330000000, + 0.208833330000000, + 0.210233330000000, + 0.209633330000000, + 0.210133330000000, + 0.211033330000000, + 0.210733330000000, + 0.210133330000000, + 0.210533330000000, + 0.208633330000000, + 0.209033330000000, + 0.209733330000000, + 0.210533330000000, + 0.210033330000000, + 0.208433330000000, + 0.210433330000000, + 0.210933330000000, + 0.209633330000000, + 0.210233330000000, + 0.212233330000000, + 0.212433330000000, + 0.211433330000000, + 0.212133330000000, + 0.212733330000000, + 0.211533330000000, + 0.212033330000000, + 0.211333330000000, + 0.209733330000000, + 0.210433330000000, + 0.211233330000000, + 0.212533330000000, + 0.211533330000000, + 0.211733330000000, + 0.210133330000000, + 0.210033330000000, + 0.210833330000000, + 0.211333330000000, + 0.211233330000000, + 0.213733330000000, + 0.211133330000000, + 0.211533330000000, + 0.214833330000000, + 0.211433330000000, + 0.214633330000000, + 0.214433330000000, + 0.214833330000000, + 0.216733330000000, + 0.215833330000000, + 0.214833330000000, + 0.219333330000000, + 0.216833330000000, + 0.215333330000000, + 0.215433330000000, + 0.217633330000000, + 0.216033330000000, + 0.215233330000000, + 0.217533330000000, + 0.216933330000000, + 0.215733330000000, + 0.209633330000000, + 0.209633330000000, + 0.216766670000000, + 0.217466670000000, + 0.215466670000000, + 0.215566670000000, + 0.214766670000000, + 0.213066670000000, + 0.212366670000000, + 0.212866670000000, + 0.213166670000000, + 0.211066670000000, + 0.212366670000000, + 0.213066670000000, + 0.211666670000000, + 0.209966670000000, + 0.209366670000000, + 0.210766670000000, + 0.210066670000000, + 0.210666670000000, + 0.211766670000000, + 0.208966670000000, + 0.208266670000000, + 0.210366670000000, + 0.210866670000000, + 0.209366670000000, + 0.208966670000000, + 0.209966670000000, + 0.208166670000000, + 0.207166670000000, + 0.208766670000000, + 0.208566670000000, + 0.207566670000000, + 0.205666670000000, + 0.206166670000000, + 0.206366670000000, + 0.206166670000000, + 0.206166670000000, + 0.205766670000000, + 0.204866670000000, + 0.206066670000000, + 0.205466670000000, + 0.205066670000000, + 0.204566670000000, + 0.204266670000000, + 0.204366670000000, + 0.203666670000000, + 0.203366670000000, + 0.202066670000000, + 0.202266670000000, + 0.203866670000000, + 0.203166670000000, + 0.202866670000000, + 0.201966670000000, + 0.201166670000000, + 0.201266670000000, + 0.201266670000000, + 0.200966670000000, + 0.200766670000000, + 0.200766670000000, + 0.201266670000000, + 0.200766670000000, + 0.200066670000000, + 0.199766670000000, + 0.199366670000000, + 0.199366670000000, + 0.199466670000000, + 0.199066670000000, + 0.198466670000000, + 0.198366670000000, + 0.198466670000000, + 0.198266670000000, + 0.197966670000000, + 0.198066670000000, + 0.197266670000000, + 0.196866670000000, + 0.196566670000000, + 0.196666670000000, + 0.196266670000000, + 0.195366670000000, + 0.195366670000000, + 0.195166670000000, + 0.194066670000000, + 0.193666670000000, + 0.193266670000000, + 0.193066670000000, + 0.192266670000000, + 0.192066670000000, + 0.191766670000000, + 0.190966670000000, + 0.190666670000000, + 0.190066670000000, + 0.190066670000000, + 0.190266670000000, + 0.190366670000000, + 0.190766670000000, + 0.190866670000000, + 0.190866670000000, + 0.190966670000000, + 0.190866670000000, + 0.191166670000000, + 0.191266670000000, + 0.191366670000000, + 0.191566670000000, + 0.191766670000000, + 0.191466670000000, + 0.191766670000000, + 0.191966670000000, + 0.192166670000000, + 0.191766670000000, + 0.192366670000000, + 0.192166670000000, + 0.192266670000000, + 0.192266670000000, + 0.191966670000000, + 0.191666670000000, + 0.191966670000000, + 0.191666670000000, + 0.191466670000000, + 0.191766670000000, + 0.192266670000000, + 0.191866670000000, + 0.191866670000000, + 0.191866670000000, + 0.191966670000000, + 0.191666670000000, + 0.191266670000000, + 0.191466670000000, + 0.191566670000000, + 0.191866670000000, + 0.192566670000000, + 0.192366670000000, + 0.191966670000000, + 0.192066670000000, + 0.192366670000000, + 0.192166670000000, + 0.192266670000000, + 0.192566670000000, + 0.192866670000000, + 0.192466670000000, + 0.192966670000000, + 0.192966670000000, + 0.192966670000000, + 0.192766670000000, + 0.193066670000000, + 0.193266670000000, + 0.193066670000000, + 0.193066670000000, + 0.193366670000000, + 0.192866670000000, + 0.193366670000000, + 0.193666670000000, + 0.193966670000000, + 0.193866670000000, + 0.193566670000000, + 0.193866670000000, + 0.193566670000000, + 0.193666670000000, + 0.193966670000000, + 0.194166670000000, + 0.194366670000000, + 0.194266670000000, + 0.194066670000000, + 0.194166670000000, + 0.194266670000000, + 0.194466670000000, + 0.194466670000000, + 0.194566670000000, + 0.194866670000000, + 0.194966670000000, + 0.194866670000000, + 0.194566670000000, + 0.194466670000000, + 0.194866670000000, + 0.195166670000000, + 0.195166670000000, + 0.195066670000000, + 0.195366670000000, + 0.195566670000000, + 0.195466670000000, + 0.195766670000000, + 0.195466670000000, + 0.195466670000000, + 0.195766670000000, + 0.195466670000000, + 0.195266670000000, + 0.195566670000000, + 0.195666670000000, + 0.195666670000000, + 0.195666670000000, + 0.196366670000000, + 0.196066670000000, + 0.195766670000000, + 0.195666670000000, + 0.195966670000000, + 0.195866670000000, + 0.195866670000000, + 0.196066670000000, + 0.196566670000000, + 0.196166670000000, + 0.196666670000000, + 0.196366670000000, + 0.196466670000000, + 0.196266670000000, + 0.196066670000000, + 0.196066670000000, + 0.196366670000000, + 0.196466670000000, + 0.196466670000000, + 0.196766670000000, + 0.196866670000000, + 0.196466670000000, + 0.196866670000000, + 0.196666670000000, + 0.196066670000000, + 0.196166670000000, + 0.196666670000000, + 0.196666670000000, + 0.196666670000000, + 0.197066670000000, + 0.197366670000000, + 0.197066670000000, + 0.197166670000000, + 0.197166670000000, + 0.197366670000000, + 0.197166670000000, + 0.197066670000000, + 0.197066670000000, + 0.196766670000000, + 0.197166670000000, + 0.197266670000000, + 0.196966670000000, + 0.196966670000000, + 0.197466670000000, + 0.197066670000000, + 0.196766670000000, + 0.196966670000000, + 0.197666670000000, + 0.197066670000000, + 0.196866670000000, + 0.197166670000000, + 0.197166670000000, + 0.197366670000000, + 0.197566670000000, + 0.197466670000000, + 0.197366670000000, + 0.197366670000000, + 0.197366670000000, + 0.197266670000000, + 0.196566670000000, + 0.197266670000000, + 0.197466670000000, + 0.197066670000000, + 0.196866670000000, + 0.197066670000000, + 0.196766670000000, + 0.196966670000000, + 0.197166670000000, + 0.197366670000000, + 0.196866670000000, + 0.196966670000000, + 0.196766670000000, + 0.196466670000000, + 0.195966670000000, + 0.195666670000000, + 0.195966670000000, + 0.196066670000000, + 0.195666670000000, + 0.195366670000000, + 0.195066670000000, + 0.194966670000000, + 0.194666670000000, + 0.194566670000000, + 0.194766670000000, + 0.194466670000000, + 0.194166670000000, + 0.193866670000000, + 0.193566670000000, + 0.193366670000000, + 0.193466670000000, + 0.193866670000000, + 0.193066670000000, + 0.192866670000000, + 0.192666670000000, + 0.192366670000000, + 0.192066670000000, + 0.191966670000000, + 0.191566670000000, + 0.190966670000000, + 0.190666670000000, + 0.190666670000000, + 0.190366670000000, + 0.190266670000000, + 0.190266670000000, + 0.189866670000000, + 0.189366670000000, + 0.189066670000000, + 0.189066670000000, + 0.188466670000000, + 0.188066670000000, + 0.188166670000000, + 0.187966670000000, + 0.187466670000000, + 0.187266670000000, + 0.187266670000000, + 0.187066670000000, + 0.186766670000000, + 0.186666670000000, + 0.186666670000000, + 0.186166670000000, + 0.186466670000000, + 0.186266670000000, + 0.185966670000000, + 0.185766670000000, + 0.185766670000000, + 0.185566670000000, + 0.185166670000000, + 0.184866670000000, + 0.184966670000000, + 0.185066670000000, + 0.185166670000000, + 0.184966670000000, + 0.184466670000000, + 0.184366670000000, + 0.183866670000000, + 0.183666670000000, + 0.183666670000000, + 0.183366670000000, + 0.183066670000000, + 0.183066670000000, + 0.182166670000000, + 0.180366670000000, + 0.180166670000000, + 0.180066670000000, + 0.179766670000000, + 0.179966670000000, + 0.180066670000000, + 0.179766670000000, + 0.179566670000000, + 0.179466670000000, + 0.179766670000000, + 0.179566670000000, + 0.179466670000000, + 0.179466670000000, + 0.179466670000000, + 0.179666670000000, + 0.179566670000000, + 0.179566670000000, + 0.179366670000000, + 0.179766670000000, + 0.180166670000000, + 0.179466670000000, + 0.179466670000000, + 0.179566670000000, + 0.179466670000000, + 0.179266670000000, + 0.179466670000000, + 0.179466670000000, + 0.179766670000000, + 0.179966670000000, + 0.180266670000000, + 0.180466670000000, + 0.179766670000000, + 0.180066670000000, + 0.180266670000000, + 0.179966670000000, + 0.180166670000000, + 0.180766670000000, + 0.180666670000000, + 0.180766670000000, + 0.181066670000000, + 0.180766670000000, + 0.180766670000000, + 0.181066670000000, + 0.181366670000000, + 0.181066670000000, + 0.181266670000000, + 0.181566670000000, + 0.181566670000000, + 0.181566670000000, + 0.182066670000000, + 0.182166670000000, + 0.182066670000000, + 0.182066670000000, + 0.182066670000000, + 0.182366670000000, + 0.182266670000000, + 0.182566670000000, + 0.182566670000000, + 0.182466670000000, + 0.182966670000000, + 0.182966670000000, + 0.183166670000000, + 0.182966670000000, + 0.182366670000000, + 0.182566670000000, + 0.182966670000000, + 0.183366670000000, + 0.183366670000000, + 0.183266670000000, + 0.183166670000000, + 0.183166670000000, + 0.183566670000000, + 0.183666670000000, + 0.183466670000000, + 0.183566670000000, + 0.183566670000000, + 0.183266670000000, + 0.183466670000000, + 0.184166670000000, + 0.184366670000000, + 0.183966670000000, + 0.184066670000000, + 0.184266670000000, + 0.183866670000000, + 0.183466670000000, + 0.183666670000000, + 0.183766670000000, + 0.183866670000000, + 0.183966670000000, + 0.184266670000000, + 0.184066670000000, + 0.184166670000000, + 0.184466670000000, + 0.184366670000000, + 0.184366670000000, + 0.184866670000000, + 0.185066670000000, + 0.184866670000000, + 0.184666670000000, + 0.185166670000000, + 0.185266670000000, + 0.185566670000000, + 0.185466670000000, + 0.185266670000000, + 0.185166670000000, + 0.184966670000000, + 0.185066670000000, + 0.185366670000000, + 0.185166670000000, + 0.185366670000000, + 0.185766670000000, + 0.185666670000000, + 0.185666670000000, + 0.185366670000000, + 0.185466670000000, + 0.185066670000000, + 0.184666670000000, + 0.184666670000000, + 0.184766670000000, + 0.185366670000000, + 0.185166670000000, + 0.185366670000000, + 0.185166670000000, + 0.184866670000000, + 0.184866670000000, + 0.184566670000000, + 0.184466670000000, + 0.184566670000000, + 0.184866670000000, + 0.184666670000000, + 0.184466670000000, + 0.184366670000000, + 0.184166670000000, + 0.183466670000000, + 0.183666670000000, + 0.183866670000000, + 0.183366670000000, + 0.182766670000000, + 0.182866670000000, + 0.183266670000000, + 0.182866670000000, + 0.182966670000000, + 0.182766670000000, + 0.181966670000000, + 0.181666670000000, + 0.181266670000000, + 0.180866670000000, + 0.180466670000000, + 0.180366670000000, + 0.180666670000000, + 0.180266670000000, + 0.179366670000000, + 0.179266670000000, + 0.179066670000000, + 0.178666670000000, + 0.178466670000000, + 0.178366670000000, + 0.177966670000000, + 0.177566670000000, + 0.177766670000000, + 0.177166670000000, + 0.176866670000000, + 0.176266670000000, + 0.175666670000000, + 0.175466670000000, + 0.174866670000000, + 0.174466670000000, + 0.174166670000000, + 0.173966670000000, + 0.174366670000000, + 0.174266670000000, + 0.173766670000000, + 0.173466670000000, + 0.173166670000000, + 0.173266670000000, + 0.172266670000000, + 0.171866670000000, + 0.171566670000000, + 0.171266670000000, + 0.170766670000000, + 0.170366670000000, + 0.169566670000000, + 0.169466670000000, + 0.169166670000000, + 0.169666670000000, + 0.169666670000000, + 0.169366670000000, + 0.169366670000000, + 0.169566670000000, + 0.169766670000000, + 0.169566670000000, + 0.169466670000000, + 0.169366670000000, + 0.168166670000000, + 0.167566670000000, + 0.166866670000000, + 0.167066670000000, + 0.166666670000000, + 0.166066670000000, + 0.166266670000000, + 0.165766670000000, + 0.165566670000000, + 0.165566670000000, + 0.165166670000000, + 0.164566670000000, + 0.164166670000000, + 0.163566670000000, + 0.162466670000000, + 0.161766670000000, + 0.161866670000000, + 0.160966670000000, + 0.160266670000000, + 0.159866670000000, + 0.159566670000000, + 0.159166670000000, + 0.158166670000000, + 0.157666670000000, + 0.157066670000000, + 0.156266670000000, + 0.155466670000000, + 0.154566670000000, + 0.153766670000000, + 0.153066670000000, + 0.152066670000000, + 0.151666670000000, + 0.150666670000000, + 0.150066670000000, + 0.149966670000000, + 0.149566670000000, + 0.148566670000000, + 0.148066670000000, + 0.147766670000000, + 0.147266670000000, + 0.146266670000000, + 0.146266670000000, + 0.145466670000000, + 0.144966670000000, + 0.144466670000000, + 0.144366670000000, + 0.144366670000000, + 0.143666670000000, + 0.143466670000000, + 0.143366670000000, + 0.142966670000000, + 0.142866670000000, + 0.142166670000000, + 0.142066670000000, + 0.142266670000000, + 0.142066670000000, + 0.141966670000000, + 0.141666670000000, + 0.141366670000000, + 0.141466670000000, + 0.141366670000000, + 0.140866670000000, + 0.140966670000000, + 0.141366670000000, + 0.141166670000000, + 0.141166670000000, + 0.141366670000000, + 0.141266670000000, + 0.140966670000000, + 0.140866670000000, + 0.141066670000000, + 0.141066670000000, + 0.140866670000000, + 0.141166670000000, + 0.140866670000000, + 0.140766670000000, + 0.141366670000000, + 0.141266670000000, + 0.140866670000000, + 0.140866670000000, + 0.140966670000000, + 0.140766670000000, + 0.140466670000000, + 0.140466670000000, + 0.140566670000000, + 0.140566670000000, + 0.140966670000000, + 0.140666670000000, + 0.140466670000000, + 0.140266670000000, + 0.140166670000000, + 0.140366670000000, + 0.140266670000000, + 0.140466670000000, + 0.140566670000000, + 0.140966670000000, + 0.141466670000000, + 0.141066670000000, + 0.141366670000000, + 0.141166670000000, + 0.141366670000000, + 0.141766670000000, + 0.141666670000000, + 0.141466670000000, + 0.141666670000000, + 0.141966670000000, + 0.142266670000000, + 0.141866670000000, + 0.141666670000000, + 0.142066670000000, + 0.142266670000000, + 0.142266670000000, + 0.142566670000000, + 0.142666670000000, + 0.142766670000000, + 0.143166670000000, + 0.143266670000000, + 0.143266670000000, + 0.143066670000000, + 0.143366670000000, + 0.143566670000000, + 0.143666670000000, + 0.143866670000000, + 0.144066670000000, + 0.144166670000000, + 0.143866670000000, + 0.144666670000000, + 0.144666670000000, + 0.144666670000000, + 0.144666670000000, + 0.144866670000000, + 0.145066670000000, + 0.145166670000000, + 0.145266670000000, + 0.145566670000000, + 0.145666670000000, + 0.146166670000000, + 0.146266670000000, + 0.145666670000000, + 0.145866670000000, + 0.146366670000000, + 0.146366670000000, + 0.146066670000000, + 0.145966670000000, + 0.145866670000000, + 0.146066670000000, + 0.146866670000000, + 0.146966670000000, + 0.146666670000000, + 0.146666670000000, + 0.146766670000000, + 0.146966670000000, + 0.146766670000000, + 0.146666670000000, + 0.146766670000000, + 0.146666670000000, + 0.147166670000000, + 0.147166670000000, + 0.147066670000000, + 0.147166670000000, + 0.146966670000000, + 0.146866670000000, + 0.147166670000000, + 0.147166670000000, + 0.147066670000000, + 0.147266670000000, + 0.147866670000000, + 0.147666670000000, + 0.147066670000000, + 0.147566670000000, + 0.147366670000000, + 0.147766670000000, + 0.147566670000000, + 0.147466670000000, + 0.147766670000000, + 0.147966670000000, + 0.147966670000000, + 0.147666670000000, + 0.147966670000000, + 0.148366670000000, + 0.148166670000000, + 0.148166670000000, + 0.148366670000000, + 0.148866670000000, + 0.148566670000000, + 0.148666670000000, + 0.148666670000000, + 0.148766670000000, + 0.149066670000000, + 0.148866670000000, + 0.148866670000000, + 0.148966670000000, + 0.148866670000000, + 0.148866670000000, + 0.149066670000000, + 0.148966670000000, + 0.149066670000000, + 0.149366670000000, + 0.149966670000000, + 0.149966670000000, + 0.149766670000000, + 0.149966670000000, + 0.149966670000000, + 0.149866670000000, + 0.149966670000000, + 0.150166670000000, + 0.150666670000000, + 0.150266670000000, + 0.150666670000000, + 0.150866670000000, + 0.151066670000000, + 0.151166670000000, + 0.150866670000000, + 0.150866670000000, + 0.151166670000000, + 0.151666670000000, + 0.152266670000000, + 0.152066670000000, + 0.151966670000000, + 0.152266670000000, + 0.152366670000000, + 0.152666670000000, + 0.152866670000000, + 0.153266670000000, + 0.153166670000000, + 0.153166670000000, + 0.153666670000000, + 0.153266670000000, + 0.153866670000000, + 0.154266670000000, + 0.154666670000000, + 0.154566670000000, + 0.154566670000000, + 0.154766670000000, + 0.154866670000000, + 0.154266670000000, + 0.154966670000000, + 0.155266670000000, + 0.155866670000000, + 0.155766670000000, + 0.156166670000000, + 0.156266670000000, + 0.156066670000000, + 0.156266670000000, + 0.156266670000000, + 0.156266670000000, + 0.156466670000000, + 0.156566670000000, + 0.156466670000000, + 0.156166670000000, + 0.156466670000000, + 0.156966670000000, + 0.156966670000000, + 0.156966670000000, + 0.157066670000000, + 0.157266670000000, + 0.157366670000000, + 0.157366670000000, + 0.157566670000000, + 0.157366670000000, + 0.157466670000000, + 0.157766670000000, + 0.157366670000000, + 0.157166670000000, + 0.157666670000000, + 0.157366670000000, + 0.157366670000000, + 0.157266670000000, + 0.157466670000000, + 0.157166670000000, + 0.156966670000000, + 0.157066670000000, + 0.156866670000000, + 0.156766670000000, + 0.156766670000000, + 0.156966670000000, + 0.156866670000000, + 0.156766670000000, + 0.156566670000000, + 0.156466670000000, + 0.156666670000000, + 0.155966670000000, + 0.155666670000000, + 0.155966670000000, + 0.155866670000000, + 0.155566670000000, + 0.155966670000000, + 0.156866670000000, + 0.156566670000000, + 0.156466670000000, + 0.156366670000000, + 0.155766670000000, + 0.155766670000000, + 0.155666670000000, + 0.155266670000000, + 0.154866670000000, + 0.155466670000000, + 0.154866670000000, + 0.154966670000000, + 0.154966670000000, + 0.154566670000000, + 0.154566670000000, + 0.153966670000000, + 0.154066670000000, + 0.154066670000000, + 0.153966670000000, + 0.154166670000000, + 0.154066670000000, + 0.153666670000000, + 0.153666670000000, + 0.153866670000000, + 0.153566670000000, + 0.153066670000000, + 0.153066670000000, + 0.153066670000000, + 0.152666670000000, + 0.152866670000000, + 0.153066670000000, + 0.153066670000000, + 0.152766670000000, + 0.152566670000000, + 0.152466670000000, + 0.152466670000000, + 0.152666670000000, + 0.152466670000000, + 0.152266670000000, + 0.152066670000000, + 0.152366670000000, + 0.152266670000000, + 0.152166670000000, + 0.151766670000000, + 0.151666670000000, + 0.151866670000000, + 0.151966670000000, + 0.151666670000000, + 0.151566670000000, + 0.151866670000000, + 0.151366670000000, + 0.151366670000000, + 0.151466670000000, + 0.151466670000000, + 0.151466670000000, + 0.151566670000000, + 0.151466670000000, + 0.151566670000000, + 0.151266670000000, + 0.151466670000000, + 0.151166670000000, + 0.151066670000000, + 0.151566670000000, + 0.151566670000000, + 0.151766670000000, + 0.152066670000000, + 0.151866670000000, + 0.151666670000000, + 0.151766670000000, + 0.151966670000000, + 0.151766670000000, + 0.151966670000000, + 0.152366670000000, + 0.152666670000000, + 0.152566670000000, + 0.152466670000000, + 0.152566670000000, + 0.152166670000000, + 0.151766670000000, + 0.152266670000000, + 0.152266670000000, + 0.151866670000000, + 0.152066670000000, + 0.152166670000000, + 0.152266670000000, + 0.152466670000000, + 0.152166670000000, + 0.152066670000000, + 0.152066670000000, + 0.152666670000000, + 0.152666670000000, + 0.152166670000000, + 0.152066670000000, + 0.151666670000000, + 0.151566670000000, + 0.150966670000000, + 0.150366670000000, + 0.150566670000000, + 0.150366670000000, + 0.150866670000000, + 0.150766670000000, + 0.150966670000000, + 0.151266670000000, + 0.150966670000000, + 0.150966670000000, + 0.150966670000000, + 0.150766670000000, + 0.151066670000000, + 0.151266670000000, + 0.151966670000000, + 0.151966670000000, + 0.151566670000000, + 0.151666670000000, + 0.151466670000000, + 0.151966670000000, + 0.152166670000000, + 0.152066670000000, + 0.152166670000000, + 0.152266670000000, + 0.152666670000000, + 0.152266670000000, + 0.151766670000000, + 0.152166670000000, + 0.152166670000000, + 0.151866670000000, + 0.152066670000000, + 0.152166670000000, + 0.152366670000000, + 0.152666670000000, + 0.153066670000000, + 0.152766670000000, + 0.152566670000000, + 0.152466670000000, + 0.152266670000000, + 0.152366670000000, + 0.152166670000000, + 0.152466670000000, + 0.152266670000000, + 0.152066670000000, + 0.153366670000000, + 0.153166670000000, + 0.153066670000000, + 0.153166670000000, + 0.152866670000000, + 0.153066670000000, + 0.153266670000000, + 0.153166670000000, + 0.153266670000000, + 0.153266670000000, + 0.153666670000000, + 0.153566670000000, + 0.154166670000000, + 0.153366670000000, + 0.152766670000000, + 0.153166670000000, + 0.153866670000000, + 0.153566670000000, + 0.153866670000000, + 0.154166670000000, + 0.154766670000000, + 0.154666670000000, + 0.154966670000000, + 0.155166670000000, + 0.155166670000000, + 0.155366670000000, + 0.155366670000000, + 0.155466670000000, + 0.155466670000000, + 0.156166670000000, + 0.156166670000000, + 0.155866670000000, + 0.155566670000000, + 0.155466670000000, + 0.155366670000000, + 0.154966670000000, + 0.154966670000000, + 0.154866670000000, + 0.154066670000000, + 0.154366670000000, + 0.155366670000000, + 0.154466670000000, + 0.153866670000000, + 0.153866670000000, + 0.153766670000000, + 0.153566670000000, + 0.153766670000000, + 0.154266670000000, + 0.154366670000000, + 0.154366670000000, + 0.154766670000000, + 0.154966670000000, + 0.154966670000000, + 0.154666670000000, + 0.155466670000000, + 0.155666670000000, + 0.156166670000000, + 0.156466670000000, + 0.156366670000000, + 0.156166670000000, + 0.156966670000000, + 0.155966670000000, + 0.154966670000000, + 0.154466670000000, + 0.152766670000000, + 0.151866670000000, + 0.151066670000000, + 0.150066670000000, + 0.148566670000000, + 0.148066670000000, + 0.147366670000000, + 0.146166670000000, + 0.145466670000000, + 0.144266670000000, + 0.143666670000000, + 0.143766670000000, + 0.143066670000000, + 0.142366670000000, + 0.141466670000000, + 0.141666670000000, + 0.141166670000000, + 0.140166670000000, + 0.139566670000000, + 0.139266670000000, + 0.138166670000000, + 0.137666670000000, + 0.136666670000000, + 0.136166670000000, + 0.134766670000000, + 0.134066670000000, + 0.132966670000000, + 0.132166670000000, + 0.131066670000000, + 0.130366670000000, + 0.129366670000000, + 0.128366670000000, + 0.127166670000000, + 0.126666670000000, + 0.124966670000000, + 0.124066670000000, + 0.123866670000000, + 0.123266670000000, + 0.121466670000000, + 0.121966670000000, + 0.121266670000000, + 0.120666670000000, + 0.120066670000000, + 0.119766670000000, + 0.118866670000000, + 0.118466670000000, + 0.118566670000000, + 0.118966670000000, + 0.118266670000000, + 0.117466670000000, + 0.118066670000000, + 0.117666670000000, + 0.117266670000000, + 0.117966670000000, + 0.118166670000000, + 0.117666670000000, + 0.117766670000000, + 0.117766670000000, + 0.117666670000000, + 0.117466670000000, + 0.117866670000000, + 0.118366670000000, + 0.118766670000000, + 0.118366670000000, + 0.118766670000000, + 0.119166670000000, + 0.119766670000000, + 0.118866670000000, + 0.118766670000000, + 0.119166670000000, + 0.119266670000000, + 0.119366670000000, + 0.119866670000000, + 0.119966670000000, + 0.120066670000000, + 0.120566670000000, + 0.120966670000000, + 0.120666670000000, + 0.120566670000000, + 0.120566670000000, + 0.120766670000000, + 0.120766670000000, + 0.121066670000000, + 0.121066670000000, + 0.120866670000000, + 0.121166670000000, + 0.121766670000000, + 0.121466670000000, + 0.121166670000000, + 0.121466670000000, + 0.121366670000000, + 0.121566670000000, + 0.121466670000000, + 0.121466670000000, + 0.121666670000000, + 0.121766670000000, + 0.122566670000000, + 0.122566670000000, + 0.122566670000000, + 0.122966670000000, + 0.123666670000000, + 0.124266670000000, + 0.124466670000000, + 0.124866670000000, + 0.125966670000000, + 0.125966670000000, + 0.127266670000000, + 0.127666670000000, + 0.128466670000000, + 0.128366670000000, + 0.128866670000000, + 0.129066670000000, + 0.129366670000000, + 0.129366670000000, + 0.129466670000000, + 0.129766670000000, + 0.130466670000000, + 0.130466670000000, + 0.130866670000000, + 0.131066670000000, + 0.131466670000000, + 0.131866670000000, + 0.132366670000000, + 0.132266670000000, + 0.132666670000000, + 0.133166670000000, + 0.133366670000000, + 0.133166670000000, + 0.133566670000000, + 0.133866670000000, + 0.133966670000000, + 0.134166670000000, + 0.134366670000000, + 0.134266670000000, + 0.134166670000000, + 0.134266670000000, + 0.135066670000000, + 0.134766670000000, + 0.134566670000000, + 0.134466670000000, + 0.134066670000000, + 0.134066670000000, + 0.133566670000000, + 0.133266670000000, + 0.133466670000000, + 0.133266670000000, + 0.133966670000000, + 0.133666670000000, + 0.133066670000000, + 0.133466670000000, + 0.133366670000000, + 0.133266670000000, + 0.133466670000000, + 0.133466670000000, + 0.133066670000000, + 0.132866670000000, + 0.132766670000000, + 0.132366670000000, + 0.132166670000000, + 0.131966670000000, + 0.131566670000000, + 0.131866670000000, + 0.131266670000000, + 0.131066670000000, + 0.130866670000000, + 0.130766670000000, + 0.130866670000000, + 0.130466670000000, + 0.129966670000000, + 0.129866670000000, + 0.129566670000000, + 0.129666670000000, + 0.129366670000000, + 0.128866670000000, + 0.128266670000000, + 0.128366670000000, + 0.128366670000000, + 0.127766670000000, + 0.127466670000000, + 0.127166670000000, + 0.126766670000000, + 0.126666670000000, + 0.126466670000000, + 0.126466670000000, + 0.126066670000000, + 0.125866670000000, + 0.125766670000000, + 0.125366670000000, + 0.125366670000000, + 0.124766670000000, + 0.124266670000000, + 0.123866670000000, + 0.123266670000000, + 0.123566670000000, + 0.123066670000000, + 0.122766670000000, + 0.122866670000000, + 0.122666670000000, + 0.122466670000000, + 0.122366670000000, + 0.122066670000000, + 0.121866670000000, + 0.121466670000000, + 0.121566670000000, + 0.121266670000000, + 0.120766670000000, + 0.121366670000000, + 0.120966670000000, + 0.120266670000000, + 0.120266670000000, + 0.120066670000000, + 0.119766670000000, + 0.120066670000000, + 0.120266670000000, + 0.119766670000000, + 0.119366670000000, + 0.119666670000000, + 0.119366670000000, + 0.119566670000000, + 0.119266670000000, + 0.118566670000000, + 0.118466670000000, + 0.119066670000000, + 0.118766670000000, + 0.118666670000000, + 0.118666670000000, + 0.119366670000000, + 0.119166670000000, + 0.119666670000000, + 0.118866670000000, + 0.118266670000000, + 0.118666670000000, + 0.119166670000000, + 0.118866670000000, + 0.118466670000000, + 0.118566670000000, + 0.119066670000000, + 0.118166670000000, + 0.119066670000000, + 0.118866670000000, + 0.118766670000000, + 0.118666670000000, + 0.118766670000000, + 0.119466670000000, + 0.118666670000000, + 0.118766670000000, + 0.119266670000000, + 0.118566670000000, + 0.118866670000000, + 0.119166670000000, + 0.118766670000000, + 0.118866670000000, + 0.118666670000000, + 0.119366670000000, + 0.119266670000000, + 0.119166670000000, + 0.119866670000000, + 0.120166670000000, + 0.119566670000000, + 0.120166670000000, + 0.120466670000000, + 0.119966670000000, + 0.120166670000000, + 0.120166670000000, + 0.120066670000000, + 0.119166670000000, + 0.120666670000000, + 0.120466670000000, + 0.120166670000000, + 0.120266670000000, + 0.119966670000000, + 0.119866670000000, + 0.120866670000000, + 0.120566670000000, + 0.120866670000000, + 0.121366670000000, + 0.121566670000000, + 0.121466670000000, + 0.121566670000000, + 0.122166670000000, + 0.123066670000000, + 0.124166670000000, + 0.123766670000000, + 0.122766670000000, + 0.123466670000000, + 0.124066670000000, + 0.125466670000000, + 0.124666670000000, + 0.124366670000000, + 0.124266670000000, + 0.124066670000000, + 0.124366670000000, + 0.124866670000000, + 0.124266670000000, + 0.124966670000000, + 0.125366670000000, + 0.125466670000000, + 0.124766670000000, + 0.124166670000000, + 0.124366670000000, + 0.124566670000000, + 0.123966670000000, + 0.124366670000000, + 0.124166670000000, + 0.124766670000000, + 0.124866670000000, + 0.125766670000000, + 0.126066670000000, + 0.125166670000000, + 0.126466670000000, + 0.126466670000000, + 0.126266670000000, + 0.127066670000000, + 0.127766670000000, + 0.127366670000000, + 0.126366670000000, + 0.128266670000000, + 0.127966670000000, + 0.127366670000000, + 0.127666670000000, + 0.128366670000000, + 0.127566670000000, + 0.126866670000000, + 0.127266670000000, + 0.128766670000000, + 0.127966670000000, + 0.129466670000000, + 0.130066670000000, + 0.129866670000000, + 0.128666670000000, + 0.128166670000000, + 0.129366670000000, + 0.128266670000000, + 0.127366670000000, + 0.129166670000000, + 0.128166670000000, + 0.130766670000000, + 0.130766670000000, + 0.130566670000000, + 0.129566670000000, + 0.128366670000000, + 0.128366670000000, + 0.128766670000000, + 0.127366670000000, + 0.127966670000000, + 0.128066670000000, + 0.129066670000000, + 0.127766670000000, + 0.127266670000000, + 0.127966670000000, + 0.129366670000000, + 0.129166670000000, + 0.128266670000000, + 0.127666670000000, + 0.125066670000000, + 0.124566670000000, + 0.126166670000000, + 0.124966670000000, + 0.125866670000000, + 0.127566670000000, + 0.125566670000000, + 0.125466670000000, + 0.122366670000000, + 0.123766670000000, + 0.121066670000000, + 0.119666670000000, + 0.122366670000000, + 0.120966670000000, + 0.119566670000000, + 0.120766670000000, + 0.119966670000000, + 0.119666670000000, + 0.118066670000000, + 0.119066670000000, + 0.118666670000000, + 0.116166670000000, + 0.117266670000000, + 0.119666670000000, + 0.118566670000000, + 0.115766670000000, + 0.115266670000000, + 0.116666670000000, + 0.116466670000000, + 0.116066670000000, + 0.112066670000000, + 0.111066670000000, + 0.112866670000000, + 0.113366670000000, + 0.114266670000000, + 0.112766670000000, + 0.112166670000000, + 0.113766670000000, + 0.110966670000000, + 0.111066670000000, + 0.111466670000000, + 0.112766670000000, + 0.112866670000000, + 0.111966670000000, + 0.110666670000000, + 0.111066670000000, + 0.113266670000000, + 0.112366670000000, + 0.110966670000000, + 0.110166670000000, + 0.110566670000000, + 0.111666670000000, + 0.113066670000000, + 0.111166670000000, + 0.112366670000000, + 0.114466670000000, + 0.112266670000000, + 0.111066670000000, + 0.111966670000000, + 0.111466670000000, + 0.110366670000000, + 0.109466670000000, + 0.114066670000000, + 0.113466670000000, + 0.113366670000000, + 0.114566670000000, + 0.113966670000000, + 0.115766670000000, + 0.113366670000000, + 0.113366670000000, + 0.111766670000000, + 0.107366670000000, + 0.111066670000000, + 0.112666670000000, + 0.110066670000000, + 0.112066670000000, + 0.113466670000000, + 0.114266670000000, + 0.113066670000000, + 0.114066670000000, + 0.107566670000000, + 0.108066670000000, + 0.116366670000000, + 0.116666670000000, + 0.115266670000000, + 0.112266670000000, + 0.114466670000000, + 0.114066670000000, + 0.113166670000000, + 0.111466670000000, + 0.109266670000000, + 0.109466670000000, + 0.111466670000000, + 0.110066670000000, + 0.111266670000000, + 0.111166670000000, + 0.111166670000000, + 0.109866670000000, + 0.110066670000000, + 0.109966670000000, + 0.106266670000000, + 0.107566670000000, + 0.111766670000000, + 0.112066670000000, + 0.111866670000000, + 0.110366670000000, + 0.107466670000000, + 0.107366670000000, + 0.111966670000000, + 0.108066670000000, + 0.108666670000000, + 0.109066670000000, + 0.111466670000000, + 0.107166670000000, + 0.104366670000000, + 0.107766670000000, + 0.110766670000000, + 0.110666670000000, + 0.110366670000000, + 0.110566670000000, + 0.111266670000000, + 0.111266670000000, + 0.113866670000000, + 0.111566670000000, + 0.109466670000000, + 0.108666670000000, + 0.110466670000000, + 0.109866670000000, + 0.105266670000000, + 0.109966670000000, + 0.108666670000000, + 0.107466670000000, + 0.112766670000000, + 0.112366670000000, + 0.111966670000000, + 0.107366670000000, + 0.110266670000000, + 0.110666670000000, + 0.109566670000000, + 0.110466670000000, + 0.110866670000000, + 0.111566670000000, + 0.109166670000000, + 0.108766670000000, + 0.104266670000000, + 0.106766670000000, + 0.107866670000000, + 0.107566670000000, + 0.109466670000000, + 0.109366670000000, + 0.106666670000000, + 0.107566670000000, + 0.116166670000000, + 0.114266670000000, + 0.114466670000000, + 0.112966670000000, + 0.109466670000000, + 0.109566670000000, + 0.107366670000000, + 0.105566670000000, + 0.109866670000000, + 0.115766670000000, + 0.117766670000000, + 0.113166670000000, + 0.111566670000000, + 0.113766670000000, + 0.112966670000000, + 0.111766670000000, + 0.114266670000000, + 0.113666670000000, + 0.108866670000000, + 0.108766670000000, + 0.113166670000000, + 0.112966670000000, + 0.111966670000000, + 0.111366670000000, + 0.111566670000000, + 0.111466670000000, + 0.110066670000000, + 0.111066670000000, + 0.113266670000000, + 0.107466670000000, + 0.114166670000000, + 0.113266670000000, + 0.111666670000000, + 0.108766670000000, + 0.105666670000000, + 0.106766670000000, + 0.106666670000000, + 0.111266670000000, + 0.109266670000000, + 0.107466670000000, + 0.112366670000000, + 0.113366670000000, + 0.110066670000000, + 0.106366670000000, + 0.109166670000000, + 0.111166670000000, + 0.105466670000000, + 0.102966670000000, + 0.105966670000000, + 0.106266670000000, + 0.112866670000000, + 0.111366670000000, + 0.107766670000000, + 0.106366670000000, + 0.104766670000000, + 0.108966670000000, + 0.109366670000000, + 0.107966670000000, + 0.106066670000000, + 0.106666670000000, + 0.105966670000000, + 0.103066670000000, + 0.102766670000000, + 0.103266670000000, + 0.099166667000000, + 0.105166670000000, + 0.105066670000000, + 0.101866670000000, + 0.104666670000000, + 0.106366670000000, + 0.105966670000000, + 0.100866670000000, + 0.101566670000000, + 0.107166670000000, + 0.105966670000000, + 0.104966670000000, + 0.105466670000000, + 0.112866670000000, + 0.106266670000000, + 0.104466670000000, + 0.106666670000000, + 0.103566670000000, + 0.103066670000000, + 0.097566667000000, + 0.108366670000000, + 0.103966670000000, + 0.102266670000000, + 0.100266670000000, + 0.102866670000000, + 0.094066667000000, + 0.104766670000000, + 0.104166670000000, + 0.091766667000000, + 0.090566667000000, + 0.094666667000000, + 0.098866667000000, + 0.095666667000000, + 0.096666667000000, + 0.094366667000000, + 0.091066667000000, + 0.097966667000000, + 0.095066667000000, + 0.099266667000000, + 0.091966667000000, + 0.094966667000000, + 0.099266667000000, + 0.094466667000000, + 0.088366667000000, + 0.092566667000000, + 0.096466667000000, + 0.094366667000000, + 0.092866667000000, + 0.102266670000000, + 0.095266667000000, + 0.089366667000000, + 0.098566667000000, + 0.099466667000000, + 0.095866667000000, + 0.085666667000000, + 0.091066667000000, + 0.103866670000000, + 0.097166667000000, + 0.102766670000000, + 0.101766670000000, + 0.099366667000000, + 0.094266667000000, + 0.091166667000000, + 0.091466667000000, + 0.084366667000000, + 0.085066667000000, + 0.100666670000000, + 0.101466670000000, + 0.098766667000000, + 0.097666667000000, + 0.097466667000000, + 0.091866667000000, + 0.084666667000000, + 0.094666667000000, + 0.096566667000000, + 0.087066667000000, + 0.107666670000000, + 0.099666667000000, + 0.093566667000000, + 0.093566667000000, + 0.094666667000000, + 0.093066667000000, + 0.086266667000000, + 0.085966667000000, + 0.092266667000000, + 0.097966667000000, + 0.099166667000000, + 0.097866667000000, + 0.088466667000000, + 0.092166667000000, + 0.096066667000000, + 0.097566667000000, + 0.107766670000000, + 0.098166667000000, + 0.092066667000000, + 0.097566667000000, + 0.107966670000000, + 0.093366667000000, + 0.102966670000000, + 0.106766670000000, + 0.100166670000000, + 0.104166670000000, + 0.099166667000000, + 0.098266667000000, + 0.095166667000000, + 0.104766670000000, + 0.098166667000000, + 0.101566670000000, + 0.097566667000000, + 0.099966667000000, + 0.085066667000000, + 0.084866667000000, + 0.094266667000000, + 0.087966667000000, + 0.094566667000000, + 0.104766670000000, + 0.104866670000000, + 0.106666670000000, + 0.104166670000000, + 0.115366670000000, + 0.110066670000000, + 0.103766670000000, + 0.104066670000000, + 0.100766670000000, + 0.112366670000000, + 0.106266670000000, + 0.116066670000000, + 0.122966670000000, + 0.106366670000000, + 0.104566670000000, + 0.114966670000000, + 0.122566670000000, + 0.115766670000000, + 0.122266670000000, + 0.112866670000000, + 0.106066670000000, + 0.128666670000000, + 0.128066670000000, + 0.120866670000000, + 0.101866670000000, + 0.108366670000000, + 0.114366670000000, + 0.114466670000000, + 0.113466670000000, + 0.110566670000000, + 0.096666667000000, + 0.118666670000000, + 0.115566670000000, + 0.107166670000000, + 0.111266670000000, + 0.117166670000000, + 0.120366670000000, + 0.123066670000000, + 0.102666670000000, + 0.098766667000000, + 0.117266670000000, + 0.145466670000000, + 0.123366670000000, + 0.123666670000000, + 0.134666670000000, + 0.129566670000000, + 0.135366670000000, + 0.120466670000000, + 0.108766670000000, + 0.112166670000000, + 0.100266670000000, + 0.128266670000000, + 0.129966670000000, + 0.118766670000000, + 0.133766670000000, + 0.129966670000000, + 0.125766670000000, + 0.127166670000000, + 0.119066670000000, + 0.116466670000000, + 0.115366670000000, + 0.124166670000000, + 0.116166670000000, + 0.109866670000000, + 0.110566670000000, + 0.116766670000000, + 0.110366670000000, + 0.111666670000000, + 0.113966670000000, + 0.107866670000000, + 0.107066670000000, + 0.118166670000000, + 0.110466670000000, + 0.109166670000000, + 0.105866670000000, + 0.095566667000000, + 0.095566667000000, + 0.097366667000000, + 0.096366667000000, + 0.092966667000000, + 0.088466667000000, + 0.092366667000000, + 0.093266667000000, + 0.095566667000000, + 0.096666667000000, + 0.102666670000000, + 0.100966670000000, + 0.092066667000000, + 0.090066667000000, + 0.093066667000000, + 0.089966667000000, + 0.095766667000000, + 0.097966667000000, + 0.099966667000000, + 0.094166667000000, + 0.092366667000000, + 0.097866667000000, + 0.094966667000000, + 0.093866667000000, + 0.094066667000000, + 0.097466667000000, + 0.106466670000000, + 0.099966667000000, + 0.102966670000000, + 0.098166667000000, + 0.103566670000000, + 0.106166670000000, + 0.103366670000000, + 0.103466670000000, + 0.092766667000000, + 0.095466667000000, + 0.114066670000000, + 0.099866667000000, + 0.094766667000000, + 0.105166670000000, + 0.092566667000000, + 0.093666667000000, + 0.080566667000000, + 0.081866667000000, + 0.080866667000000, + 0.075166667000000, + 0.101966670000000, + 0.093266667000000, + 0.074666667000000, + 0.078366667000000, + 0.085066667000000, + 0.089066667000000, + 0.087566667000000, + 0.091166667000000, + 0.098666667000000, + 0.092466667000000, + 0.139666670000000, + 0.083266667000000, + 0.064766667000000, + 0.087166667000000, + 0.156066670000000, + 0.181266670000000, + 0.122966670000000, + 0.173566670000000, + 0.207666670000000, + 0.213466670000000, + 0.178966670000000, + 0.277466670000000, + ])), + AgfaIT872SetDatasetLoader(): ('agfa', 289, '5', + np.array([ + 8.6300000000000000, + 12.090000000000000, + 14.140000000000000, + 14.020000000000000, + 14.160000000000000, + 14.190000000000000, + 14.250000000000000, + 14.530000000000000, + 14.810000000000000, + 14.880000000000000, + 14.480000000000000, + 13.610000000000000, + 12.600000000000000, + 11.720000000000000, + 11.600000000000000, + 12.690000000000000, + 14.160000000000000, + 16.350000000000000, + 18.900000000000000, + 20.870000000000000, + 21.630000000000000, + 21.230000000000000, + 20.360000000000000, + 19.520000000000000, + 18.790000000000000, + 18.400000000000000, + 18.530000000000000, + 19.180000000000000, + 20.460000000000000, + 22.580000000000000, + 25.470000000000000, + ])), + } + for dataset_loader, values in dataset_loaders.items(): + self.assertEqual(len(dataset_loader.load()[values[0]]), values[1]) + np.testing.assert_array_almost_equal( + dataset_loader.content[values[0]][values[2]].values, + values[3], + decimal=7) + + +if __name__ == '__main__': + unittest.main() diff --git a/colour_datasets/loaders/tests/test_labsphere2019.py b/colour_datasets/loaders/tests/test_labsphere2019.py index f0676a8..e569d02 100644 --- a/colour_datasets/loaders/tests/test_labsphere2019.py +++ b/colour_datasets/loaders/tests/test_labsphere2019.py @@ -57,7 +57,7 @@ def test_load(self): dataset = Labsphere2019DatasetLoader() self.assertEqual( sorted(dataset.load().keys()), ['Labsphere SRS-99-020']) - self.assertEqual(dataset.data['Labsphere SRS-99-020'].shape, + self.assertEqual(dataset.content['Labsphere SRS-99-020'].shape, SpectralShape(250, 2500, 1)) diff --git a/colour_datasets/loaders/tests/test_luo1999.py b/colour_datasets/loaders/tests/test_luo1999.py new file mode 100644 index 0000000..3b772cd --- /dev/null +++ b/colour_datasets/loaders/tests/test_luo1999.py @@ -0,0 +1,175 @@ +# -*- coding: utf-8 -*- +""" +Defines unit tests for :mod:`colour_datasets.loaders.luo1999` module. +""" + +from __future__ import division, unicode_literals + +import numpy as np +import unittest + +from colour_datasets.loaders import Luo1999DatasetLoader, build_Luo1999 + +__author__ = 'Colour Developers' +__copyright__ = 'Copyright (C) 2019 - Colour Developers' +__license__ = 'New BSD License - https://opensource.org/licenses/BSD-3-Clause' +__maintainer__ = 'Colour Developers' +__email__ = 'colour-science@googlegroups.com' +__status__ = 'Production' + +__all__ = ['TestLuo1999DatasetLoader', 'TestBuildLuo1999'] + + +class TestLuo1999DatasetLoader(unittest.TestCase): + """ + Defines :class:`colour_datasets.loaders.luo1999.Luo1999DatasetLoader` + class unit tests methods. + """ + + def test_required_attributes(self): + """ + Tests presence of required attributes. + """ + + required_attributes = ('ID', ) + + for attribute in required_attributes: + self.assertIn(attribute, dir(Luo1999DatasetLoader)) + + def test_required_methods(self): + """ + Tests presence of required methods. + """ + + required_methods = ('load', ) + + for method in required_methods: + self.assertIn(method, dir(Luo1999DatasetLoader)) + + def test_load(self): + """ + Tests :func:`colour_datasets.loaders.luo1999.Luo1999DatasetLoader.\ +load` method. + """ + + dataset = Luo1999DatasetLoader() + self.assertEqual(len(dataset.load().keys()), 37) + + np.set_printoptions( + formatter={'float': '{:0.8f}'.format}, suppress=True) + + np.testing.assert_almost_equal( + dataset.content['CSAJ-C - da'].XYZ_ct, + np.array([ + [9.31000000, 7.33000000, 2.12000000], + [8.85000000, 7.26000000, 1.73000000], + [7.57000000, 6.72000000, 1.45000000], + [6.93000000, 6.78000000, 1.81000000], + [6.10000000, 6.41000000, 2.17000000], + [5.89000000, 6.36000000, 2.65000000], + [5.96000000, 6.24000000, 3.14000000], + [6.60000000, 6.21000000, 3.24000000], + [8.13000000, 6.74000000, 3.12000000], + [9.29000000, 7.46000000, 2.71000000], + [11.21000000, 7.78000000, 1.73000000], + [9.76000000, 7.28000000, 1.07000000], + [8.52000000, 7.32000000, 0.89000000], + [6.48000000, 6.77000000, 1.10000000], + [4.75000000, 5.99000000, 1.93000000], + [4.28000000, 5.55000000, 2.83000000], + [4.88000000, 5.80000000, 3.97000000], + [6.15000000, 5.98000000, 4.26000000], + [8.85000000, 6.81000000, 3.74000000], + [10.74000000, 7.76000000, 2.68000000], + [13.58000000, 8.66000000, 1.58000000], + [3.88000000, 5.80000000, 1.83000000], + [3.14000000, 4.99000000, 3.10000000], + [3.83000000, 5.35000000, 4.93000000], + [5.73000000, 5.80000000, 5.43000000], + [9.92000000, 7.23000000, 4.52000000], + [12.28000000, 7.66000000, 2.66000000], + [25.06000000, 20.96000000, 6.42000000], + [24.39000000, 20.65000000, 5.50000000], + [22.85000000, 20.46000000, 5.04000000], + [20.84000000, 19.87000000, 5.33000000], + [19.00000000, 19.45000000, 6.67000000], + [18.49000000, 19.08000000, 7.53000000], + [19.44000000, 19.34000000, 8.58000000], + [20.25000000, 18.84000000, 8.35000000], + [23.50000000, 20.47000000, 8.20000000], + [24.98000000, 21.02000000, 7.25000000], + [28.00000000, 21.26000000, 5.27000000], + [27.66000000, 21.94000000, 4.20000000], + [23.88000000, 20.89000000, 3.26000000], + [19.65000000, 19.72000000, 3.75000000], + [16.48000000, 18.87000000, 6.21000000], + [15.78000000, 18.46000000, 8.10000000], + [16.39000000, 17.92000000, 9.86000000], + [18.81000000, 17.89000000, 9.97000000], + [24.53000000, 20.27000000, 9.32000000], + [28.10000000, 21.73000000, 7.13000000], + [36.31000000, 23.75000000, 4.25000000], + [32.47000000, 23.05000000, 2.04000000], + [25.96000000, 22.33000000, 1.40000000], + [16.94000000, 19.34000000, 1.51000000], + [11.51000000, 17.13000000, 5.43000000], + [10.66000000, 16.24000000, 9.11000000], + [11.81000000, 15.73000000, 13.45000000], + [16.48000000, 16.69000000, 14.05000000], + [26.75000000, 20.01000000, 11.24000000], + [35.94000000, 23.61000000, 7.31000000], + [51.48000000, 44.17000000, 13.98000000], + [52.10000000, 44.99000000, 12.77000000], + [49.35000000, 44.23000000, 11.47000000], + [45.88000000, 43.36000000, 11.77000000], + [42.03000000, 42.04000000, 14.30000000], + [38.92000000, 39.17000000, 14.89000000], + [41.21000000, 40.22000000, 16.66000000], + [45.21000000, 41.75000000, 17.15000000], + [48.11000000, 42.48000000, 16.43000000], + [51.28000000, 44.35000000, 15.45000000], + [55.86000000, 44.57000000, 11.95000000], + [56.48000000, 46.28000000, 10.25000000], + [50.94000000, 45.06000000, 8.49000000], + [44.30000000, 43.47000000, 8.99000000], + [37.51000000, 40.86000000, 13.42000000], + [35.35000000, 39.12000000, 16.03000000], + [37.26000000, 38.70000000, 18.63000000], + [43.24000000, 40.67000000, 19.79000000], + [49.20000000, 41.81000000, 17.63000000], + [55.55000000, 45.18000000, 15.45000000], + [63.57000000, 47.85000000, 11.77000000], + [59.61000000, 46.66000000, 7.81000000], + [52.37000000, 45.89000000, 6.15000000], + [41.84000000, 42.37000000, 7.00000000], + [33.71000000, 40.09000000, 12.81000000], + [30.22000000, 36.68000000, 16.27000000], + [33.26000000, 37.35000000, 21.58000000], + [41.99000000, 40.27000000, 23.06000000], + [53.44000000, 44.07000000, 20.61000000], + [63.08000000, 47.24000000, 15.10000000], + ]) / 100, + decimal=7) + + self.assertEqual( + dataset.content['CSAJ-C - da'].metadata['Experimental Method'], + 'Haploscopic') + + +class TestBuildLuo1999(unittest.TestCase): + """ + Defines :func:`colour_datasets.loaders.luo1999.build_Luo1999` + definition unit tests methods. + """ + + def test_build_Luo1999(self): + """ + Tests :func:`colour_datasets.loaders.luo1999.build_Luo1999` + definition. + """ + + self.assertIs(build_Luo1999(), build_Luo1999()) + + +if __name__ == '__main__': + unittest.main() diff --git a/colour_datasets/loaders/tests/test_xrite2016.py b/colour_datasets/loaders/tests/test_xrite2016.py index 1b79167..29fb6f9 100644 --- a/colour_datasets/loaders/tests/test_xrite2016.py +++ b/colour_datasets/loaders/tests/test_xrite2016.py @@ -9,7 +9,7 @@ from colour.characterisation import ColourChecker -from colour_datasets.loaders import (XRite2016DatasetLoader, build_XRite2016) +from colour_datasets.loaders import XRite2016DatasetLoader, build_XRite2016 __author__ = 'Colour Developers' __copyright__ = 'Copyright (C) 2019 - Colour Developers' @@ -62,7 +62,7 @@ def test_load(self): 'ColorCheckerSG - Before November 2014', ]) self.assertIsInstance( - dataset.data['ColorChecker24 - After November 2014'], + dataset.content['ColorChecker24 - After November 2014'], ColourChecker) diff --git a/colour_datasets/loaders/xrite2016.py b/colour_datasets/loaders/xrite2016.py index b11783e..6e9eb8d 100644 --- a/colour_datasets/loaders/xrite2016.py +++ b/colour_datasets/loaders/xrite2016.py @@ -25,7 +25,7 @@ import os from collections import OrderedDict -from colour import Lab_to_XYZ, XYZ_to_xyY, XYZ_to_xy +from colour import ILLUMINANTS, Lab_to_XYZ, XYZ_to_xyY from colour.characterisation import ColourChecker from colour_datasets.records import datasets @@ -73,14 +73,15 @@ def __init__(self): def load(self): """ - Syncs, parses, converts and returns the dataset content. + Syncs, parses, converts and returns the *X-Rite (2016)* + *New Color Specifications for ColorChecker SG and Classic Charts* + dataset content. Returns ------- OrderedDict - Dataset content as an :class:`OrderedDict` of - *Colour Checkers* and their - :class:`colour.characterisation.ColourChecker` class instances. + *X-Rite (2016)* *New Color Specifications for ColorChecker SG and + Classic Charts* dataset content. Examples -------- @@ -88,7 +89,7 @@ def load(self): >>> dataset = XRite2016DatasetLoader() >>> with suppress_stdout(): ... dataset.load() - >>> len(dataset.data.keys()) + >>> len(dataset.content.keys()) 4 """ @@ -109,10 +110,10 @@ def load(self): # TODO: Implement support for "CGATS" file format in "Colour": # https://github.com/colour-science/colour/issues/354 - # TODO: Add "ICC D50" to "Colour". - illuminant = XYZ_to_xy([96.42, 100, 82.49]) + illuminant = ( + ILLUMINANTS['CIE 1931 2 Degree Standard Observer']['ICC D50']) - self._data = OrderedDict() + self._content = OrderedDict() for key, filename in zip(keys, filenames): directory = os.path.splitext(filename)[0] path = os.path.join(self.record.repository, 'dataset', directory, @@ -145,10 +146,11 @@ def load(self): samples = np.transpose(samples.reshape([i, j, 2]), [1, 0, 2]) keys, values = zip(*samples.reshape([-1, 2])) values = XYZ_to_xyY(Lab_to_XYZ(values, illuminant)) - self._data[key] = ColourChecker(key, OrderedDict( - zip(keys, values)), illuminant) + self._content[key] = ColourChecker(key, + OrderedDict(zip(keys, values)), + illuminant) - return self._data + return self._content _XRITE2016_DATASET_LOADER = None diff --git a/colour_datasets/records/configuration.py b/colour_datasets/records/configuration.py index 30a3d0e..5c29d72 100644 --- a/colour_datasets/records/configuration.py +++ b/colour_datasets/records/configuration.py @@ -26,7 +26,7 @@ DEFAULT_CONFIGURATION = DocstringDict({ 'repository': os.environ.get( - 'COLOUR_SCIENCE__COLOUR_DATASETS', + 'COLOUR_SCIENCE__COLOUR_DATASETS__REPOSITORY', os.path.join( os.path.expanduser('~'), '.colour-science', diff --git a/colour_datasets/records/tests/test_zenodo.py b/colour_datasets/records/tests/test_zenodo.py index 2a94f8c..458455f 100644 --- a/colour_datasets/records/tests/test_zenodo.py +++ b/colour_datasets/records/tests/test_zenodo.py @@ -228,7 +228,7 @@ def setUp(self): 'https://zenodo.org/api/communities/colour-science-datasets') records_data = json_open( 'https://zenodo.org/api/records/?q=communities:' - 'colour-science-datasets') + 'colour-science-datasets-tests') self._data = { 'community': community_data, @@ -318,8 +318,8 @@ def test__str__(self): colour-science-datasets ======================= -Datasets : 3 -Owned : 0 +Datasets : 4 +Synced : 0 URL : https://zenodo.org/communities/colour-science-datasets/ Datasets @@ -328,7 +328,8 @@ def test__str__(self): [ ] 3245883 : Camera Spectral Sensitivity Database [ ] 3245875 : Labsphere SRS-99-020 [ ] 3245895 : New Color Specifications for ColorChecker SG and Classic \ -Charts""")[1:]) +Charts +[ ] 3252742 : Observer Function Database""")[1:]) def test__repr__(self): """ diff --git a/colour_datasets/records/zenodo.py b/colour_datasets/records/zenodo.py index 820dd9b..0281f8f 100644 --- a/colour_datasets/records/zenodo.py +++ b/colour_datasets/records/zenodo.py @@ -6,8 +6,8 @@ Defines the objects implementing support for a *Zenodo* community and its records: -- :class:`colour_datasets.records.Record` -- :class:`colour_datasets.records.Community` +- :class:`colour_datasets.Record` +- :class:`colour_datasets.Community` """ from __future__ import division, unicode_literals @@ -16,6 +16,7 @@ import six import shutil import setuptools.archive_util +import stat import tempfile import textwrap from collections import Mapping @@ -291,8 +292,8 @@ def __repr__(self): @staticmethod def from_id(id_, configuration=None, retries=3): """ - :class:`colour_datasets.records.Record` class factory that builds an - instance using given *Zenodo* record id. + :class:`colour_datasets.Record` class factory that builds an instance + using given *Zenodo* record id. Parameters ---------- @@ -339,8 +340,10 @@ def synced(self): Examples -------- + >>> from colour_datasets.utilities import suppress_stdout >>> record = Record.from_id('3245883') - >>> record.pull() + >>> with suppress_stdout(): + ... record.pull() >>> record.synced() True >>> record.remove() @@ -374,16 +377,25 @@ def pull(self, use_urls_txt_file=True, retries=3): Examples -------- + >>> from colour_datasets.utilities import suppress_stdout >>> record = Record.from_id('3245883') >>> record.remove() - >>> record.pull() + >>> with suppress_stdout(): + ... record.pull() >>> record.synced() True """ + print('Pulling "{0}" record content...'.format(self.title)) + if not os.path.exists(self._configuration.repository): os.makedirs(self._configuration.repository) + downloads_directory = os.path.join( + self.repository, self._configuration.downloads_directory) + if not os.path.exists(downloads_directory): + os.makedirs(downloads_directory) + # As much as possible, the original file urls are used, those are # given by the content of :attr:`URLS_TXT_FILE` attribute file. urls_txt = None @@ -392,9 +404,20 @@ def pull(self, use_urls_txt_file=True, retries=3): urls_txt = file_data break + def _urls_download(urls): + """ + Downloads given urls. + """ + + for url, md5 in urls.items(): + filename = os.path.join( + downloads_directory, + urllib.parse.unquote(url.split('/')[-1])) + url_download(url, filename, md5.split(':')[-1], retries) + try: - urls = {} if use_urls_txt_file and urls_txt: + urls = {} urls_txt_file = tempfile.mktemp() url_download(urls_txt['links']['self'], urls_txt_file, urls_txt['checksum'].split(':')[-1], retries) @@ -403,12 +426,23 @@ def pull(self, use_urls_txt_file=True, retries=3): urls_txt_json = json.load(json_file) for url, md5 in urls_txt_json['urls'].items(): urls[url] = md5.split(':')[-1] + + shutil.copyfile( + urls_txt_file, + os.path.join(downloads_directory, + self._configuration.urls_txt_file)) + + _urls_download(urls) else: - raise ValueError('"{0}" file was not found!') + raise ValueError( + '"{0}" file was not found in record data!'.format( + self._configuration.urls_txt_file)) except (urllib.error.URLError, ValueError) as error: - warning('An error occurred using urls from "{0}" file: {1}' - ', switching to record urls...'.format( + warning('An error occurred using urls from "{0}" file: {1}\n' + 'Switching to record urls...'.format( self._configuration.urls_txt_file, error)) + + urls = {} for file_data in self.data['files']: if file_data['key'] == self._configuration.urls_txt_file: continue @@ -416,20 +450,12 @@ def pull(self, use_urls_txt_file=True, retries=3): urls[file_data['links']['self']] = ( file_data['checksum'].split(':')[-1]) - downloads_directory = os.path.join( - self.repository, self._configuration.downloads_directory) - if not os.path.exists(downloads_directory): - os.makedirs(downloads_directory) - - for url, md5 in urls.items(): - filename = os.path.join(downloads_directory, - urllib.parse.unquote(url.split('/')[-1])) - url_download(url, filename, md5.split(':')[-1], retries) + _urls_download(urls) deflate_directory = os.path.join(self.repository, self._configuration.deflate_directory) if os.path.exists(deflate_directory): - shutil.rmtree(deflate_directory) + shutil.rmtree(deflate_directory, onerror=_remove_readonly) shutil.copytree(downloads_directory, deflate_directory) @@ -441,9 +467,11 @@ def pull(self, use_urls_txt_file=True, retries=3): basename, extension = os.path.splitext(filename) basename = os.path.basename(basename) if extension.lower() in ('.zip', '.tar', '.gz', '.bz2'): + if basename.lower().endswith('.tar'): + basename = basename.rsplit('.', 1)[0] + + basename = basename.replace('.', '_') unpacking_directory = os.path.join(deflate_directory, basename) - if unpacking_directory.lower().endswith('.tar'): - unpacking_directory = unpacking_directory.rsplit('.', 1)[0] print('Unpacking "{0}" archive...'.format(filename)) setuptools.archive_util.unpack_archive(filename, @@ -460,15 +488,17 @@ def remove(self): Examples -------- + >>> from colour_datasets.utilities import suppress_stdout >>> record = Record.from_id('3245883') - >>> record.pull() + >>> with suppress_stdout(): + ... record.pull() >>> record.remove() >>> record.synced() False """ if os.path.exists(self.repository): - shutil.rmtree(self.repository) + shutil.rmtree(self.repository, onerror=_remove_readonly) class Community(Mapping): @@ -613,15 +643,16 @@ def __str__(self): Examples -------- - >>> community = Community.from_id('colour-science-datasets') + >>> community = Community.from_id('colour-science-datasets-tests') >>> print('\\n'.join(str(community).splitlines()[:6])) ... # doctest: +ELLIPSIS - colour-science-datasets - ======================= + colour-science-datasets-tests + ============================= Datasets : ... - Owned : ... - URL : https://zenodo.org/communities/colour-science-datasets/ + Synced : ... + URL : https://zenodo.org/communities/\ +colour-science-datasets-tests/ """ datasets = '\n'.join([ @@ -632,7 +663,7 @@ def __str__(self): representation = ('{0}\n' '{1}\n\n' 'Datasets : {2}\n' - 'Owned : {3}\n' + 'Synced : {3}\n' 'URL : {4}\n\n' 'Datasets\n--------\n\n' '{5}'.format( @@ -663,7 +694,7 @@ def __repr__(self): Examples -------- - >>> community = Community.from_id('colour-science-datasets') + >>> community = Community.from_id('colour-science-datasets-tests') # Doctests skip for Python 2.x compatibility. >>> print('\\n'.join(repr(community).splitlines()[:4])) @@ -699,7 +730,7 @@ def __getitem__(self, id_): Examples -------- - >>> community = Community.from_id('colour-science-datasets') + >>> community = Community.from_id('colour-science-datasets-tests') # Doctests skip for Python 2.x compatibility. >>> community['3245883'].title # doctest: +SKIP @@ -720,7 +751,7 @@ def __iter__(self): Examples -------- # Doctests skip for Python 2.x compatibility. - >>> for record in Community.from_id('colour-science-datasets'): + >>> for record in Community.from_id('colour-science-datasets-tests'): ... print(record) # doctest: +SKIP """ @@ -738,7 +769,8 @@ def __len__(self): Examples -------- # Doctests skip for Python 2.x compatibility. - >>> len(Community.from_id('colour-science-datasets')) # doctest: +SKIP + >>> len(Community.from_id('colour-science-datasets-tests')) + ... # doctest: +SKIP 3 """ @@ -747,7 +779,7 @@ def __len__(self): @staticmethod def from_id(id_, configuration=None, retries=3): """ - :class:`colour_datasets.records.Community` class factory that builds an + :class:`colour_datasets.Community` class factory that builds an instance using given *Zenodo* community id. Parameters @@ -767,7 +799,7 @@ def from_id(id_, configuration=None, retries=3): Examples -------- - >>> community = Community.from_id('colour-science-datasets') + >>> community = Community.from_id('colour-science-datasets-tests') # Doctests skip for Python 2.x compatibility. >>> community['3245883'].title # doctest: +SKIP @@ -783,7 +815,10 @@ def from_id(id_, configuration=None, retries=3): community_url = '{0}/communities/{1}'.format(configuration.api_url, configuration.community) - records_url = '{0}/records/?q=communities:{1}'.format( + # NOTE: Retrieving 512 datasets at most. This should cover needs for + # the foreseeable future. There is likely an undocumented hard limit on + # "Zenodo" server side. + records_url = '{0}/records/?q=communities:{1}&size=512'.format( configuration.api_url, configuration.community) community_json_filename = os.path.join( @@ -840,10 +875,10 @@ def synced(self): Examples -------- >>> from colour_datasets.utilities import suppress_stdout - >>> community = Community.from_id('colour-science-datasets') + >>> community = Community.from_id('colour-science-datasets-tests') >>> with suppress_stdout(): - ... community.pull() - >>> community.synced() + ... community.pull() # doctest: +SKIP + >>> community.synced() # doctest: +SKIP True >>> community.remove() >>> community.synced() @@ -870,11 +905,11 @@ def pull(self, use_urls_txt_file=True, retries=3): Examples -------- >>> from colour_datasets.utilities import suppress_stdout - >>> community = Community.from_id('colour-science-datasets') + >>> community = Community.from_id('colour-science-datasets-tests') >>> community.remove() >>> with suppress_stdout(): - ... community.pull() - >>> community.synced() + ... community.pull() # doctest: +SKIP + >>> community.synced() # doctest: +SKIP True """ @@ -891,13 +926,24 @@ def remove(self): Examples -------- >>> from colour_datasets.utilities import suppress_stdout - >>> community = Community.from_id('colour-science-datasets') + >>> community = Community.from_id('colour-science-datasets-tests') >>> with suppress_stdout(): - ... community.pull() + ... community.pull() # doctest: +SKIP >>> community.remove() >>> community.synced() False """ if os.path.exists(self.repository): - shutil.rmtree(self.repository) + shutil.rmtree(self.repository, onerror=_remove_readonly) + + +def _remove_readonly(function, path, excinfo): + """ + Error handler for :func:`shutil.rmtree` definition that removes read-only + files. + """ + + os.chmod(path, stat.S_IWRITE) + + function(path) diff --git a/colour_datasets/utilities/__init__.py b/colour_datasets/utilities/__init__.py index c5d1066..d621f83 100644 --- a/colour_datasets/utilities/__init__.py +++ b/colour_datasets/utilities/__init__.py @@ -2,6 +2,16 @@ from __future__ import absolute_import -from .common import suppress_stdout, hash_md5, url_download, json_open +from .common import (suppress_stdout, hash_md5, url_download, json_open, + unpack_gzipfile) +from .spreadsheet import (row_to_index, index_to_row, column_to_index, + index_to_column, cell_range_values) -__all__ = ['suppress_stdout', 'hash_md5', 'url_download', 'json_open'] +__all__ = [ + 'suppress_stdout', 'hash_md5', 'url_download', 'json_open', + 'unpack_gzipfile' +] +__all__ += [ + 'row_to_index', 'index_to_row', 'column_to_index', 'index_to_column', + 'cell_range_values' +] diff --git a/colour_datasets/utilities/common.py b/colour_datasets/utilities/common.py index 5c86577..a13a56c 100644 --- a/colour_datasets/utilities/common.py +++ b/colour_datasets/utilities/common.py @@ -9,12 +9,16 @@ from __future__ import division, unicode_literals import functools +import gzip import hashlib import json import os +import setuptools.archive_util +import shutil import sys from six.moves import urllib from tqdm import tqdm +from cachetools import cached, TTLCache __author__ = 'Colour Developers' __copyright__ = 'Copyright (C) 2019 - Colour Developers' @@ -24,7 +28,8 @@ __status__ = 'Production' __all__ = [ - 'suppress_stdout', 'TqdmUpTo', 'hash_md5', 'url_download', 'json_open' + 'suppress_stdout', 'TqdmUpTo', 'hash_md5', 'url_download', 'json_open', + 'unpack_gzipfile' ] @@ -173,9 +178,10 @@ def url_download(url, filename, md5=None, retries=3): raise error +@cached(cache=TTLCache(maxsize=256, ttl=300)) def json_open(url, retries=3): """ - Opens given url and return its content as "JSON". + Opens given url and return its content as *JSON*. Parameters ---------- @@ -184,6 +190,10 @@ def json_open(url, retries=3): retries : int, optional Number of retries in case where a networking error occurs. + Notes + ----- + - The definition caches the request *JSON* output for 5 minutes. + Examples -------- # Doctests skip for Python 2.x compatibility. @@ -204,3 +214,57 @@ def json_open(url, retries=3): 'during attempt {1}, retrying...'.format(url, attempt)) if attempt == retries: raise error + + +def unpack_gzipfile(filename, extraction_directory, *args): + """ + Unpacks given *GZIP* file to given extraction directory. + + Parameters + ---------- + filename : unicode + *GZIP* file to extract. + extraction_directory : unicode + Directory where to extract the *GZIP* file. + + Other Parameters + ---------------- + \\*args : list, optional + Arguments. + + Returns + ------- + bool + Definition success. + + Notes + ----- + - This definition is used as an extra driver for + :func:`setuptools.archive_util.unpack archive` definition. + """ + + extraction_path = os.path.join( + extraction_directory, + os.path.splitext(os.path.basename(filename))[0]) + + if not os.path.exists(extraction_directory): + os.makedirs(extraction_directory) + + try: + with gzip.open(filename) as gzip_file, open(extraction_path, + 'wb') as output_file: + shutil.copyfileobj(gzip_file, output_file) + except Exception as e: + print(e) + raise setuptools.archive_util.UnrecognizedFormat( + '{0} is not a "GZIP" file!'.format(filename)) + + return True + + +setuptools.archive_util.extraction_drivers = ( + setuptools.archive_util.unpack_directory, + setuptools.archive_util.unpack_zipfile, + setuptools.archive_util.unpack_tarfile, + unpack_gzipfile, +) diff --git a/colour_datasets/utilities/spreadsheet.py b/colour_datasets/utilities/spreadsheet.py new file mode 100644 index 0000000..9f65c6b --- /dev/null +++ b/colour_datasets/utilities/spreadsheet.py @@ -0,0 +1,240 @@ +# -*- coding: utf-8 -*- +""" +Spreadsheet Utilities +===================== + +Defines various spreadsheet related utilities. + +References +---------- +- :cite:`OpenpyxlDevelopers2019` : Openpyxl Developers. (2019). openpyxl. + Retrieved from https://bitbucket.org/openpyxl/openpyxl/ +""" + +from __future__ import division, unicode_literals + +import re +import six + +from colour.utilities import CaseInsensitiveMapping + +__author__ = 'Colour Developers, Openpyxl Developers' +__copyright__ = 'Copyright (C) 2019 - Colour Developers' +__copyright__ += ', ' +__copyright__ = 'Copyright (C) 2010 openpyxl' +__license__ = 'New BSD License - https://opensource.org/licenses/BSD-3-Clause' +__license__ += ', ' +__license__ += 'MIT Licence - https://opensource.org/licenses/MIT' +__maintainer__ = 'Colour Developers' +__email__ = 'colour-science@googlegroups.com' +__status__ = 'Production' + +__all__ = [ + 'column_to_index', 'row_to_index', 'index_to_column', 'index_to_row', + 'cell_range_values' +] + + +def _column_number_to_letters(number): + """ + Converts given column number into a column letters. + + Right shifts the column index by 26 to find column letters in reverse + order. These numbers are 1-based, and can be converted to ASCII + ordinals by adding 64. + + Parameters + ---------- + number : int + Column number to convert to column letters. + + Returns + ------- + unicode + Column letters. + + References + ---------- + :cite:`OpenpyxlDevelopers2019` + + Examples + -------- + # Doctests skip for Python 2.x compatibility. + >>> _column_number_to_letters(128) # doctest: +SKIP + 'DX' + """ + + assert 1 <= number <= 18278, ( + 'Column number {0} must be in range [1, 18278]!'.format(number)) + + letters = [] + while number > 0: + number, remainder = divmod(number, 26) + if remainder == 0: + remainder = 26 + number -= 1 + letters.append(chr(remainder + 64)) + + return ''.join(reversed(letters)) + + +_LETTERS_TO_NUMBER_CACHE = CaseInsensitiveMapping() +""" +Letters, e.g. *Microsoft Excel* column letters to numbers cache. + +_LETTERS_TO_NUMBER_CACHE : CaseInsensitiveMapping +""" + +_NUMBER_TO_LETTERS_CACHE = {} +""" +Numbers to letters, e.g. *Microsoft Excel* column letters cache. + +_NUMBER_TO_LETTERS_CACHE : dict +""" + +for i in range(1, 18279): + letter = _column_number_to_letters(i) + _NUMBER_TO_LETTERS_CACHE[i] = letter + _LETTERS_TO_NUMBER_CACHE[letter] = i + + +def row_to_index(row): + """ + Returns the 0-based index of given row name. + + Parameters + ---------- + row : int or unicode + Row name. + + Returns + ------- + int + 0-based row index. + + Examples + -------- + >>> row_to_index('1') + 0 + """ + + row = int(row) + + assert row > 0, 'Row must be greater than 0!' + + return row - 1 + + +def index_to_row(index): + """ + Returns the row name of given 0-based index. + + Parameters + ---------- + index : int + 0-based row index. + + Returns + ------- + unicode + Row name. + + Examples + -------- + # Doctests skip for Python 2.x compatibility. + >>> index_to_row(0) # doctest: +SKIP + '1' + """ + + return six.text_type(index + 1) + + +def column_to_index(column): + """ + Returns the 0-based index of given column letters. + + Parameters + ---------- + column : unicode + Column letters + + Returns + ------- + int + 0-based column index. + + Examples + -------- + >>> column_to_index('A') + 0 + """ + + return _LETTERS_TO_NUMBER_CACHE[column] - 1 + + +def index_to_column(index): + """ + Returns the column letters of given 0-based index. + + Parameters + ---------- + index : unicode + 0-based column index. + + Returns + ------- + unicode + Column letters + + Examples + -------- + # Doctests skip for Python 2.x compatibility. + >>> index_to_column(0) # doctest: +SKIP + 'A' + """ + + return _NUMBER_TO_LETTERS_CACHE[index + 1] + + +_CELL_RANGE_REGEX = re.compile( + r'^[$]?(?P[A-Za-z]{1,3})?[$]?(?P\d+)?' + r'(:[$]?(?P[A-Za-z]{1,3})?[$]?(?P\d+)?)?$') +""" +Regular expression to match a cell range, e.g. "A1:C3". + +_CELL_RANGE_REGEX : unicode +""" + + +def cell_range_values(sheet, cell_range): + """ + Returns given workbook sheet cell range values, i.e. the values of the + rows and columns for given cell range. + + Parameters + ---------- + sheet : Sheet + Workbook sheet. + cell_range + Cell range values, e.g. "A1:C3". + + Returns + ------- + list + List of row values. + """ + + groups = re.match(_CELL_RANGE_REGEX, cell_range).groupdict() + + column_in = column_to_index(groups.get('column_in')) + row_in = row_to_index(groups.get('row_in')) + column_out = column_to_index(groups.get('column_out')) + row_out = row_to_index(groups.get('row_out')) + + table = [] + for row in range(row_in, row_out + 1, 1): + table.append( + sheet.row_values( + row, start_colx=column_in, end_colx=column_out + 1)) + + return table diff --git a/colour_datasets/utilities/tests/resources/Workbook.xlsx b/colour_datasets/utilities/tests/resources/Workbook.xlsx new file mode 100644 index 0000000..0295ac0 Binary files /dev/null and b/colour_datasets/utilities/tests/resources/Workbook.xlsx differ diff --git a/colour_datasets/utilities/tests/resources/example.txt.gz b/colour_datasets/utilities/tests/resources/example.txt.gz new file mode 100644 index 0000000..afcb706 Binary files /dev/null and b/colour_datasets/utilities/tests/resources/example.txt.gz differ diff --git a/colour_datasets/utilities/tests/test_common.py b/colour_datasets/utilities/tests/test_common.py index 29398d1..967beee 100644 --- a/colour_datasets/utilities/tests/test_common.py +++ b/colour_datasets/utilities/tests/test_common.py @@ -8,9 +8,11 @@ import os import unittest import tempfile +import shutil from colour_datasets.loaders import build_Labsphere2019 -from colour_datasets.utilities import hash_md5, url_download, json_open +from colour_datasets.utilities import (hash_md5, url_download, json_open, + unpack_gzipfile) __author__ = 'Colour Developers' __copyright__ = 'Copyright (C) 2019 - Colour Developers' @@ -19,7 +21,9 @@ __email__ = 'colour-science@googlegroups.com' __status__ = 'Production' -__all__ = ['TestHashMd5', 'TestUrlDownload', 'TestJsonOpen'] +__all__ = [ + 'TestHashMd5', 'TestUrlDownload', 'TestJsonOpen', 'TestUnpackGzipfile' +] class TestHashMd5(unittest.TestCase): @@ -118,5 +122,44 @@ def test_json_open(self): self.assertRaises(IOError, lambda: json_open('https://nemo.io')) +class TestUnpackGzipfile(unittest.TestCase): + """ + Defines :func:`colour_datasets.utilities.common.unpack_gzipfile` definition + unit tests methods. + """ + + def setUp(self): + """ + Initialises common tests attributes. + """ + + self._temporary_directory = tempfile.mkdtemp() + + def tearDown(self): + """ + After tests actions. + """ + + shutil.rmtree(self._temporary_directory) + + def test_unpack_gzipfile(self): + """ + Tests :func:`colour_datasets.utilities.common.unpack_gzipfile` + definition. + """ + + unpack_gzipfile( + os.path.join( + os.path.dirname(__file__), 'resources', 'example.txt.gz'), + self._temporary_directory) + + with open(os.path.join(self._temporary_directory, + 'example.txt')) as file_handle: + self.assertEqual( + file_handle.read(), + 'This is the content of a text file stored ' + 'inside a "GZIP" file.') + + if __name__ == '__main__': unittest.main() diff --git a/colour_datasets/utilities/tests/test_spreadsheet.py b/colour_datasets/utilities/tests/test_spreadsheet.py new file mode 100644 index 0000000..52a5636 --- /dev/null +++ b/colour_datasets/utilities/tests/test_spreadsheet.py @@ -0,0 +1,135 @@ +# -*- coding: utf-8 -*- +""" +Defines unit tests for :mod:`colour_datasets.utilities.spreadsheet` module. +""" + +from __future__ import division, unicode_literals + +import os +import unittest +import xlrd + +from colour_datasets.utilities import (row_to_index, index_to_row, + column_to_index, index_to_column, + cell_range_values) + +__author__ = 'Colour Developers' +__copyright__ = 'Copyright (C) 2019 - Colour Developers' +__license__ = 'New BSD License - https://opensource.org/licenses/BSD-3-Clause' +__maintainer__ = 'Colour Developers' +__email__ = 'colour-science@googlegroups.com' +__status__ = 'Production' + +__all__ = [ + 'TestRowToIndex', 'TestIndexToRow', 'TestColumnToIndex', + 'TestIndexToColumn', 'TestCellRangeValues' +] + + +class TestRowToIndex(unittest.TestCase): + """ + Defines :func:`colour_datasets.utilities.spreadsheet.row_to_index` + definition unit tests methods. + """ + + def test_row_to_index(self): + """ + Tests :func:`colour_datasets.utilities.spreadsheet.row_to_index` + definition. + """ + + self.assertEqual(row_to_index(1), 0) + + self.assertEqual(row_to_index(10), 9) + + self.assertEqual(row_to_index('100'), 99) + + self.assertRaises(AssertionError, lambda: row_to_index(0)) + + +class TestIndexToRow(unittest.TestCase): + """ + Defines :func:`colour_datasets.utilities.spreadsheet.index_to_row` + definition unit tests methods. + """ + + def test_index_to_row(self): + """ + Tests :func:`colour_datasets.utilities.spreadsheet.index_to_row` + definition. + """ + + self.assertEqual(index_to_row(0), '1') + + self.assertEqual(index_to_row(9), '10') + + self.assertEqual(index_to_row(99), '100') + + +class TestColumnToIndex(unittest.TestCase): + """ + Defines :func:`colour_datasets.utilities.spreadsheet.column_to_index` + definition unit tests methods. + """ + + def test_column_to_index(self): + """ + Tests :func:`colour_datasets.utilities.spreadsheet.column_to_index` + definition. + """ + + self.assertEqual(column_to_index('A'), 0) + + self.assertEqual(column_to_index('J'), 9) + + self.assertEqual(column_to_index('AA'), 26) + + self.assertRaises(KeyError, lambda: column_to_index('AAAA')) + + +class TestIndexToColumn(unittest.TestCase): + """ + Defines :func:`colour_datasets.utilities.spreadsheet.index_to_column` + definition unit tests methods. + """ + + def test_index_to_column(self): + """ + Tests :func:`colour_datasets.utilities.spreadsheet.index_to_column` + definition. + """ + + self.assertEqual(index_to_column(0), 'A') + + self.assertEqual(index_to_column(9), 'J') + + self.assertEqual(index_to_column(26), 'AA') + + +class TestCellRangeValues(unittest.TestCase): + """ + Defines :func:`colour_datasets.utilities.spreadsheet.cell_range_values` + definition unit tests methods. + """ + + def test_cell_range_values(self): + """ + Tests :func:`colour_datasets.utilities.spreadsheet.cell_range_values` + definition. + """ + + workbook_path = os.path.join( + os.path.dirname(__file__), 'resources', 'Workbook.xlsx') + sheet = xlrd.open_workbook(workbook_path).sheet_by_index(0) + self.assertListEqual( + cell_range_values(sheet, 'A1:E5'), [ + [1.0, 2.0, 3.0, 4.0, 5.0], + [2.0, 3.0, 4.0, 5.0, 6.0], + [3.0, 4.0, 5.0, 6.0, 7.0], + [4.0, 5.0, 6.0, 7.0, 8.0], + [5.0, 6.0, 7.0, 8.0, 9.0], + ]) + + +if __name__ == '__main__': + unittest.main() diff --git a/docs/_static/Logo_Medium_001.png b/docs/_static/Logo_Medium_001.png index defdc15..486ab63 100644 Binary files a/docs/_static/Logo_Medium_001.png and b/docs/_static/Logo_Medium_001.png differ diff --git a/docs/_static/Logo_Small_001.png b/docs/_static/Logo_Small_001.png index 50fae32..7409e2c 100644 Binary files a/docs/_static/Logo_Small_001.png and b/docs/_static/Logo_Small_001.png differ diff --git a/docs/bibliography.rst b/docs/bibliography.rst index b8ea67e..47346a7 100644 --- a/docs/bibliography.rst +++ b/docs/bibliography.rst @@ -4,3 +4,10 @@ Bibliography .. bibliography:: bibliography.bib :all: :encoding: utf8 + +Indirect References +------------------- + +Some extra references used in the codebase but not directly part of the public api: + +- :cite:`OpenpyxlDevelopers2019` diff --git a/docs/colour_datasets.loaders.rst b/docs/colour_datasets.loaders.rst index c82d368..8065fc3 100644 --- a/docs/colour_datasets.loaders.rst +++ b/docs/colour_datasets.loaders.rst @@ -10,6 +10,15 @@ Datasets .. currentmodule:: colour_datasets.loaders +Agfa IT8.7/2 Set +~~~~~~~~~~~~~~~~ + +.. autosummary:: + :toctree: generated/ + + AgfaIT872SetDatasetLoader + build_AgfaIT872Set + Camera Spectral Sensitivity Database - Jiang et al. (2013) ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -19,6 +28,42 @@ Camera Spectral Sensitivity Database - Jiang et al. (2013) Jiang2013DatasetLoader build_Jiang2013 +Constant Hue Loci Data - Hung and Berns (1995) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. autosummary:: + :toctree: generated/ + + Hung1995DatasetLoader + build_Hung1995 + +Constant Perceived-Hue Data - Ebner and Fairchild (1998) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. autosummary:: + :toctree: generated/ + + Ebner1998DatasetLoader + build_Ebner1998 + +Corresponding-Colour Datasets - Luo and Rhodes (1999) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. autosummary:: + :toctree: generated/ + + Luo1999DatasetLoader + build_Luo1999 + +Forest Colors +~~~~~~~~~~~~~ + +.. autosummary:: + :toctree: generated/ + + ForestColorsDatasetLoader + build_ForestColors + Labsphere SRS-99-020 - Labsphere (2019) ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -28,6 +73,51 @@ Labsphere SRS-99-020 - Labsphere (2019) Labsphere2019DatasetLoader build_Labsphere2019 +Lumber Spectra +~~~~~~~~~~~~~~ + +.. autosummary:: + :toctree: generated/ + + LumberSpectraDatasetLoader + build_LumberSpectra + +Munsell Colors Glossy (All) (Spectrofotometer Measured) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. autosummary:: + :toctree: generated/ + + MunsellColorsGlossyAllSpectrofotometerMeasuredDatasetLoader + build_MunsellColorsGlossyAllSpectrofotometerMeasured + +Munsell Colors Glossy (Spectrofotometer Measured) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. autosummary:: + :toctree: generated/ + + MunsellColorsGlossySpectrofotometerMeasuredDatasetLoader + build_MunsellColorsGlossySpectrofotometerMeasured + +Munsell Colors Matt (AOTF Measured) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. autosummary:: + :toctree: generated/ + + MunsellColorsMattAOTFMeasuredDatasetLoader + build_MunsellColorsMattAOTFMeasured + +Munsell Colors Matt (Spectrofotometer Measured) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. autosummary:: + :toctree: generated/ + + MunsellColorsMattSpectrofotometerMeasuredDatasetLoader + build_MunsellColorsMattSpectrofotometerMeasured + New Color Specifications for ColorChecker SG and Classic Charts - X-Rite (2016) ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -37,6 +127,33 @@ New Color Specifications for ColorChecker SG and Classic Charts - X-Rite (2016) XRite2016DatasetLoader build_XRite2016 +Observer Function Database - Asano (2015) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. autosummary:: + :toctree: generated/ + + Asano2015DatasetLoader + build_Asano2015 + +Paper Spectra +~~~~~~~~~~~~~ + +.. autosummary:: + :toctree: generated/ + + PaperSpectraDatasetLoader + build_PaperSpectra + +RAW to ACES Utility Data - Dyer et al. (2017) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. autosummary:: + :toctree: generated/ + + Dyer2017DatasetLoader + build_Dyer2017 + Loading the Datasets -------------------- diff --git a/docs/colour_datasets.records.rst b/docs/colour_datasets.records.rst index 0a6b5a5..5b31ce4 100644 --- a/docs/colour_datasets.records.rst +++ b/docs/colour_datasets.records.rst @@ -13,6 +13,7 @@ Configuration .. autosummary:: :toctree: generated/ + Configuration sandbox ``colour_datasets.records`` @@ -22,15 +23,14 @@ Configuration .. autosummary:: :toctree: generated/ - Configuration use_sandbox Record ------ -``colour_datasets.records`` +``colour_datasets`` -.. currentmodule:: colour_datasets.records +.. currentmodule:: colour_datasets .. autosummary:: :toctree: generated/ @@ -47,13 +47,5 @@ Community .. autosummary:: :toctree: generated/ + Community datasets - -``colour_datasets.records`` - -.. currentmodule:: colour_datasets.records - -.. autosummary:: - :toctree: generated/ - - Community \ No newline at end of file diff --git a/docs/colour_datasets.utilities.rst b/docs/colour_datasets.utilities.rst index 44dfc7f..ce1c177 100644 --- a/docs/colour_datasets.utilities.rst +++ b/docs/colour_datasets.utilities.rst @@ -17,3 +17,19 @@ Common hash_md5 suppress_stdout url_download + +Spreadsheet +----------- + +``colour_datasets.utilities`` + +.. currentmodule:: colour_datasets.utilities + +.. autosummary:: + :toctree: generated/ + + row_to_index + index_to_row + column_to_index + index_to_column + cell_range_values diff --git a/docs/conf.py b/docs/conf.py index bf268d9..0b5b6da 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -16,7 +16,7 @@ import colour_datasets as package -basename = re.sub('_(\w)', lambda x: x.group(1).upper(), +basename = re.sub('_(\\w)', lambda x: x.group(1).upper(), package.__name__.title()) autosummary_generate = True @@ -99,7 +99,7 @@ # show_authors = False # The name of the Pygments (syntax highlighting) style to use. -pygments_style = 'sphinx' +pygments_style = 'lovelace' # A list of ignored prefixes for module index sorting. # modindex_common_prefix = [] @@ -198,7 +198,7 @@ latex_elements = { # The paper size ('letterpaper' or 'a4paper'). 'papersize': - 'letterpaper', + 'a4paper', # The font size ('10pt', '11pt' or '12pt'). 'pointsize': @@ -285,10 +285,10 @@ # The basename for the epub file. It defaults to the project name. # epub_basename = basename -# The HTML theme for the epub output. Since the default themes are not optimized -# for small screen space, using the same theme for HTML and epub output is -# usually not wise. This defaults to 'epub', a theme designed to save visual -# space. +# The HTML theme for the epub output. Since the default themes are not +# optimized for small screen space, using the same theme for HTML and epub +# output is usually not wise. This defaults to 'epub', a theme designed to save +# visual space. # epub_theme = 'epub' # The language of the text. It defaults to the language option diff --git a/docs/generated/colour_datasets.datasets.rst b/docs/generated/colour_datasets.datasets.rst deleted file mode 100644 index 0aeb0b2..0000000 --- a/docs/generated/colour_datasets.datasets.rst +++ /dev/null @@ -1,6 +0,0 @@ -colour\_datasets.datasets -========================= - -.. currentmodule:: colour_datasets - -.. autofunction:: datasets \ No newline at end of file diff --git a/docs/generated/colour_datasets.load.rst b/docs/generated/colour_datasets.load.rst deleted file mode 100644 index 6665927..0000000 --- a/docs/generated/colour_datasets.load.rst +++ /dev/null @@ -1,6 +0,0 @@ -colour\_datasets.load -===================== - -.. currentmodule:: colour_datasets - -.. autofunction:: load \ No newline at end of file diff --git a/docs/generated/colour_datasets.loaders.AbstractDatasetLoader.rst b/docs/generated/colour_datasets.loaders.AbstractDatasetLoader.rst deleted file mode 100644 index 0d9e5dc..0000000 --- a/docs/generated/colour_datasets.loaders.AbstractDatasetLoader.rst +++ /dev/null @@ -1,33 +0,0 @@ -colour\_datasets.loaders.AbstractDatasetLoader -============================================== - -.. currentmodule:: colour_datasets.loaders - -.. autoclass:: AbstractDatasetLoader - - - .. automethod:: __init__ - - - .. rubric:: Methods - - .. autosummary:: - - ~AbstractDatasetLoader.__init__ - ~AbstractDatasetLoader.load - ~AbstractDatasetLoader.sync - - - - - - .. rubric:: Attributes - - .. autosummary:: - - ~AbstractDatasetLoader.ID - ~AbstractDatasetLoader.data - ~AbstractDatasetLoader.id - ~AbstractDatasetLoader.record - - \ No newline at end of file diff --git a/docs/generated/colour_datasets.loaders.DATASET_LOADERS.rst b/docs/generated/colour_datasets.loaders.DATASET_LOADERS.rst deleted file mode 100644 index 8c8ed9b..0000000 --- a/docs/generated/colour_datasets.loaders.DATASET_LOADERS.rst +++ /dev/null @@ -1,6 +0,0 @@ -colour\_datasets.loaders.DATASET\_LOADERS -========================================= - -.. currentmodule:: colour_datasets.loaders - -.. autodata:: DATASET_LOADERS \ No newline at end of file diff --git a/docs/generated/colour_datasets.loaders.Jiang2013DatasetLoader.rst b/docs/generated/colour_datasets.loaders.Jiang2013DatasetLoader.rst deleted file mode 100644 index 0753fd8..0000000 --- a/docs/generated/colour_datasets.loaders.Jiang2013DatasetLoader.rst +++ /dev/null @@ -1,33 +0,0 @@ -colour\_datasets.loaders.Jiang2013DatasetLoader -=============================================== - -.. currentmodule:: colour_datasets.loaders - -.. autoclass:: Jiang2013DatasetLoader - - - .. automethod:: __init__ - - - .. rubric:: Methods - - .. autosummary:: - - ~Jiang2013DatasetLoader.__init__ - ~Jiang2013DatasetLoader.load - ~Jiang2013DatasetLoader.sync - - - - - - .. rubric:: Attributes - - .. autosummary:: - - ~Jiang2013DatasetLoader.ID - ~Jiang2013DatasetLoader.data - ~Jiang2013DatasetLoader.id - ~Jiang2013DatasetLoader.record - - \ No newline at end of file diff --git a/docs/generated/colour_datasets.loaders.Labsphere2019DatasetLoader.rst b/docs/generated/colour_datasets.loaders.Labsphere2019DatasetLoader.rst deleted file mode 100644 index 9bfa790..0000000 --- a/docs/generated/colour_datasets.loaders.Labsphere2019DatasetLoader.rst +++ /dev/null @@ -1,33 +0,0 @@ -colour\_datasets.loaders.Labsphere2019DatasetLoader -=================================================== - -.. currentmodule:: colour_datasets.loaders - -.. autoclass:: Labsphere2019DatasetLoader - - - .. automethod:: __init__ - - - .. rubric:: Methods - - .. autosummary:: - - ~Labsphere2019DatasetLoader.__init__ - ~Labsphere2019DatasetLoader.load - ~Labsphere2019DatasetLoader.sync - - - - - - .. rubric:: Attributes - - .. autosummary:: - - ~Labsphere2019DatasetLoader.ID - ~Labsphere2019DatasetLoader.data - ~Labsphere2019DatasetLoader.id - ~Labsphere2019DatasetLoader.record - - \ No newline at end of file diff --git a/docs/generated/colour_datasets.loaders.XRite2016DatasetLoader.rst b/docs/generated/colour_datasets.loaders.XRite2016DatasetLoader.rst deleted file mode 100644 index bcb04f1..0000000 --- a/docs/generated/colour_datasets.loaders.XRite2016DatasetLoader.rst +++ /dev/null @@ -1,33 +0,0 @@ -colour\_datasets.loaders.XRite2016DatasetLoader -=============================================== - -.. currentmodule:: colour_datasets.loaders - -.. autoclass:: XRite2016DatasetLoader - - - .. automethod:: __init__ - - - .. rubric:: Methods - - .. autosummary:: - - ~XRite2016DatasetLoader.__init__ - ~XRite2016DatasetLoader.load - ~XRite2016DatasetLoader.sync - - - - - - .. rubric:: Attributes - - .. autosummary:: - - ~XRite2016DatasetLoader.ID - ~XRite2016DatasetLoader.data - ~XRite2016DatasetLoader.id - ~XRite2016DatasetLoader.record - - \ No newline at end of file diff --git a/docs/generated/colour_datasets.loaders.build_Jiang2013.rst b/docs/generated/colour_datasets.loaders.build_Jiang2013.rst deleted file mode 100644 index 72845a5..0000000 --- a/docs/generated/colour_datasets.loaders.build_Jiang2013.rst +++ /dev/null @@ -1,6 +0,0 @@ -colour\_datasets.loaders.build\_Jiang2013 -========================================= - -.. currentmodule:: colour_datasets.loaders - -.. autofunction:: build_Jiang2013 \ No newline at end of file diff --git a/docs/generated/colour_datasets.loaders.build_Labsphere2019.rst b/docs/generated/colour_datasets.loaders.build_Labsphere2019.rst deleted file mode 100644 index de7120d..0000000 --- a/docs/generated/colour_datasets.loaders.build_Labsphere2019.rst +++ /dev/null @@ -1,6 +0,0 @@ -colour\_datasets.loaders.build\_Labsphere2019 -============================================= - -.. currentmodule:: colour_datasets.loaders - -.. autofunction:: build_Labsphere2019 \ No newline at end of file diff --git a/docs/generated/colour_datasets.loaders.build_XRite2016.rst b/docs/generated/colour_datasets.loaders.build_XRite2016.rst deleted file mode 100644 index 063ab76..0000000 --- a/docs/generated/colour_datasets.loaders.build_XRite2016.rst +++ /dev/null @@ -1,6 +0,0 @@ -colour\_datasets.loaders.build\_XRite2016 -========================================= - -.. currentmodule:: colour_datasets.loaders - -.. autofunction:: build_XRite2016 \ No newline at end of file diff --git a/docs/generated/colour_datasets.records.Community.rst b/docs/generated/colour_datasets.records.Community.rst deleted file mode 100644 index d0e8be4..0000000 --- a/docs/generated/colour_datasets.records.Community.rst +++ /dev/null @@ -1,39 +0,0 @@ -colour\_datasets.records.Community -================================== - -.. currentmodule:: colour_datasets.records - -.. autoclass:: Community - - - .. automethod:: __init__ - - - .. rubric:: Methods - - .. autosummary:: - - ~Community.__init__ - ~Community.from_id - ~Community.get - ~Community.items - ~Community.keys - ~Community.pull - ~Community.remove - ~Community.synced - ~Community.values - - - - - - .. rubric:: Attributes - - .. autosummary:: - - ~Community.configuration - ~Community.data - ~Community.records - ~Community.repository - - \ No newline at end of file diff --git a/docs/generated/colour_datasets.records.Configuration.rst b/docs/generated/colour_datasets.records.Configuration.rst deleted file mode 100644 index b6bc1cd..0000000 --- a/docs/generated/colour_datasets.records.Configuration.rst +++ /dev/null @@ -1,33 +0,0 @@ -colour\_datasets.records.Configuration -====================================== - -.. currentmodule:: colour_datasets.records - -.. autoclass:: Configuration - - - .. automethod:: __init__ - - - .. rubric:: Methods - - .. autosummary:: - - ~Configuration.__init__ - ~Configuration.clear - ~Configuration.copy - ~Configuration.fromkeys - ~Configuration.get - ~Configuration.items - ~Configuration.keys - ~Configuration.pop - ~Configuration.popitem - ~Configuration.setdefault - ~Configuration.update - ~Configuration.values - - - - - - \ No newline at end of file diff --git a/docs/generated/colour_datasets.records.Record.rst b/docs/generated/colour_datasets.records.Record.rst deleted file mode 100644 index c26fce9..0000000 --- a/docs/generated/colour_datasets.records.Record.rst +++ /dev/null @@ -1,36 +0,0 @@ -colour\_datasets.records.Record -=============================== - -.. currentmodule:: colour_datasets.records - -.. autoclass:: Record - - - .. automethod:: __init__ - - - .. rubric:: Methods - - .. autosummary:: - - ~Record.__init__ - ~Record.from_id - ~Record.pull - ~Record.remove - ~Record.synced - - - - - - .. rubric:: Attributes - - .. autosummary:: - - ~Record.configuration - ~Record.data - ~Record.id - ~Record.repository - ~Record.title - - \ No newline at end of file diff --git a/docs/generated/colour_datasets.records.use_sandbox.rst b/docs/generated/colour_datasets.records.use_sandbox.rst deleted file mode 100644 index 4c2ae29..0000000 --- a/docs/generated/colour_datasets.records.use_sandbox.rst +++ /dev/null @@ -1,6 +0,0 @@ -colour\_datasets.records.use\_sandbox -===================================== - -.. currentmodule:: colour_datasets.records - -.. autofunction:: use_sandbox \ No newline at end of file diff --git a/docs/generated/colour_datasets.sandbox.rst b/docs/generated/colour_datasets.sandbox.rst deleted file mode 100644 index a72cf16..0000000 --- a/docs/generated/colour_datasets.sandbox.rst +++ /dev/null @@ -1,22 +0,0 @@ -colour\_datasets.sandbox -======================== - -.. currentmodule:: colour_datasets - -.. autoclass:: sandbox - - - .. automethod:: __init__ - - - .. rubric:: Methods - - .. autosummary:: - - ~sandbox.__init__ - - - - - - \ No newline at end of file diff --git a/docs/generated/colour_datasets.utilities.hash_md5.rst b/docs/generated/colour_datasets.utilities.hash_md5.rst deleted file mode 100644 index c6e1e53..0000000 --- a/docs/generated/colour_datasets.utilities.hash_md5.rst +++ /dev/null @@ -1,6 +0,0 @@ -colour\_datasets.utilities.hash\_md5 -==================================== - -.. currentmodule:: colour_datasets.utilities - -.. autofunction:: hash_md5 \ No newline at end of file diff --git a/docs/generated/colour_datasets.utilities.json_open.rst b/docs/generated/colour_datasets.utilities.json_open.rst deleted file mode 100644 index 532c221..0000000 --- a/docs/generated/colour_datasets.utilities.json_open.rst +++ /dev/null @@ -1,6 +0,0 @@ -colour\_datasets.utilities.json\_open -===================================== - -.. currentmodule:: colour_datasets.utilities - -.. autofunction:: json_open \ No newline at end of file diff --git a/docs/generated/colour_datasets.utilities.suppress_stdout.rst b/docs/generated/colour_datasets.utilities.suppress_stdout.rst deleted file mode 100644 index 5788885..0000000 --- a/docs/generated/colour_datasets.utilities.suppress_stdout.rst +++ /dev/null @@ -1,16 +0,0 @@ -colour\_datasets.utilities.suppress\_stdout -=========================================== - -.. currentmodule:: colour_datasets.utilities - -.. autoclass:: suppress_stdout - - - .. automethod:: __init__ - - - - - - - \ No newline at end of file diff --git a/docs/generated/colour_datasets.utilities.url_download.rst b/docs/generated/colour_datasets.utilities.url_download.rst deleted file mode 100644 index de22b01..0000000 --- a/docs/generated/colour_datasets.utilities.url_download.rst +++ /dev/null @@ -1,6 +0,0 @@ -colour\_datasets.utilities.url\_download -======================================== - -.. currentmodule:: colour_datasets.utilities - -.. autofunction:: url_download \ No newline at end of file diff --git a/docs/index.rst b/docs/index.rst index 2335d1d..28d319a 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -2,14 +2,14 @@ Colour - Datasets ================= Colour science datasets for use with -`Colour `_ or any Python package -manipulating colours. The datasets are hosted in `Zenodo `_ +`Colour `__ or any Python package +manipulating colours. The datasets are hosted in `Zenodo `__ under the -`Colour Science - Datasets `_ +`Colour Science - Datasets `__ community. It is open source and freely available under the -`New BSD License `_ terms. +`New BSD License `__ terms. .. contents:: **Table of Contents** :backlinks: none @@ -20,6 +20,35 @@ It is open source and freely available under the Features -------- +**Colour - Datasets** was created to overcome issues encountered frequently +when trying to access or use colour science datasets: + +- No straightforward ingestion path for dataset content. +- No simple loading mechanism for dataset content. +- Unavailability of the dataset, e.g. download url is down, dataset + content is passed directly from hand to hand. +- No information regarding the definitive origination of the dataset. + +**Colour - Datasets** offers all the above: it allows users to ingest and load +colour science datasets with a single function call. The datasets information +is hosted on `Zenodo `__ +where the record for a dataset typically contain: + +- An *urls.txt* file describing the urls to source the dataset files from. +- A copy of those files in the eventuality where the source files are not + available or the content has changed without notice. +- Information about the authors, content and licensing. + +When no explicit licensing information is available, the dataset adopts the +**Other (Not Open)** licensing scheme, implying that assessing usage conditions +is at the sole discretion of the users. + +Online +------ + +**Colour - Datasets** can be used online with +`Google Colab `__. + Installation ------------ @@ -28,16 +57,17 @@ Primary Dependencies **Colour - Datasets** requires various dependencies in order to run: -- `Python 2.7 `_ or - `Python 3.7 `_ -- `Colour Science `_ -- `tqdm `_ +- `Python 2.7 `__ or + `Python 3.7 `__ +- `Colour Science `__ +- `tqdm `__ +- `xlrd `__ Pypi ^^^^ Once the dependencies satisfied, **Colour - Datasets** can be installed from -the `Python Package Index `_ by +the `Python Package Index `__ by issuing this command in a shell:: pip install colour-datasets @@ -61,7 +91,7 @@ API ^^^ The main reference for -`Colour - Datasets `_ +`Colour - Datasets `__ is the manual: .. toctree:: @@ -72,27 +102,101 @@ is the manual: Examples ^^^^^^^^ -Various usage examples are available from the -`examples directory `_. +Most of the objects are available from the ``colour_datasets`` namespace: + +.. code-block:: python + + >>> import colour_datasets + +The available datasets are listed with the ``colour_datasets.datasets()`` +definition: + +.. code-block:: python + + >>> print(colour_datasets.datasets()) + +:: + + colour-science-datasets + ======================= + + Datasets : 16 + Synced : 1 + URL : https://zenodo.org/communities/colour-science-datasets/ + + Datasets + -------- + + [ ] 3269926 : Agfa IT8.7/2 Set + [ ] 3245883 : Camera Spectral Sensitivity Database + [ ] 3367463 : Constant Hue Loci Data + [ ] 3362536 : Constant Perceived-Hue Data + [ ] 3270903 : Corresponding-Colour Datasets + [ ] 3269920 : Forest Colors + [x] 3245875 : Labsphere SRS-99-020 + [ ] 3269924 : Lumber Spectra + [ ] 3269918 : Munsell Colors Glossy (All) (Spectrofotometer Measured) + [ ] 3269916 : Munsell Colors Glossy (Spectrofotometer Measured) + [ ] 3269914 : Munsell Colors Matt (AOTF Measured) + [ ] 3269912 : Munsell Colors Matt (Spectrofotometer Measured) + [ ] 3245895 : New Color Specifications for ColorChecker SG and Classic Charts + [ ] 3252742 : Observer Function Database + [ ] 3269922 : Paper Spectra + [ ] 3372171 : RAW to ACES Utility Data + +A ticked checkbox means that the particular dataset has been synced locally. +A dataset is loaded by using its unique number: *3245895*: + +.. code-block:: python + + >>> print(colour_datasets.load('3245895').keys()) + +:: + + Pulling "New Color Specifications for ColorChecker SG and Classic Charts" record content... + Downloading "urls.txt" file: 8.19kB [00:01, 5.05kB/s] + Downloading "ColorChecker24_After_Nov2014.zip" file: 8.19kB [00:01, 6.52kB/s] + Downloading "ColorChecker24_Before_Nov2014.zip" file: 8.19kB [00:01, 7.66kB/s] + Downloading "ColorCheckerSG_After_Nov2014.zip" file: 8.19kB [00:01, 7.62kB/s] + Downloading "ColorCheckerSG_Before_Nov2014.zip" file: 8.19kB [00:00, 9.39kB/s] + Unpacking "/Users/kelsolaar/.colour-science/colour-datasets/3245895/dataset/ColorCheckerSG_Before_Nov2014.zip" archive... + Unpacking "/Users/kelsolaar/.colour-science/colour-datasets/3245895/dataset/ColorCheckerSG_After_Nov2014.zip" archive... + Unpacking "/Users/kelsolaar/.colour-science/colour-datasets/3245895/dataset/ColorChecker24_After_Nov2014.zip" archive... + Unpacking "/Users/kelsolaar/.colour-science/colour-datasets/3245895/dataset/ColorChecker24_Before_Nov2014.zip" archive... + odict_keys(['ColorChecker24 - After November 2014', 'ColorChecker24 - Before November 2014', 'ColorCheckerSG - After November 2014', 'ColorCheckerSG - Before November 2014']) + +Alternatively, a dataset can be loaded by using its full title: +*New Color Specifications for ColorChecker SG and Classic Charts* + +.. code-block:: python + + >>> print(colour_datasets.load('3245895').keys()) + odict_keys(['ColorChecker24 - After November 2014', 'ColorChecker24 - Before November 2014', 'ColorCheckerSG - After November 2014', 'ColorCheckerSG - Before November 2014']) Contributing ------------ -If you would like to contribute to `Colour - Datasets `_, -please refer to the following `Contributing `_ -guide for `Colour `_. +If you would like to contribute to `Colour - Datasets `__, +please refer to the following `Contributing `__ +guide for `Colour `__. Bibliography ------------ The bibliography is available in the repository in -`BibTeX `_ +`BibTeX `__ format. +Code of Conduct +--------------- + +The *Code of Conduct*, adapted from the `Contributor Covenant 1.4 `__, +is available on the `Code of Conduct `__ page. + About ----- | **Colour - Datasets** by Colour Developers -| Copyright © 2019 – Colour Developers – `colour-science@googlegroups.com `_ +| Copyright © 2019 – Colour Developers – `colour-science@googlegroups.com `__ | This software is released under terms of New BSD License: https://opensource.org/licenses/BSD-3-Clause -| `https://github.com/colour-science/colour-datasets `_ +| `https://github.com/colour-science/colour-datasets `__ diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..8f0a3e1 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,111 @@ +[tool.poetry] +name = "colour-datasets" +version = "0.1.0" +description = "Colour science datasets for use with Colour" +license = "BSD-3-Clause" +authors = [ "Colour Developers" ] +readme = 'README.rst' +repository = "https://github.com/colour-science/colour-datasets" +homepage = "https://www.colour-science.org/" +keywords = [ + "color", + "color-science", + "color-space", + "color-spaces", + "colorspace", + "colorspaces", + "colour", + "colour-science", + "colour-space", + "colour-spaces", + "colourspace", + "colourspaces", + "data", + "dataset", + "datasets", + "python", + "spectral-data", + "spectral-dataset", + "spectral-datasets" +] +classifiers = [ + "Development Status :: 3 - Alpha", + "Environment :: Console", + "Intended Audience :: Developers", + "Intended Audience :: Science/Research", + "License :: OSI Approved", + "Natural Language :: English", + "Operating System :: OS Independent", + "Programming Language :: Python :: 2.7", + "Programming Language :: Python :: 3", + "Topic :: Scientific/Engineering", + "Topic :: Software Development" +] + +[tool.poetry.dependencies] +python = "~2.7 || ^3.5" +cachetools = "*" +colour-science = "^0.3.14" +tqdm = "*" +xlrd = "*" + +biblib-simple = { version = "*", optional = true } # Development dependency. +coverage = { version = "*", optional = true } # Development dependency. +coveralls = { version = "*", optional = true } # Development dependency. +flake8 = { version = "*", optional = true } # Development dependency. +invoke = { version = "*", optional = true } # Development dependency. +mock = { version = "*", optional = true } # Development dependency. +nose = { version = "*", optional = true } # Development dependency. +numpy = { version = "*", optional = true } +pre-commit = { version = "*", optional = true } # Development dependency. +pytest = { version = "*", optional = true } # Development dependency. +restructuredtext-lint = { version = "*", optional = true } # Development dependency. +sphinx = { version = "*", optional = true } # Development dependency. +sphinx_rtd_theme = { version = "*", optional = true } # Development dependency. +sphinxcontrib-bibtex = { version = "*", optional = true } # Development dependency. +toml = { version = "*", optional = true } # Development dependency. +twine = { version = "*", optional = true } # Development dependency. +yapf = { version = "0.23", optional = true } # Development dependency. + +[tool.poetry.dev-dependencies] +biblib-simple = "*" +coverage = "*" +coveralls = "*" +flake8 = "*" +invoke = "*" +mock = "*" +nose = "*" +pre-commit = "*" +pytest = "*" +restructuredtext-lint = "*" +sphinx = "*" +sphinx_rtd_theme = "*" +sphinxcontrib-bibtex = "*" +toml = "*" +twine = "*" +yapf = "0.23" + +[tool.poetry.extras] +development = [ + "biblib-simple", + "coverage", + "coveralls", + "flake8", + "invoke", + "mock", + "nose", + "pre-commit", + "pytest", + "restructuredtext-lint", + "sphinx", + "sphinx_rtd_theme", + "sphinxcontrib-bibtex", + "toml", + "twine", + "yapf" +] +read-the-docs = [ "mock", "numpy", "sphinxcontrib-bibtex" ] + +[build-system] +requires = [ "poetry>=0.12" ] +build-backend = "poetry.masonry.api" diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..5788ac2 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,75 @@ +alabaster==0.7.12 +aspy.yaml==1.3.0 +atomicwrites==1.3.0 +attrs==19.3.0 +Babel==2.7.0 +biblib-simple==0.1.1 +bleach==3.1.0 +cachetools==3.1.1 +certifi==2019.9.11 +cfgv==2.0.1 +chardet==3.0.4 +colour-science==0.3.14 +coverage==4.5.4 +coveralls==1.8.2 +docopt==0.6.2 +docutils==0.15.2 +entrypoints==0.3 +flake8==3.7.8 +identify==1.4.7 +idna==2.8 +imageio==2.6.1 +imagesize==1.1.0 +importlib-metadata==0.23 +invoke==1.3.0 +Jinja2==2.10.3 +latexcodec==1.0.7 +MarkupSafe==1.1.1 +mccabe==0.6.1 +mock==3.0.5 +more-itertools==7.2.0 +nodeenv==1.3.3 +nose==1.3.7 +numpy==1.17.3 +oset==0.1.3 +packaging==19.2 +Pillow==6.2.1 +pkginfo==1.5.0.1 +pluggy==0.13.0 +pre-commit==1.19.0 +py==1.8.0 +pybtex==0.22.2 +pybtex-docutils==0.2.2 +pycodestyle==2.5.0 +pyflakes==2.1.1 +Pygments==2.4.2 +pyparsing==2.4.2 +pytest==5.2.2 +pytz==2019.3 +PyYAML==5.1.2 +readme-renderer==24.0 +requests==2.22.0 +requests-toolbelt==0.9.1 +restructuredtext-lint==1.3.0 +scipy==1.3.1 +six==1.12.0 +snowballstemmer==2.0.0 +Sphinx==2.2.1 +sphinx-rtd-theme==0.4.3 +sphinxcontrib-applehelp==1.0.1 +sphinxcontrib-bibtex==1.0.0 +sphinxcontrib-devhelp==1.0.1 +sphinxcontrib-htmlhelp==1.0.2 +sphinxcontrib-jsmath==1.0.1 +sphinxcontrib-qthelp==1.0.2 +sphinxcontrib-serializinghtml==1.1.3 +toml==0.10.0 +tqdm==4.36.1 +twine==1.15.0 +urllib3==1.25.6 +virtualenv==16.7.7 +wcwidth==0.1.7 +webencodings==0.5.1 +xlrd==1.2.0 +yapf==0.23.0 +zipp==0.6.0 diff --git a/setup.py b/setup.py deleted file mode 100644 index e1e0ed2..0000000 --- a/setup.py +++ /dev/null @@ -1,104 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- -""" -Pypi Setup -========== -""" - -from __future__ import unicode_literals - -import os -import re -import sys -from setuptools import setup -from setuptools import find_packages - -__author__ = 'Colour Developers' -__copyright__ = 'Copyright (C) 2019 - Colour Developers' -__license__ = 'New BSD License - https://opensource.org/licenses/BSD-3-Clause' -__maintainer__ = 'Colour Developers' -__email__ = 'colour-science@googlegroups.com' -__status__ = 'Production' - -__all__ = [ - 'SHORT_DESCRIPTION', 'LONG_DESCRIPTION', 'INSTALLATION_REQUIREMENTS', - 'OPTIONAL_REQUIREMENTS', 'DOCS_REQUIREMENTS', 'TESTS_REQUIREMENTS', - 'DEVELOPMENT_REQUIREMENTS' -] - -SHORT_DESCRIPTION = 'Colour Science - Datasets' - -LONG_DESCRIPTION = open('README.rst').read() - -INSTALLATION_REQUIREMENTS = ['colour-science>=0.3.12', 'tqdm'] - -if os.environ.get('READTHEDOCS') == 'True': - INSTALLATION_REQUIREMENTS += [ - 'numpy>=1.8.1', 'mock', 'sphinxcontrib-bibtex' - ] - -OPTIONAL_REQUIREMENTS = [] - -DOCS_REQUIREMENTS = [ - 'sphinx>=1.6.6', 'sphinxcontrib-bibtex', 'sphinx_rtd_theme' -] - -TESTS_REQUIREMENTS = ['coverage>=3.7.1', 'flake8>=2.1.0', 'nose>=1.3.4'] - -DEVELOPMENT_REQUIREMENTS = DOCS_REQUIREMENTS + TESTS_REQUIREMENTS + [ - 'invoke', 'restructuredtext_lint', 'twine', 'yapf==0.23.0' -] -if sys.version_info[:2] >= (3, 2): - DEVELOPMENT_REQUIREMENTS += ['biblib-simple'] - - -def get_version(): - """ - Returns the package full version. - - Returns - ------- - unicode - Package full version. - """ - - with open(os.path.join('colour_datasets', '__init__.py')) as file_handle: - file_content = file_handle.read() - major_version = re.search("__major_version__\s+=\s+'(.*)'", - file_content).group(1) - minor_version = re.search("__minor_version__\s+=\s+'(.*)'", - file_content).group(1) - change_version = re.search("__change_version__\s+=\s+'(.*)'", - file_content).group(1) - - return '.'.join((major_version, minor_version, change_version)) - - -setup( - name='colour-datasets', - version=get_version(), - author=__author__, - author_email=__email__, - include_package_data=True, - packages=find_packages(), - scripts=[], - url='https://github.com/colour-science/colour-datasets', - license=__license__, - description=SHORT_DESCRIPTION, - long_description=LONG_DESCRIPTION, - install_requires=INSTALLATION_REQUIREMENTS, - extras_require={ - 'docs': DOCS_REQUIREMENTS, - 'development': DEVELOPMENT_REQUIREMENTS, - 'optional': OPTIONAL_REQUIREMENTS, - 'tests': TESTS_REQUIREMENTS - }, - classifiers=[ - 'Development Status :: 3 - Alpha', 'Environment :: Console', - 'Intended Audience :: Developers', - 'Intended Audience :: Science/Research', 'License :: OSI Approved', - 'Natural Language :: English', 'Operating System :: OS Independent', - 'Programming Language :: Python :: 2.7', - 'Programming Language :: Python :: 3', - 'Topic :: Scientific/Engineering', 'Topic :: Software Development' - ]) diff --git a/tasks.py b/tasks.py index 25ff889..f35c320 100644 --- a/tasks.py +++ b/tasks.py @@ -7,11 +7,14 @@ from __future__ import unicode_literals import sys -if sys.version_info[:2] >= (3, 2): +try: import biblib.bib +except ImportError: + pass import fnmatch import os import re +import uuid from invoke import task import colour_datasets @@ -25,14 +28,16 @@ __status__ = 'Production' __all__ = [ - 'APPLICATION_NAME', 'PYTHON_PACKAGE_NAME', 'PYPI_PACKAGE_NAME', - 'BIBLIOGRAPHY_NAME', 'clean', 'formatting', 'tests', 'quality', 'examples', - 'docs', 'todo', 'preflight', 'build', 'virtualise', 'tag', 'release', - 'sha256' + 'APPLICATION_NAME', 'APPLICATION_VERSION', 'PYTHON_PACKAGE_NAME', + 'PYPI_PACKAGE_NAME', 'BIBLIOGRAPHY_NAME', 'clean', 'formatting', 'tests', + 'quality', 'examples', 'preflight', 'docs', 'todo', 'requirements', + 'build', 'virtualise', 'tag', 'release', 'sha256' ] APPLICATION_NAME = colour_datasets.__application_name__ +APPLICATION_VERSION = colour_datasets.__version__ + PYTHON_PACKAGE_NAME = colour_datasets.__name__ PYPI_PACKAGE_NAME = 'colour-datasets' @@ -151,7 +156,8 @@ def tests(ctx, nose=True): format(PYTHON_PACKAGE_NAME)) else: message_box('Running "Pytest"...') - ctx.run('pytest -W ignore') + ctx.run('py.test --disable-warnings --doctest-modules ' + '--ignore={0}/examples {0}'.format(PYTHON_PACKAGE_NAME)) @task @@ -208,6 +214,26 @@ def examples(ctx): ctx.run('python {0}'.format(os.path.join(root, filename))) +@task(formatting, tests, quality, examples) +def preflight(ctx): + """ + Performs the preflight tasks, i.e. *formatting*, *tests*, *quality*, and + *examples*. + + Parameters + ---------- + ctx : invoke.context.Context + Context. + + Returns + ------- + bool + Task success. + """ + + message_box('Finishing "Preflight"...') + + @task def docs(ctx, html=True, pdf=True): """ @@ -261,11 +287,10 @@ def todo(ctx): ctx.run('./export_todo.py') -@task(formatting, tests, quality, examples) -def preflight(ctx): +@task +def requirements(ctx): """ - Performs the preflight tasks, i.e. *formatting*, *tests*, *quality*, and - *examples*. + Export the *requirements.txt* file. Parameters ---------- @@ -278,10 +303,12 @@ def preflight(ctx): Task success. """ - message_box('Finishing "Preflight"...') + message_box('Exporting "requirements.txt" file...') + ctx.run('poetry run pip freeze | grep -v "github.com/colour-science" ' + '> requirements.txt') -@task(docs, todo, preflight) +@task(preflight, docs, todo, requirements) def build(ctx): """ Builds the project and runs dependency tasks, i.e. *docs*, *todo*, and @@ -299,8 +326,7 @@ def build(ctx): """ message_box('Building...') - ctx.run('python setup.py sdist') - ctx.run('python setup.py bdist_wheel --universal') + ctx.run('poetry build') @task(clean, build) @@ -321,25 +347,18 @@ def virtualise(ctx, tests=True): Task success. """ - pip_binary = '../staging/bin/pip' - nosetests_binary = '../staging/bin/nosetests' - + unique_name = '{0}-{1}'.format(PYPI_PACKAGE_NAME, uuid.uuid1()) with ctx.cd('dist'): - ctx.run('tar -xvf {0}-*.tar.gz'.format(PYPI_PACKAGE_NAME)) - ctx.run('virtualenv staging') - with ctx.cd('{0}-*'.format(PYPI_PACKAGE_NAME)): - ctx.run('pwd') - ctx.run('{0} install numpy'.format(pip_binary)) - ctx.run('{0} install -e .'.format(pip_binary)) - ctx.run('{0} install matplotlib'.format(pip_binary)) - ctx.run('{0} install nose'.format(pip_binary)) - ctx.run('{0} install mock'.format(pip_binary)) + ctx.run('tar -xvf {0}-{1}.tar.gz'.format(PYPI_PACKAGE_NAME, + APPLICATION_VERSION)) + ctx.run('mv {0}-{1} {2}'.format(PYPI_PACKAGE_NAME, APPLICATION_VERSION, + unique_name)) + with ctx.cd(unique_name): + ctx.run('poetry env use 3') + ctx.run('poetry install') + ctx.run('source $(poetry env info -p)/bin/activate') if tests: - # TODO: Find a way to deploy OpenImageIO. - - return - - ctx.run(nosetests_binary) + ctx.run('poetry run nosetests') @task @@ -359,17 +378,18 @@ def tag(ctx): """ message_box('Tagging...') - result = ctx.run('git reverse-parse --abbrev-ref HEAD', hide='both') + result = ctx.run('git rev-parse --abbrev-ref HEAD', hide='both') + assert result.stdout.strip() == 'develop', ( 'Are you still on a feature or master branch?') with open(os.path.join(PYTHON_PACKAGE_NAME, '__init__.py')) as file_handle: file_content = file_handle.read() - major_version = re.search("__major_version__\s+=\s+'(.*)'", + major_version = re.search("__major_version__\\s+=\\s+'(.*)'", file_content).group(1) - minor_version = re.search("__minor_version__\s+=\s+'(.*)'", + minor_version = re.search("__minor_version__\\s+=\\s+'(.*)'", file_content).group(1) - change_version = re.search("__change_version__\s+=\s+'(.*)'", + change_version = re.search("__change_version__\\s+=\\s+'(.*)'", file_content).group(1) version = '.'.join((major_version, minor_version, change_version)) diff --git a/utilities/export_todo.py b/utilities/export_todo.py index 817c2e7..6dada25 100755 --- a/utilities/export_todo.py +++ b/utilities/export_todo.py @@ -32,9 +32,12 @@ ----- | **Colour - Datasets** by Colour Developers -| Copyright © 2019 – Colour Developers – `colour-science@googlegroups.com `_ -| This software is released under terms of New BSD License: https://opensource.org/licenses/BSD-3-Clause -| `https://github.com/colour-science/colour-datasets `_ +| Copyright © 2019 – Colour Developers – \ +`colour-science@googlegroups.com `_ +| This software is released under terms of New BSD License: \ +https://opensource.org/licenses/BSD-3-Clause +| `https://github.com/colour-science/colour-datasets \ +`_ """ [1:] diff --git a/utilities/unicode_to_ascii.py b/utilities/unicode_to_ascii.py index 29d9ae5..3032228 100755 --- a/utilities/unicode_to_ascii.py +++ b/utilities/unicode_to_ascii.py @@ -11,9 +11,9 @@ reload(sys) # noqa sys.setdefaultencoding('utf-8') -import codecs -import os -import unicodedata +import codecs # noqa +import os # noqa +import unicodedata # noqa __copyright__ = 'Copyright (C) 2018-2019 - Colour Developers' __license__ = 'New BSD License - https://opensource.org/licenses/BSD-3-Clause'