├── .coveragerc ├── .github └── workflows │ └── ci.yml ├── .gitignore ├── .travis.yml ├── CHANGELOG.rst ├── CODE_OF_CONDUCT.md ├── MANIFEST.in ├── README.rst ├── conftest.py ├── demo ├── Cubehelix Demo.ipynb └── Palettable Demo.ipynb ├── docs ├── Makefile ├── README.rst ├── _layouts │ ├── _base.html │ ├── analytics.html │ ├── footer.html │ ├── home.html │ ├── index.html │ ├── page.html │ ├── sharing.html │ └── simple_page.html ├── _python │ ├── __init__.py │ └── filters.py ├── _site.yml ├── cartocolors │ ├── diverging │ │ └── index.md.tpl │ ├── index.md │ ├── qualitative │ │ └── index.md.tpl │ └── sequential │ │ └── index.md.tpl ├── cmocean │ ├── diverging │ │ └── index.md.tpl │ ├── index.md │ └── sequential │ │ └── index.md.tpl ├── colorbrewer │ ├── diverging │ │ └── index.md.tpl │ ├── index.md │ ├── qualitative │ │ └── index.md.tpl │ └── sequential │ │ └── index.md.tpl ├── css │ ├── site.css │ └── syntax.css ├── cubehelix │ └── index.md.tpl ├── gendocs.py ├── index.md ├── lightbartlein │ ├── diverging │ │ └── index.md.tpl │ ├── index.md │ └── sequential │ │ └── index.md.tpl ├── matplotlib │ └── index.md.tpl ├── mycarta │ └── index.md.tpl ├── plotly │ ├── diverging │ │ └── index.md.tpl │ ├── index.md.tpl │ ├── qualitative │ │ └── index.md.tpl │ └── sequential │ │ └── index.md.tpl ├── scientific │ ├── diverging │ │ └── index.md.tpl │ ├── index.md │ ├── qualitative │ │ └── index.md.tpl │ └── sequential │ │ └── index.md.tpl ├── tableau │ └── index.md.tpl └── wesanderson │ └── index.md.tpl ├── license.txt ├── palettable ├── __init__.py ├── cartocolors │ ├── __init__.py │ ├── cartocolorspalette.py │ ├── colormaps.py │ ├── diverging.py │ ├── qualitative.py │ ├── sequential.py │ └── test │ │ ├── __init__.py │ │ └── test_cartocolors.py ├── cmocean │ ├── __init__.py │ ├── cmoceanpalette.py │ ├── colormaps.py │ ├── diverging.py │ ├── sequential.py │ └── test │ │ ├── __init__.py │ │ └── test_cmocean.py ├── colorbrewer │ ├── __init__.py │ ├── colorbrewer.py │ ├── colorbrewer_all_schemes.py │ ├── data │ │ ├── colorbrewer_all_schemes.csv │ │ ├── colorbrewer_licence.txt │ │ └── colorbrewer_schemes_csv_to_py.py │ ├── diverging.py │ ├── qualitative.py │ ├── sequential.py │ └── test │ │ ├── __init__.py │ │ ├── test_colorbrewer.py │ │ ├── test_get_map.py │ │ └── test_print_functions.py ├── cubehelix │ ├── __init__.py │ ├── cubehelix.py │ └── test │ │ ├── __init__.py │ │ └── test_cubehelix.py ├── lightbartlein │ ├── __init__.py │ ├── colordata.py │ ├── diverging.py │ ├── lightbartlein.py │ ├── sequential.py │ └── test │ │ ├── __init__.py │ │ └── test_lightbartlein.py ├── matplotlib │ ├── __init__.py │ ├── colormaps.py │ ├── matplotlib.py │ └── test │ │ ├── __init__.py │ │ └── test_matplotlib.py ├── mycarta │ ├── __init__.py │ ├── colordata.py │ ├── mycarta.py │ └── test │ │ ├── __init__.py │ │ └── test_mycarta.py ├── palette.py ├── plotly │ ├── __init__.py │ ├── colordata.py │ ├── diverging.py │ ├── plotly.py │ ├── qualitative.py │ ├── sequential.py │ └── test │ │ ├── __init__.py │ │ └── test_plotly.py ├── scientific │ ├── __init__.py │ ├── colordata.py │ ├── colordata_qualitative.py │ ├── diverging.py │ ├── qualitative.py │ ├── scientific.py │ ├── sequential.py │ └── test │ │ ├── __init__.py │ │ └── test_scientific.py ├── tableau │ ├── __init__.py │ ├── tableau.py │ └── test │ │ ├── __init__.py │ │ └── test_tableau.py ├── test │ ├── __init__.py │ ├── test_brewermap.py │ └── test_utils.py ├── utils.py └── wesanderson │ ├── __init__.py │ ├── test │ ├── __init__.py │ └── test_wesanderson.py │ └── wesanderson.py ├── pyproject.toml ├── scripts └── scientific.py ├── setup.cfg └── test └── test_installed.py /.coveragerc: -------------------------------------------------------------------------------- 1 | [run] 2 | branch = False 3 | source = brewer2mpl 4 | omit = *test_*.py 5 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | pull_request: 8 | branches: 9 | - master 10 | # Run daily at 2:34 UTC 11 | schedule: 12 | - cron: '34 2 * * *' 13 | workflow_dispatch: 14 | 15 | # Cancel existing runs when a new push happens 16 | concurrency: 17 | group: ${{ github.workflow }}-${{ github.ref }} 18 | cancel-in-progress: ${{ github.ref != 'refs/heads/main' }} 19 | 20 | jobs: 21 | test: 22 | runs-on: ${{ matrix.os }} 23 | strategy: 24 | matrix: 25 | os: [ubuntu-latest] 26 | python-version: ["3.7", "3.8", "3.9", "3.10", "3.11", "3.12"] 27 | include: 28 | - os: macos-latest 29 | python-version: "3.8" 30 | - os: macos-latest 31 | python-version: "3.12" 32 | 33 | steps: 34 | - name: Checkout code 35 | uses: actions/checkout@v4 36 | 37 | - name: Set up Python ${{ matrix.python-version }} 38 | uses: actions/setup-python@v5 39 | with: 40 | python-version: ${{ matrix.python-version }} 41 | 42 | - name: Install Python dependencies 43 | run: | 44 | python -m pip install --upgrade pip setuptools wheel 45 | python -m pip install . 46 | python -m pip --quiet install ipythonblocks matplotlib pytest 47 | python -m pip list 48 | #---------------------------------------------- 49 | # load pip cache if cache exists 50 | #---------------------------------------------- 51 | - uses: actions/cache@v3 52 | with: 53 | path: ~/.cache/pip 54 | key: ${{ runner.os }}-pip 55 | restore-keys: ${{ runner.os }}-pip 56 | - name: Run unit tests 57 | run: | 58 | pytest 59 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Created by https://www.gitignore.io/api/python,visualstudiocode,jupyternotebooks 2 | # Edit at https://www.gitignore.io/?templates=python,visualstudiocode,jupyternotebooks 3 | 4 | ### JupyterNotebooks ### 5 | # gitignore template for Jupyter Notebooks 6 | # website: http://jupyter.org/ 7 | 8 | .ipynb_checkpoints 9 | */.ipynb_checkpoints/* 10 | 11 | # Remove previous ipynb_checkpoints 12 | # git rm -r .ipynb_checkpoints/ 13 | # 14 | 15 | ### Python ### 16 | # Byte-compiled / optimized / DLL files 17 | __pycache__/ 18 | *.py[cod] 19 | *$py.class 20 | 21 | # C extensions 22 | *.so 23 | 24 | # Distribution / packaging 25 | .Python 26 | build/ 27 | develop-eggs/ 28 | dist/ 29 | downloads/ 30 | eggs/ 31 | .eggs/ 32 | lib/ 33 | lib64/ 34 | parts/ 35 | sdist/ 36 | var/ 37 | wheels/ 38 | pip-wheel-metadata/ 39 | share/python-wheels/ 40 | *.egg-info/ 41 | .installed.cfg 42 | *.egg 43 | MANIFEST 44 | 45 | # PyInstaller 46 | # Usually these files are written by a python script from a template 47 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 48 | *.manifest 49 | *.spec 50 | 51 | # Installer logs 52 | pip-log.txt 53 | pip-delete-this-directory.txt 54 | 55 | # Unit test / coverage reports 56 | htmlcov/ 57 | .tox/ 58 | .nox/ 59 | .coverage 60 | .coverage.* 61 | .cache 62 | nosetests.xml 63 | coverage.xml 64 | *.cover 65 | .hypothesis/ 66 | .pytest_cache/ 67 | 68 | # Translations 69 | *.mo 70 | *.pot 71 | 72 | # Django stuff: 73 | *.log 74 | local_settings.py 75 | db.sqlite3 76 | db.sqlite3-journal 77 | 78 | # Flask stuff: 79 | instance/ 80 | .webassets-cache 81 | 82 | # Scrapy stuff: 83 | .scrapy 84 | 85 | # Sphinx documentation 86 | docs/_build/ 87 | 88 | # PyBuilder 89 | target/ 90 | 91 | # Jupyter Notebook 92 | 93 | # IPython 94 | profile_default/ 95 | ipython_config.py 96 | 97 | # pyenv 98 | .python-version 99 | 100 | # pipenv 101 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 102 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 103 | # having no cross-platform support, pipenv may install dependencies that don't work, or not 104 | # install all needed dependencies. 105 | #Pipfile.lock 106 | 107 | # celery beat schedule file 108 | celerybeat-schedule 109 | 110 | # SageMath parsed files 111 | *.sage.py 112 | 113 | # Environments 114 | .env 115 | .venv 116 | env/ 117 | venv/ 118 | ENV/ 119 | env.bak/ 120 | venv.bak/ 121 | 122 | # Spyder project settings 123 | .spyderproject 124 | .spyproject 125 | 126 | # Rope project settings 127 | .ropeproject 128 | 129 | # mkdocs documentation 130 | /site 131 | 132 | # mypy 133 | .mypy_cache/ 134 | .dmypy.json 135 | dmypy.json 136 | 137 | # Pyre type checker 138 | .pyre/ 139 | 140 | ### VisualStudioCode ### 141 | .vscode/* 142 | !.vscode/settings.json 143 | !.vscode/tasks.json 144 | !.vscode/launch.json 145 | !.vscode/extensions.json 146 | 147 | ### VisualStudioCode Patch ### 148 | # Ignore all local history of files 149 | .history 150 | 151 | # End of https://www.gitignore.io/api/python,visualstudiocode,jupyternotebooks 152 | 153 | # Generated docs stuff 154 | docs/**/*.png 155 | docs/_build 156 | docs/**/index.md 157 | 158 | # Editor files 159 | .vscode 160 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: python 2 | sudo: false 3 | python: 4 | - "3.4" 5 | - "3.5" 6 | - "3.6" 7 | - "3.7" 8 | env: 9 | - IPYTHON_INSTALL='pip install ipython' MPL_INSTALL='pip install matplotlib' 10 | matrix: 11 | include: 12 | - python: "2.7" 13 | env: > 14 | IPYTHON_INSTALL='pip install ipython>=5,<6' 15 | MPL_INSTALL='pip install matplotlib' 16 | - python: "pypy" 17 | env: > 18 | IPYTHON_INSTALL='pip install ipython>=5,<6' 19 | MPL_INSTALL='echo "not installing matplotlib on pypy"' 20 | - python: "pypy3" 21 | env: > 22 | IPYTHON_INSTALL='pip install ipython' 23 | MPL_INSTALL='echo "not installing matplotlib on pypy"' 24 | install: 25 | - pip install --upgrade pip 26 | - $IPYTHON_INSTALL 27 | - $MPL_INSTALL 28 | - pip install ipythonblocks 29 | - pip install . 30 | - pip install pytest-cov 31 | - pip install coveralls 32 | script: 33 | - py.test --cov palettable --cov-report term-missing 34 | after_success: 35 | - coveralls 36 | -------------------------------------------------------------------------------- /CHANGELOG.rst: -------------------------------------------------------------------------------- 1 | Version 3.3.2 2 | ------------- 3 | 4 | * Set `python_requires` metadata in `setup.py` 5 | 6 | Version 3.3.1 7 | ------------- 8 | 9 | * Removed setuptools as a runtime dependency (thanks @wch in #46) 10 | 11 | Version 3.3.0 12 | ------------- 13 | 14 | * Added `Scientific Colour Maps `_. 15 | * Updated Wes Anderson palettes 16 | 17 | Version 3.2.0 18 | ------------- 19 | 20 | * Light & Bartlein palettes (thanks @dcherian in #30!) 21 | * Drop official support for Python 2.6 and 3.3 22 | 23 | Version 3.1.0 24 | ------------- 25 | 26 | * CartoColors palettes (thanks @andy-esch in #21!) 27 | 28 | Version 3.0.0 29 | ------------- 30 | 31 | * Added new Wes Anderson palettes 32 | * Changed WesAndersonMap.wap_url attribute to .url to match the rest 33 | of the API 34 | * Added modules for cmocean, matplotlib, and mycarta palettes 35 | 36 | Version 2.1 37 | ----------- 38 | 39 | * Add cubehelix palettes (thanks @jonathansick and @jradavenport!) 40 | * Add two new Wes Anderson palettes 41 | 42 | Version 2.0 43 | ----------- 44 | 45 | * Change name of library to Palettable 46 | * Add Tableau palettes 47 | * Additional Wes Anderson palettes 48 | * Pre-make all palettes so they are available at import time 49 | * Change naming scheme to _ 50 | 51 | Version 1.4 52 | ----------- 53 | 54 | * Fix colorbrewer2 URLs, thanks @mbforbes! 55 | * Add ``.show_as_blocks()`` method for displaying color maps 56 | in an IPython Notebook using `ipythonblocks `_. 57 | * Add ``brewer2mpl.wesanderson`` module with color maps from 58 | `Wes Anderson Palettes `_ 59 | 60 | Version 1.3.2 61 | ------------- 62 | 63 | * Fixes for Python 3, thanks @astrofrog! 64 | 65 | Version 1.3.1 66 | ------------- 67 | 68 | * Bugfix release for a Python 2.6 incompatible format string. 69 | 70 | Version 1.3 71 | ----------- 72 | 73 | * Add a ``colorbrewer2`` method to ``BrewerMap`` objects that launches 74 | colorbrewer2.org in the user's browser. 75 | * Added ``sequential``, ``diverging``, and ``qualitative`` modules to provide 76 | direct access to ``BrewerMap`` objects. 77 | 78 | Version 1.2 79 | ----------- 80 | 81 | * The ``print_maps_by_type`` and ``get_map`` functions are now insensitive 82 | to the case of the ``map_type`` parameter. 83 | * The ``get_map`` function is now insensitive to the case of the name parameter. 84 | * Fixed a bug in ``get_map`` that caused color maps not to get reversed 85 | when they should have been. 86 | * Added a test suite. 87 | 88 | Version 1.1 89 | ----------- 90 | 91 | * Removed the ``number`` parameter from ``BrewerMap`` construction. This attribute 92 | is now set from the length of the ``colors`` input. 93 | * Added the ``BrewerMap`` class to the list of names imported in the brewer2mpl 94 | namespace. This will make it easier for users to make their own color maps 95 | by mixing and matching existing ones. 96 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Code of Conduct 2 | ## Version 0.4 3 | 4 | As contributors and maintainers of this project, we pledge to respect all people who contribute through reporting issues, posting feature requests, updating documentation, submitting pull requests or patches, and other activities. 5 | 6 | If any participant in this project has issues or takes exception with a contribution, they are obligated to provide constructive feedback and never resort to personal attacks, trolling, public or private harassment, insults, or other unprofessional conduct. 7 | 8 | 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. Project maintainers who do not follow the Code of Conduct may be removed from the project team. 9 | 10 | Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by opening an issue or contacting one or more of the project maintainers. 11 | 12 | We promise to extend courtesy and respect to everyone involved in this project regardless of gender, gender identity, sexual orientation, ability or disability, ethnicity, religion, or level of experience. 13 | -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | include README.rst 2 | include license.txt 3 | -------------------------------------------------------------------------------- /README.rst: -------------------------------------------------------------------------------- 1 | Palettable 2 | ========== 3 | 4 | .. image:: https://github.com/jiffyclub/palettable/actions/workflows/ci.yml/badge.svg 5 | :target: https://github.com/jiffyclub/palettable/actions/workflows/ci.yml 6 | :alt: Build Status 7 | 8 | .. image:: https://coveralls.io/repos/jiffyclub/palettable/badge.svg 9 | :target: https://coveralls.io/r/jiffyclub/palettable 10 | :alt: Coveralls 11 | 12 | .. image:: https://img.shields.io/pypi/v/palettable.svg 13 | :target: https://pypi.python.org/pypi/palettable/ 14 | :alt: Latest Version 15 | 16 | .. image:: https://img.shields.io/pypi/pyversions/palettable.svg 17 | :target: https://pypi.python.org/pypi/palettable/ 18 | :alt: Supported Python versions 19 | 20 | .. image:: https://img.shields.io/pypi/wheel/palettable.svg 21 | :target: https://pypi.python.org/pypi/palettable/ 22 | :alt: Wheel Status 23 | 24 | Color Palettes for Python 25 | ------------------------- 26 | 27 | Palettable (formerly brewer2mpl) is a library of color palettes for Python. 28 | It's written in pure Python with no dependencies, but it can supply color maps 29 | for matplotlib. You can use Palettable to customize matplotlib plots or supply 30 | colors for a web application. 31 | 32 | For more information see the 33 | `documentation `_. 34 | -------------------------------------------------------------------------------- /conftest.py: -------------------------------------------------------------------------------- 1 | try: 2 | import matplotlib 3 | except ImportError: 4 | pass 5 | else: 6 | matplotlib.use('Agg') 7 | -------------------------------------------------------------------------------- /docs/Makefile: -------------------------------------------------------------------------------- 1 | build: 2 | python -m urubu build 3 | touch _build/.nojekyll 4 | 5 | compile: 6 | python gendocs.py 7 | 8 | images: 9 | python gendocs.py --images 10 | 11 | serve: 12 | tserve --prefix palettable _build 13 | 14 | .PHONY: build, compile, images, serve 15 | -------------------------------------------------------------------------------- /docs/README.rst: -------------------------------------------------------------------------------- 1 | Building Palettable Docs 2 | ~~~~~~~~~~~~~~~~~~~~~~~~ 3 | 4 | The Palettable documentation is a mixture of hand curated and generated 5 | content because it contains a large number of palettes and images that 6 | would be painful to list manually. 7 | Files that contain generated content have a suffix ``.md.tpl``, 8 | the ``gendocs.py`` uses Jinja to compile them into Markdown files 9 | that can be turned into HTML by `Urubu `__. 10 | 11 | Palettable sub-modules are mapped to a directory in the docs in the 12 | ``MODULES`` dictionary of the ``gendocs.py`` script. 13 | Each of those directories must contain an ``index.md.tpl`` file that 14 | contains Jinja templating for building out a Palettable doc page with 15 | palette preview images. 16 | (See for example `matplotlib/index.md.tpl <./matplotlib/index.md.tpl>`__.) 17 | 18 | Building the docs requires 19 | -------------------------- 20 | 21 | - Palettable 22 | - Matplotlib 23 | - Jinja 24 | - Urubu 25 | - `tservice `__ 26 | 27 | Steps to build the docs 28 | ----------------------- 29 | 30 | 1. Generate images and compile ``index.md.tpl`` files 31 | 32 | - ``make images`` 33 | - If all images are up-to-date, then you can compile ``index.md.tpl`` 34 | files only with ``make compile`` 35 | 36 | 2. Have Urubu build HTML 37 | 38 | - Urubu configuration lives in ``_site.yml`` 39 | - Run the build with ``make build`` 40 | 41 | 3. Preview the docs with ``make serve`` 42 | 43 | Adding new Palettable modules 44 | ----------------------------- 45 | 46 | 1. Create a new directory for the module's docs 47 | 2. Create an ``index.md.tpl`` file in the new directory and document 48 | the module therein. Include Jinja templating to create a table-of-contents 49 | and include preview images. 50 | (See for example `matplotlib/index.md.tpl <./matplotlib/index.md.tpl>`__.) 51 | 3. Update the ``MODULES`` dict in ``gendocs.py`` to map 52 | the new module to its directory location 53 | 4. Build docs as above to preview 54 | -------------------------------------------------------------------------------- /docs/_layouts/_base.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | {{this.title}} 5 | 6 | 7 | 8 | {% set bootstrap = "3.1.1" %} 9 | {% if site.bootstrap %} 10 | {% set bootstrap = site.bootstrap %} 11 | {% endif %} 12 | {% if site.bootswatch %} 13 | {% set theme_path = "bootswatch/"+ bootstrap + '/' + site.bootswatch %} 14 | {% else %} 15 | {% set theme_path = "bootstrap/" + bootstrap + "/css" %} 16 | {% endif %} 17 | 18 | 19 | {% set url_prefix = '' %} 20 | {% if site.baseurl %} 21 | {% set url_prefix = '/' + site.baseurl %} 22 | {% endif %} 23 | 24 | 25 | 26 | 27 | 28 | 32 | 33 | 34 | 35 | 36 | 37 | {% set navbar_style = "navbar-default" %} 38 | {% if site.navbar_inverse %} 39 | {% set navbar_style = "navbar-inverse" %} 40 | {% endif %} 41 | {% set navbar_right_items = 1 %} 42 | {% if site.navbar_right_items %} 43 | {% set navbar_right_items = site.navbar_right_items %} 44 | {% endif %} 45 | 106 | 107 | {% block body %} 108 | {% endblock %} 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | -------------------------------------------------------------------------------- /docs/_layouts/analytics.html: -------------------------------------------------------------------------------- 1 | 11 | 12 | -------------------------------------------------------------------------------- /docs/_layouts/footer.html: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /docs/_layouts/home.html: -------------------------------------------------------------------------------- 1 | {% extends "_base.html" %} 2 | 3 | {% block home %} 4 | {% endblock %} 5 | 6 | {% block body %} 7 | 8 |
9 |
10 |
11 |
12 |

{{this.title}}

13 |

{{this.tagline}}

14 |
15 |
16 |
17 |
18 | 19 |
20 |
21 | 22 | {% block sidebar %} 23 | 33 | {% endblock %} 34 | 35 |
36 | {% block content %} 37 |
38 | {{this.body}} 39 |
40 | {% endblock %} 41 |
42 | 43 |
44 |
45 | 46 | {% endblock %} 47 | -------------------------------------------------------------------------------- /docs/_layouts/index.html: -------------------------------------------------------------------------------- 1 | {% extends "_base.html" %} 2 | 3 | {% block body %} 4 | 5 | {% block jumbotron %} 6 |
7 |
8 |
9 |
10 |

{{this.title}}

11 |

{{this.abstract}}

12 |
13 |
14 |
15 |
16 | {% endblock %} 17 | 18 |
19 |
20 |
21 | {% for item in this.content %} 22 |

{{item.title}} 23 | {% if item.date|d %} 24 | {{item.date|dateformat}}

25 | {% endif %} 26 | 27 |

{{item.teaser}}

28 | {% endfor %} 29 |
30 |
31 |
32 | 33 | {% endblock %} 34 | -------------------------------------------------------------------------------- /docs/_layouts/page.html: -------------------------------------------------------------------------------- 1 | {% extends "_base.html" %} 2 | 3 | {% block body %} 4 | 5 |
6 | 7 | {% block breadcrumbs %} 8 | 15 | {% endblock %} 16 | 17 | 22 | 23 |
24 | 25 | {% block sidebar %} 26 | 36 | {% endblock %} 37 | 38 |
39 | {% block content %} 40 |
41 | {{this.body}} 42 |
43 | {% endblock %} 44 |
45 | 46 |
47 | 48 | {% if this.pager %} 49 | 57 | {% endif %} 58 | 59 | {% include 'footer.html' %} 60 | 61 |
62 | 63 | {% endblock %} 64 | 65 | -------------------------------------------------------------------------------- /docs/_layouts/sharing.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 |
6 | 7 | 8 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /docs/_layouts/simple_page.html: -------------------------------------------------------------------------------- 1 | {% extends "page.html" %} 2 | 3 | {% block sidebar %} 4 | {% endblock %} 5 | -------------------------------------------------------------------------------- /docs/_python/__init__.py: -------------------------------------------------------------------------------- 1 | from .filters import filters 2 | -------------------------------------------------------------------------------- /docs/_python/filters.py: -------------------------------------------------------------------------------- 1 | def dateformat(value, format="%d-%b-%Y"): 2 | return value.strftime(format) 3 | 4 | filters = {} 5 | filters['dateformat'] = dateformat 6 | -------------------------------------------------------------------------------- /docs/_site.yml: -------------------------------------------------------------------------------- 1 | brand: Palettable 2 | baseurl: palettable 3 | 4 | bootswatch: cosmo # flatly, yeti, lumen,... 5 | navbar_inverse: true 6 | bootstrap: 3.3.1 7 | navbar_right_items: 0 8 | 9 | reflinks: 10 | ipythonblocks: 11 | url: http://ipythonblocks.org/ 12 | title: ipythonblocks 13 | 14 | ignore_patterns: 15 | - gendocs.py 16 | - '*.md.tpl' 17 | - README.rst 18 | -------------------------------------------------------------------------------- /docs/cartocolors/diverging/index.md.tpl: -------------------------------------------------------------------------------- 1 | --- 2 | title: 'cartocolors : Diverging' 3 | layout: page 4 | content: [] 5 | --- 6 | 7 | Diverging palettes taken from [cartocolors](https://github.com/CartoDB/cartocolor). 8 | 9 | # Contents 10 | 11 | {% for p in palettes %} 12 | - [{{p}}](#{{p | lower}}) 13 | {%- endfor %} 14 | 15 | # Previews 16 | 17 | {% for p in palettes %} 18 |
19 |

{{p}}

20 | 21 |
{{p + ' continuous'}}
22 |
23 | {{p + ' discrete'}} 24 | 25 |
26 | {% endfor %} 27 | -------------------------------------------------------------------------------- /docs/cartocolors/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: 'CartoColors' 3 | layout: simple_page 4 | content: [] 5 | --- 6 | 7 | CartoColor palettes come from the [CartoColors node module](https://github.com/CartoDB/cartocolor). 8 | They come in three sub-modules grouped by their use: 9 | 10 | - [`palettable.cartocolors.diverging`][diverging] 11 | - [`palettable.cartocolors.qualitative`][qualitative] 12 | - [`palettable.cartocolors.sequential`][sequential] 13 | -------------------------------------------------------------------------------- /docs/cartocolors/qualitative/index.md.tpl: -------------------------------------------------------------------------------- 1 | --- 2 | title: 'cartocolors : Qualitative' 3 | layout: page 4 | content: [] 5 | --- 6 | 7 | Qualitative palettes taken from [CartoColors](https://github.com/CartoDB/cartocolor). 8 | 9 | # Contents 10 | 11 | {% for p in palettes %} 12 | - [{{p}}](#{{p | lower}}) 13 | {%- endfor %} 14 | 15 | # Previews 16 | 17 | {% for p in palettes %} 18 |
19 |

{{p}}

20 | {{p + ' discrete'}} 21 | 22 |
23 | {% endfor %} 24 | -------------------------------------------------------------------------------- /docs/cartocolors/sequential/index.md.tpl: -------------------------------------------------------------------------------- 1 | --- 2 | title: 'cartocolors : Sequential' 3 | layout: page 4 | content: [] 5 | --- 6 | 7 | Sequential palettes taken from [cartocolors](https://github.com/CartoDB/cartocolor). 8 | 9 | # Contents 10 | 11 | {% for p in palettes %} 12 | - [{{p}}](#{{p | lower}}) 13 | {%- endfor %} 14 | 15 | # Previews 16 | 17 | {% for p in palettes %} 18 |
19 |

{{p}}

20 | 21 |
{{p + ' continuous'}}
22 |
23 | {{p + ' discrete'}} 24 | 25 |
26 | {% endfor %} 27 | -------------------------------------------------------------------------------- /docs/cmocean/diverging/index.md.tpl: -------------------------------------------------------------------------------- 1 | --- 2 | title: 'cmocean : Diverging' 3 | layout: page 4 | content: [] 5 | --- 6 | 7 | Diverging palettes taken from [cmocean](http://matplotlib.org/cmocean/). 8 | 9 | # Contents 10 | 11 | {% for p in palettes %} 12 | - [{{p}}](#{{p | lower}}) 13 | {%- endfor %} 14 | 15 | # Previews 16 | 17 | {% for p in palettes %} 18 |
19 |

{{p}}

20 | 21 |
{{p + ' continuous'}}
22 |
23 | {{p + ' discrete'}} 24 | 25 |
26 | {% endfor %} 27 | -------------------------------------------------------------------------------- /docs/cmocean/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: 'cmocean' 3 | layout: simple_page 4 | content: [] 5 | --- 6 | 7 | cmocean palettes come from the [cmocean package](http://matplotlib.org/cmocean/). 8 | They come in two sub-modules grouped by their use: 9 | 10 | - [`palettable.cmocean.diverging`][diverging] 11 | - [`palettable.cmocean.sequential`][sequential] 12 | -------------------------------------------------------------------------------- /docs/cmocean/sequential/index.md.tpl: -------------------------------------------------------------------------------- 1 | --- 2 | title: 'cmocean : Sequential' 3 | layout: page 4 | content: [] 5 | --- 6 | 7 | Sequential palettes taken from [cmocean](http://matplotlib.org/cmocean/). 8 | 9 | # Contents 10 | 11 | {% for p in palettes %} 12 | - [{{p}}](#{{p | lower}}) 13 | {%- endfor %} 14 | 15 | # Previews 16 | 17 | {% for p in palettes %} 18 |
19 |

{{p}}

20 | 21 |
{{p + ' continuous'}}
22 |
23 | {{p + ' discrete'}} 24 | 25 |
26 | {% endfor %} 27 | -------------------------------------------------------------------------------- /docs/colorbrewer/diverging/index.md.tpl: -------------------------------------------------------------------------------- 1 | --- 2 | title: 'Colorbrewer : Diverging' 3 | layout: page 4 | content: [] 5 | --- 6 | 7 | # Contents 8 | 9 | {% for p in palettes %} 10 | - [{{p}}](#{{p | lower}}) 11 | {%- endfor %} 12 | 13 | # Previews 14 | 15 | {% for p in palettes %} 16 |
17 |

{{p}}

18 | 19 |
{{p + ' continuous'}}
20 |
21 |
{{p + ' discrete'}}
22 | 23 |
24 | {% endfor %} 25 | -------------------------------------------------------------------------------- /docs/colorbrewer/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: 'Colorbrewer' 3 | layout: simple_page 4 | content: [] 5 | --- 6 | 7 | Colorbrewer palettes are taken from 8 | [http://colorbrewer2.org/](http://colorbrewer2.org/). 9 | They come in three sub-modules grouped by their use: 10 | 11 | - [palettable.colorbrewer.diverging][diverging] 12 | - [palettable.colorbrewer.qualitative][qualitative] 13 | - [palettable.colorbrewer.sequential][sequential] 14 | 15 | Colorbrewer maps have an additional attribute and method related to viewing 16 | the palettes online. 17 | The `.colorbrewer2_url` attribute is the URL at 18 | [http://colorbrewer2.org/](http://colorbrewer2.org/) 19 | at which to view the palette online, 20 | and the `.colorbrewer2()` method will open your 21 | browser pointed to that URL. 22 | -------------------------------------------------------------------------------- /docs/colorbrewer/qualitative/index.md.tpl: -------------------------------------------------------------------------------- 1 | --- 2 | title: 'Colorbrewer : Qualitative' 3 | layout: page 4 | content: [] 5 | --- 6 | 7 | # Contents 8 | 9 | {% for p in palettes %} 10 | - [{{p}}](#{{p | lower}}) 11 | {%- endfor %} 12 | 13 | # Previews 14 | 15 | {% for p in palettes %} 16 |
17 |

{{p}}

18 | 19 |
{{p + ' discrete'}}
20 | 21 |
22 | {% endfor %} 23 | -------------------------------------------------------------------------------- /docs/colorbrewer/sequential/index.md.tpl: -------------------------------------------------------------------------------- 1 | --- 2 | title: 'Colorbrewer : Sequential' 3 | layout: page 4 | content: [] 5 | --- 6 | 7 | # Contents 8 | 9 | {% for p in palettes %} 10 | - [{{p}}](#{{p | lower}}) 11 | {%- endfor %} 12 | 13 | # Previews 14 | 15 | {% for p in palettes %} 16 |
17 |

{{p}}

18 | 19 |
{{p + ' continuous'}}
20 |
21 |
{{p + ' discrete'}}
22 | 23 |
24 | {% endfor %} 25 | -------------------------------------------------------------------------------- /docs/css/site.css: -------------------------------------------------------------------------------- 1 | body { 2 | position: relative; 3 | padding-top: 50px; 4 | padding-bottom: 20px; 5 | } 6 | 7 | code { 8 | /* color: inherit; */ 9 | background-color: transparent; 10 | } 11 | 12 | .page-header { 13 | margin-top: 30px; 14 | } 15 | 16 | .breadcrumb { 17 | margin-top: 20px; 18 | } 19 | 20 | .content h2:first-of-type { 21 | margin-top: 0px; 22 | } 23 | 24 | .half-rule { 25 | width: 100px; 26 | margin: 25px auto; 27 | } 28 | 29 | 30 | .fa { 31 | margin-right: 0.5em; 32 | } 33 | 34 | .checklist { 35 | padding: 0; 36 | list-style: none; 37 | } 38 | 39 | /* footer */ 40 | 41 | .footer { 42 | margin-top: 30px; 43 | padding-top: 16px; 44 | color: #777; 45 | border-top: 1px solid #eee; 46 | font-size: 90%; 47 | text-align: center; 48 | } 49 | 50 | .footer p { 51 | margin: 0px; 52 | } 53 | 54 | /* toc */ 55 | 56 | .sidebar { 57 | font-size: 90%; 58 | line-height: normal 59 | } 60 | 61 | .toc ul { 62 | padding-left: 0; 63 | list-style: none; 64 | } 65 | 66 | .toc ul li { 67 | padding-top: 3px; 68 | } 69 | 70 | .toc ul ul { 71 | padding-left: 10px; 72 | font-size: 95%; 73 | } 74 | 75 | /* heading scrolling */ 76 | 77 | h2[id]:before, 78 | h3[id]:before{ 79 | content: ""; 80 | display: block; 81 | height: 70px; 82 | margin-top:-70px; 83 | } 84 | 85 | /* affix hacks from boostrap 3.0 docs */ 86 | .sidebar.affix { 87 | position: static; 88 | } 89 | 90 | @media (min-width: 992px) { 91 | /* Widen the fixed sidebar */ 92 | .sidebar.affix, 93 | .sidebar.affix-bottom { 94 | width: 213px; 95 | } 96 | .sidebar.affix { 97 | position: fixed; /* Undo the static from mobile first approach */ 98 | top: 80px; 99 | } 100 | .sidebar.affix-bottom { 101 | position: absolute; /* Undo the static from mobile first approach */ 102 | } 103 | } 104 | 105 | @media (min-width: 1200px) { 106 | /* Widen the fixed sidebar again */ 107 | .sidebar.affix, 108 | .sidebar.affix-bottom { 109 | width: 263px; 110 | } 111 | } 112 | 113 | 114 | -------------------------------------------------------------------------------- /docs/css/syntax.css: -------------------------------------------------------------------------------- 1 | .codehilite { background: #ffffff; } 2 | .codehilite .c { color: #999988; font-style: italic } /* Comment */ 3 | .codehilite .err { color: #a61717; background-color: #e3d2d2 } /* Error */ 4 | .codehilite .k { font-weight: bold } /* Keyword */ 5 | .codehilite .o { font-weight: bold } /* Operator */ 6 | .codehilite .cm { color: #999988; font-style: italic } /* Comment.Multiline */ 7 | .codehilite .cp { color: #999999; font-weight: bold } /* Comment.Preproc */ 8 | .codehilite .c1 { color: #999988; font-style: italic } /* Comment.Single */ 9 | .codehilite .cs { color: #999999; font-weight: bold; font-style: italic } /* Comment.Special */ 10 | .codehilite .gd { color: #000000; background-color: #ffdddd } /* Generic.Deleted */ 11 | .codehilite .gd .x { color: #000000; background-color: #ffaaaa } /* Generic.Deleted.Specific */ 12 | .codehilite .ge { font-style: italic } /* Generic.Emph */ 13 | .codehilite .gr { color: #aa0000 } /* Generic.Error */ 14 | .codehilite .gh { color: #999999 } /* Generic.Heading */ 15 | .codehilite .gi { color: #000000; background-color: #ddffdd } /* Generic.Inserted */ 16 | .codehilite .gi .x { color: #000000; background-color: #aaffaa } /* Generic.Inserted.Specific */ 17 | .codehilite .go { color: #888888 } /* Generic.Output */ 18 | .codehilite .gp { color: #555555 } /* Generic.Prompt */ 19 | .codehilite .gs { font-weight: bold } /* Generic.Strong */ 20 | .codehilite .gu { color: #aaaaaa } /* Generic.Subheading */ 21 | .codehilite .gt { color: #aa0000 } /* Generic.Traceback */ 22 | .codehilite .kc { font-weight: bold } /* Keyword.Constant */ 23 | .codehilite .kd { font-weight: bold } /* Keyword.Declaration */ 24 | .codehilite .kp { font-weight: bold } /* Keyword.Pseudo */ 25 | .codehilite .kr { font-weight: bold } /* Keyword.Reserved */ 26 | .codehilite .kt { color: #445588; font-weight: bold } /* Keyword.Type */ 27 | .codehilite .m { color: #009999 } /* Literal.Number */ 28 | .codehilite .s { color: #d14 } /* Literal.String */ 29 | .codehilite .na { color: #008080 } /* Name.Attribute */ 30 | .codehilite .nb { color: #0086B3 } /* Name.Builtin */ 31 | .codehilite .nc { color: #445588; font-weight: bold } /* Name.Class */ 32 | .codehilite .no { color: #008080 } /* Name.Constant */ 33 | .codehilite .ni { color: #800080 } /* Name.Entity */ 34 | .codehilite .ne { color: #990000; font-weight: bold } /* Name.Exception */ 35 | .codehilite .nf { color: #990000; font-weight: bold } /* Name.Function */ 36 | .codehilite .nn { color: #555555 } /* Name.Namespace */ 37 | .codehilite .nt { color: #000080 } /* Name.Tag */ 38 | .codehilite .nv { color: #008080 } /* Name.Variable */ 39 | .codehilite .ow { font-weight: bold } /* Operator.Word */ 40 | .codehilite .w { color: #bbbbbb } /* Text.Whitespace */ 41 | .codehilite .mf { color: #009999 } /* Literal.Number.Float */ 42 | .codehilite .mh { color: #009999 } /* Literal.Number.Hex */ 43 | .codehilite .mi { color: #009999 } /* Literal.Number.Integer */ 44 | .codehilite .mo { color: #009999 } /* Literal.Number.Oct */ 45 | .codehilite .sb { color: #d14 } /* Literal.String.Backtick */ 46 | .codehilite .sc { color: #d14 } /* Literal.String.Char */ 47 | .codehilite .sd { color: #d14 } /* Literal.String.Doc */ 48 | .codehilite .s2 { color: #d14 } /* Literal.String.Double */ 49 | .codehilite .se { color: #d14 } /* Literal.String.Escape */ 50 | .codehilite .sh { color: #d14 } /* Literal.String.Heredoc */ 51 | .codehilite .si { color: #d14 } /* Literal.String.Interpol */ 52 | .codehilite .sx { color: #d14 } /* Literal.String.Other */ 53 | .codehilite .sr { color: #009926 } /* Literal.String.Regex */ 54 | .codehilite .s1 { color: #d14 } /* Literal.String.Single */ 55 | .codehilite .ss { color: #990073 } /* Literal.String.Symbol */ 56 | .codehilite .bp { color: #999999 } /* Name.Builtin.Pseudo */ 57 | .codehilite .vc { color: #008080 } /* Name.Variable.Class */ 58 | .codehilite .vg { color: #008080 } /* Name.Variable.Global */ 59 | .codehilite .vi { color: #008080 } /* Name.Variable.Instance */ 60 | .codehilite .il { color: #009999 } /* Literal.Number.Integer.Long */ 61 | -------------------------------------------------------------------------------- /docs/cubehelix/index.md.tpl: -------------------------------------------------------------------------------- 1 | --- 2 | title: 'Cubehelix Palettes' 3 | layout: page 4 | content: [] 5 | --- 6 | 7 | Cubehelix was designed by [D.A. Green](http://adsabs.harvard.edu/abs/2011arXiv1108.5083G) to provide a color mapping that would degrade gracefully to grayscale without losing information. 8 | This quality makes Cubehelix useful for continuous color scales in scientific visualizations that might be printed in grayscale at some point. 9 | 10 | The `palettable.cubehelix` module provides several pre-made Cubehelix palettes, or you can [make your own](#make). 11 | 12 | ### See Also 13 | 14 | - *[A colour scheme for the display of astronomical intensity images](http://adsabs.harvard.edu/abs/2011BASI...39..289G)*, D.A. Green (2011) Bulletin of the Astronomical Society of India, 39, 289 15 | - *[Cubehelix, or How I Learned to Love Black & White Printers](http://www.ifweassume.com/2013/05/cubehelix-or-how-i-learned-to-love.html)* by James Davenport. 16 | 17 | # Contents 18 | 19 | - Previews 20 | {% for p in palettes %} 21 | * [{{p}}](#{{p | lower}}) 22 | {%- endfor %} 23 | 24 | - [Making your own Cubehelix palette](#make) 25 | 26 | # Previews 27 | 28 | {% for p in palettes %} 29 |
30 |

{{p}}

31 | 32 |
{{p + ' continuous'}}
33 |
34 |
{{p + ' discrete'}}
35 | 36 |
37 | {% endfor %} 38 | 39 | 40 | 41 | # Making your own Cubehelix palette 42 | 43 | With the `Cubehelix.make` classmethod you can create arbitrary Cubehelix palettes. 44 | For example: 45 | 46 | from palettable.cubehelix import Cubehelix 47 | palette = Cubehelix.make(start=0.3, rotation=-0.5, n=16) 48 | 49 | and then use that `palette` instance as usual. 50 | 51 | 52 | ## `Cubehelix.make` Argument Reference 53 | 54 | - `start` (scalar, optional). 55 | Sets the starting position in the RGB color space. 0=blue, 1=red, 56 | 2=green. Default is `0.5` (purple). 57 | - `rotation` (scalar, optional). 58 | The number of rotations through the rainbow. Can be positive 59 | or negative, indicating direction of rainbow. Negative values 60 | correspond to Blue→Red direction. Default is `-1.5`. 61 | - `start_hue` (scalar, optional). 62 | Sets the starting color, ranging from (-360, 360). Combined with 63 | `end_hue`, this parameter overrides `start` and `rotation`. 64 | This parameter is based on the D3 implementation by @mbostock. 65 | Default is `None`. 66 | - `end_hue` (scalar, optional) 67 | Sets the ending color, ranging from (-360, 360). Combined with 68 | `start_hue`, this parameter overrides ``start`` and ``rotation``. 69 | This parameter is based on the D3 implementation by @mbostock. 70 | Default is ``None``. 71 | - `gamma` (scalar, optional). 72 | The gamma correction for intensity. Values of `gamma < 1` 73 | emphasize low intensities while `gamma > 1` emphasises high 74 | intensities. Default is `1.0`. 75 | - `sat` (scalar, optional). 76 | The uniform saturation intensity factor. `sat=0` produces 77 | grayscale, while `sat=1` retains the full saturation. Setting 78 | `sat>1` oversaturates the color map, at the risk of clipping 79 | the color scale. Note that `sat` overrides both `min_stat` 80 | and `max_sat` if set. 81 | - `min_sat` (scalar, optional). 82 | Saturation at the minimum level. Default is `1.2`. 83 | - `max_sat` (scalar, optional). 84 | Satuation at the maximum level. Default is `1.2`. 85 | - `min_light` (scalar, optional). 86 | Minimum lightness value. Default is `0`. 87 | - `max_light` (scalar, optional). 88 | Maximum lightness value. Default is `1`. 89 | - `n` (scalar, optional). 90 | Number of discrete rendered colors. Default is `256`. 91 | - `reverse` (bool, optional). 92 | Set to `True` to reverse the color map. Will go from black to 93 | white. Good for density plots where shade → density. 94 | Default is `False`. 95 | - `name` (str, optional). 96 | Name of the color map (defaults to `'custom_cubehelix'`). 97 | -------------------------------------------------------------------------------- /docs/gendocs.py: -------------------------------------------------------------------------------- 1 | """ 2 | Generate color map images and fill in the docs to point to them. 3 | 4 | """ 5 | from __future__ import print_function 6 | 7 | import argparse 8 | import os 9 | import sys 10 | from importlib import import_module 11 | 12 | from jinja2 import Template 13 | from palettable.palette import Palette 14 | 15 | MODULES = { 16 | 'palettable.cartocolors.diverging': './cartocolors/diverging', 17 | 'palettable.cartocolors.qualitative': './cartocolors/qualitative', 18 | 'palettable.cartocolors.sequential': './cartocolors/sequential', 19 | 'palettable.colorbrewer.diverging': './colorbrewer/diverging', 20 | 'palettable.colorbrewer.qualitative': './colorbrewer/qualitative', 21 | 'palettable.colorbrewer.sequential': './colorbrewer/sequential', 22 | 'palettable.cmocean.diverging': './cmocean/diverging', 23 | 'palettable.cmocean.sequential': './cmocean/sequential', 24 | 'palettable.cubehelix': './cubehelix', 25 | 'palettable.lightbartlein.diverging': './lightbartlein/diverging', 26 | 'palettable.lightbartlein.sequential': './lightbartlein/sequential', 27 | 'palettable.matplotlib': './matplotlib', 28 | 'palettable.mycarta': './mycarta', 29 | 'palettable.plotly.diverging': './plotly/diverging', 30 | 'palettable.plotly.qualitative': './plotly/qualitative', 31 | 'palettable.plotly.sequential': './plotly/sequential', 32 | 'palettable.scientific.diverging': './scientific/diverging', 33 | 'palettable.scientific.sequential': './scientific/sequential', 34 | 'palettable.scientific.qualitative': './scientific/qualitative', 35 | 'palettable.tableau': './tableau', 36 | 'palettable.wesanderson': './wesanderson', 37 | } 38 | 39 | 40 | def find_palettes(mod): 41 | """ 42 | Find all Palette instances in mod. 43 | 44 | """ 45 | return { 46 | k: v for k, v in vars(mod).items() 47 | if isinstance(v, Palette) and not k.endswith('_r')} 48 | 49 | 50 | def gen_images(palettes, dir_): 51 | """ 52 | Create images for each palette in the palettes dict. 53 | For qualitative palettes only the discrete images is made. 54 | 55 | """ 56 | img_dir = os.path.join(dir_, 'img') 57 | os.makedirs(img_dir, exist_ok=True) 58 | 59 | discrete_fmt = '{}_discrete.png'.format 60 | continuous_fmt = '{}_continuous.png'.format 61 | 62 | img_size = (6, 0.5) 63 | 64 | for name, p in palettes.items(): 65 | print('Making discrete image for palette {}'.format(name)) 66 | p.save_discrete_image( 67 | os.path.join(img_dir, discrete_fmt(name)), size=img_size) 68 | 69 | if p.type != 'qualitative': 70 | print('Making continuous image for palette {}'.format(name)) 71 | p.save_continuous_image( 72 | os.path.join(img_dir, continuous_fmt(name)), size=img_size) 73 | 74 | 75 | def render_doc_page(dir_, palette_names, palette_dict): 76 | """ 77 | Render the documentation page in a given directory. 78 | 79 | """ 80 | print('Rendering index in dir {}'.format(dir_)) 81 | 82 | with open(os.path.join(dir_, 'index.md.tpl')) as f: 83 | tpl = Template(f.read()) 84 | 85 | with open(os.path.join(dir_, 'index.md'), 'w') as f: 86 | f.write(tpl.render(palettes=palette_names, palette_dict=palette_dict)) 87 | 88 | 89 | def palette_name_sort_key(name): 90 | base, length = name.rsplit('_', maxsplit=1) 91 | return base, int(length) 92 | 93 | 94 | def mkdocs(mod, dir_, images=False): 95 | palettes = find_palettes(mod) 96 | if images: 97 | gen_images(palettes, dir_) 98 | render_doc_page( 99 | dir_, sorted(palettes.keys(), key=palette_name_sort_key), palettes) 100 | 101 | 102 | def parse_args(args=None): 103 | parser = argparse.ArgumentParser( 104 | description='Build Palettable documentation.') 105 | parser.add_argument( 106 | '-i', '--images', action='store_true', help='force rebuild images') 107 | return parser.parse_args(args) 108 | 109 | 110 | def main(args=None): 111 | args = parse_args(args) 112 | 113 | for mod, dir_ in MODULES.items(): 114 | print('Running module {}'.format(mod)) 115 | mkdocs(import_module(mod), dir_, images=args.images) 116 | 117 | 118 | if __name__ == '__main__': 119 | sys.exit(main()) 120 | -------------------------------------------------------------------------------- /docs/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Palettable 3 | layout: home 4 | content: [] 5 | tagline: 6 | Color palettes for Python 7 | --- 8 | 9 | Palettable (formerly brewer2mpl) is a library of color palettes for Python. 10 | It's written in pure Python with no dependencies, 11 | but it can supply color maps for [matplotlib](http://matplotlib.org/). 12 | You can use Palettable to customize matplotlib plots or 13 | supply colors for a web application. 14 | 15 | Palettable has color palettes from: 16 | 17 | - [CartoColors][cartocolors] 18 | - [cmocean][cmocean] 19 | - [Colorbrewer2][colorbrewer] 20 | - [Cubehelix][cubehelix] 21 | - [Light & Bartlein][lightbartlein] 22 | - [matplotlib][matplotlib] 23 | - [MyCarta][mycarta] 24 | - [Plotly][plotly] 25 | - [Scientific][scientific] 26 | - [Tableau][tableau] 27 | - The [Wes Anderson Palettes][wesanderson] blog 28 | 29 | # Documentation 30 | 31 | ## Installation 32 | 33 | Palettable is available on PyPI for installation via pip: 34 | `pip install palettable`. 35 | Palettable is compatible with Python 2.6, 2.7, and Python 3. 36 | 37 | ## Finding Palettes 38 | 39 | Palettes are pre-built and loaded at import time. 40 | They have a naming convention of `_`. 41 | For example, the Colorbrewer2 palette Dark2 with seven colors is 42 | named `Dark2_7`. 43 | Every palette also has a reversed version with the same name plus 44 | the suffix `_r` (e.g. `Dark2_7_r`). 45 | 46 | The modules with palettes are: 47 | 48 | - [`palettable.cartocolors.diverging`][cartocolors/diverging] 49 | - [`palettable.cartocolors.qualitative`][cartocolors/qualitative] 50 | - [`palettable.cartocolors.sequential`][cartocolors/sequential] 51 | - [`palettable.cmocean.diverging`][cmocean/diverging] 52 | - [`palettable.cmocean.sequential`][cmocean/sequential] 53 | - [`palettable.colorbrewer.diverging`][colorbrewer/diverging] 54 | - [`palettable.colorbrewer.qualitative`][colorbrewer/qualitative] 55 | - [`palettable.colorbrewer.sequential`][colorbrewer/sequential] 56 | - [`palettable.lightbartlein.diverging`][lightbartlein/diverging] 57 | - [`palettable.lightbartlein.sequential`][lightbartlein/sequential] 58 | - [`palettable.matplotlib`][matplotlib] 59 | - [`palettable.mycarta`][mycarta] 60 | - [`palettable.plotly.diverging`][plotly/diverging] 61 | - [`palettable.plotly.qualitative`][plotly/qualitative] 62 | - [`palettable.plotly.sequential`][plotly/sequential] 63 | - [`palettable.scientific.diverging`][scientific/diverging] 64 | - [`palettable.scientific.sequential`][scientific/sequential] 65 | - [`palettable.tableau`][tableau] 66 | - [`palettable.wesanderson`][wesanderson] 67 | 68 | The `Dark2_7` palette could be imported via: 69 | 70 | ```python 71 | from palettable.colorbrewer.qualitative import Dark2_7 72 | ``` 73 | 74 | ## Palette Interface 75 | 76 | All the palette instances have a common interface including these attributes: 77 | 78 | `name` 79 | : The name of the palette. 80 | 81 | `type` 82 | : One of `'diverging'`, `'qualitative'`, or `'sequential`'. 83 | 84 | `number` 85 | : The number of defined colors in the palette. 86 | 87 | `colors` 88 | : The defined colors in the palette as a list of RGB tuples 89 | in the range 0-255. 90 | 91 | `hex_colors` 92 | : Colors as a list of hex strings (e.g. '#A912F4'). 93 | 94 | `mpl_colors` 95 | : Colors as a list of RGB tuples in the range 0-1 as used by matplotlib. 96 | 97 | `mpl_colormap` 98 | : A continuous, interpolated matplotlib 99 | [`LinearSegmentedColormap`](http://matplotlib.org/api/colors_api.html#matplotlib.colors.LinearSegmentedColormap). 100 | 101 | Palettes also have these methods: 102 | 103 | `get_mpl_colormap` 104 | : Use this method to get a matplotlib color map and pass custom keyword 105 | arguments to 106 | [`LinearSegmentedColormap.from_list`](http://matplotlib.org/api/colors_api.html#matplotlib.colors.LinearSegmentedColormap.from_list). 107 | 108 | `show_as_blocks` 109 | : Show the defined colors of the palette in the IPython Notebook. 110 | Requires [ipythonblocks][] to be installed. 111 | 112 | `show_discrete_image` 113 | : Show the defined colors of the palette in the IPython Notebook. 114 | Requires [matplotlib][] to be installed. 115 | 116 | `show_continuous_image` 117 | : Show the continuous, interpolated palette in the IPython Notebook. 118 | Requires [matplotlib][] to be installed. 119 | 120 | `save_discrete_image` 121 | : Save an image of the defined colors of palette to a file. 122 | Requires [matplotlib][] to be installed. 123 | 124 | `save_continuous_image` 125 | : Save an image of the continuous, interpolated palette to a file. 126 | Requires [matplotlib][] to be installed. 127 | 128 | ## Cookbook 129 | 130 | ### matplotlib Color Cycle 131 | 132 | matplotlib follows a default color cycle when drawing a plot. 133 | This can be modified as described 134 | [in this example](http://matplotlib.org/examples/color/color_cycle_demo.html). 135 | To substitute a Palettable palette use the `.mpl_colors` attribute: 136 | 137 | ```python 138 | ax.set_prop_cycle('color', palettable.colorbrewer.qualitative.Dark2_8.mpl_colors) 139 | ``` 140 | 141 | ### matplotlib Colormap 142 | 143 | Many matplotlib functions and methods take a `cmap` argument. 144 | You can use the `.mpl_colormap` attribute with this: 145 | 146 | ```python 147 | from palettable.colorbrewer.sequential import Blues_8 148 | ax.imshow(data, cmap=Blues_8.mpl_colormap) 149 | ``` 150 | 151 | Note that the colorbrewer2 color palettes are all available in [matplotlib][] 152 | already. 153 | See the full list of available color maps in matplotlib here: 154 | [http://matplotlib.org/examples/color/colormaps_reference.html](http://matplotlib.org/examples/color/colormaps_reference.html). 155 | 156 | ### matplotlib Discrete Colormap 157 | 158 | The `.mpl_colormap` attribute is a continuous, interpolated map. 159 | If you want to make discrete color map you can use matplotlib's 160 | [`ListedColormap`](http://matplotlib.org/api/colors_api.html#matplotlib.colors.ListedColormap): 161 | 162 | ```python 163 | cmap = ListedColormap(palettable.colorbrewer.qualitative.Dark2_7.mpl_colors) 164 | ``` 165 | 166 | ### plotly 167 | 168 | plotly takes colors as lists of hex strings. So you can use `hex_colors` attributes to pass it to plotly, like this: 169 | 170 | ```python 171 | import numpy as np 172 | import palettable 173 | import plotly.express as px 174 | 175 | data = np.arange(9).reshape(3, 3) 176 | color = palettable.scientific.sequential.Batlow_9 177 | px.imshow(data, color_continuous_scale=color.hex_colors) 178 | ``` 179 | 180 | # Contact 181 | 182 | Palettable is on GitHub at 183 | [https://github.com/jiffyclub/palettable](https://github.com/jiffyclub/palettable). 184 | Please report issues there. 185 | -------------------------------------------------------------------------------- /docs/lightbartlein/diverging/index.md.tpl: -------------------------------------------------------------------------------- 1 | --- 2 | title: 'lightbartlein : Diverging' 3 | layout: page 4 | content: [] 5 | --- 6 | 7 | Diverging palettes taken from [Light & Bartlein](http://geog.uoregon.edu/datagraphics/color_scales.htm). 8 | 9 | # Contents 10 | 11 | {% for p in palettes %} 12 | - [{{p}}](#{{p | lower}}) 13 | {%- endfor %} 14 | 15 | # Previews 16 | 17 | {% for p in palettes %} 18 |
19 |

{{p}}

20 | 21 |
{{p + ' continuous'}}
22 |
23 | {{p + ' discrete'}} 24 | 25 |
26 | {% endfor %} 27 | -------------------------------------------------------------------------------- /docs/lightbartlein/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: 'Light and Bartlein' 3 | layout: simple_page 4 | content: [] 5 | --- 6 | 7 | Light and Bartlein palettes come from the 8 | [Department of Geography at the University of Oregon](http://geog.uoregon.edu/datagraphics/color_scales.htm). 9 | They come in two sub-modules grouped by their use: 10 | 11 | - [`palettable.lightbartlein.diverging`][diverging] 12 | - [`palettable.lightbartlein.sequential`][sequential] 13 | -------------------------------------------------------------------------------- /docs/lightbartlein/sequential/index.md.tpl: -------------------------------------------------------------------------------- 1 | --- 2 | title: 'lightbartlein : Sequential' 3 | layout: page 4 | content: [] 5 | --- 6 | 7 | Sequential palettes taken from [Light & Bartlein](http://geog.uoregon.edu/datagraphics/color_scales.htm). 8 | 9 | # Contents 10 | 11 | {% for p in palettes %} 12 | - [{{p}}](#{{p | lower}}) 13 | {%- endfor %} 14 | 15 | # Previews 16 | 17 | {% for p in palettes %} 18 |
19 |

{{p}}

20 | 21 |
{{p + ' continuous'}}
22 |
23 | {{p + ' discrete'}} 24 | 25 |
26 | {% endfor %} 27 | -------------------------------------------------------------------------------- /docs/matplotlib/index.md.tpl: -------------------------------------------------------------------------------- 1 | --- 2 | title: 'Matplotlib Palettes' 3 | layout: page 4 | content: [] 5 | --- 6 | 7 | Palettes taken from the [new perceptual colormaps](https://bids.github.io/colormap) 8 | added to Matplotlib in version 1.5. 9 | All are sequential. 10 | 11 | # Contents 12 | 13 | {% for p in palettes %} 14 | - [{{p}}](#{{p | lower}}) 15 | {%- endfor %} 16 | 17 | # Previews 18 | 19 | {% for p in palettes %} 20 |
21 |

{{p}}

22 | 23 |
{{p + ' continuous'}}
24 |
25 | {{p + ' discrete'}} 26 | 27 |
28 | {% endfor %} 29 | -------------------------------------------------------------------------------- /docs/mycarta/index.md.tpl: -------------------------------------------------------------------------------- 1 | --- 2 | title: 'MyCarta Palettes' 3 | layout: page 4 | content: [] 5 | --- 6 | 7 | Palettes taken from [MyCarta](https://mycarta.wordpress.com/color-palettes/). 8 | All MyCarta palettes are sequential. 9 | 10 | # Contents 11 | 12 | {% for p in palettes %} 13 | - [{{p}}](#{{p | lower}}) 14 | {%- endfor %} 15 | 16 | # Previews 17 | 18 | {% for p in palettes %} 19 |
20 |

{{p}}

21 | 22 |
{{p + ' continuous'}}
23 |
24 | {{p + ' discrete'}} 25 | 26 |
27 | {% endfor %} 28 | -------------------------------------------------------------------------------- /docs/plotly/diverging/index.md.tpl: -------------------------------------------------------------------------------- 1 | --- 2 | title: 'plotly : Diverging' 3 | layout: page 4 | content: [] 5 | --- 6 | 7 | Diverging palettes taken from 8 | [Plotly](https://github.com/plotly/plotly.py). 9 | 10 | # Contents 11 | 12 | {% for p in palettes %} 13 | - [{{p}}](#{{p | lower}}) 14 | {%- endfor %} 15 | 16 | # Previews 17 | 18 | {% for p in palettes %} 19 |
20 |

{{p}}

21 | {{p + ' discrete'}} 22 | 23 |
24 | {% endfor %} 25 | -------------------------------------------------------------------------------- /docs/plotly/index.md.tpl: -------------------------------------------------------------------------------- 1 | --- 2 | title: 'Plotly' 3 | layout: page 4 | content: [] 5 | --- 6 | 7 | Plotly palettes are made by 8 | [Plotly.com](https://plotly.com/). 9 | They come in two sub-modules grouped by their use: 10 | 11 | - [`palettable.plotly.diverging`][diverging] 12 | - [`palettable.plotly.sequential`][sequential] 13 | - [`palettable.plotly.qualitative`][qualitative] 14 | -------------------------------------------------------------------------------- /docs/plotly/qualitative/index.md.tpl: -------------------------------------------------------------------------------- 1 | --- 2 | title: 'plotly : Qualitative' 3 | layout: page 4 | content: [] 5 | --- 6 | 7 | Qualitative palettes taken from 8 | [Plotly](https://github.com/plotly/plotly.py). 9 | 10 | # Contents 11 | 12 | {% for p in palettes %} 13 | - [{{p}}](#{{p | lower}}) 14 | {%- endfor %} 15 | 16 | # Previews 17 | 18 | {% for p in palettes %} 19 |
20 |

{{p}}

21 | {{p + ' discrete'}} 22 | 23 |
24 | {% endfor %} 25 | -------------------------------------------------------------------------------- /docs/plotly/sequential/index.md.tpl: -------------------------------------------------------------------------------- 1 | --- 2 | title: 'plotly : Sequential' 3 | layout: page 4 | content: [] 5 | --- 6 | 7 | Sequential palettes taken from 8 | [Plotly](https://github.com/plotly/plotly.py). 9 | 10 | # Contents 11 | 12 | {% for p in palettes %} 13 | - [{{p}}](#{{p | lower}}) 14 | {%- endfor %} 15 | 16 | # Previews 17 | 18 | {% for p in palettes %} 19 |
20 |

{{p}}

21 | {{p + ' discrete'}} 22 | 23 |
24 | {% endfor %} 25 | -------------------------------------------------------------------------------- /docs/scientific/diverging/index.md.tpl: -------------------------------------------------------------------------------- 1 | --- 2 | title: 'scientific : Diverging' 3 | layout: page 4 | content: [] 5 | --- 6 | 7 | Diverging palettes taken from 8 | [Scientific Colour-Maps](https://www.fabiocrameri.ch/colourmaps/). 9 | 10 | # Contents 11 | 12 | {% for p in palettes %} 13 | - [{{p}}](#{{p | lower}}) 14 | {%- endfor %} 15 | 16 | # Previews 17 | 18 | {% for p in palettes %} 19 |
20 |

{{p}}

21 | 22 |
{{p + ' continuous'}}
23 |
24 | {{p + ' discrete'}} 25 | 26 |
27 | {% endfor %} 28 | -------------------------------------------------------------------------------- /docs/scientific/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: 'Scientific' 3 | layout: simple_page 4 | content: [] 5 | --- 6 | 7 | Scientific palettes are made by 8 | [Fabio Crameri](http://www.fabiocrameri.ch/colourmaps.php). 9 | All Scientific palettes are available with up to 256 discreetly defined colors. 10 | They come in two sub-modules grouped by their use: 11 | 12 | - [`palettable.scientific.diverging`][diverging] 13 | - [`palettable.scientific.sequential`][sequential] 14 | - [`palettable.scientific.qualitative`][qualitative] 15 | -------------------------------------------------------------------------------- /docs/scientific/qualitative/index.md.tpl: -------------------------------------------------------------------------------- 1 | --- 2 | title: 'scientific : Qualitative' 3 | layout: page 4 | content: [] 5 | --- 6 | 7 | Qualitative palettes taken from 8 | [Scientific Colour-Maps](https://www.fabiocrameri.ch/colourmaps/). 9 | 10 | # Contents 11 | 12 | {% for p in palettes %} 13 | - [{{p}}](#{{p | lower}}) 14 | {%- endfor %} 15 | 16 | # Previews 17 | 18 | {% for p in palettes %} 19 |
20 |

{{p}}

21 | {{p + ' discrete'}} 22 | 23 |
24 | {% endfor %} 25 | -------------------------------------------------------------------------------- /docs/scientific/sequential/index.md.tpl: -------------------------------------------------------------------------------- 1 | --- 2 | title: 'scientific : Sequential' 3 | layout: page 4 | content: [] 5 | --- 6 | 7 | Sequential palettes taken from 8 | [Scientific Colour-Maps](https://www.fabiocrameri.ch/colourmaps/). 9 | 10 | # Contents 11 | 12 | {% for p in palettes %} 13 | - [{{p}}](#{{p | lower}}) 14 | {%- endfor %} 15 | 16 | # Previews 17 | 18 | {% for p in palettes %} 19 |
20 |

{{p}}

21 | 22 |
{{p + ' continuous'}}
23 |
24 | {{p + ' discrete'}} 25 | 26 |
27 | {% endfor %} 28 | -------------------------------------------------------------------------------- /docs/tableau/index.md.tpl: -------------------------------------------------------------------------------- 1 | --- 2 | title: 'Tableau Palettes' 3 | layout: page 4 | content: [] 5 | --- 6 | 7 | Palettes taken from [Tableau](http://www.tableau.com/). 8 | All Tableau palettes are qualitative. 9 | 10 | # Contents 11 | 12 | {% for p in palettes %} 13 | - [{{p}}](#{{p | lower}}) 14 | {%- endfor %} 15 | 16 | # Previews 17 | 18 | {% for p in palettes %} 19 |
20 |

{{p}}

21 | 22 | {{p + ' discrete'}} 23 | 24 |
25 | {% endfor %} 26 | -------------------------------------------------------------------------------- /docs/wesanderson/index.md.tpl: -------------------------------------------------------------------------------- 1 | --- 2 | title: 'Wes Anderson Palettes' 3 | layout: page 4 | content: [] 5 | --- 6 | 7 | These are taken from the 8 | [Wes Anderson Palettes](http://wesandersonpalettes.tumblr.com/) blog. 9 | All Wes Anderson palletes are qualitative. 10 | 11 | # Contents 12 | 13 | {% for p in palettes %} 14 | - [{{p}}](#{{p | lower}}) 15 | {%- endfor %} 16 | 17 | # Previews 18 | 19 | {% for p in palettes %} 20 |
21 |

{{p}}

22 | 23 | {{p + ' discrete'}} 24 | 25 |
26 | {% endfor %} 27 | -------------------------------------------------------------------------------- /license.txt: -------------------------------------------------------------------------------- 1 | palettable 2 | Copyright (c) 2019 Matt Davis 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software 5 | and associated documentation files (the "Software"), to deal in the Software without 6 | restriction, including without limitation the rights to use, copy, modify, merge, publish, 7 | distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the 8 | Software is furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all copies or 11 | substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 14 | BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 15 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 16 | DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 17 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 18 | -------------------------------------------------------------------------------- /palettable/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | Palettable is a pure Python package for accessing 3 | a variety of color maps from Python, including colorbrewer2, 4 | Tableau, and whimsical Wes Anderson maps. 5 | 6 | """ 7 | from __future__ import absolute_import 8 | 9 | from . import cmocean 10 | from . import cartocolors 11 | from . import colorbrewer 12 | from . import cubehelix 13 | from . import lightbartlein 14 | from . import matplotlib 15 | from . import mycarta 16 | from . import plotly 17 | from . import scientific 18 | from . import tableau 19 | from . import wesanderson 20 | 21 | VERSION = version = __version__ = '3.4.0.dev.0' 22 | -------------------------------------------------------------------------------- /palettable/cartocolors/__init__.py: -------------------------------------------------------------------------------- 1 | from __future__ import absolute_import 2 | 3 | from . import diverging, sequential, qualitative 4 | -------------------------------------------------------------------------------- /palettable/cartocolors/cartocolorspalette.py: -------------------------------------------------------------------------------- 1 | """ 2 | Palette class and utilities for CartoColors palettes. 3 | 4 | """ 5 | from __future__ import absolute_import 6 | 7 | from ..palette import Palette 8 | 9 | 10 | class CartoColorsMap(Palette): 11 | """ 12 | Representation of a color map with matplotlib compatible 13 | views of the map. 14 | 15 | Parameters 16 | ---------- 17 | name : str 18 | palette_type : str 19 | colors : list 20 | Colors as list of 0-255 RGB triplets. 21 | 22 | Attributes 23 | ---------- 24 | name : str 25 | type : str 26 | number : int 27 | Number of colors in color map. 28 | colors : list 29 | Colors as list of 0-255 RGB triplets. 30 | hex_colors : list 31 | mpl_colors : list 32 | mpl_colormap : matplotlib LinearSegmentedColormap 33 | url : str 34 | Website with related info. 35 | 36 | """ 37 | url = 'https://github.com/CartoDB/CartoColor/wiki/CARTOColor-Scheme-Names' 38 | 39 | def __init__(self, name, palette_type, colors): 40 | super(CartoColorsMap, self).__init__(name, palette_type, colors) 41 | -------------------------------------------------------------------------------- /palettable/cartocolors/colormaps.py: -------------------------------------------------------------------------------- 1 | """ 2 | Color maps from CARTO's CartoColors 3 | Learn more at https://github.com/CartoDB/CartoColor 4 | CARTOColors are made available under a Creative Commons Attribution license: 5 | https://creativecommons.org/licenses/by/3.0/us/ 6 | """ 7 | # Sequential schemes 8 | 9 | _BURG = [ 10 | [255, 198, 196], 11 | [244, 163, 168], 12 | [227, 129, 145], 13 | [204, 96, 125], 14 | [173, 70, 108], 15 | [139, 48, 88], 16 | [103, 32, 68], 17 | ] 18 | 19 | _BURGYL = [ 20 | [251, 230, 197], 21 | [245, 186, 152], 22 | [238, 138, 130], 23 | [220, 113, 118], 24 | [200, 88, 108], 25 | [156, 63, 93], 26 | [112, 40, 74], 27 | ] 28 | 29 | _REDOR = [ 30 | [246, 210, 169], 31 | [245, 183, 142], 32 | [241, 156, 124], 33 | [234, 129, 113], 34 | [221, 104, 108], 35 | [202, 82, 104], 36 | [177, 63, 100], 37 | ] 38 | 39 | _ORYEL = [ 40 | [236, 218, 154], 41 | [239, 196, 126], 42 | [243, 173, 106], 43 | [247, 148, 93], 44 | [249, 123, 87], 45 | [246, 99, 86], 46 | [238, 77, 90], 47 | ] 48 | 49 | _PEACH = [ 50 | [253, 224, 197], 51 | [250, 203, 166], 52 | [248, 181, 139], 53 | [245, 158, 114], 54 | [242, 133, 93], 55 | [239, 106, 76], 56 | [235, 74, 64], 57 | ] 58 | 59 | _PINKYL = [ 60 | [254, 246, 181], 61 | [255, 221, 154], 62 | [255, 194, 133], 63 | [255, 166, 121], 64 | [250, 138, 118], 65 | [241, 109, 122], 66 | [225, 83, 131], 67 | ] 68 | 69 | _MINT = [ 70 | [228, 241, 225], 71 | [180, 217, 204], 72 | [137, 192, 182], 73 | [99, 166, 160], 74 | [68, 140, 138], 75 | [40, 114, 116], 76 | [13, 88, 95], 77 | ] 78 | 79 | _BLUGRN = [ 80 | [196, 230, 195], 81 | [150, 210, 164], 82 | [109, 188, 144], 83 | [77, 162, 132], 84 | [54, 135, 122], 85 | [38, 107, 110], 86 | [29, 79, 96], 87 | ] 88 | 89 | _DARKMINT = [ 90 | [210, 251, 212], 91 | [165, 219, 194], 92 | [123, 188, 176], 93 | [85, 156, 158], 94 | [58, 124, 137], 95 | [35, 93, 114], 96 | [18, 63, 90], 97 | ] 98 | 99 | _EMRLD = [ 100 | [211, 242, 163], 101 | [151, 225, 150], 102 | [108, 192, 139], 103 | [76, 155, 130], 104 | [33, 122, 121], 105 | [16, 89, 101], 106 | [7, 64, 80], 107 | ] 108 | 109 | _AGGRNYL = [ 110 | [36, 86, 104], 111 | [15, 114, 121], 112 | [13, 143, 129], 113 | [57, 171, 126], 114 | [110, 197, 116], 115 | [169, 220, 103], 116 | [237, 239, 93], 117 | ] 118 | 119 | _BLUYL = [ 120 | [247, 254, 174], 121 | [183, 230, 165], 122 | [124, 203, 162], 123 | [70, 174, 160], 124 | [8, 144, 153], 125 | [0, 113, 139], 126 | [4, 82, 117], 127 | ] 128 | 129 | _TEAL = [ 130 | [209, 238, 234], 131 | [168, 219, 217], 132 | [133, 196, 201], 133 | [104, 171, 184], 134 | [79, 144, 166], 135 | [59, 115, 143], 136 | [42, 86, 116], 137 | ] 138 | 139 | _TEALGRN = [ 140 | [176, 242, 188], 141 | [137, 232, 172], 142 | [103, 219, 165], 143 | [76, 200, 163], 144 | [56, 178, 163], 145 | [44, 152, 160], 146 | [37, 125, 152], 147 | ] 148 | 149 | _PURP = [ 150 | [243, 224, 247], 151 | [228, 199, 241], 152 | [209, 175, 232], 153 | [185, 152, 221], 154 | [159, 130, 206], 155 | [130, 109, 186], 156 | [99, 88, 159], 157 | ] 158 | 159 | _PURPOR = [ 160 | [249, 221, 218], 161 | [242, 185, 196], 162 | [229, 151, 185], 163 | [206, 120, 179], 164 | [173, 95, 173], 165 | [131, 75, 160], 166 | [87, 59, 136], 167 | ] 168 | 169 | _SUNSET = [ 170 | [243, 231, 155], 171 | [250, 196, 132], 172 | [248, 160, 126], 173 | [235, 127, 134], 174 | [206, 102, 147], 175 | [160, 89, 160], 176 | [92, 83, 165], 177 | ] 178 | 179 | _MAGENTA = [ 180 | [243, 203, 211], 181 | [234, 169, 189], 182 | [221, 136, 172], 183 | [202, 105, 157], 184 | [177, 77, 142], 185 | [145, 53, 125], 186 | [108, 33, 103], 187 | ] 188 | 189 | _SUNSETDARK = [ 190 | [252, 222, 156], 191 | [250, 164, 118], 192 | [240, 116, 110], 193 | [227, 79, 111], 194 | [220, 57, 119], 195 | [185, 37, 122], 196 | [124, 29, 111], 197 | ] 198 | 199 | _AGSUNSET = [ 200 | [75, 41, 145], 201 | [135, 44, 162], 202 | [192, 54, 157], 203 | [234, 79, 136], 204 | [250, 120, 118], 205 | [246, 169, 122], 206 | [237, 217, 163], 207 | ] 208 | 209 | _BRWNYL = [ 210 | [237, 229, 207], 211 | [224, 194, 162], 212 | [211, 156, 131], 213 | [193, 118, 111], 214 | [166, 84, 97], 215 | [129, 55, 83], 216 | [84, 31, 63], 217 | ] 218 | 219 | # Diverging schemes 220 | 221 | _ARMYROSE = [ 222 | [121, 130, 52], 223 | [163, 173, 98], 224 | [208, 211, 162], 225 | [253, 251, 228], 226 | [240, 198, 195], 227 | [223, 145, 163], 228 | [212, 103, 128], 229 | ] 230 | 231 | _FALL = [ 232 | [61, 89, 65], 233 | [119, 136, 104], 234 | [181, 185, 145], 235 | [246, 237, 189], 236 | [237, 187, 138], 237 | [222, 138, 90], 238 | [202, 86, 44], 239 | ] 240 | 241 | _GEYSER = [ 242 | [0, 128, 128], 243 | [112, 164, 148], 244 | [180, 200, 168], 245 | [246, 237, 189], 246 | [237, 187, 138], 247 | [222, 138, 90], 248 | [202, 86, 44], 249 | ] 250 | 251 | _TEMPS = [ 252 | [0, 147, 146], 253 | [57, 177, 133], 254 | [156, 203, 134], 255 | [233, 226, 156], 256 | [238, 180, 121], 257 | [232, 132, 113], 258 | [207, 89, 126], 259 | ] 260 | 261 | _TEALROSE = [ 262 | [0, 147, 146], 263 | [114, 170, 161], 264 | [177, 199, 179], 265 | [241, 234, 200], 266 | [229, 185, 173], 267 | [217, 137, 148], 268 | [208, 88, 126], 269 | ] 270 | 271 | _TROPIC = [ 272 | [0, 155, 158], 273 | [66, 183, 185], 274 | [167, 211, 212], 275 | [241, 241, 241], 276 | [228, 193, 217], 277 | [214, 145, 193], 278 | [199, 93, 171], 279 | ] 280 | 281 | _EARTH = [ 282 | [161, 105, 40], 283 | [189, 146, 90], 284 | [214, 189, 141], 285 | [237, 234, 194], 286 | [181, 200, 184], 287 | [121, 167, 172], 288 | [40, 135, 161], 289 | ] 290 | 291 | # Qualitative palettes 292 | 293 | _ANTIQUE = [ 294 | [133, 92, 117], 295 | [217, 175, 107], 296 | [175, 100, 88], 297 | [115, 111, 76], 298 | [82, 106, 131], 299 | [98, 83, 119], 300 | [104, 133, 92], 301 | [156, 156, 94], 302 | [160, 97, 119], 303 | [140, 120, 93], 304 | [124, 124, 124], 305 | ] 306 | 307 | _BOLD = [ 308 | [127, 60, 141], 309 | [17, 165, 121], 310 | [57, 105, 172], 311 | [242, 183, 1], 312 | [231, 63, 116], 313 | [128, 186, 90], 314 | [230, 131, 16], 315 | [0, 134, 149], 316 | [207, 28, 144], 317 | [249, 123, 114], 318 | [165, 170, 153], 319 | ] 320 | 321 | _PASTEL = [ 322 | [102, 197, 204], 323 | [246, 207, 113], 324 | [248, 156, 116], 325 | [220, 176, 242], 326 | [135, 197, 95], 327 | [158, 185, 243], 328 | [254, 136, 177], 329 | [201, 219, 116], 330 | [139, 224, 164], 331 | [180, 151, 231], 332 | [179, 179, 179], 333 | ] 334 | 335 | _PRISM = [ 336 | [95, 70, 144], 337 | [29, 105, 150], 338 | [56, 166, 165], 339 | [15, 133, 84], 340 | [115, 175, 72], 341 | [237, 173, 8], 342 | [225, 124, 5], 343 | [204, 80, 62], 344 | [148, 52, 110], 345 | [111, 64, 112], 346 | [102, 102, 102], 347 | ] 348 | 349 | _SAFE = [ 350 | [136, 204, 238], 351 | [204, 102, 119], 352 | [221, 204, 119], 353 | [17, 119, 51], 354 | [51, 34, 136], 355 | [170, 68, 153], 356 | [68, 170, 153], 357 | [153, 153, 51], 358 | [136, 34, 85], 359 | [102, 17, 0], 360 | [136, 136, 136], 361 | ] 362 | 363 | _VIVID = [ 364 | [229, 134, 6], 365 | [93, 105, 177], 366 | [82, 188, 163], 367 | [153, 201, 69], 368 | [204, 97, 176], 369 | [36, 121, 108], 370 | [218, 165, 27], 371 | [47, 138, 196], 372 | [118, 78, 159], 373 | [237, 100, 90], 374 | [165, 170, 153], 375 | ] 376 | -------------------------------------------------------------------------------- /palettable/cartocolors/diverging.py: -------------------------------------------------------------------------------- 1 | """ 2 | Diverging color maps from the CartoColors schemes: 3 | https://github.com/CartoDB/CartoColor/wiki/CARTOColor-Scheme-Names 4 | """ 5 | from __future__ import absolute_import 6 | 7 | import itertools 8 | 9 | from . import cartocolorspalette 10 | from . import colormaps 11 | from .. import utils 12 | 13 | _PALETTE_TYPE = 'diverging' 14 | _NAMES_TO_DATA = { 15 | 'ArmyRose': colormaps._ARMYROSE, 16 | 'Fall': colormaps._FALL, 17 | 'Geyser': colormaps._GEYSER, 18 | 'Temps': colormaps._TEMPS, 19 | 'TealRose': colormaps._TEALROSE, 20 | 'Tropic': colormaps._TROPIC, 21 | 'Earth': colormaps._EARTH, 22 | } 23 | _NAME_MAP = utils.make_name_map(_NAMES_TO_DATA.keys()) 24 | _NAMES_AND_LENGTHS = utils.make_names_and_lengths( 25 | sorted(_NAMES_TO_DATA.keys()), 26 | range(2, 8)) 27 | 28 | 29 | print_maps = utils.print_maps_factory( 30 | 'diverging cartocolors', _NAMES_AND_LENGTHS, _PALETTE_TYPE) 31 | get_map = utils.get_map_factory( 32 | 'diverging cartocolors', __name__, _NAMES_TO_DATA, _PALETTE_TYPE, 33 | cartocolorspalette.CartoColorsMap) 34 | 35 | 36 | globals().update(utils.load_all_palettes(_NAMES_AND_LENGTHS, get_map)) 37 | -------------------------------------------------------------------------------- /palettable/cartocolors/qualitative.py: -------------------------------------------------------------------------------- 1 | """ 2 | Qualitative color maps from the CartoColors schemes: 3 | https://github.com/CartoDB/CartoColor/wiki/CARTOColor-Scheme-Names 4 | """ 5 | from __future__ import absolute_import 6 | 7 | import itertools 8 | 9 | from . import cartocolorspalette 10 | from . import colormaps 11 | from .. import utils 12 | 13 | _PALETTE_TYPE = 'qualitative' 14 | _NAMES_TO_DATA = { 15 | 'Antique': colormaps._ANTIQUE, 16 | 'Bold': colormaps._BOLD, 17 | 'Pastel': colormaps._PASTEL, 18 | 'Prism': colormaps._PRISM, 19 | 'Safe': colormaps._SAFE, 20 | 'Vivid': colormaps._VIVID, 21 | } 22 | 23 | _NAME_MAP = utils.make_name_map(_NAMES_TO_DATA.keys()) 24 | _NAMES_AND_LENGTHS = utils.make_names_and_lengths(sorted(_NAMES_TO_DATA.keys()), 25 | range(2, 11)) 26 | 27 | 28 | print_maps = utils.print_maps_factory('qualitative cartocolors', 29 | _NAMES_AND_LENGTHS, 30 | _PALETTE_TYPE) 31 | 32 | get_map = utils.get_map_factory('qualitative cartocolors', 33 | __name__, 34 | _NAMES_TO_DATA, 35 | _PALETTE_TYPE, 36 | cartocolorspalette.CartoColorsMap, 37 | is_evenly_spaced=False) 38 | 39 | 40 | globals().update(utils.load_all_palettes(_NAMES_AND_LENGTHS, get_map)) 41 | -------------------------------------------------------------------------------- /palettable/cartocolors/sequential.py: -------------------------------------------------------------------------------- 1 | """ 2 | Sequential color maps from the CartoColors schemes: 3 | https://github.com/CartoDB/CartoColor/wiki/CARTOColor-Scheme-Names 4 | """ 5 | from __future__ import absolute_import 6 | 7 | from . import cartocolorspalette 8 | from . import colormaps 9 | from .. import utils 10 | 11 | _PALETTE_TYPE = 'sequential' 12 | _NAMES_TO_DATA = { 13 | 'Burg': colormaps._BURG, 14 | 'BurgYl': colormaps._BURGYL, 15 | 'RedOr': colormaps._REDOR, 16 | 'OrYel': colormaps._ORYEL, 17 | 'Peach': colormaps._PEACH, 18 | 'PinkYl': colormaps._PINKYL, 19 | 'Mint': colormaps._MINT, 20 | 'BluGrn': colormaps._BLUGRN, 21 | 'DarkMint': colormaps._DARKMINT, 22 | 'Emrld': colormaps._EMRLD, 23 | 'agGrnYl': colormaps._AGGRNYL, 24 | 'BluYl': colormaps._BLUYL, 25 | 'Teal': colormaps._TEAL, 26 | 'TealGrn': colormaps._TEALGRN, 27 | 'Purp': colormaps._PURP, 28 | 'PurpOr': colormaps._PURPOR, 29 | 'Sunset': colormaps._SUNSET, 30 | 'Magenta': colormaps._MAGENTA, 31 | 'SunsetDark': colormaps._SUNSETDARK, 32 | 'agSunset': colormaps._AGSUNSET, 33 | 'BrwnYl': colormaps._BRWNYL, 34 | } 35 | _NAMES_AND_LENGTHS = utils.make_names_and_lengths( 36 | sorted(_NAMES_TO_DATA.keys()), 37 | range(2, 8)) 38 | 39 | 40 | print_maps = utils.print_maps_factory( 41 | 'sequential cartocolors', _NAMES_AND_LENGTHS, _PALETTE_TYPE) 42 | get_map = utils.get_map_factory( 43 | 'sequential cartocolors', __name__, _NAMES_TO_DATA, _PALETTE_TYPE, 44 | cartocolorspalette.CartoColorsMap) 45 | 46 | 47 | globals().update(utils.load_all_palettes(_NAMES_AND_LENGTHS, get_map)) 48 | -------------------------------------------------------------------------------- /palettable/cartocolors/test/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jiffyclub/palettable/339a45c347d34383aeb8fb3d8415d9631affb82c/palettable/cartocolors/test/__init__.py -------------------------------------------------------------------------------- /palettable/cartocolors/test/test_cartocolors.py: -------------------------------------------------------------------------------- 1 | from __future__ import absolute_import 2 | 3 | import pytest 4 | 5 | from ... import cartocolors 6 | from ... import utils 7 | 8 | 9 | def test_print_maps_diverging(capsys): 10 | cartocolors.diverging.print_maps() 11 | out, err = capsys.readouterr() 12 | lines = out.split('\n') 13 | assert lines[0] == 'ArmyRose_2 diverging 2' 14 | 15 | 16 | def test_print_maps_qualitative(capsys): 17 | cartocolors.qualitative.print_maps() 18 | out, err = capsys.readouterr() 19 | lines = out.split('\n') 20 | assert lines[0] == 'Antique_2 qualitative 2' 21 | 22 | 23 | def test_print_maps_sequential(capsys): 24 | cartocolors.sequential.print_maps() 25 | out, err = capsys.readouterr() 26 | lines = out.split('\n') 27 | assert lines[0] == 'BluGrn_2 sequential 2' 28 | 29 | 30 | def test_get_map_diverging(): 31 | palette = cartocolors.diverging.get_map('Geyser_5') 32 | assert isinstance(palette, cartocolors.cartocolorspalette.CartoColorsMap) 33 | assert palette.name == 'Geyser_5' 34 | assert palette.type == 'diverging' 35 | assert len(palette.colors) == 5 36 | assert palette.url == 'https://github.com/CartoDB/CartoColor/wiki/CARTOColor-Scheme-Names' 37 | 38 | 39 | def test_get_map_qualitative(): 40 | palette = cartocolors.qualitative.get_map('Bold_5') 41 | assert isinstance(palette, cartocolors.cartocolorspalette.CartoColorsMap) 42 | assert palette.name == 'Bold_5' 43 | assert palette.type == 'qualitative' 44 | assert len(palette.colors) == 5 45 | assert palette.url == 'https://github.com/CartoDB/CartoColor/wiki/CARTOColor-Scheme-Names' 46 | 47 | 48 | def test_get_map_sequential(): 49 | palette = cartocolors.sequential.get_map('agGrnYl_3') 50 | assert isinstance(palette, cartocolors.cartocolorspalette.CartoColorsMap) 51 | assert palette.name == 'agGrnYl_3' 52 | assert palette.type == 'sequential' 53 | assert len(palette.colors) == 3 54 | assert palette.url == 'https://github.com/CartoDB/CartoColor/wiki/CARTOColor-Scheme-Names' 55 | 56 | 57 | def test_get_map_diverging_reversed(): 58 | palette = cartocolors.diverging.get_map('Earth_3_r', reverse=True) 59 | assert isinstance(palette, cartocolors.cartocolorspalette.CartoColorsMap) 60 | assert palette.name == 'Earth_3_r' 61 | assert palette.type == 'diverging' 62 | assert len(palette.colors) == 3 63 | assert palette.url == 'https://github.com/CartoDB/CartoColor/wiki/CARTOColor-Scheme-Names' 64 | 65 | 66 | def test_get_map_qualitative_reversed(): 67 | palette = cartocolors.qualitative.get_map('Safe_3_r', reverse=True) 68 | assert isinstance(palette, cartocolors.cartocolorspalette.CartoColorsMap) 69 | assert palette.name == 'Safe_3_r' 70 | assert palette.type == 'qualitative' 71 | assert len(palette.colors) == 3 72 | assert palette.url == 'https://github.com/CartoDB/CartoColor/wiki/CARTOColor-Scheme-Names' 73 | 74 | 75 | def test_get_map_sequential_reversed(): 76 | palette = cartocolors.sequential.get_map('Mint_5', reverse=True) 77 | assert isinstance(palette, cartocolors.cartocolorspalette.CartoColorsMap) 78 | assert palette.name == 'Mint_5_r' 79 | assert palette.type == 'sequential' 80 | assert len(palette.colors) == 5 81 | assert palette.url == 'https://github.com/CartoDB/CartoColor/wiki/CARTOColor-Scheme-Names' 82 | 83 | 84 | def test_palettes_loaded(): 85 | assert isinstance(cartocolors.diverging.Earth_7, 86 | cartocolors.cartocolorspalette.CartoColorsMap) 87 | assert isinstance(cartocolors.diverging.Earth_7_r, 88 | cartocolors.cartocolorspalette.CartoColorsMap) 89 | assert cartocolors.diverging.Earth_7.type == 'diverging' 90 | 91 | assert isinstance(cartocolors.qualitative.Vivid_4, 92 | cartocolors.cartocolorspalette.CartoColorsMap) 93 | assert isinstance(cartocolors.qualitative.Vivid_4_r, 94 | cartocolors.cartocolorspalette.CartoColorsMap) 95 | assert cartocolors.qualitative.Vivid_4.type == 'qualitative' 96 | 97 | assert isinstance(cartocolors.sequential.BluGrn_7, 98 | cartocolors.cartocolorspalette.CartoColorsMap) 99 | assert isinstance(cartocolors.sequential.BluGrn_7_r, 100 | cartocolors.cartocolorspalette.CartoColorsMap) 101 | assert cartocolors.sequential.BluGrn_7.type == 'sequential' 102 | 103 | 104 | def test_get_all_maps(): 105 | # Smoke tests. 106 | assert isinstance( 107 | utils.load_all_palettes(cartocolors.diverging._NAMES_AND_LENGTHS, 108 | cartocolors.diverging.get_map), 109 | dict) 110 | assert isinstance( 111 | utils.load_all_palettes(cartocolors.qualitative._NAMES_AND_LENGTHS, 112 | cartocolors.qualitative.get_map), 113 | dict) 114 | assert isinstance( 115 | utils.load_all_palettes(cartocolors.sequential._NAMES_AND_LENGTHS, 116 | cartocolors.sequential.get_map), 117 | dict) 118 | -------------------------------------------------------------------------------- /palettable/cmocean/__init__.py: -------------------------------------------------------------------------------- 1 | from __future__ import absolute_import 2 | 3 | from . import diverging, sequential 4 | -------------------------------------------------------------------------------- /palettable/cmocean/cmoceanpalette.py: -------------------------------------------------------------------------------- 1 | """ 2 | Palette class and utilities for cmocean palettes. 3 | 4 | """ 5 | from __future__ import absolute_import 6 | 7 | from ..palette import Palette 8 | 9 | 10 | class CmoceanMap(Palette): 11 | """ 12 | Representation of a color map with matplotlib compatible 13 | views of the map. 14 | 15 | Parameters 16 | ---------- 17 | name : str 18 | palette_type : str 19 | colors : list 20 | Colors as list of 0-255 RGB triplets. 21 | 22 | Attributes 23 | ---------- 24 | name : str 25 | type : str 26 | number : int 27 | Number of colors in color map. 28 | colors : list 29 | Colors as list of 0-255 RGB triplets. 30 | hex_colors : list 31 | mpl_colors : list 32 | mpl_colormap : matplotlib LinearSegmentedColormap 33 | url : str 34 | Website with related info. 35 | 36 | """ 37 | url = 'http://matplotlib.org/cmocean/' 38 | 39 | def __init__(self, name, palette_type, colors): 40 | super(CmoceanMap, self).__init__(name, palette_type, colors) 41 | -------------------------------------------------------------------------------- /palettable/cmocean/diverging.py: -------------------------------------------------------------------------------- 1 | """ 2 | Diverging color maps from the cmocean package: 3 | https://github.com/matplotlib/cmocean. 4 | 5 | """ 6 | from __future__ import absolute_import 7 | 8 | import itertools 9 | 10 | from . import cmoceanpalette 11 | from . import colormaps 12 | from .. import utils 13 | 14 | _PALETTE_TYPE = 'diverging' 15 | _NAMES_TO_DATA = { 16 | 'Balance': colormaps._BALANCE, 17 | 'Curl': colormaps._CURL, 18 | 'Delta': colormaps._DELTA, 19 | } 20 | _NAME_MAP = utils.make_name_map(_NAMES_TO_DATA.keys()) 21 | _NAMES_AND_LENGTHS = utils.make_names_and_lengths( 22 | sorted(_NAMES_TO_DATA.keys())) 23 | 24 | 25 | print_maps = utils.print_maps_factory( 26 | 'diverging cmocean', _NAMES_AND_LENGTHS, _PALETTE_TYPE) 27 | get_map = utils.get_map_factory( 28 | 'divergine cmocean', __name__, _NAMES_TO_DATA, _PALETTE_TYPE, 29 | cmoceanpalette.CmoceanMap) 30 | 31 | 32 | globals().update(utils.load_all_palettes(_NAMES_AND_LENGTHS, get_map)) 33 | -------------------------------------------------------------------------------- /palettable/cmocean/sequential.py: -------------------------------------------------------------------------------- 1 | """ 2 | Sequential color maps from the cmocean package: 3 | https://github.com/matplotlib/cmocean. 4 | 5 | """ 6 | from __future__ import absolute_import 7 | 8 | import itertools 9 | 10 | from . import cmoceanpalette 11 | from . import colormaps 12 | from .. import utils 13 | 14 | _PALETTE_TYPE = 'sequential' 15 | _NAMES_TO_DATA = { 16 | 'Algae': colormaps._ALGAE, 17 | 'Amp': colormaps._AMP, 18 | 'Deep': colormaps._DEEP, 19 | 'Dense': colormaps._DENSE, 20 | 'Gray': colormaps._GRAY, 21 | 'Haline': colormaps._HALINE, 22 | 'Ice': colormaps._ICE, 23 | 'Matter': colormaps._MATTER, 24 | 'Oxy': colormaps._OXY, 25 | 'Phase': colormaps._PHASE, 26 | 'Solar': colormaps._SOLAR, 27 | 'Speed': colormaps._SPEED, 28 | 'Tempo': colormaps._TEMPO, 29 | 'Thermal': colormaps._THERMAL, 30 | 'Turbid': colormaps._TURBID, 31 | } 32 | _NAMES_AND_LENGTHS = utils.make_names_and_lengths( 33 | sorted(_NAMES_TO_DATA.keys())) 34 | 35 | 36 | print_maps = utils.print_maps_factory( 37 | 'sequential cmocean', _NAMES_AND_LENGTHS, _PALETTE_TYPE) 38 | get_map = utils.get_map_factory( 39 | 'sequential cmocean', __name__, _NAMES_TO_DATA, _PALETTE_TYPE, 40 | cmoceanpalette.CmoceanMap) 41 | 42 | 43 | globals().update(utils.load_all_palettes(_NAMES_AND_LENGTHS, get_map)) 44 | -------------------------------------------------------------------------------- /palettable/cmocean/test/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jiffyclub/palettable/339a45c347d34383aeb8fb3d8415d9631affb82c/palettable/cmocean/test/__init__.py -------------------------------------------------------------------------------- /palettable/cmocean/test/test_cmocean.py: -------------------------------------------------------------------------------- 1 | from __future__ import absolute_import 2 | 3 | import pytest 4 | 5 | from ... import cmocean 6 | from ... import utils 7 | 8 | 9 | def test_print_maps_diverging(capsys): 10 | cmocean.diverging.print_maps() 11 | out, err = capsys.readouterr() 12 | lines = out.split('\n') 13 | assert lines[0] == 'Balance_3 diverging 3' 14 | 15 | 16 | def test_print_maps_sequential(capsys): 17 | cmocean.sequential.print_maps() 18 | out, err = capsys.readouterr() 19 | lines = out.split('\n') 20 | assert lines[0] == 'Algae_3 sequential 3' 21 | 22 | 23 | def test_get_map_diverging(): 24 | palette = cmocean.diverging.get_map('BALANCE_5') 25 | assert isinstance(palette, cmocean.cmoceanpalette.CmoceanMap) 26 | assert palette.name == 'Balance_5' 27 | assert palette.type == 'diverging' 28 | assert len(palette.colors) == 5 29 | assert palette.url == 'http://matplotlib.org/cmocean/' 30 | 31 | 32 | def test_get_map_sequential(): 33 | palette = cmocean.sequential.get_map('AMP_5') 34 | assert isinstance(palette, cmocean.cmoceanpalette.CmoceanMap) 35 | assert palette.name == 'Amp_5' 36 | assert palette.type == 'sequential' 37 | assert len(palette.colors) == 5 38 | assert palette.url == 'http://matplotlib.org/cmocean/' 39 | 40 | 41 | def test_get_map_diverging_reversed(): 42 | palette = cmocean.diverging.get_map('BALANCE_5', reverse=True) 43 | assert isinstance(palette, cmocean.cmoceanpalette.CmoceanMap) 44 | assert palette.name == 'Balance_5_r' 45 | assert palette.type == 'diverging' 46 | assert len(palette.colors) == 5 47 | assert palette.url == 'http://matplotlib.org/cmocean/' 48 | 49 | 50 | def test_get_map_sequential_reversed(): 51 | palette = cmocean.sequential.get_map('AMP_5', reverse=True) 52 | assert isinstance(palette, cmocean.cmoceanpalette.CmoceanMap) 53 | assert palette.name == 'Amp_5_r' 54 | assert palette.type == 'sequential' 55 | assert len(palette.colors) == 5 56 | assert palette.url == 'http://matplotlib.org/cmocean/' 57 | 58 | 59 | def test_palettes_loaded(): 60 | assert isinstance( 61 | cmocean.diverging.Balance_8, cmocean.cmoceanpalette.CmoceanMap) 62 | assert isinstance( 63 | cmocean.diverging.Balance_8_r, cmocean.cmoceanpalette.CmoceanMap) 64 | assert cmocean.diverging.Balance_8.type == 'diverging' 65 | 66 | assert isinstance( 67 | cmocean.sequential.Amp_8, cmocean.cmoceanpalette.CmoceanMap) 68 | assert isinstance( 69 | cmocean.sequential.Amp_8_r, cmocean.cmoceanpalette.CmoceanMap) 70 | assert cmocean.sequential.Amp_8.type == 'sequential' 71 | 72 | 73 | def test_get_all_maps(): 74 | # Smoke tests. 75 | assert isinstance( 76 | utils.load_all_palettes( 77 | cmocean.diverging._NAMES_AND_LENGTHS, cmocean.diverging.get_map), 78 | dict) 79 | assert isinstance( 80 | utils.load_all_palettes( 81 | cmocean.sequential._NAMES_AND_LENGTHS, cmocean.sequential.get_map), 82 | dict) 83 | -------------------------------------------------------------------------------- /palettable/colorbrewer/__init__.py: -------------------------------------------------------------------------------- 1 | from __future__ import absolute_import 2 | 3 | from .colorbrewer import * 4 | from . import diverging, qualitative, sequential 5 | -------------------------------------------------------------------------------- /palettable/colorbrewer/colorbrewer.py: -------------------------------------------------------------------------------- 1 | from __future__ import absolute_import 2 | from __future__ import print_function 3 | 4 | import webbrowser 5 | 6 | from ..palette import Palette 7 | from .colorbrewer_all_schemes import COLOR_MAPS 8 | 9 | __all__ = ('COLOR_MAPS', 'print_maps', 'print_all_maps', 'print_maps_by_type', 10 | 'get_map', 'MAP_TYPES', 'BrewerMap') 11 | 12 | 13 | MAP_TYPES = ('sequential', 'diverging', 'qualitative') 14 | 15 | 16 | def print_maps(map_type=None, number=None): 17 | """ 18 | Print maps by type and/or number of defined colors. 19 | 20 | Parameters 21 | ---------- 22 | map_type : {'sequential', 'diverging', 'qualitative'}, optional 23 | Filter output by map type. By default all maps are printed. 24 | number : int, optional 25 | Filter output by number of defined colors. By default there is 26 | no numeric filtering. 27 | 28 | """ 29 | if not map_type and not number: 30 | print_all_maps() 31 | 32 | elif map_type: 33 | print_maps_by_type(map_type, number) 34 | 35 | else: 36 | s = ('Invalid parameter combination. ' 37 | 'number without map_type is not supported.') 38 | raise ValueError(s) 39 | 40 | 41 | def print_all_maps(): 42 | """ 43 | Print the name and number of defined colors of all available color maps. 44 | 45 | """ 46 | for t in MAP_TYPES: 47 | print_maps_by_type(t) 48 | 49 | 50 | def print_maps_by_type(map_type, number=None): 51 | """ 52 | Print all available maps of a given type. 53 | 54 | Parameters 55 | ---------- 56 | map_type : {'sequential', 'diverging', 'qualitative'} 57 | Select map type to print. 58 | number : int, optional 59 | Filter output by number of defined colors. By default there is 60 | no numeric filtering. 61 | 62 | """ 63 | if map_type.lower() not in MAP_TYPES: 64 | s = 'Invalid map type, must be one of {0}'.format(MAP_TYPES) 65 | raise ValueError(s) 66 | 67 | print(map_type) 68 | 69 | # maps are keyed by capitalized types in COLOR_MAPS 70 | map_type = map_type.capitalize() 71 | map_keys = sorted(COLOR_MAPS[map_type].keys()) 72 | 73 | format_str = '{0:8} : {1}' 74 | 75 | for mk in map_keys: 76 | num_keys = sorted(COLOR_MAPS[map_type][mk].keys(), key=int) 77 | 78 | if not number or str(number) in num_keys: 79 | num_str = '{' + ', '.join(num_keys) + '}' 80 | print(format_str.format(mk, num_str)) 81 | 82 | 83 | class BrewerMap(Palette): 84 | """ 85 | Representation of a colorbrewer2 color map with matplotlib compatible 86 | views of the map. 87 | 88 | Parameters 89 | ---------- 90 | name : str 91 | map_type : str 92 | colors : list 93 | Colors as list of 0-255 RGB triplets. 94 | 95 | Attributes 96 | ---------- 97 | name : str 98 | type : str 99 | number : int 100 | Number of colors in color map. 101 | colors : list 102 | Colors as list of 0-255 RGB triplets. 103 | colorbrewer2_url : str 104 | hex_colors : list 105 | mpl_colors : list 106 | mpl_colormap : matplotlib LinearSegmentedColormap 107 | 108 | """ 109 | @property 110 | def colorbrewer2_url(self): 111 | """ 112 | URL that can be used to view the color map at colorbrewer2.org. 113 | 114 | """ 115 | url = 'http://colorbrewer2.org/index.html?type={0}&scheme={1}&n={2}' 116 | return url.format(self.type.lower(), self.name, self.number) 117 | 118 | def colorbrewer2(self): 119 | """ 120 | View this color map at colorbrewer2.org. This will open 121 | colorbrewer2.org in your default web browser. 122 | 123 | """ 124 | webbrowser.open_new_tab(self.colorbrewer2_url) # pragma: no cover 125 | 126 | 127 | def get_map(name, map_type, number, reverse=False): 128 | """ 129 | Return a `BrewerMap` representation of the specified color map. 130 | 131 | Parameters 132 | ---------- 133 | name : str 134 | Name of color map. Use `print_maps` to see available color maps. 135 | map_type : {'sequential', 'diverging', 'qualitative'} 136 | Select color map type. 137 | number : int 138 | Number of defined colors in color map. 139 | reverse : bool, optional 140 | Set to True to get the reversed color map. 141 | 142 | """ 143 | number = str(number) 144 | 145 | # check for valid type 146 | if map_type.lower() not in MAP_TYPES: 147 | s = 'Invalid map type, must be one of {0}'.format(MAP_TYPES) 148 | raise ValueError(s) 149 | 150 | # maps are keyed by capitalized types in COLOR_MAPS 151 | map_type = map_type.capitalize() 152 | 153 | # make a dict of lower case map name to map name so this can be 154 | # insensitive to case. 155 | # this would be a perfect spot for a dict comprehension but going to 156 | # wait on that to preserve 2.6 compatibility. 157 | # map_names = {k.lower(): k for k in COLOR_MAPS[map_type].iterkeys()} 158 | map_names = dict((k.lower(), k) for k in COLOR_MAPS[map_type].keys()) 159 | 160 | # check for valid name 161 | if name.lower() not in map_names: 162 | s = 'Invalid color map name {0!r} for type {1!r}.\n' 163 | s = s.format(name, map_type) 164 | valid_names = [str(k) for k in COLOR_MAPS[map_type].keys()] 165 | valid_names.sort() 166 | s += 'Valid names are: {0}'.format(valid_names) 167 | raise ValueError(s) 168 | 169 | name = map_names[name.lower()] 170 | 171 | # check for valid number 172 | if number not in COLOR_MAPS[map_type][name]: 173 | s = 'Invalid number for map type {0!r} and name {1!r}.\n' 174 | s = s.format(map_type, str(name)) 175 | valid_numbers = [int(k) for k in COLOR_MAPS[map_type][name].keys()] 176 | valid_numbers.sort() 177 | s += 'Valid numbers are : {0}'.format(valid_numbers) 178 | raise ValueError(s) 179 | 180 | colors = COLOR_MAPS[map_type][name][number]['Colors'] 181 | 182 | if reverse: 183 | name += '_r' 184 | colors = [x for x in reversed(colors)] 185 | 186 | return BrewerMap(name, map_type.lower(), colors) 187 | 188 | 189 | def _load_maps_by_type(map_type): 190 | """ 191 | Load all maps of a given type into a dictionary. 192 | 193 | Color maps are loaded as BrewerMap objects. Dictionary is 194 | keyed by map name and then integer numbers of defined 195 | colors. There is an additional 'max' key that points to the 196 | color map with the largest number of defined colors. 197 | 198 | Parameters 199 | ---------- 200 | map_type : {'sequential', 'diverging', 'qualitative'} 201 | 202 | Returns 203 | ------- 204 | maps : dict of BrewerMap 205 | 206 | """ 207 | map_type = map_type.capitalize() 208 | seq_maps = COLOR_MAPS[map_type] 209 | 210 | loaded_maps = {} 211 | 212 | for map_name in seq_maps: 213 | for num in seq_maps[map_name]: 214 | inum = int(num) 215 | name = '{0}_{1}'.format(map_name, num) 216 | loaded_maps[name] = get_map(map_name, map_type, inum) 217 | loaded_maps[name + '_r'] = get_map( 218 | map_name, map_type, inum, reverse=True) 219 | 220 | return loaded_maps 221 | -------------------------------------------------------------------------------- /palettable/colorbrewer/data/colorbrewer_licence.txt: -------------------------------------------------------------------------------- 1 | Apache-Style Software License for ColorBrewer software and ColorBrewer Color Schemes 2 | 3 | Copyright (c) 2002 Cynthia Brewer, Mark Harrower, and The Pennsylvania State University. 4 | 5 | Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and limitations under the License. 13 | 14 | 15 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 16 | 1. Redistributions as source code must retain the above copyright notice, this list of conditions and the following disclaimer. 17 | 2. The end-user documentation included with the redistribution, if any, must include the following acknowledgment: 18 | This product includes color specifications and designs developed by Cynthia Brewer (http://colorbrewer.org/). 19 | Alternately, this acknowledgment may appear in the software itself, if and wherever such third-party acknowledgments normally appear. 20 | 4. The name "ColorBrewer" must not be used to endorse or promote products derived from this software without prior written permission. 21 | For written permission, please contact Cynthia Brewer at cbrewer@psu.edu. 22 | 5. Products derived from this software may not be called "ColorBrewer", nor may "ColorBrewer" appear in their name, without prior written permission of Cynthia Brewer. 23 | -------------------------------------------------------------------------------- /palettable/colorbrewer/data/colorbrewer_schemes_csv_to_py.py: -------------------------------------------------------------------------------- 1 | """ 2 | Color maps come from colorbrewer2.org as an Excel file. I've converted the 3 | Excel file to CSV and here I convert it to JSON for easy reading into Python. 4 | 5 | """ 6 | 7 | import sys 8 | from csv import DictReader 9 | from collections import OrderedDict 10 | import json 11 | 12 | 13 | def new_sub_map(row, sm_dict): 14 | num_colors = int(row['NumOfColors']) 15 | sm_dict[num_colors] = OrderedDict() 16 | sub_map = sm_dict[num_colors] 17 | 18 | sub_map['NumOfColors'] = num_colors 19 | sub_map['Type'] = row['Type'] 20 | sub_map['Colors'] = [(int(row['R']), int(row['G']), int(row['B']))] 21 | 22 | return sub_map 23 | 24 | 25 | def read_csv_to_dict(): 26 | color_maps = OrderedDict() 27 | 28 | for scheme_type in ('Sequential', 'Diverging', 'Qualitative'): 29 | color_maps[scheme_type] = OrderedDict() 30 | 31 | with open('colorbrewer_all_schemes.csv', 'r') as csvf: 32 | csv = DictReader(csvf) 33 | 34 | for row in csv: 35 | if row['SchemeType']: 36 | # first row of a new color map block 37 | color_maps[row['SchemeType']][row['ColorName']] = OrderedDict() 38 | current_map = color_maps[row['SchemeType']][row['ColorName']] 39 | 40 | current_submap = new_sub_map(row, current_map) 41 | 42 | elif row['ColorName']: 43 | # first row of a new sub-map block 44 | current_submap = new_sub_map(row, current_map) 45 | 46 | elif not row['ColorName']: 47 | # continuation of a sub-map block 48 | current_submap['Colors'].append((int(row['R']), 49 | int(row['G']), 50 | int(row['B']))) 51 | 52 | return color_maps 53 | 54 | 55 | def save_to_json(color_maps): 56 | # A JSON dump of color_maps is valid Python code to create nested 57 | # dicts/lists, so we'll just treat the JSON as Python code and store the 58 | # value in a variable. 59 | with open('../colorbrewer_all_schemes.py', 'w') as f: 60 | f.write("COLOR_MAPS = ") 61 | json.dump(color_maps, f, indent=1) 62 | 63 | 64 | def main(): 65 | color_maps = read_csv_to_dict() 66 | save_to_json(color_maps) 67 | 68 | 69 | if __name__ == '__main__': 70 | sys.exit(main()) 71 | -------------------------------------------------------------------------------- /palettable/colorbrewer/diverging.py: -------------------------------------------------------------------------------- 1 | from __future__ import absolute_import 2 | 3 | from .colorbrewer import _load_maps_by_type 4 | 5 | globals().update(_load_maps_by_type('diverging')) 6 | -------------------------------------------------------------------------------- /palettable/colorbrewer/qualitative.py: -------------------------------------------------------------------------------- 1 | from __future__ import absolute_import 2 | 3 | from .colorbrewer import _load_maps_by_type 4 | 5 | globals().update(_load_maps_by_type('qualitative')) 6 | -------------------------------------------------------------------------------- /palettable/colorbrewer/sequential.py: -------------------------------------------------------------------------------- 1 | from __future__ import absolute_import 2 | 3 | from .colorbrewer import _load_maps_by_type 4 | 5 | globals().update(_load_maps_by_type('sequential')) 6 | -------------------------------------------------------------------------------- /palettable/colorbrewer/test/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jiffyclub/palettable/339a45c347d34383aeb8fb3d8415d9631affb82c/palettable/colorbrewer/test/__init__.py -------------------------------------------------------------------------------- /palettable/colorbrewer/test/test_colorbrewer.py: -------------------------------------------------------------------------------- 1 | """ 2 | Miscellaneous tests of colorbrewer functionality. 3 | 4 | """ 5 | from __future__ import absolute_import 6 | 7 | try: 8 | import pytest 9 | except ImportError: 10 | raise ImportError('Tests require pytest >= 2.2.') 11 | 12 | from .. import colorbrewer 13 | from .. import diverging 14 | from .. import qualitative 15 | from .. import sequential 16 | 17 | 18 | @pytest.mark.parametrize( 19 | 'map_type', ['sequential', 'diverging', 'qualitative']) 20 | def test_load_maps_by_type(map_type): 21 | maps = colorbrewer._load_maps_by_type(map_type) 22 | 23 | m = list(maps.values())[0] 24 | 25 | assert isinstance(m, colorbrewer.BrewerMap) 26 | assert m.type == map_type 27 | 28 | 29 | def test_diverging(): 30 | assert hasattr(diverging, 'BrBG_11_r') 31 | assert isinstance(diverging.BrBG_11_r, colorbrewer.BrewerMap) 32 | assert diverging.BrBG_11_r.type == 'diverging' 33 | 34 | 35 | def test_qualitative(): 36 | assert hasattr(qualitative, 'Set3_12') 37 | assert isinstance(qualitative.Set3_12, colorbrewer.BrewerMap) 38 | assert qualitative.Set3_12.type == 'qualitative' 39 | 40 | 41 | def test_sequential(): 42 | assert hasattr(sequential, 'Blues_6_r') 43 | assert isinstance(sequential.Blues_6_r, colorbrewer.BrewerMap) 44 | assert sequential.Blues_6_r.type == 'sequential' 45 | -------------------------------------------------------------------------------- /palettable/colorbrewer/test/test_get_map.py: -------------------------------------------------------------------------------- 1 | """ 2 | Test the get_map function. 3 | 4 | """ 5 | from __future__ import absolute_import 6 | 7 | try: 8 | import pytest 9 | except ImportError: 10 | raise ImportError('Tests require pytest >= 2.2.') 11 | 12 | from .. import colorbrewer 13 | 14 | 15 | def reverse(sequence): 16 | return [x for x in reversed(sequence)] 17 | 18 | 19 | def test_get_map_reverse(): 20 | bmap = colorbrewer.get_map('Greens', 'sequential', 8) 21 | bmap_r = colorbrewer.get_map('Greens', 'sequential', 8, reverse=True) 22 | 23 | assert bmap.type == bmap_r.type 24 | assert bmap.name + '_r' == bmap_r.name 25 | assert bmap.number == bmap_r.number 26 | assert bmap.colors == reverse(bmap_r.colors) 27 | 28 | 29 | def test_get_map_raises_bad_type(): 30 | with pytest.raises(ValueError): 31 | colorbrewer.get_map('Greens', 'FakeType', 8) 32 | 33 | 34 | def test_get_map_raises_bad_name(): 35 | with pytest.raises(ValueError): 36 | colorbrewer.get_map('FakeName', 'sequential', 8) 37 | 38 | 39 | def test_get_map_raises_bad_number(): 40 | with pytest.raises(ValueError): 41 | colorbrewer.get_map('Greens', 'sequential', 99) 42 | 43 | 44 | class TestCaseSensitivity(object): 45 | def test_type1(self): 46 | bmap = colorbrewer.get_map('Greens', 'SEQUENTIAL', 8) 47 | assert bmap.name == 'Greens' 48 | assert bmap.type == 'sequential' 49 | assert bmap.number == 8 50 | 51 | def test_type2(self): 52 | bmap = colorbrewer.get_map('Greens', 'sequential', 8) 53 | assert bmap.name == 'Greens' 54 | assert bmap.type == 'sequential' 55 | assert bmap.number == 8 56 | 57 | def test_type3(self): 58 | bmap = colorbrewer.get_map('Greens', 'SeQuEnTiAl', 8) 59 | assert bmap.name == 'Greens' 60 | assert bmap.type == 'sequential' 61 | assert bmap.number == 8 62 | 63 | def test_name1(self): 64 | bmap = colorbrewer.get_map('GREENS', 'Sequential', 8) 65 | assert bmap.name == 'Greens' 66 | assert bmap.type == 'sequential' 67 | assert bmap.number == 8 68 | 69 | def test_name2(self): 70 | bmap = colorbrewer.get_map('greens', 'Sequential', 8) 71 | assert bmap.name == 'Greens' 72 | assert bmap.type == 'sequential' 73 | assert bmap.number == 8 74 | 75 | def test_name3(self): 76 | bmap = colorbrewer.get_map('GrEeNs', 'Sequential', 8) 77 | assert bmap.name == 'Greens' 78 | assert bmap.type == 'sequential' 79 | assert bmap.number == 8 80 | 81 | def test_name4(self): 82 | bmap = colorbrewer.get_map('piyg', 'Diverging', 8) 83 | assert bmap.name == 'PiYG' 84 | assert bmap.type == 'diverging' 85 | assert bmap.number == 8 86 | -------------------------------------------------------------------------------- /palettable/colorbrewer/test/test_print_functions.py: -------------------------------------------------------------------------------- 1 | """ 2 | Test the colorbrewer print functions. The output is not actually tested, 3 | but the functions are fully exercised to catch errors. 4 | 5 | """ 6 | from __future__ import absolute_import 7 | 8 | try: 9 | import pytest 10 | except ImportError: 11 | raise ImportError('Tests require pytest >= 2.2.') 12 | 13 | from .. import colorbrewer 14 | 15 | 16 | def test_print_maps1(capsys): 17 | # just make sure there are no errors 18 | colorbrewer.print_maps() 19 | out, err = capsys.readouterr() 20 | assert out 21 | 22 | 23 | def test_print_maps2(capsys): 24 | # just make sure there are no errors 25 | colorbrewer.print_maps('sequential') 26 | out, err = capsys.readouterr() 27 | assert out 28 | 29 | 30 | def test_print_maps3(capsys): 31 | # just make sure there are no errors 32 | colorbrewer.print_maps('sequential', 6) 33 | out, err = capsys.readouterr() 34 | assert out 35 | 36 | 37 | def test_print_maps_raises(): 38 | with pytest.raises(ValueError): 39 | colorbrewer.print_maps(number=6) 40 | 41 | 42 | def test_print_all_maps(capsys): 43 | # just make sure there are no errors 44 | colorbrewer.print_all_maps() 45 | out, err = capsys.readouterr() 46 | assert out 47 | 48 | 49 | def test_print_maps_by_type1(capsys): 50 | # just make sure there are no errors 51 | colorbrewer.print_maps_by_type('qualitative') 52 | out, err = capsys.readouterr() 53 | assert out 54 | 55 | 56 | def test_print_maps_by_type2(capsys): 57 | # just make sure there are no errors 58 | colorbrewer.print_maps_by_type('qualitative', number=6) 59 | out, err = capsys.readouterr() 60 | assert out 61 | 62 | 63 | def test_print_maps_by_type_raises(): 64 | with pytest.raises(ValueError): 65 | colorbrewer.print_maps_by_type('notarealtype') 66 | -------------------------------------------------------------------------------- /palettable/cubehelix/__init__.py: -------------------------------------------------------------------------------- 1 | from __future__ import absolute_import 2 | 3 | from .cubehelix import __doc__, Cubehelix, print_maps, get_map, _get_all_maps 4 | 5 | globals().update(_get_all_maps()) 6 | -------------------------------------------------------------------------------- /palettable/cubehelix/test/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jiffyclub/palettable/339a45c347d34383aeb8fb3d8415d9631affb82c/palettable/cubehelix/test/__init__.py -------------------------------------------------------------------------------- /palettable/cubehelix/test/test_cubehelix.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | from __future__ import absolute_import 3 | 4 | try: 5 | import pytest 6 | except ImportError: 7 | raise ImportError('Tests require pytest >= 2.2.') 8 | 9 | from ... import cubehelix 10 | 11 | HAVE_NPY = cubehelix.cubehelix.HAVE_NPY 12 | 13 | 14 | def test_print_maps(capsys): 15 | # just make sure there are no errors 16 | cubehelix.print_maps() 17 | out, err = capsys.readouterr() 18 | assert out 19 | 20 | 21 | def test_get_map(): 22 | palette = cubehelix.get_map('CLASSIC_16') 23 | assert palette.name == 'classic_16' 24 | assert palette.type == 'sequential' 25 | assert len(palette.colors) == 16 26 | assert palette.url == 'http://adsabs.harvard.edu/abs/2011arXiv1108.5083G' 27 | 28 | 29 | def test_get_map_bad_name(): 30 | with pytest.raises(KeyError): 31 | cubehelix.get_map('bad name') 32 | 33 | 34 | def test_get_map_reversed(): 35 | palette = cubehelix.get_map('classic_16', reverse=False) 36 | palette_r = cubehelix.get_map('classic_16', reverse=True) 37 | assert palette.colors == palette_r.colors[::-1] 38 | 39 | 40 | @pytest.mark.skipif('not HAVE_NPY') 41 | def test_make_map_reversed(): 42 | palette = cubehelix.Cubehelix.make(n=16, reverse=False) 43 | palette_r = cubehelix.Cubehelix.make(n=16, reverse=True) 44 | assert palette.colors == palette_r.colors[::-1] 45 | 46 | 47 | def test_palettes_loaded(): 48 | assert isinstance(cubehelix.classic_16, cubehelix.Cubehelix) 49 | assert isinstance(cubehelix.classic_16_r, cubehelix.Cubehelix) 50 | 51 | 52 | @pytest.mark.skipif('not HAVE_NPY') 53 | def test_default_is_classic(): 54 | classic_palette = cubehelix.get_map('classic_16') 55 | default_palette = cubehelix.Cubehelix.make(n=16) 56 | assert classic_palette.colors == default_palette.colors 57 | 58 | 59 | @pytest.mark.skipif('not HAVE_NPY') 60 | def test_classic(): 61 | palette = cubehelix.Cubehelix.make(start=0.5, rotation=-1.5, gamma=1.0, 62 | sat=1.2, min_light=0., max_light=1., 63 | n=16) 64 | assert palette.colors == cubehelix.get_map('classic_16').colors 65 | 66 | 67 | @pytest.mark.skipif('not HAVE_NPY') 68 | def test_perceptual_rainbow(): 69 | palette = cubehelix.Cubehelix.make(start_hue=240., end_hue=-300., 70 | min_sat=1., max_sat=2.5, 71 | min_light=0.3, max_light=0.8, gamma=.9, 72 | n=16) 73 | assert palette.colors == cubehelix.get_map('perceptual_rainbow_16').colors 74 | 75 | 76 | @pytest.mark.skipif('not HAVE_NPY') 77 | def test_purple(): 78 | palette = cubehelix.Cubehelix.make(start=0., rotation=0.0, n=16) 79 | assert palette.colors == cubehelix.get_map('purple_16').colors 80 | 81 | 82 | @pytest.mark.skipif('not HAVE_NPY') 83 | def test_jim_special(): 84 | palette = cubehelix.Cubehelix.make(start=0.3, rotation=-0.5, n=16) 85 | assert palette.colors == cubehelix.get_map('jim_special_16').colors 86 | 87 | 88 | @pytest.mark.skipif('not HAVE_NPY') 89 | def test_red(): 90 | palette = cubehelix.Cubehelix.make(start=0., rotation=0.5, n=16) 91 | assert palette.colors == cubehelix.get_map('red_16').colors 92 | 93 | 94 | @pytest.mark.skipif('not HAVE_NPY') 95 | def test_cubehelix1(): 96 | palette = cubehelix.Cubehelix.make(gamma=1.0, start=1.5, 97 | rotation=-1.0, sat=1.5, n=16) 98 | assert palette.colors == cubehelix.get_map('cubehelix1_16').colors 99 | 100 | 101 | @pytest.mark.skipif('not HAVE_NPY') 102 | def test_cubehelix2(): 103 | palette = cubehelix.Cubehelix.make(gamma=1.0, start=2.0, rotation=1.0, 104 | sat=1.5, n=16) 105 | assert palette.colors == cubehelix.get_map('cubehelix2_16').colors 106 | 107 | 108 | @pytest.mark.skipif('not HAVE_NPY') 109 | def test_cubehelix3(): 110 | palette = cubehelix.Cubehelix.make(gamma=1.0, start=2.0, rotation=1.0, 111 | sat=3, n=16) 112 | assert palette.colors == cubehelix.get_map('cubehelix3_16').colors 113 | 114 | 115 | @pytest.mark.skipif('not HAVE_NPY') 116 | def test_hex_color(): 117 | palette = cubehelix.Cubehelix.make(start=0.5, rotation=-1.5, gamma=1.0, 118 | sat=1.2, min_light=0., max_light=1., 119 | n=16) 120 | for color in palette.hex_colors: 121 | assert 'L' not in color 122 | -------------------------------------------------------------------------------- /palettable/lightbartlein/__init__.py: -------------------------------------------------------------------------------- 1 | from __future__ import absolute_import 2 | 3 | from . import diverging, sequential 4 | -------------------------------------------------------------------------------- /palettable/lightbartlein/colordata.py: -------------------------------------------------------------------------------- 1 | """ 2 | Color data for Light and Bartlein color maps. 3 | See more at http://geog.uoregon.edu/datagraphics/color_scales.htm. 4 | 5 | """ 6 | # 7 | # Diverging Colormaps 8 | # 9 | 10 | _BROWN_TO_BLUE_10 = [ 11 | [102, 47, 0], 12 | [153, 96, 53], 13 | [204, 155, 122], 14 | [216, 175, 151], 15 | [242, 218, 205], 16 | [204, 253, 255], 17 | [153, 248, 255], 18 | [101, 239, 255], 19 | [50, 227, 255], 20 | [0, 169, 204], 21 | ] 22 | 23 | _BROWN_TO_BLUE_12 = [ 24 | [51, 25, 0], 25 | [2, 47, 0], 26 | [53, 96, 53], 27 | [4, 155, 122], 28 | [16, 175, 151], 29 | [42, 218, 205], 30 | [4, 253, 255], 31 | [53, 248, 255], 32 | [1, 239, 255], 33 | [50, 227, 255], 34 | [0, 169, 204], 35 | [0, 122, 153], 36 | ] 37 | 38 | _BLUE_TO_ORANGE_8 = [ 39 | [0, 127, 255], 40 | [76, 195, 255], 41 | [153, 237, 255], 42 | [204, 255, 255], 43 | [255, 255, 204], 44 | [255, 238, 153], 45 | [255, 195, 76], 46 | [255, 127, 0], 47 | ] 48 | 49 | _BLUE_TO_ORANGE_10 = [ 50 | [0, 84, 255], 51 | [50, 153, 255], 52 | [101, 204, 255], 53 | [153, 237, 255], 54 | [204, 255, 255], 55 | [255, 255, 204], 56 | [255, 238, 153], 57 | [255, 204, 101], 58 | [255, 153, 50], 59 | [255, 85, 0], 60 | ] 61 | 62 | _BLUE_TO_ORANGE_12 = [ 63 | [0, 42, 255], 64 | [25, 101, 255], 65 | [50, 153, 255], 66 | [153, 237, 255], 67 | [101, 204, 255], 68 | [204, 255, 255], 69 | [255, 255, 204], 70 | [255, 238, 153], 71 | [255, 204, 101], 72 | [255, 153, 50], 73 | [255, 102, 25], 74 | [255, 42, 0], 75 | ] 76 | 77 | _GREEN_TO_MAGENTA = [ 78 | [0, 80, 0], 79 | [0, 134, 0], 80 | [0, 187, 0], 81 | [0, 241, 0], 82 | [80, 255, 80], 83 | [134, 255, 134], 84 | [187, 255, 187], 85 | [255, 255, 255], 86 | [255, 241, 255], 87 | [255, 187, 255], 88 | [255, 134, 255], 89 | [255, 80, 255], 90 | [241, 0, 241], 91 | [187, 0, 187], 92 | [134, 0, 134], 93 | [80, 0, 80], 94 | ] 95 | 96 | _BLUE_TO_DARK_RED_12 = [ 97 | [41, 10, 216], 98 | [38, 77, 255], 99 | [63, 160, 255], 100 | [114, 217, 255], 101 | [170, 247, 255], 102 | [224, 255, 255], 103 | [255, 255, 191], 104 | [255, 224, 153], 105 | [255, 173, 114], 106 | [247, 109, 94], 107 | [216, 38, 50], 108 | [165, 0, 33], 109 | ] 110 | 111 | _BLUE_TO_DARK_RED_18 = [ 112 | [36, 0, 216], 113 | [24, 28, 247], 114 | [40, 87, 255], 115 | [61, 135, 255], 116 | [86, 176, 255], 117 | [117, 211, 255], 118 | [153, 234, 255], 119 | [188, 249, 255], 120 | [234, 255, 255], 121 | [255, 255, 234], 122 | [255, 241, 188], 123 | [255, 214, 153], 124 | [255, 172, 117], 125 | [255, 120, 86], 126 | [255, 61, 61], 127 | [247, 39, 53], 128 | [216, 21, 47], 129 | [165, 0, 33], 130 | ] 131 | 132 | _BLUE_TO_DARK_ORANGE_12 = [ 133 | [30, 142, 153], 134 | [81, 195, 204], 135 | [153, 249, 255], 136 | [178, 252, 255], 137 | [204, 254, 255], 138 | [229, 255, 255], 139 | [255, 229, 204], 140 | [255, 202, 153], 141 | [255, 173, 101], 142 | [255, 142, 50], 143 | [204, 88, 0], 144 | [153, 63, 0], 145 | ] 146 | 147 | _BLUE_TO_DARK_ORANGE_18 = [ 148 | [0, 102, 102], 149 | [0, 153, 153], 150 | [0, 204, 204], 151 | [0, 255, 255], 152 | [51, 255, 255], 153 | [101, 255, 255], 154 | [153, 255, 255], 155 | [178, 255, 255], 156 | [203, 255, 255], 157 | [229, 255, 255], 158 | [255, 229, 203], 159 | [255, 202, 153], 160 | [255, 173, 101], 161 | [255, 142, 51], 162 | [255, 110, 0], 163 | [204, 85, 0], 164 | [153, 61, 0], 165 | [102, 39, 0], 166 | ] 167 | 168 | _BLUE_TO_GREEN = [ 169 | [0, 0, 255], 170 | [51, 51, 255], 171 | [101, 101, 255], 172 | [153, 153, 255], 173 | [178, 178, 255], 174 | [203, 203, 255], 175 | [229, 229, 255], 176 | [229, 255, 229], 177 | [203, 255, 203], 178 | [178, 255, 178], 179 | [153, 255, 153], 180 | [101, 255, 101], 181 | [51, 255, 51], 182 | [0, 255, 0], 183 | ] 184 | 185 | _BLUE_TO_GREY = [ 186 | [0, 153, 204], 187 | [102, 229, 255], 188 | [153, 255, 255], 189 | [204, 255, 255], 190 | [229, 229, 229], 191 | [153, 153, 153], 192 | [102, 102, 102], 193 | [51, 51, 51], 194 | ] 195 | 196 | _BLUE_ORANGE_RED = [ 197 | [7, 90, 255], 198 | [50, 118, 255], 199 | [89, 144, 255], 200 | [140, 178, 255], 201 | [191, 212, 255], 202 | [229, 238, 255], 203 | [247, 249, 255], 204 | [255, 255, 204], 205 | [255, 255, 153], 206 | [255, 255, 0], 207 | [255, 204, 0], 208 | [255, 153, 0], 209 | [255, 102, 0], 210 | [255, 0, 0], 211 | ] 212 | 213 | _RED_YELLOW_BLUE = [ 214 | [165, 0, 33], 215 | [216, 38, 50], 216 | [247, 109, 94], 217 | [255, 173, 114], 218 | [255, 224, 153], 219 | [255, 255, 191], 220 | [224, 255, 255], 221 | [170, 247, 255], 222 | [114, 216, 255], 223 | [63, 160, 255], 224 | [38, 76, 255], 225 | ] 226 | 227 | # 228 | # Sequential colormaps 229 | # 230 | 231 | _BLUE_7 = [ 232 | [255, 255, 255], 233 | [204, 253, 255], 234 | [153, 248, 255], 235 | [102, 239, 255], 236 | [51, 227, 255], 237 | [0, 170, 204], 238 | [0, 122, 153], 239 | ] 240 | 241 | _BLUE_10 = [ 242 | [229, 255, 255], 243 | [204, 250, 255], 244 | [178, 242, 255], 245 | [153, 229, 255], 246 | [127, 212, 255], 247 | [101, 191, 255], 248 | [76, 165, 255], 249 | [50, 136, 255], 250 | [25, 101, 255], 251 | [0, 63, 255], 252 | ] 253 | -------------------------------------------------------------------------------- /palettable/lightbartlein/diverging.py: -------------------------------------------------------------------------------- 1 | from __future__ import absolute_import, print_function 2 | """ 3 | Diverging Light & Bartlein palettes as described at 4 | http://geog.uoregon.edu/datagraphics/color_scales.htm 5 | 6 | """ 7 | import itertools as it 8 | 9 | from . import colordata 10 | from . import lightbartlein 11 | from .. import utils 12 | 13 | _PALETTE_TYPE = 'diverging' 14 | _NAMES_TO_DATA = { 15 | 'BlueDarkOrange12': colordata._BLUE_TO_DARK_ORANGE_12, 16 | 'BlueDarkOrange18': colordata._BLUE_TO_DARK_ORANGE_18, 17 | 'BlueDarkRed12': colordata._BLUE_TO_DARK_RED_12, 18 | 'BlueDarkRed18': colordata._BLUE_TO_DARK_RED_18, 19 | 'BlueGreen': colordata._BLUE_TO_GREEN, 20 | 'BlueGrey': colordata._BLUE_TO_GREY, 21 | 'BlueGray': colordata._BLUE_TO_GREY, 22 | 'BlueOrange8': colordata._BLUE_TO_ORANGE_8, 23 | 'BlueOrange10': colordata._BLUE_TO_ORANGE_10, 24 | 'BlueOrange12': colordata._BLUE_TO_ORANGE_12, 25 | 'BlueOrangeRed': colordata._BLUE_ORANGE_RED, 26 | 'BrownBlue10': colordata._BROWN_TO_BLUE_10, 27 | 'BrownBlue12': colordata._BROWN_TO_BLUE_12, 28 | 'GreenMagenta': colordata._GREEN_TO_MAGENTA, 29 | 'RedYellowBlue': colordata._RED_YELLOW_BLUE, 30 | } 31 | _MAX_LENS = { 32 | 'BlueDarkOrange12': 12, 33 | 'BlueDarkOrange18': 18, 34 | 'BlueDarkRed12': 12, 35 | 'BlueDarkRed18': 18, 36 | 'BlueGreen': 14, 37 | 'BlueGrey': 8, 38 | 'BlueGray': 8, 39 | 'BlueOrange8': 8, 40 | 'BlueOrange10': 10, 41 | 'BlueOrange12': 12, 42 | 'BlueOrangeRed': 14, 43 | 'BrownBlue10': 10, 44 | 'BrownBlue12': 12, 45 | 'GreenMagenta': 16, 46 | 'RedYellowBlue': 11, 47 | } 48 | _NAMES_AND_LENGTHS = list( 49 | it.chain.from_iterable( 50 | utils.make_names_and_lengths([name], range(2, _MAX_LENS[name] + 1)) 51 | for name in sorted(_NAMES_TO_DATA) 52 | ) 53 | ) 54 | 55 | print_maps = utils.print_maps_factory('diverging Light & Bartlein', 56 | _NAMES_AND_LENGTHS, 57 | _PALETTE_TYPE) 58 | 59 | get_map = utils.get_map_factory('diverging Light & Bartlein', 60 | __name__, 61 | _NAMES_TO_DATA, 62 | _PALETTE_TYPE, 63 | lightbartlein.LightBartleinMap, 64 | is_evenly_spaced=True) 65 | 66 | globals().update(utils.load_all_palettes(_NAMES_AND_LENGTHS, get_map)) 67 | -------------------------------------------------------------------------------- /palettable/lightbartlein/lightbartlein.py: -------------------------------------------------------------------------------- 1 | from __future__ import absolute_import, print_function 2 | """ 3 | Light & Bartlein palettes as described at 4 | http://geog.uoregon.edu/datagraphics/color_scales.htm 5 | 6 | """ 7 | 8 | from ..palette import Palette 9 | 10 | 11 | class LightBartleinMap(Palette): 12 | """ 13 | Representation of a Light & Bartlein color map with matplotlib compatible 14 | views of the map. 15 | 16 | Parameters 17 | ---------- 18 | name : str 19 | palette_type : str 20 | colors : list 21 | Colors as list of 0-255 RGB triplets. 22 | 23 | Attributes 24 | ---------- 25 | name : str 26 | type : str 27 | number : int 28 | Number of colors in color map. 29 | colors : list 30 | Colors as list of 0-255 RGB triplets. 31 | hex_colors : list 32 | mpl_colors : list 33 | mpl_colormap : matplotlib LinearSegmentedColormap 34 | url : str 35 | Website with related info. 36 | 37 | """ 38 | url = 'http://geog.uoregon.edu/datagraphics/color_scales.htm' 39 | 40 | def __init__(self, name, palette_type, colors): 41 | super(LightBartleinMap, self).__init__(name, palette_type, colors) 42 | -------------------------------------------------------------------------------- /palettable/lightbartlein/sequential.py: -------------------------------------------------------------------------------- 1 | from __future__ import absolute_import, print_function 2 | """ 3 | Sequential Light & Bartlein palettes as described at 4 | http://geog.uoregon.edu/datagraphics/color_scales.htm 5 | 6 | """ 7 | import itertools as it 8 | 9 | from . import colordata 10 | from . import lightbartlein 11 | from .. import utils 12 | 13 | _PALETTE_TYPE = 'sequential' 14 | _NAMES_TO_DATA = { 15 | 'Blues7': colordata._BLUE_7, 16 | 'Blues10': colordata._BLUE_10, 17 | } 18 | _MAX_LENS = { 19 | 'Blues7': 7, 20 | 'Blues10': 10, 21 | } 22 | _NAMES_AND_LENGTHS = list( 23 | it.chain.from_iterable( 24 | utils.make_names_and_lengths([name], range(2, _MAX_LENS[name] + 1)) 25 | for name in sorted(_NAMES_TO_DATA) 26 | ) 27 | ) 28 | 29 | print_maps = utils.print_maps_factory('sequential Light & Bartlein', 30 | _NAMES_AND_LENGTHS, 31 | _PALETTE_TYPE) 32 | 33 | get_map = utils.get_map_factory('sequential Light & Bartlein', 34 | __name__, 35 | _NAMES_TO_DATA, 36 | _PALETTE_TYPE, 37 | lightbartlein.LightBartleinMap, 38 | is_evenly_spaced=True) 39 | 40 | globals().update(utils.load_all_palettes(_NAMES_AND_LENGTHS, get_map)) 41 | -------------------------------------------------------------------------------- /palettable/lightbartlein/test/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jiffyclub/palettable/339a45c347d34383aeb8fb3d8415d9631affb82c/palettable/lightbartlein/test/__init__.py -------------------------------------------------------------------------------- /palettable/lightbartlein/test/test_lightbartlein.py: -------------------------------------------------------------------------------- 1 | from __future__ import absolute_import 2 | 3 | from ... import lightbartlein 4 | from ... import utils 5 | 6 | 7 | def test_print_maps_diverging(capsys): 8 | lightbartlein.diverging.print_maps() 9 | out, err = capsys.readouterr() 10 | lines = out.split("\n") 11 | assert lines[0] == "BlueDarkOrange12_2 diverging 2" 12 | 13 | 14 | def test_print_maps_sequential(capsys): 15 | lightbartlein.sequential.print_maps() 16 | out, err = capsys.readouterr() 17 | lines = out.split("\n") 18 | assert lines[0] == "Blues10_2 sequential 2" 19 | 20 | 21 | def test_get_map_diverging(): 22 | palette = lightbartlein.diverging.get_map("GreenMagenta_5") 23 | assert isinstance(palette, lightbartlein.lightbartlein.LightBartleinMap) 24 | assert palette.name == "GreenMagenta_5" 25 | assert palette.type == "diverging" 26 | assert len(palette.colors) == 5 27 | assert ( 28 | palette.url == "http://geog.uoregon.edu/datagraphics/color_scales.htm" 29 | ) 30 | 31 | 32 | def test_get_map_sequential(): 33 | palette = lightbartlein.sequential.get_map("Blues7_5") 34 | assert isinstance(palette, lightbartlein.lightbartlein.LightBartleinMap) 35 | assert palette.name == "Blues7_5" 36 | assert palette.type == "sequential" 37 | assert len(palette.colors) == 5 38 | assert ( 39 | palette.url == "http://geog.uoregon.edu/datagraphics/color_scales.htm" 40 | ) 41 | 42 | 43 | def test_get_map_diverging_reversed(): 44 | palette = lightbartlein.diverging.get_map("GreenMagenta_5", reverse=True) 45 | assert isinstance(palette, lightbartlein.lightbartlein.LightBartleinMap) 46 | assert palette.name == "GreenMagenta_5_r" 47 | assert palette.type == "diverging" 48 | assert len(palette.colors) == 5 49 | assert ( 50 | palette.url == "http://geog.uoregon.edu/datagraphics/color_scales.htm" 51 | ) 52 | 53 | 54 | def test_get_map_sequential_reversed(): 55 | palette = lightbartlein.sequential.get_map("Blues7_5", reverse=True) 56 | assert isinstance(palette, lightbartlein.lightbartlein.LightBartleinMap) 57 | assert palette.name == "Blues7_5_r" 58 | assert palette.type == "sequential" 59 | assert len(palette.colors) == 5 60 | assert ( 61 | palette.url == "http://geog.uoregon.edu/datagraphics/color_scales.htm" 62 | ) 63 | 64 | 65 | def test_palettes_loaded(): 66 | assert isinstance( 67 | lightbartlein.diverging.GreenMagenta_10, 68 | lightbartlein.lightbartlein.LightBartleinMap, 69 | ) 70 | assert isinstance( 71 | lightbartlein.diverging.GreenMagenta_10_r, 72 | lightbartlein.lightbartlein.LightBartleinMap, 73 | ) 74 | assert lightbartlein.diverging.GreenMagenta_10.type == 'diverging' 75 | 76 | assert isinstance( 77 | lightbartlein.sequential.Blues10_4, 78 | lightbartlein.lightbartlein.LightBartleinMap, 79 | ) 80 | assert isinstance( 81 | lightbartlein.sequential.Blues10_4_r, 82 | lightbartlein.lightbartlein.LightBartleinMap, 83 | ) 84 | assert lightbartlein.sequential.Blues10_4.type == 'sequential' 85 | 86 | 87 | def test_get_all_maps(): 88 | # Smoke tests. 89 | assert isinstance( 90 | utils.load_all_palettes(lightbartlein.diverging._NAMES_AND_LENGTHS, 91 | lightbartlein.diverging.get_map), 92 | dict) 93 | assert isinstance( 94 | utils.load_all_palettes(lightbartlein.sequential._NAMES_AND_LENGTHS, 95 | lightbartlein.sequential.get_map), 96 | dict) 97 | -------------------------------------------------------------------------------- /palettable/matplotlib/__init__.py: -------------------------------------------------------------------------------- 1 | from __future__ import absolute_import 2 | 3 | from .. import utils 4 | from .matplotlib import __doc__, print_maps, get_map, _NAMES_AND_LENGTHS 5 | 6 | 7 | globals().update(utils.load_all_palettes(_NAMES_AND_LENGTHS, get_map)) 8 | -------------------------------------------------------------------------------- /palettable/matplotlib/matplotlib.py: -------------------------------------------------------------------------------- 1 | from __future__ import absolute_import, print_function 2 | """ 3 | New matplotlib color palettes as described at https://bids.github.io/colormap 4 | 5 | """ 6 | 7 | import itertools 8 | 9 | from . import colormaps 10 | from .. import utils 11 | from ..palette import Palette 12 | 13 | _PALETTE_TYPE = 'sequential' 14 | _NAMES_TO_DATA = { 15 | 'Magma': colormaps._MAGMA_DATA, 16 | 'Inferno': colormaps._INFERNO_DATA, 17 | 'Plasma': colormaps._PLASMA_DATA, 18 | 'Viridis': colormaps._VIRIDIS_DATA 19 | } 20 | _NAME_MAP = utils.make_name_map(_NAMES_TO_DATA.keys()) 21 | _NAMES_AND_LENGTHS = utils.make_names_and_lengths( 22 | sorted(_NAMES_TO_DATA.keys())) 23 | 24 | 25 | class MatplotlibMap(Palette): 26 | """ 27 | Representation of a color map with matplotlib compatible 28 | views of the map. 29 | 30 | Parameters 31 | ---------- 32 | name : str 33 | palette_type : str 34 | colors : list 35 | Colors as list of 0-255 RGB triplets. 36 | 37 | Attributes 38 | ---------- 39 | name : str 40 | type : str 41 | number : int 42 | Number of colors in color map. 43 | colors : list 44 | Colors as list of 0-255 RGB triplets. 45 | hex_colors : list 46 | mpl_colors : list 47 | mpl_colormap : matplotlib LinearSegmentedColormap 48 | url : str 49 | Website with related info. 50 | 51 | """ 52 | url = 'https://bids.github.io/colormap' 53 | 54 | def __init__(self, name, palette_type, colors): 55 | super(MatplotlibMap, self).__init__(name, palette_type, colors) 56 | 57 | 58 | print_maps = utils.print_maps_factory( 59 | 'matplotlib', _NAMES_AND_LENGTHS, _PALETTE_TYPE) 60 | get_map = utils.get_map_factory( 61 | 'matplotlib', __name__, _NAMES_TO_DATA, _PALETTE_TYPE, 62 | MatplotlibMap) 63 | -------------------------------------------------------------------------------- /palettable/matplotlib/test/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jiffyclub/palettable/339a45c347d34383aeb8fb3d8415d9631affb82c/palettable/matplotlib/test/__init__.py -------------------------------------------------------------------------------- /palettable/matplotlib/test/test_matplotlib.py: -------------------------------------------------------------------------------- 1 | from __future__ import absolute_import 2 | 3 | from ... import matplotlib as mpl 4 | from ... import utils 5 | 6 | 7 | def test_print_maps(capsys): 8 | mpl.print_maps() 9 | out, err = capsys.readouterr() 10 | lines = out.split('\n') 11 | assert lines[0] == 'Inferno_3 sequential 3' 12 | 13 | 14 | def test_get_map(): 15 | palette = mpl.get_map('VIRIDIS_5') 16 | assert isinstance(palette, mpl.matplotlib.MatplotlibMap) 17 | assert palette.name == 'Viridis_5' 18 | assert palette.type == 'sequential' 19 | assert len(palette.colors) == 5 20 | assert palette.url == 'https://bids.github.io/colormap' 21 | 22 | 23 | def test_get_map_reversed(): 24 | palette = mpl.get_map('VIRIDIS_5', reverse=True) 25 | assert isinstance(palette, mpl.matplotlib.MatplotlibMap) 26 | assert palette.name == 'Viridis_5_r' 27 | assert palette.type == 'sequential' 28 | assert len(palette.colors) == 5 29 | assert palette.url == 'https://bids.github.io/colormap' 30 | 31 | 32 | def test_palettes_loaded(): 33 | assert isinstance(mpl.Viridis_8, mpl.matplotlib.MatplotlibMap) 34 | assert isinstance(mpl.Viridis_8_r, mpl.matplotlib.MatplotlibMap) 35 | assert mpl.Viridis_8.type == 'sequential' 36 | 37 | 38 | def test_get_all_maps(): 39 | # Smoke tests. 40 | assert isinstance( 41 | utils.load_all_palettes(mpl._NAMES_AND_LENGTHS, mpl.get_map), dict) 42 | -------------------------------------------------------------------------------- /palettable/mycarta/__init__.py: -------------------------------------------------------------------------------- 1 | from __future__ import absolute_import 2 | 3 | from .. import utils 4 | from .mycarta import __doc__, print_maps, get_map, _NAMES_AND_LENGTHS 5 | 6 | 7 | globals().update(utils.load_all_palettes(_NAMES_AND_LENGTHS, get_map)) 8 | -------------------------------------------------------------------------------- /palettable/mycarta/mycarta.py: -------------------------------------------------------------------------------- 1 | from __future__ import absolute_import, print_function 2 | """ 3 | Mycarta palettes as described at https://mycarta.wordpress.com/color-palettes/ 4 | 5 | """ 6 | 7 | import itertools 8 | 9 | from . import colordata 10 | from .. import utils 11 | from ..palette import Palette 12 | 13 | _PALETTE_TYPE = 'sequential' 14 | _NAMES_TO_DATA = { 15 | 'Cube1': colordata.CUBE1, 16 | 'CubeYF': colordata.CUBEYF, 17 | 'LinearL': colordata.LINEARL, 18 | } 19 | _NAME_MAP = utils.make_name_map(_NAMES_TO_DATA.keys()) 20 | _NAMES_AND_LENGTHS = utils.make_names_and_lengths( 21 | sorted(_NAMES_TO_DATA.keys())) 22 | 23 | 24 | class MycartaMap(Palette): 25 | """ 26 | Representation of a color map with matplotlib compatible 27 | views of the map. 28 | 29 | Parameters 30 | ---------- 31 | name : str 32 | palette_type : str 33 | colors : list 34 | Colors as list of 0-255 RGB triplets. 35 | 36 | Attributes 37 | ---------- 38 | name : str 39 | type : str 40 | number : int 41 | Number of colors in color map. 42 | colors : list 43 | Colors as list of 0-255 RGB triplets. 44 | hex_colors : list 45 | mpl_colors : list 46 | mpl_colormap : matplotlib LinearSegmentedColormap 47 | url : str 48 | Website with related info. 49 | 50 | """ 51 | url = 'https://mycarta.wordpress.com/color-palettes/' 52 | 53 | def __init__(self, name, palette_type, colors): 54 | super(MycartaMap, self).__init__(name, palette_type, colors) 55 | 56 | 57 | print_maps = utils.print_maps_factory( 58 | 'mycarta', _NAMES_AND_LENGTHS, _PALETTE_TYPE) 59 | get_map = utils.get_map_factory( 60 | 'mycarta', __name__, _NAMES_TO_DATA, _PALETTE_TYPE, 61 | MycartaMap) 62 | -------------------------------------------------------------------------------- /palettable/mycarta/test/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jiffyclub/palettable/339a45c347d34383aeb8fb3d8415d9631affb82c/palettable/mycarta/test/__init__.py -------------------------------------------------------------------------------- /palettable/mycarta/test/test_mycarta.py: -------------------------------------------------------------------------------- 1 | from __future__ import absolute_import 2 | 3 | from ... import mycarta 4 | from ... import utils 5 | 6 | 7 | def test_print_maps(capsys): 8 | mycarta.print_maps() 9 | out, err = capsys.readouterr() 10 | lines = out.split('\n') 11 | assert lines[0] == 'Cube1_3 sequential 3' 12 | 13 | 14 | def test_get_map(): 15 | palette = mycarta.get_map('LINEARL_5') 16 | assert isinstance(palette, mycarta.mycarta.MycartaMap) 17 | assert palette.name == 'LinearL_5' 18 | assert palette.type == 'sequential' 19 | assert len(palette.colors) == 5 20 | assert palette.url == 'https://mycarta.wordpress.com/color-palettes/' 21 | 22 | 23 | def test_get_map_reversed(): 24 | palette = mycarta.get_map('LINEARL_5', reverse=True) 25 | assert isinstance(palette, mycarta.mycarta.MycartaMap) 26 | assert palette.name == 'LinearL_5_r' 27 | assert palette.type == 'sequential' 28 | assert len(palette.colors) == 5 29 | assert palette.url == 'https://mycarta.wordpress.com/color-palettes/' 30 | 31 | 32 | def test_palettes_loaded(): 33 | assert isinstance(mycarta.CubeYF_8, mycarta.mycarta.MycartaMap) 34 | assert isinstance(mycarta.CubeYF_8_r, mycarta.mycarta.MycartaMap) 35 | assert mycarta.CubeYF_8.type == 'sequential' 36 | 37 | 38 | def test_get_all_maps(): 39 | # Smoke tests. 40 | assert isinstance( 41 | utils.load_all_palettes(mycarta._NAMES_AND_LENGTHS, mycarta.get_map), 42 | dict) 43 | -------------------------------------------------------------------------------- /palettable/palette.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | 3 | from __future__ import absolute_import 4 | 5 | import sys 6 | 7 | try: 8 | import matplotlib.pyplot as plt 9 | from matplotlib.colors import ( 10 | ListedColormap, BoundaryNorm, Normalize, LinearSegmentedColormap) 11 | from matplotlib.colorbar import ColorbarBase 12 | except ImportError: # pragma: no cover 13 | HAVE_MPL = False 14 | except RuntimeError: # e.g. OS X, if Python is not installed as a framework 15 | HAVE_MPL = False 16 | else: 17 | HAVE_MPL = True 18 | 19 | 20 | class Palette(object): 21 | """ 22 | Representation of a color map with matplotlib compatible 23 | views of the map. 24 | 25 | Parameters 26 | ---------- 27 | name : str 28 | map_type : str 29 | colors : list 30 | Colors as list of 0-255 RGB triplets. 31 | 32 | Attributes 33 | ---------- 34 | name : str 35 | type : str 36 | number : int 37 | Number of colors in color map. 38 | colors : list 39 | Colors as list of 0-255 RGB triplets. 40 | hex_colors : list 41 | mpl_colors : list 42 | mpl_colormap : matplotlib LinearSegmentedColormap 43 | 44 | """ 45 | def __init__(self, name, map_type, colors): 46 | self.name = name 47 | self.type = map_type 48 | self.number = len(colors) 49 | self.colors = colors 50 | 51 | @property 52 | def hex_colors(self): 53 | """ 54 | Colors as a tuple of hex strings. (e.g. '#A912F4') 55 | 56 | """ 57 | hc = [] 58 | 59 | for color in self.colors: 60 | h = '#' + ''.join('{0:>02}'.format(hex(c)[2:].upper()) 61 | for c in color) 62 | hc.append(h) 63 | 64 | return hc 65 | 66 | @property 67 | def mpl_colors(self): 68 | """ 69 | Colors expressed on the range 0-1 as used by matplotlib. 70 | 71 | """ 72 | mc = [] 73 | 74 | for color in self.colors: 75 | mc.append(tuple([x / 255. for x in color])) 76 | 77 | return mc 78 | 79 | @property 80 | def mpl_colormap(self): 81 | """ 82 | A basic matplotlib color map. If you want to specify keyword arguments 83 | use the `get_mpl_colormap` method. 84 | 85 | """ 86 | return self.get_mpl_colormap() 87 | 88 | def get_mpl_colormap(self, **kwargs): 89 | """ 90 | A color map that can be used in matplotlib plots. Requires matplotlib 91 | to be importable. Keyword arguments are passed to 92 | `matplotlib.colors.LinearSegmentedColormap.from_list`. 93 | 94 | """ 95 | if not HAVE_MPL: # pragma: no cover 96 | raise RuntimeError('matplotlib not available.') 97 | 98 | cmap = LinearSegmentedColormap.from_list(self.name, 99 | self.mpl_colors, **kwargs) 100 | 101 | return cmap 102 | 103 | def show_as_blocks(self, block_size=100): 104 | """ 105 | Show colors in the IPython Notebook using ipythonblocks. 106 | 107 | Parameters 108 | ---------- 109 | block_size : int, optional 110 | Size of displayed blocks. 111 | 112 | """ 113 | from ipythonblocks import BlockGrid 114 | 115 | grid = BlockGrid(self.number, 1, block_size=block_size) 116 | 117 | for block, color in zip(grid, self.colors): 118 | block.rgb = color 119 | 120 | grid.show() 121 | 122 | def _write_image(self, fp, style, format='png', size=(6, 1)): 123 | """ 124 | Write the color map as an image to a file-like object. 125 | 126 | Parameters 127 | ---------- 128 | fp : file-like 129 | A file-like object such as an open file pointer or 130 | a StringIO/BytesIO instance. 131 | style : {'discrete', 'continuous'} 132 | Whether to make the color map image as a discrete map 133 | or a continuous map. 134 | format : str, optional 135 | An image format that will be understood by matplotlib. 136 | size : tuple of int, optional 137 | (width, height) of image to make in units of inches. 138 | 139 | """ 140 | if not HAVE_MPL: # pragma: no cover 141 | raise RuntimeError('matplotlib not available.') 142 | 143 | fig = plt.figure(figsize=size, frameon=False) 144 | ax = fig.add_axes([0, 0, 1, 1], frameon=False) 145 | ax.set_axis_off() 146 | 147 | if style == 'discrete': 148 | # make a bounded color map showing only the defined colors 149 | ncolors = self.number 150 | norm = BoundaryNorm(range(ncolors + 1), ncolors=ncolors) 151 | cmap = ListedColormap(self.mpl_colors) 152 | 153 | elif style == 'continuous': 154 | # make the smooth, interpolated color map 155 | cmap = self.mpl_colormap 156 | norm = Normalize(vmin=0, vmax=1) 157 | 158 | ColorbarBase(ax, cmap=cmap, norm=norm, orientation='horizontal') 159 | fig.savefig(fp, format=format) 160 | plt.close(fig) 161 | 162 | def show_discrete_image(self, size=(6, 1)): 163 | """ 164 | Embed an image of this discrete color map in the IPython Notebook. 165 | 166 | Parameters 167 | ---------- 168 | size : tuple of int, optional 169 | (width, height) of image to make in units of inches. 170 | 171 | """ 172 | if sys.version_info[0] == 2: 173 | from StringIO import StringIO as BytesIO 174 | elif sys.version_info[0] == 3: 175 | from io import BytesIO 176 | 177 | from IPython.display import display 178 | from IPython.display import Image as ipyImage 179 | 180 | im = BytesIO() 181 | self._write_image(im, 'discrete', format='png', size=size) 182 | display(ipyImage(data=im.getvalue(), format='png')) 183 | 184 | def save_discrete_image(self, filename, size=(6, 1), format=None): 185 | """ 186 | Save an image of this discrete color map to a file. 187 | 188 | Parameters 189 | ---------- 190 | filename : str 191 | If `format` is None the format will be inferred from the 192 | `filename` extension. 193 | size : tuple of int, optional 194 | (width, height) of image to make in units of inches. 195 | format : str, optional 196 | An image format that will be understood by matplotlib. 197 | 198 | """ 199 | with open(filename, 'wb') as f: 200 | self._write_image( 201 | f, 'discrete', format=filename.split('.')[-1], size=size) 202 | 203 | def show_continuous_image(self, size=(6, 1)): 204 | """ 205 | Embed an image of this continuous color map in the IPython Notebook. 206 | 207 | Parameters 208 | ---------- 209 | size : tuple of int, optional 210 | (width, height) of image to make in units of inches. 211 | 212 | """ 213 | if sys.version_info[0] == 2: 214 | from StringIO import StringIO as BytesIO 215 | elif sys.version_info[0] == 3: 216 | from io import BytesIO 217 | 218 | from IPython.display import display 219 | from IPython.display import Image as ipyImage 220 | 221 | im = BytesIO() 222 | self._write_image(im, 'continuous', format='png', size=size) 223 | display(ipyImage(data=im.getvalue(), format='png')) 224 | 225 | def save_continuous_image(self, filename, size=(6, 1), format=None): 226 | """ 227 | Save an image of this continuous color map to a file. 228 | 229 | Parameters 230 | ---------- 231 | filename : str 232 | If `format` is None the format will be inferred from the 233 | `filename` extension. 234 | size : tuple of int, optional 235 | (width, height) of image to make in units of inches. 236 | format : str, optional 237 | An image format that will be understood by matplotlib. 238 | 239 | """ 240 | with open(filename, 'wb') as f: 241 | self._write_image( 242 | f, 'continuous', format=filename.split('.')[-1], size=size) 243 | -------------------------------------------------------------------------------- /palettable/plotly/__init__.py: -------------------------------------------------------------------------------- 1 | from __future__ import absolute_import 2 | 3 | from . import diverging, sequential, qualitative 4 | -------------------------------------------------------------------------------- /palettable/plotly/colordata.py: -------------------------------------------------------------------------------- 1 | """ 2 | Color maps from Plotly package 3 | Learn more at https://github.com/plotly/plotly.py and view the MIT license at 4 | https://github.com/plotly/plotly.py/blob/master/LICENSE.txt 5 | 6 | """ 7 | 8 | PLOTLY = [ 9 | (99, 110, 250), 10 | (239, 85, 59), 11 | (0, 204, 150), 12 | (171, 99, 250), 13 | (255, 161, 90), 14 | (25, 211, 243), 15 | (255, 102, 146), 16 | (182, 232, 128), 17 | (255, 151, 255), 18 | (254, 203, 82), 19 | ] 20 | 21 | D3 = [ 22 | (31, 119, 180), 23 | (255, 127, 14), 24 | (44, 160, 44), 25 | (214, 39, 40), 26 | (148, 103, 189), 27 | (140, 86, 75), 28 | (227, 119, 194), 29 | (127, 127, 127), 30 | (188, 189, 34), 31 | (23, 190, 207), 32 | ] 33 | 34 | G10 = [ 35 | (51, 102, 204), 36 | (220, 57, 18), 37 | (255, 153, 0), 38 | (16, 150, 24), 39 | (153, 0, 153), 40 | (0, 153, 198), 41 | (221, 68, 119), 42 | (102, 170, 0), 43 | (184, 46, 46), 44 | (49, 99, 149), 45 | ] 46 | 47 | T10 = [ 48 | (76, 120, 168), 49 | (245, 133, 24), 50 | (228, 87, 86), 51 | (114, 183, 178), 52 | (84, 162, 75), 53 | (238, 202, 59), 54 | (178, 121, 162), 55 | (255, 157, 166), 56 | (157, 117, 93), 57 | (186, 176, 172), 58 | ] 59 | 60 | ALPHABET = [ 61 | (170, 13, 254), 62 | (50, 131, 254), 63 | (133, 102, 13), 64 | (120, 42, 182), 65 | (86, 86, 86), 66 | (28, 131, 86), 67 | (22, 255, 50), 68 | (247, 225, 160), 69 | (226, 226, 226), 70 | (28, 190, 79), 71 | (196, 69, 28), 72 | (222, 160, 253), 73 | (254, 0, 250), 74 | (50, 90, 155), 75 | (254, 175, 22), 76 | (248, 161, 159), 77 | (144, 173, 28), 78 | (246, 34, 46), 79 | (28, 255, 206), 80 | (46, 217, 255), 81 | (177, 13, 161), 82 | (192, 117, 166), 83 | (252, 28, 191), 84 | (176, 0, 104), 85 | (251, 228, 38), 86 | (250, 0, 135), 87 | ] 88 | 89 | DARK24 = [ 90 | (46, 145, 229), 91 | (225, 95, 153), 92 | (28, 167, 28), 93 | (251, 13, 13), 94 | (218, 22, 255), 95 | (34, 42, 42), 96 | (182, 129, 0), 97 | (117, 13, 134), 98 | (235, 102, 59), 99 | (81, 28, 251), 100 | (0, 160, 139), 101 | (251, 0, 209), 102 | (252, 0, 128), 103 | (178, 130, 141), 104 | (108, 124, 50), 105 | (119, 138, 174), 106 | (134, 42, 22), 107 | (167, 119, 241), 108 | (98, 0, 66), 109 | (22, 22, 167), 110 | (218, 96, 202), 111 | (108, 69, 22), 112 | (13, 42, 99), 113 | (175, 0, 56), 114 | ] 115 | 116 | LIGHT24 = [ 117 | (253, 50, 22), 118 | (0, 254, 53), 119 | (106, 118, 252), 120 | (254, 212, 196), 121 | (254, 0, 206), 122 | (13, 249, 255), 123 | (246, 249, 38), 124 | (255, 150, 22), 125 | (71, 155, 85), 126 | (238, 166, 251), 127 | (220, 88, 125), 128 | (214, 38, 255), 129 | (110, 137, 156), 130 | (0, 181, 247), 131 | (182, 142, 0), 132 | (201, 251, 229), 133 | (255, 0, 146), 134 | (34, 255, 167), 135 | (227, 238, 158), 136 | (134, 206, 0), 137 | (188, 113, 150), 138 | (126, 125, 205), 139 | (252, 105, 85), 140 | (228, 143, 114), 141 | ] 142 | 143 | PICNIC = [ 144 | (0, 0, 255), 145 | (51, 153, 255), 146 | (102, 204, 255), 147 | (153, 204, 255), 148 | (204, 204, 255), 149 | (255, 255, 255), 150 | (255, 204, 255), 151 | (255, 153, 255), 152 | (255, 102, 204), 153 | (255, 102, 102), 154 | (255, 0, 0), 155 | ] 156 | 157 | PORTLAND = [ 158 | (12, 51, 131), 159 | (10, 136, 186), 160 | (242, 211, 56), 161 | (242, 143, 56), 162 | (217, 30, 30), 163 | ] 164 | 165 | BLACKBODY = [ 166 | (0, 0, 0), 167 | (230, 0, 0), 168 | (230, 210, 0), 169 | (255, 255, 255), 170 | (160, 200, 255), 171 | ] 172 | 173 | BLUERED = [(0, 0, 255), (255, 0, 0)] 174 | 175 | ELECTRIC = [ 176 | (0, 0, 0), 177 | (30, 0, 100), 178 | (120, 0, 100), 179 | (160, 90, 0), 180 | (230, 200, 0), 181 | (255, 250, 220), 182 | ] 183 | 184 | HOT = [(0, 0, 0), (230, 0, 0), (255, 210, 0), (255, 255, 255)] 185 | 186 | JET = [ 187 | (0, 0, 131), 188 | (0, 60, 170), 189 | (5, 255, 255), 190 | (255, 255, 0), 191 | (250, 0, 0), 192 | (128, 0, 0), 193 | ] 194 | 195 | RAINBOW = [ 196 | (150, 0, 90), 197 | (0, 0, 200), 198 | (0, 25, 255), 199 | (0, 152, 255), 200 | (44, 255, 150), 201 | (151, 255, 0), 202 | (255, 234, 0), 203 | (255, 111, 0), 204 | (255, 0, 0), 205 | ] 206 | -------------------------------------------------------------------------------- /palettable/plotly/diverging.py: -------------------------------------------------------------------------------- 1 | """ 2 | Color maps from Plotly package 3 | Learn more at https://github.com/plotly/plotly.py and view the MIT license at 4 | https://github.com/plotly/plotly.py/blob/master/LICENSE.txt 5 | 6 | """ 7 | 8 | from __future__ import absolute_import 9 | 10 | from . import plotly 11 | from . import colordata 12 | from .. import utils 13 | 14 | _PALETTE_TYPE = "diverging" 15 | _NAMES_TO_DATA = { 16 | "Picnic": colordata.PICNIC, 17 | "Portland": colordata.PORTLAND, 18 | } 19 | _NAME_MAP = utils.make_name_map(_NAMES_TO_DATA.keys()) 20 | _NAMES_AND_LENGTHS = utils.make_names_and_lengths( 21 | ["Picnic"], range(2, 12) 22 | ) + utils.make_names_and_lengths(["Portland"], range(2, 6)) 23 | 24 | 25 | print_maps = utils.print_maps_factory( 26 | "diverging plotly", _NAMES_AND_LENGTHS, _PALETTE_TYPE 27 | ) 28 | 29 | get_map = utils.get_map_factory( 30 | "diverging plotly", 31 | __name__, 32 | _NAMES_TO_DATA, 33 | _PALETTE_TYPE, 34 | plotly.PlotlyColorMap, 35 | is_evenly_spaced=False, 36 | ) 37 | 38 | globals().update(utils.load_all_palettes(_NAMES_AND_LENGTHS, get_map)) 39 | -------------------------------------------------------------------------------- /palettable/plotly/plotly.py: -------------------------------------------------------------------------------- 1 | """ 2 | Color maps from Plotly package 3 | Learn more at https://github.com/plotly/plotly.py and view the MIT license at 4 | https://github.com/plotly/plotly.py/blob/master/LICENSE.txt 5 | 6 | """ 7 | from ..palette import Palette 8 | 9 | 10 | class PlotlyColorMap(Palette): 11 | """ 12 | Representation of a Scientific color map with matplotlib compatible 13 | views of the map. 14 | 15 | Parameters 16 | ---------- 17 | name : str 18 | palette_type : str 19 | colors : list 20 | Colors as list of 0-255 RGB triplets. 21 | 22 | Attributes 23 | ---------- 24 | name : str 25 | type : str 26 | number : int 27 | Number of colors in color map. 28 | colors : list 29 | Colors as list of 0-255 RGB triplets. 30 | hex_colors : list 31 | mpl_colors : list 32 | mpl_colormap : matplotlib LinearSegmentedColormap 33 | url : str 34 | Website with related info. 35 | 36 | """ 37 | 38 | url = "https://plotly.com/python/" 39 | 40 | def __init__(self, name, palette_type, colors): 41 | super(PlotlyColorMap, self).__init__(name, palette_type, colors) 42 | -------------------------------------------------------------------------------- /palettable/plotly/qualitative.py: -------------------------------------------------------------------------------- 1 | """ 2 | Color maps from Plotly package 3 | Learn more at https://github.com/plotly/plotly.py and view the MIT license at 4 | https://github.com/plotly/plotly.py/blob/master/LICENSE.txt 5 | 6 | """ 7 | 8 | from __future__ import absolute_import 9 | 10 | from . import plotly 11 | from . import colordata 12 | from .. import utils 13 | 14 | _PALETTE_TYPE = "qualitative" 15 | _NAMES_TO_DATA = { 16 | "Plotly": colordata.PLOTLY, 17 | "D3": colordata.D3, 18 | "G10": colordata.G10, 19 | "T10": colordata.T10, 20 | "Alphabet": colordata.ALPHABET, 21 | "Dark24": colordata.DARK24, 22 | "Light24": colordata.LIGHT24, 23 | } 24 | _NAME_MAP = utils.make_name_map(_NAMES_TO_DATA.keys()) 25 | _NAMES_AND_LENGTHS = ( 26 | utils.make_names_and_lengths(["Plotly", "D3", "G10", "T10"], range(2, 11)) 27 | + utils.make_names_and_lengths(["Alphabet"], range(2, 27)) 28 | + utils.make_names_and_lengths(["Dark24", "Light24"], range(2, 25)) 29 | ) 30 | 31 | print_maps = utils.print_maps_factory( 32 | "qualitative plotly", _NAMES_AND_LENGTHS, _PALETTE_TYPE 33 | ) 34 | 35 | get_map = utils.get_map_factory( 36 | "qualitative plotly", 37 | __name__, 38 | _NAMES_TO_DATA, 39 | _PALETTE_TYPE, 40 | plotly.PlotlyColorMap, 41 | is_evenly_spaced=False, 42 | ) 43 | 44 | globals().update(utils.load_all_palettes(_NAMES_AND_LENGTHS, get_map)) 45 | -------------------------------------------------------------------------------- /palettable/plotly/sequential.py: -------------------------------------------------------------------------------- 1 | """ 2 | Color maps from Plotly package 3 | Learn more at https://github.com/plotly/plotly.py and view the MIT license at 4 | https://github.com/plotly/plotly.py/blob/master/LICENSE.txt 5 | 6 | """ 7 | 8 | from __future__ import absolute_import 9 | 10 | from . import plotly 11 | from . import colordata 12 | from .. import utils 13 | 14 | _PALETTE_TYPE = "sequential" 15 | _NAMES_TO_DATA = { 16 | "Blackbody": colordata.BLACKBODY, 17 | "Bluered": colordata.BLUERED, 18 | "Electric": colordata.ELECTRIC, 19 | "Hot": colordata.HOT, 20 | "Jet": colordata.JET, 21 | "Rainbow": colordata.RAINBOW, 22 | } 23 | _NAME_MAP = utils.make_name_map(_NAMES_TO_DATA.keys()) 24 | _NAMES_AND_LENGTHS = ( 25 | utils.make_names_and_lengths(["Blackbody"], range(2, 6)) 26 | + utils.make_names_and_lengths(["Bluered"], range(2, 3)) 27 | + utils.make_names_and_lengths(["Electric"], range(2, 7)) 28 | + utils.make_names_and_lengths(["Hot"], range(2, 5)) 29 | + utils.make_names_and_lengths(["Jet"], range(2, 7)) 30 | + utils.make_names_and_lengths(["Rainbow"], range(2, 10)) 31 | ) 32 | 33 | print_maps = utils.print_maps_factory( 34 | "sequential plotly", _NAMES_AND_LENGTHS, _PALETTE_TYPE 35 | ) 36 | 37 | get_map = utils.get_map_factory( 38 | "sequential plotly", 39 | __name__, 40 | _NAMES_TO_DATA, 41 | _PALETTE_TYPE, 42 | plotly.PlotlyColorMap, 43 | is_evenly_spaced=False, 44 | ) 45 | 46 | globals().update(utils.load_all_palettes(_NAMES_AND_LENGTHS, get_map)) 47 | -------------------------------------------------------------------------------- /palettable/plotly/test/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jiffyclub/palettable/339a45c347d34383aeb8fb3d8415d9631affb82c/palettable/plotly/test/__init__.py -------------------------------------------------------------------------------- /palettable/plotly/test/test_plotly.py: -------------------------------------------------------------------------------- 1 | from __future__ import absolute_import 2 | 3 | from ... import plotly 4 | from ... import utils 5 | 6 | 7 | def test_print_maps_diverging(capsys): 8 | plotly.diverging.print_maps() 9 | out, err = capsys.readouterr() 10 | lines = out.split("\n") 11 | assert lines[0] == "Picnic_2 diverging 2" 12 | 13 | 14 | def test_print_maps_sequential(capsys): 15 | plotly.sequential.print_maps() 16 | out, err = capsys.readouterr() 17 | lines = out.split("\n") 18 | assert lines[0] == "Blackbody_2 sequential 2" 19 | 20 | 21 | def test_print_maps_qualitative(capsys): 22 | plotly.qualitative.print_maps() 23 | out, err = capsys.readouterr() 24 | lines = out.split("\n") 25 | assert lines[0] == "Plotly_2 qualitative 2" 26 | 27 | 28 | def test_get_map_diverging(): 29 | palette = plotly.diverging.get_map("Picnic_9") 30 | assert isinstance(palette, plotly.plotly.PlotlyColorMap) 31 | assert palette.name == "Picnic_9" 32 | assert palette.type == "diverging" 33 | assert len(palette.colors) == 9 34 | assert palette.url == "https://plotly.com/python/" 35 | 36 | 37 | def test_get_map_sequential(): 38 | palette = plotly.sequential.get_map("Jet_6") 39 | assert isinstance(palette, plotly.plotly.PlotlyColorMap) 40 | assert palette.name == "Jet_6" 41 | assert palette.type == "sequential" 42 | assert len(palette.colors) == 6 43 | assert palette.url == "https://plotly.com/python/" 44 | 45 | 46 | def test_get_map_qualitative(): 47 | palette = plotly.qualitative.get_map("D3_10") 48 | assert isinstance(palette, plotly.plotly.PlotlyColorMap) 49 | assert palette.name == "D3_10" 50 | assert palette.type == "qualitative" 51 | assert len(palette.colors) == 10 52 | assert palette.url == "https://plotly.com/python/" 53 | 54 | 55 | def test_get_map_diverging_reversed(): 56 | palette = plotly.diverging.get_map("Picnic_9", reverse=True) 57 | assert isinstance(palette, plotly.plotly.PlotlyColorMap) 58 | assert palette.name == "Picnic_9_r" 59 | assert palette.type == "diverging" 60 | assert len(palette.colors) == 9 61 | assert palette.url == "https://plotly.com/python/" 62 | 63 | 64 | def test_get_map_sequential_reversed(): 65 | palette = plotly.sequential.get_map("Jet_6", reverse=True) 66 | assert isinstance(palette, plotly.plotly.PlotlyColorMap) 67 | assert palette.name == "Jet_6_r" 68 | assert palette.type == "sequential" 69 | assert len(palette.colors) == 6 70 | assert palette.url == "https://plotly.com/python/" 71 | 72 | 73 | def test_get_map_qualitative_reversed(): 74 | palette = plotly.qualitative.get_map("D3_10", reverse=True) 75 | assert isinstance(palette, plotly.plotly.PlotlyColorMap) 76 | assert palette.name == "D3_10_r" 77 | assert palette.type == "qualitative" 78 | assert len(palette.colors) == 10 79 | assert palette.url == "https://plotly.com/python/" 80 | 81 | 82 | def test_palettes_loaded(): 83 | assert isinstance( 84 | plotly.diverging.Picnic_5, 85 | plotly.plotly.PlotlyColorMap, 86 | ) 87 | assert isinstance( 88 | plotly.diverging.Picnic_5_r, 89 | plotly.plotly.PlotlyColorMap, 90 | ) 91 | assert plotly.diverging.Picnic_5.type == "diverging" 92 | 93 | assert isinstance( 94 | plotly.sequential.Electric_4, 95 | plotly.plotly.PlotlyColorMap, 96 | ) 97 | assert isinstance( 98 | plotly.sequential.Electric_4_r, 99 | plotly.plotly.PlotlyColorMap, 100 | ) 101 | assert plotly.sequential.Electric_4.type == "sequential" 102 | 103 | assert isinstance( 104 | plotly.qualitative.Alphabet_14, 105 | plotly.plotly.PlotlyColorMap, 106 | ) 107 | assert isinstance( 108 | plotly.qualitative.Alphabet_14_r, 109 | plotly.plotly.PlotlyColorMap, 110 | ) 111 | assert plotly.qualitative.Alphabet_10.type == "qualitative" 112 | 113 | 114 | def test_get_all_maps(): 115 | # Smoke tests. 116 | assert isinstance( 117 | utils.load_all_palettes( 118 | plotly.diverging._NAMES_AND_LENGTHS, plotly.diverging.get_map 119 | ), 120 | dict, 121 | ) 122 | assert isinstance( 123 | utils.load_all_palettes( 124 | plotly.sequential._NAMES_AND_LENGTHS, 125 | plotly.sequential.get_map, 126 | ), 127 | dict, 128 | ) 129 | assert isinstance( 130 | utils.load_all_palettes( 131 | plotly.qualitative._NAMES_AND_LENGTHS, 132 | plotly.qualitative.get_map, 133 | ), 134 | dict, 135 | ) 136 | -------------------------------------------------------------------------------- /palettable/scientific/__init__.py: -------------------------------------------------------------------------------- 1 | from __future__ import absolute_import 2 | 3 | from . import diverging, sequential, qualitative 4 | -------------------------------------------------------------------------------- /palettable/scientific/diverging.py: -------------------------------------------------------------------------------- 1 | """ 2 | Diverging colormaps from Scientific Colour-Maps: 3 | http://www.fabiocrameri.ch/colourmaps.php 4 | 5 | """ 6 | from __future__ import absolute_import 7 | 8 | from . import scientific 9 | from . import colordata 10 | from .. import utils 11 | 12 | _PALETTE_TYPE = 'diverging' 13 | _MAP_NAMES = ( 14 | 'Broc', 15 | 'Cork', 16 | 'Vik', 17 | 'Lisbon', 18 | 'Tofino', 19 | 'Berlin', 20 | 'Bam', 21 | 'Roma', 22 | 'Vanimo', 23 | 'Managua', 24 | ) 25 | _NAMES_TO_DATA = { 26 | name: getattr(colordata, name.upper()) for name in _MAP_NAMES 27 | } 28 | _NAMES_AND_LENGTHS = utils.make_names_and_lengths(_MAP_NAMES) 29 | 30 | print_maps = utils.print_maps_factory( 31 | 'diverging scientific', _NAMES_AND_LENGTHS, _PALETTE_TYPE) 32 | get_map = utils.get_map_factory( 33 | 'diverging scientific', __name__, _NAMES_TO_DATA, _PALETTE_TYPE, 34 | scientific.ScientificMap, is_evenly_spaced=True) 35 | 36 | globals().update(utils.load_all_palettes(_NAMES_AND_LENGTHS, get_map)) 37 | -------------------------------------------------------------------------------- /palettable/scientific/qualitative.py: -------------------------------------------------------------------------------- 1 | """ 2 | Qualitative colormaps from Scientific Colour-Maps: 3 | http://www.fabiocrameri.ch/colourmaps.php 4 | 5 | """ 6 | from __future__ import absolute_import 7 | 8 | from . import scientific 9 | from . import colordata_qualitative 10 | from .. import utils 11 | 12 | _PALETTE_TYPE = 'qualitative' 13 | _NAMES_TO_DATA = { 14 | 'Acton': colordata_qualitative.ACTON, 15 | 'Bamako': colordata_qualitative.BAMAKO, 16 | 'Batlow': colordata_qualitative.BATLOW, 17 | 'BatlowK': colordata_qualitative.BATLOWK, 18 | 'BatlowW': colordata_qualitative.BATLOWW, 19 | 'Bilbao': colordata_qualitative.BILBAO, 20 | 'Buda': colordata_qualitative.BUDA, 21 | 'Davos': colordata_qualitative.DAVOS, 22 | 'Devon': colordata_qualitative.DEVON, 23 | 'Glasgow': colordata_qualitative.GLASGOW, 24 | 'GrayC': colordata_qualitative.GRAYC, 25 | 'Hawaii': colordata_qualitative.HAWAII, 26 | 'Imola': colordata_qualitative.IMOLA, 27 | 'Lajolla': colordata_qualitative.LAJOLLA, 28 | 'Lapaz': colordata_qualitative.LAPAZ, 29 | 'Lipari': colordata_qualitative.LIPARI, 30 | 'Navia': colordata_qualitative.NAVIA, 31 | 'Nuuk': colordata_qualitative.NUUK, 32 | 'Oslo': colordata_qualitative.OSLO, 33 | 'Tokyo': colordata_qualitative.TOKYO, 34 | 'Turku': colordata_qualitative.TURKU, 35 | } 36 | _NAME_MAP = utils.make_name_map(_NAMES_TO_DATA.keys()) 37 | _NAMES_AND_LENGTHS = utils.make_names_and_lengths( 38 | sorted(_NAMES_TO_DATA.keys()), range(2, 11) 39 | ) 40 | 41 | print_maps = utils.print_maps_factory( 42 | 'qualitative scientific', _NAMES_AND_LENGTHS, _PALETTE_TYPE) 43 | 44 | get_map = utils.get_map_factory( 45 | 'qualitative scientific', __name__, _NAMES_TO_DATA, _PALETTE_TYPE, 46 | scientific.ScientificMap, is_evenly_spaced=False) 47 | 48 | globals().update(utils.load_all_palettes(_NAMES_AND_LENGTHS, get_map)) 49 | -------------------------------------------------------------------------------- /palettable/scientific/scientific.py: -------------------------------------------------------------------------------- 1 | """ 2 | Scientific Colour-Maps: http://www.fabiocrameri.ch/colourmaps.php 3 | 4 | """ 5 | from ..palette import Palette 6 | 7 | 8 | class ScientificMap(Palette): 9 | """ 10 | Representation of a Scientific color map with matplotlib compatible 11 | views of the map. 12 | 13 | Parameters 14 | ---------- 15 | name : str 16 | palette_type : str 17 | colors : list 18 | Colors as list of 0-255 RGB triplets. 19 | 20 | Attributes 21 | ---------- 22 | name : str 23 | type : str 24 | number : int 25 | Number of colors in color map. 26 | colors : list 27 | Colors as list of 0-255 RGB triplets. 28 | hex_colors : list 29 | mpl_colors : list 30 | mpl_colormap : matplotlib LinearSegmentedColormap 31 | url : str 32 | Website with related info. 33 | 34 | """ 35 | url = 'http://www.fabiocrameri.ch/colourmaps.php' 36 | 37 | def __init__(self, name, palette_type, colors): 38 | super(ScientificMap, self).__init__(name, palette_type, colors) 39 | -------------------------------------------------------------------------------- /palettable/scientific/sequential.py: -------------------------------------------------------------------------------- 1 | """ 2 | Sequential colormaps from Scientific Colour-Maps: 3 | http://www.fabiocrameri.ch/colourmaps.php 4 | 5 | """ 6 | from __future__ import absolute_import 7 | 8 | from . import scientific 9 | from . import colordata 10 | from .. import utils 11 | 12 | _PALETTE_TYPE = 'sequential' 13 | _MAP_NAMES = ( 14 | 'Batlow', 15 | 'BatlowW', 16 | 'BatlowK', 17 | 'Glasgow', 18 | 'Lipari', 19 | 'Navia', 20 | 'Hawaii', 21 | 'Buda', 22 | 'Imola', 23 | 'Oslo', 24 | 'GrayC', 25 | 'Nuuk', 26 | 'Devon', 27 | 'LaJolla', 28 | 'Bamako', 29 | 'Davos', 30 | 'Bilbao', 31 | 'LaPaz', 32 | 'Acton', 33 | 'Turku', 34 | 'Tokyo', # Sequential gradients 35 | 'Oleron', 36 | 'Bukavu', 37 | 'Fes', # Multi-sequential gradients 38 | 'RomaO', 39 | 'BamO', 40 | 'BrocO', 41 | 'CorkO', 42 | 'VikO', # Cyclic gradients 43 | ) 44 | _NAMES_TO_DATA = { 45 | name: getattr(colordata, name.upper()) for name in _MAP_NAMES 46 | } 47 | _NAMES_AND_LENGTHS = utils.make_names_and_lengths(_MAP_NAMES) 48 | 49 | print_maps = utils.print_maps_factory( 50 | 'sequential scientific', _NAMES_AND_LENGTHS, _PALETTE_TYPE) 51 | get_map = utils.get_map_factory( 52 | 'sequential scientific', __name__, _NAMES_TO_DATA, _PALETTE_TYPE, 53 | scientific.ScientificMap, is_evenly_spaced=True) 54 | 55 | globals().update(utils.load_all_palettes(_NAMES_AND_LENGTHS, get_map)) 56 | -------------------------------------------------------------------------------- /palettable/scientific/test/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jiffyclub/palettable/339a45c347d34383aeb8fb3d8415d9631affb82c/palettable/scientific/test/__init__.py -------------------------------------------------------------------------------- /palettable/scientific/test/test_scientific.py: -------------------------------------------------------------------------------- 1 | from __future__ import absolute_import 2 | 3 | from ... import scientific 4 | from ... import utils 5 | 6 | 7 | def test_print_maps_diverging(capsys): 8 | scientific.diverging.print_maps() 9 | out, err = capsys.readouterr() 10 | lines = out.split("\n") 11 | assert lines[0] == "Broc_3 diverging 3" 12 | 13 | 14 | def test_print_maps_sequential(capsys): 15 | scientific.sequential.print_maps() 16 | out, err = capsys.readouterr() 17 | lines = out.split("\n") 18 | assert lines[0] == "Batlow_3 sequential 3" 19 | 20 | 21 | def test_print_maps_qualitative(capsys): 22 | scientific.qualitative.print_maps() 23 | out, err = capsys.readouterr() 24 | lines = out.split("\n") 25 | assert lines[0] == "Acton_2 qualitative 2" 26 | 27 | 28 | def test_get_map_diverging(): 29 | palette = scientific.diverging.get_map("Lisbon_19") 30 | assert isinstance(palette, scientific.scientific.ScientificMap) 31 | assert palette.name == "Lisbon_19" 32 | assert palette.type == "diverging" 33 | assert len(palette.colors) == 19 34 | assert palette.url == "http://www.fabiocrameri.ch/colourmaps.php" 35 | 36 | 37 | def test_get_map_sequential(): 38 | palette = scientific.sequential.get_map("Buda_6") 39 | assert isinstance(palette, scientific.scientific.ScientificMap) 40 | assert palette.name == "Buda_6" 41 | assert palette.type == "sequential" 42 | assert len(palette.colors) == 6 43 | assert palette.url == "http://www.fabiocrameri.ch/colourmaps.php" 44 | 45 | 46 | def test_get_map_qualitative(): 47 | palette = scientific.qualitative.get_map("Navia_10") 48 | assert isinstance(palette, scientific.scientific.ScientificMap) 49 | assert palette.name == "Navia_10" 50 | assert palette.type == "qualitative" 51 | assert len(palette.colors) == 10 52 | assert palette.url == "http://www.fabiocrameri.ch/colourmaps.php" 53 | 54 | 55 | def test_get_map_diverging_reversed(): 56 | palette = scientific.diverging.get_map("Lisbon_19", reverse=True) 57 | assert isinstance(palette, scientific.scientific.ScientificMap) 58 | assert palette.name == "Lisbon_19_r" 59 | assert palette.type == "diverging" 60 | assert len(palette.colors) == 19 61 | assert palette.url == "http://www.fabiocrameri.ch/colourmaps.php" 62 | 63 | 64 | def test_get_map_sequential_reversed(): 65 | palette = scientific.sequential.get_map("Buda_6", reverse=True) 66 | assert isinstance(palette, scientific.scientific.ScientificMap) 67 | assert palette.name == "Buda_6_r" 68 | assert palette.type == "sequential" 69 | assert len(palette.colors) == 6 70 | assert palette.url == "http://www.fabiocrameri.ch/colourmaps.php" 71 | 72 | 73 | def test_get_map_qualitative_reversed(): 74 | palette = scientific.qualitative.get_map("Navia_10", reverse=True) 75 | assert isinstance(palette, scientific.scientific.ScientificMap) 76 | assert palette.name == "Navia_10_r" 77 | assert palette.type == "qualitative" 78 | assert len(palette.colors) == 10 79 | assert palette.url == "http://www.fabiocrameri.ch/colourmaps.php" 80 | 81 | 82 | def test_palettes_loaded(): 83 | assert isinstance( 84 | scientific.diverging.Tofino_10, 85 | scientific.scientific.ScientificMap, 86 | ) 87 | assert isinstance( 88 | scientific.diverging.Tofino_10_r, 89 | scientific.scientific.ScientificMap, 90 | ) 91 | assert scientific.diverging.Tofino_10.type == "diverging" 92 | 93 | assert isinstance( 94 | scientific.sequential.Nuuk_9, 95 | scientific.scientific.ScientificMap, 96 | ) 97 | assert isinstance( 98 | scientific.sequential.Nuuk_9_r, 99 | scientific.scientific.ScientificMap, 100 | ) 101 | assert scientific.sequential.Nuuk_9.type == "sequential" 102 | 103 | assert isinstance( 104 | scientific.qualitative.Imola_10, 105 | scientific.scientific.ScientificMap, 106 | ) 107 | assert isinstance( 108 | scientific.qualitative.Imola_10_r, 109 | scientific.scientific.ScientificMap, 110 | ) 111 | assert scientific.qualitative.Imola_10.type == "qualitative" 112 | 113 | 114 | def test_get_all_maps(): 115 | # Smoke tests. 116 | assert isinstance( 117 | utils.load_all_palettes(scientific.diverging._NAMES_AND_LENGTHS, 118 | scientific.diverging.get_map), 119 | dict) 120 | assert isinstance( 121 | utils.load_all_palettes(scientific.sequential._NAMES_AND_LENGTHS, 122 | scientific.sequential.get_map), 123 | dict) 124 | assert isinstance( 125 | utils.load_all_palettes(scientific.qualitative._NAMES_AND_LENGTHS, 126 | scientific.qualitative.get_map), 127 | dict) 128 | -------------------------------------------------------------------------------- /palettable/tableau/__init__.py: -------------------------------------------------------------------------------- 1 | from __future__ import absolute_import 2 | 3 | from .tableau import __doc__, print_maps, get_map, _get_all_maps 4 | 5 | globals().update(_get_all_maps()) 6 | -------------------------------------------------------------------------------- /palettable/tableau/tableau.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | """ 3 | Color palettes derived from Tableau: http://www.tableausoftware.com/ 4 | 5 | See also: 6 | 7 | http://kb.tableausoftware.com/articles/knowledgebase/creating-custom-color-palettes 8 | http://tableaufriction.blogspot.ro/2012/11/finally-you-can-use-tableau-data-colors.html 9 | 10 | """ 11 | from __future__ import absolute_import, print_function 12 | 13 | from ..palette import Palette 14 | 15 | # There is no documentation page that lists the color palettes. 16 | url = 'http://www.tableausoftware.com' 17 | palette_type = 'qualitative' 18 | 19 | palette_names = [ 20 | 'Tableau_10', 21 | 'TableauLight_10', 22 | 'TableauMedium_10', 23 | 'Tableau_20', 24 | 'Gray_5', 25 | 'ColorBlind_10', 26 | 'TrafficLight_9', 27 | 'PurpleGray_6', 28 | 'PurpleGray_12', 29 | 'BlueRed_6', 30 | 'BlueRed_12', 31 | 'GreenOrange_6', 32 | 'GreenOrange_12' 33 | ] 34 | 35 | # Dictionary from name or short name to index. 36 | lookup = dict((name.lower(), i) for i, name in enumerate(palette_names)) 37 | 38 | colors_rgb = [ 39 | # Tableau 10 40 | [[ 31, 119, 180], 41 | [255, 127, 14], 42 | [ 44, 160, 44], 43 | [214, 39, 40], 44 | [148, 103, 189], 45 | [140, 86, 75], 46 | [227, 119, 194], 47 | [127, 127, 127], 48 | [188, 189, 34], 49 | [ 23, 190, 207]], 50 | # Tableau 10 Light 51 | [[174, 199, 232], 52 | [255, 187, 120], 53 | [152, 223, 138], 54 | [255, 152, 150], 55 | [197, 176, 213], 56 | [196, 156, 148], 57 | [247, 182, 210], 58 | [199, 199, 199], 59 | [219, 219, 141], 60 | [158, 218, 229]], 61 | # Tableau 10 Medium 62 | [[114, 158, 206], 63 | [255, 158, 74], 64 | [103, 191, 92], 65 | [237, 102, 93], 66 | [173, 139, 201], 67 | [168, 120, 110], 68 | [237, 151, 202], 69 | [162, 162, 162], 70 | [205, 204, 93], 71 | [109, 204, 218]], 72 | # Tableau 20 73 | [[ 31, 119, 180], 74 | [174, 199, 232], 75 | [255, 127, 14], 76 | [255, 187, 120], 77 | [ 44, 160, 44], 78 | [152, 223, 138], 79 | [214, 39, 40], 80 | [255, 152, 150], 81 | [148, 103, 189], 82 | [197, 176, 213], 83 | [140, 86, 75], 84 | [196, 156, 148], 85 | [227, 119, 194], 86 | [247, 182, 210], 87 | [127, 127, 127], 88 | [199, 199, 199], 89 | [188, 189, 34], 90 | [219, 219, 141], 91 | [ 23, 190, 207], 92 | [158, 218, 229]], 93 | # Gray 5 94 | [[ 96, 99, 106], 95 | [165, 172, 175], 96 | [ 65, 68, 81], 97 | [143, 135, 130], 98 | [207, 207, 207]], 99 | # Color Blind 10 100 | [[ 0, 107, 164], 101 | [255, 128, 14], 102 | [171, 171, 171], 103 | [ 89, 89, 89], 104 | [ 95, 158, 209], 105 | [200, 82, 0], 106 | [137, 137, 137], 107 | [162, 200, 236], 108 | [255, 188, 121], 109 | [207, 207, 207]], 110 | # Traffic Light 9 111 | [[177, 3, 24], 112 | [219, 161, 58], 113 | [ 48, 147, 67], 114 | [216, 37, 38], 115 | [255, 193, 86], 116 | [105, 183, 100], 117 | [242, 108, 100], 118 | [255, 221, 113], 119 | [159, 205, 153]], 120 | # Purple-Gray 6 121 | [[123, 102, 210], 122 | [220, 95, 189], 123 | [148, 145, 123], 124 | [153, 86, 136], 125 | [208, 152, 238], 126 | [215, 213, 197]], 127 | # Purple-Gray 12 128 | [[123, 102, 210], 129 | [166, 153, 232], 130 | [220, 95, 189], 131 | [255, 192, 218], 132 | [ 95, 90, 65], 133 | [180, 177, 155], 134 | [153, 86, 136], 135 | [216, 152, 186], 136 | [171, 106, 213], 137 | [208, 152, 238], 138 | [139, 124, 110], 139 | [219, 212, 197]], 140 | # Blue-Red 6 141 | [[ 44, 105, 176], 142 | [240, 39, 32], 143 | [172, 97, 60], 144 | [107, 163, 214], 145 | [234, 107, 115], 146 | [233, 195, 155]], 147 | # Blue-Red 12 148 | [[ 44, 105, 176], 149 | [181, 200, 226], 150 | [240, 39, 32], 151 | [255, 182, 176], 152 | [172, 97, 60], 153 | [233, 195, 155], 154 | [107, 163, 214], 155 | [181, 223, 253], 156 | [172, 135, 99], 157 | [221, 201, 180], 158 | [189, 10, 54], 159 | [244, 115, 122]], 160 | # Green-Orange 6 161 | [[ 50, 162, 81], 162 | [255, 127, 15], 163 | [ 60, 183, 204], 164 | [255, 217, 74], 165 | [ 57, 115, 124], 166 | [184, 90, 13]], 167 | # Green-Orange 12 168 | [[ 50, 162, 81], 169 | [172, 217, 141], 170 | [255, 127, 15], 171 | [255, 185, 119], 172 | [ 60, 183, 204], 173 | [152, 217, 228], 174 | [184, 90, 13], 175 | [255, 217, 74], 176 | [ 57, 115, 124], 177 | [134, 180, 169], 178 | [130, 133, 59], 179 | [204, 201, 77]] 180 | ] 181 | 182 | 183 | class TableauMap(Palette): 184 | """ 185 | Representation of a color map with matplotlib compatible 186 | views of the map. 187 | 188 | Parameters 189 | ---------- 190 | name : str 191 | colors : list 192 | Colors as list of 0-255 RGB triplets. 193 | 194 | Attributes 195 | ---------- 196 | name : str 197 | type : str 198 | number : int 199 | Number of colors in color map. 200 | colors : list 201 | Colors as list of 0-255 RGB triplets. 202 | hex_colors : list 203 | mpl_colors : list 204 | mpl_colormap : matplotlib LinearSegmentedColormap 205 | 206 | """ 207 | url = url 208 | 209 | def __init__(self, name, colors): 210 | super(TableauMap, self).__init__(name, palette_type, colors) 211 | 212 | 213 | def print_maps(): 214 | """ 215 | Print a list of Tableau palettes. 216 | 217 | """ 218 | namelen = max(len(name) for name in palette_names) 219 | fmt = '{0:' + str(namelen + 4) + '}{1:16}{2:}' 220 | 221 | for i, name in enumerate(palette_names): 222 | print(fmt.format(name, palette_type, len(colors_rgb[i]))) 223 | 224 | 225 | def get_map(name, reverse=False): 226 | """ 227 | Get a Tableau palette by name. 228 | 229 | Parameters 230 | ---------- 231 | name : str 232 | Name of map. Use `print_maps` to see available names. If `None`, then 233 | return a list of all colormaps. 234 | reverse : bool, optional 235 | If True reverse colors from their default order. 236 | 237 | Returns 238 | ------- 239 | palette : TableauMap 240 | 241 | """ 242 | try: 243 | index = lookup[name.lower()] 244 | except KeyError: 245 | msg = "{0!r} is an unknown Tableau palette." 246 | raise KeyError(msg.format(name)) 247 | 248 | colors = colors_rgb[index] 249 | if reverse: 250 | name = name + '_r' 251 | colors = list(reversed(colors)) 252 | 253 | return TableauMap(name, colors) 254 | 255 | 256 | def _get_all_maps(): 257 | """ 258 | Returns a dictionary of all Tableau palettes, including reversed ones. 259 | 260 | """ 261 | d = dict((name, get_map(name)) for name in palette_names) 262 | d.update(dict( 263 | (name + '_r', get_map(name, reverse=True)) for name in palette_names)) 264 | return d 265 | -------------------------------------------------------------------------------- /palettable/tableau/test/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jiffyclub/palettable/339a45c347d34383aeb8fb3d8415d9631affb82c/palettable/tableau/test/__init__.py -------------------------------------------------------------------------------- /palettable/tableau/test/test_tableau.py: -------------------------------------------------------------------------------- 1 | from __future__ import absolute_import 2 | 3 | try: 4 | import pytest 5 | except ImportError: 6 | raise ImportError('Tests require pytest >= 2.2.') 7 | 8 | from ... import tableau 9 | 10 | 11 | def test_print_maps(capsys): 12 | # just make sure there are no errors 13 | tableau.print_maps() 14 | out, err = capsys.readouterr() 15 | assert out 16 | 17 | 18 | def test_get_map_bad_name(): 19 | with pytest.raises(KeyError): 20 | tableau.get_map('bad name') 21 | 22 | 23 | def test_get_map(): 24 | # Smoke tests. 25 | assert isinstance( 26 | tableau.get_map('Tableau_10'), tableau.tableau.TableauMap) 27 | assert isinstance( 28 | tableau.get_map( 29 | 'Tableau_10', reverse=True), tableau.tableau.TableauMap) 30 | 31 | 32 | def test_get_all_maps(): 33 | # Smoke tests. 34 | maps = tableau.tableau._get_all_maps() 35 | assert isinstance(maps, dict) 36 | assert 'Tableau_10' in maps 37 | assert 'Tableau_10_r' in maps 38 | 39 | 40 | def test_maps_loaded(): 41 | assert hasattr(tableau, 'ColorBlind_10') 42 | assert hasattr(tableau, 'ColorBlind_10_r') 43 | assert tableau.ColorBlind_10.type == 'qualitative' 44 | -------------------------------------------------------------------------------- /palettable/test/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jiffyclub/palettable/339a45c347d34383aeb8fb3d8415d9631affb82c/palettable/test/__init__.py -------------------------------------------------------------------------------- /palettable/test/test_brewermap.py: -------------------------------------------------------------------------------- 1 | """ 2 | Test the BrewerMap class. 3 | 4 | """ 5 | from __future__ import absolute_import 6 | 7 | import os 8 | import tempfile 9 | import urllib.request as urllib 10 | from unittest import mock 11 | 12 | try: 13 | from matplotlib.colors import LinearSegmentedColormap 14 | except ImportError: 15 | HAVE_MPL = False 16 | else: 17 | HAVE_MPL = True 18 | 19 | import pytest 20 | from ipythonblocks import BlockGrid 21 | 22 | from .. import colorbrewer 23 | 24 | 25 | @pytest.fixture 26 | def img_filename(request): 27 | with tempfile.NamedTemporaryFile(suffix='.png') as f: 28 | fname = f.name 29 | 30 | def delete(): 31 | if os.path.exists(fname): 32 | os.remove(fname) 33 | request.addfinalizer(delete) 34 | 35 | return fname 36 | 37 | 38 | class TestBrewerMap(object): 39 | @classmethod 40 | def setup_class(cls): 41 | name = 'TestMap' 42 | map_type = 'TestType' 43 | colors = [(0, 0, 0), (12, 134, 245), (255, 255, 255)] 44 | 45 | cls.bmap = colorbrewer.BrewerMap(name, map_type, colors) 46 | 47 | cls.name = name 48 | cls.map_type = map_type 49 | cls.colors = colors 50 | 51 | def test_init(self): 52 | assert self.bmap.name == self.name 53 | assert self.bmap.type == self.map_type 54 | assert self.bmap.colors == self.colors 55 | assert self.bmap.number == len(self.colors) 56 | 57 | def test_colorbrewer2_url(self): 58 | url = 'http://colorbrewer2.org/index.html?type=testtype&scheme=TestMap&n=3' 59 | assert self.bmap.colorbrewer2_url == url 60 | 61 | def test_colorbrewer2_url_exists(self): 62 | '''Simple check to ensure a URL is valid. Thanks to 63 | http://stackoverflow.com/questions/4041443''' 64 | try: 65 | urllib.urlopen(self.bmap.colorbrewer2_url) 66 | assert True 67 | except: 68 | assert False 69 | 70 | def test_hex_colors(self): 71 | hex_colors = ['#000000', '#0C86F5', '#FFFFFF'] 72 | assert self.bmap.hex_colors == hex_colors 73 | 74 | def test_mpl_colors(self): 75 | mpl_colors = [(0, 0, 0), (12/255., 134/255., 245/255.), (1, 1, 1)] 76 | assert self.bmap.mpl_colors == mpl_colors 77 | 78 | @pytest.mark.skipif('not HAVE_MPL') 79 | def test_mpl_colormap(self): 80 | mpl_colormap = self.bmap.mpl_colormap 81 | assert isinstance(mpl_colormap, LinearSegmentedColormap) 82 | 83 | @mock.patch.object(BlockGrid, 'show') 84 | def test_show_as_blocks(self, mock_show): 85 | self.bmap.show_as_blocks() 86 | mock_show.assert_called_with() 87 | 88 | @pytest.mark.skipif('not HAVE_MPL') 89 | def test_save_discrete_image(self, img_filename): 90 | self.bmap.save_discrete_image(img_filename) 91 | assert os.path.isfile(img_filename) 92 | 93 | @pytest.mark.skipif('not HAVE_MPL') 94 | def test_save_continuous_image(self, img_filename): 95 | self.bmap.save_continuous_image(img_filename) 96 | assert os.path.isfile(img_filename) 97 | -------------------------------------------------------------------------------- /palettable/test/test_utils.py: -------------------------------------------------------------------------------- 1 | from __future__ import absolute_import 2 | 3 | import inspect 4 | 5 | import pytest 6 | 7 | from .. import utils 8 | from ..mycarta import mycarta 9 | 10 | 11 | def test_round_as_py3(): 12 | assert utils.round_as_py3(2.2) == 2.0 13 | assert utils.round_as_py3(2.5) == 2.0 14 | assert utils.round_as_py3(2.6) == 3.0 15 | assert utils.round_as_py3(3.5) == 4.0 16 | 17 | 18 | @pytest.mark.parametrize('num, length, expected', [ 19 | (2, 5, [0, 4]), 20 | (3, 5, [0, 2, 4]), 21 | (4, 5, [0, 1, 3, 4]), 22 | (5, 5, [0, 1, 2, 3, 4]), 23 | (2, 10, [0, 9]), 24 | (3, 10, [0, 4, 9]), 25 | (4, 10, [0, 3, 6, 9]), 26 | (5, 10, [0, 2, 4, 7, 9]), 27 | (6, 10, [0, 2, 4, 5, 7, 9]), 28 | (10, 10, list(range(10))) 29 | ]) 30 | def test_n_to_indices(num, length, expected): 31 | assert list(utils.n_to_indices(num, length)) == expected 32 | assert utils.evenly_spaced_values(num, list(range(length))) == expected 33 | 34 | 35 | def test_n_to_indices_raises(): 36 | with pytest.raises(ValueError): 37 | utils.n_to_indices(1, 5) 38 | 39 | with pytest.raises(ValueError): 40 | utils.n_to_indices(10, 5) 41 | 42 | 43 | def test_make_name_map(): 44 | assert utils.make_name_map(('A', 'b', 'CdEf')) == \ 45 | {'a': 'A', 'b': 'b', 'cdef': 'CdEf'} 46 | 47 | 48 | def test_make_names_and_lengths(): 49 | assert utils.make_names_and_lengths(('a', 'b'), (1, 2)) == \ 50 | [('a', 1), ('a', 2), ('b', 1), ('b', 2)] 51 | 52 | sample = utils.make_names_and_lengths(('a', 'b')) 53 | assert sample[0] == ('a', 3) 54 | assert sample[-1] == ('b', 20) 55 | 56 | 57 | def test_palette_name(): 58 | assert utils.palette_name('Pants', 8) == 'Pants_8' 59 | 60 | 61 | def test_split_name_length(): 62 | assert utils.split_name_length('Pants_8') == ('Pants', 8) 63 | 64 | 65 | def test_print_maps_factory(capsys): 66 | func = utils.print_maps_factory( 67 | 'sample', [('a', 1), ('a', 2), ('b', 1), ('b', 2)], 'sequential') 68 | assert inspect.isfunction(func) 69 | assert 'sample' in inspect.getdoc(func) 70 | 71 | func() 72 | out, _ = capsys.readouterr() 73 | 74 | assert 'a_1 sequential 1' in out 75 | 76 | 77 | @pytest.mark.parametrize('reverse', [(True,), (False,)]) 78 | def test_get_map_factory(reverse): 79 | name = 'sample_3' 80 | name_not_evenly = 'sample_2' 81 | expected_name = 'Sample_3' 82 | expected_name_not_evenly = 'Sample_2' 83 | colors = [1, 2, 3] 84 | if reverse: 85 | expected_name += '_r' 86 | expected_name_not_evenly += '_r' 87 | expected_colors = colors[::-1] 88 | expected_colors_not_evenly = colors[:2][::-1] 89 | else: 90 | expected_colors = colors 91 | expected_colors_not_evenly = colors[:2] 92 | 93 | def test_func(name, type_, colors): 94 | assert name == expected_name 95 | assert type_ == 'diverging' 96 | assert colors == expected_colors 97 | return True 98 | 99 | def test_func_not_evenly(name, type_, colors): 100 | assert name == expected_name_not_evenly 101 | assert type_ == 'qualitative' 102 | assert colors == expected_colors_not_evenly 103 | return True 104 | 105 | get_map = utils.get_map_factory( 106 | 'sample desc', 'sample.test', {'Sample': colors}, 'diverging', test_func) 107 | 108 | get_map_not_evenly = utils.get_map_factory( 109 | 'sample desc', 'sample.test', {'Sample': colors}, 'qualitative', 110 | test_func_not_evenly, is_evenly_spaced=False) 111 | 112 | assert get_map(name, reverse=reverse) 113 | assert get_map_not_evenly(name_not_evenly, reverse=reverse) 114 | 115 | doc = inspect.getdoc(get_map) 116 | assert doc.startswith('Get a sample desc palette by name') 117 | assert 'sample.test' in doc 118 | assert doc.endswith('function') 119 | 120 | with pytest.raises(ValueError): 121 | # requesting more than available colors should throw ValueError 122 | get_map('Sample_4', reverse=reverse) 123 | 124 | 125 | def test_load_all_palettes(): 126 | palettes = utils.load_all_palettes( 127 | mycarta._NAMES_AND_LENGTHS, mycarta.get_map) 128 | 129 | for suffix in ('', '_r'): 130 | assert ('LinearL_13' + suffix) in palettes 131 | assert isinstance(palettes['LinearL_13' + suffix], mycarta.MycartaMap) 132 | -------------------------------------------------------------------------------- /palettable/utils.py: -------------------------------------------------------------------------------- 1 | from __future__ import absolute_import, division 2 | 3 | import itertools 4 | import math 5 | import sys 6 | import textwrap 7 | 8 | 9 | def round_as_py3(value): 10 | """ 11 | Implement round behaviour consistent with Python 3 for use in Python 2. 12 | (Such that halves are rounded toward the even side. 13 | Only for positive numbers.) 14 | Adapted from https://github.com/python/cpython/blob/6b678aea1ca5c3c3728cd5a7a6eb112b2dad8553/Python/pytime.c#L71 15 | 16 | """ 17 | if math.fmod(value, 1) == 0.5: 18 | return 2 * round(value / 2) 19 | else: 20 | return round(value) 21 | 22 | if sys.version_info[0] >= 3: 23 | round_ = round 24 | else: 25 | round_ = round_as_py3 26 | 27 | 28 | def n_to_indices(num, length): 29 | """ 30 | Calculate `num` evenly spaced indices for a sequence of length `length`. 31 | 32 | Should be used with num >= 2, result will always include first and last. 33 | 34 | Parameters 35 | ---------- 36 | num : int 37 | length : int 38 | 39 | Returns 40 | ------- 41 | list of int 42 | 43 | """ 44 | if num < 2: 45 | raise ValueError('num must be 2 or larger, got {0}'.format(num)) 46 | elif num > length: 47 | raise ValueError('num cannot be greater than length') 48 | 49 | # subtract 1 from length to make it equivalent to the last index, 50 | # subtract 1 from num to make the calculation include the last index 51 | step = (length - 1) / (num - 1) 52 | 53 | return (int(round_(step * i)) for i in range(num)) 54 | 55 | 56 | def evenly_spaced_values(num, data): 57 | """ 58 | Returns `num` evenly spaced values from sequence `data`. 59 | 60 | Parameters 61 | ---------- 62 | num : int 63 | data : sequence 64 | 65 | Returns 66 | ------- 67 | values : list 68 | 69 | """ 70 | return [data[i] for i in n_to_indices(num, len(data))] 71 | 72 | 73 | def make_name_map(names): 74 | """ 75 | Create a dictionary mapping lowercase names to capitalized names. 76 | 77 | Parameters 78 | ---------- 79 | names : sequence 80 | 81 | Returns 82 | ------- 83 | dict 84 | 85 | """ 86 | return dict((name.lower(), name) for name in names) 87 | 88 | 89 | def make_names_and_lengths(names, lengths=None): 90 | """ 91 | Create a list pairing palette names with lengths. (Mostly used to define 92 | the set of palettes that are automatically built.) 93 | 94 | Parameters 95 | ---------- 96 | names : sequence of str 97 | lengths : sequence of int, optional 98 | 99 | Returns 100 | ------- 101 | list of tuple 102 | Pairs of names and lengths. 103 | 104 | """ 105 | lengths = lengths or range(3, 21) 106 | return list(itertools.product(names, lengths)) 107 | 108 | 109 | def palette_name(name, length): 110 | """Create a palette name like CubeYF_8""" 111 | return '{0}_{1}'.format(name, length) 112 | 113 | 114 | def split_name_length(name): 115 | """Split name and length from a name like CubeYF_8""" 116 | split = name.split('_') 117 | return split[0], int(split[1]) 118 | 119 | 120 | def print_maps_factory(desc, names_and_lengths, palette_type): 121 | """ 122 | Create a function that will print the names and lengths of palettes. 123 | 124 | Parameters 125 | ---------- 126 | desc : str 127 | Short description of palettes, for example "sequential cmocean". 128 | Used to populate the print_maps docstring. 129 | names_and_lengths : sequence of tuple 130 | Pairs of names and lengths. 131 | palette_type : str 132 | Palette type to include in printed messages. 133 | 134 | Returns 135 | ------- 136 | function 137 | Takes no arguments. 138 | 139 | """ 140 | def print_maps(): 141 | namelen = max( 142 | len(palette_name(name, length)) 143 | for name, length in names_and_lengths) 144 | fmt = '{0:' + str(namelen + 4) + '}{1:16}{2:}' 145 | 146 | for name, length in names_and_lengths: 147 | print(fmt.format( 148 | palette_name(name, length), palette_type, length)) 149 | print_maps.__doc__ = 'Print a list of {0} palettes'.format(desc) 150 | return print_maps 151 | 152 | 153 | def get_map_factory(desc, mod_path, names_to_data, palette_type, palette_class, 154 | is_evenly_spaced=True): 155 | """ 156 | Create a function that builds a Palette instance from available data 157 | and the given Palette sub-class. 158 | 159 | Parameters 160 | ---------- 161 | desc : str 162 | Short description of palettes, for example "sequential cmocean". 163 | Used to populate the get_map docstring. 164 | mod_path : str 165 | Path to module where get_map will be used. Use to point users to 166 | the print_maps function. E.g. 'palettable.cmocean.sequential'. 167 | names_to_data : dict 168 | Dictionary mapping string palette names to color data. 169 | (Lists of 0-255 integer RGB tuples.) 170 | palette_type : str 171 | Palette type to pass into Palette subclass, e.g. 'diverging'. 172 | palette_class : Palette subclass 173 | Subclass of Palette to use when creating new Palettes. 174 | Must have __init__ signature (name, palette_type, colors). 175 | is_evenly_spaced : bool 176 | Sets sampling of palette. If True, then choose values evenly spaced 177 | in palette array, otherwise choose colors from the beginning of the 178 | array. 179 | 180 | Returns 181 | ------- 182 | function 183 | The function will have the definition: 184 | 185 | def get_map(name, reverse=False): 186 | 187 | """ 188 | name_map = make_name_map(names_to_data.keys()) 189 | 190 | def get_map(name, reverse=False): 191 | # name will be something like Viridis_8 192 | name, length = split_name_length(name) 193 | name_lower = name.lower() 194 | 195 | if name_lower not in name_map: 196 | raise KeyError('Unknown palette name: {0}'.format(name)) 197 | 198 | name = name_map[name_lower] 199 | 200 | if len(names_to_data[name]) < length: 201 | raise ValueError('Number of requested colors larger than ' 202 | 'the number available in {0}'.format(name)) 203 | if is_evenly_spaced: 204 | colors = evenly_spaced_values(length, names_to_data[name]) 205 | else: 206 | colors = names_to_data[name][:length] 207 | 208 | # add number back to name 209 | name = palette_name(name, length) 210 | 211 | if reverse: 212 | name += '_r' 213 | colors = list(reversed(colors)) 214 | 215 | return palette_class(name, palette_type, colors) 216 | 217 | get_map.__doc__ = textwrap.dedent("""\ 218 | Get a {0} palette by name. 219 | 220 | Parameters 221 | ---------- 222 | name : str 223 | Name of map. Use {1}.print_maps 224 | to see available names. 225 | reverse : bool, optional 226 | If True reverse colors from their default order. 227 | 228 | Returns 229 | ------- 230 | {2} 231 | 232 | """).format(desc, mod_path, palette_class.__class__.__name__) 233 | 234 | return get_map 235 | 236 | 237 | def load_all_palettes(names_and_lengths, get_map_func): 238 | """ 239 | Load all palettes (including reversed ones) into a dictionary, 240 | given a dictionary of names and lengths, plus a get_map function. 241 | 242 | Parameters 243 | ---------- 244 | names_and_lengths : dict 245 | names_and_lengths : sequence of tuple 246 | Pairs of names and lengths. 247 | get_map_func : function 248 | Function with signature get_map(name, reverse=False) that returns 249 | a Palette subclass instance. 250 | 251 | Returns 252 | ------- 253 | dict 254 | Maps Name_Length strings to instances of a Palette subclass. 255 | 256 | """ 257 | maps = {} 258 | for name, length in names_and_lengths: 259 | map_name = palette_name(name, length) 260 | maps[map_name] = get_map_func(map_name) 261 | maps[map_name + '_r'] = get_map_func(map_name, reverse=True) 262 | return maps 263 | -------------------------------------------------------------------------------- /palettable/wesanderson/__init__.py: -------------------------------------------------------------------------------- 1 | from __future__ import absolute_import 2 | 3 | from .wesanderson import __doc__, _palettes, print_maps, get_map, _get_all_maps 4 | 5 | 6 | globals().update(_get_all_maps()) 7 | -------------------------------------------------------------------------------- /palettable/wesanderson/test/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jiffyclub/palettable/339a45c347d34383aeb8fb3d8415d9631affb82c/palettable/wesanderson/test/__init__.py -------------------------------------------------------------------------------- /palettable/wesanderson/test/test_wesanderson.py: -------------------------------------------------------------------------------- 1 | from __future__ import absolute_import 2 | 3 | from ... import wesanderson as wap 4 | 5 | 6 | def test_print_maps(capsys): 7 | wap.print_maps() 8 | out, err = capsys.readouterr() 9 | lines = out.split('\n') 10 | assert lines[0] == 'Aquatic1 qualitative 5' 11 | 12 | 13 | def test_get_map(): 14 | palette = wap.get_map('cavalcanTi') 15 | assert isinstance(palette, wap.wesanderson.WesAndersonMap) 16 | assert palette.name == 'Cavalcanti' 17 | assert palette.type == 'qualitative' 18 | assert len(palette.colors) == 5 19 | assert palette.url == \ 20 | ('http://wesandersonpalettes.tumblr.com/post/' 21 | '79348553036/castello-cavalcanti-how-can-i-help') 22 | 23 | 24 | def test_get_map_reversed(): 25 | palette = wap.get_map('cavalcanTi', reverse=True) 26 | assert isinstance(palette, wap.wesanderson.WesAndersonMap) 27 | assert palette.name == 'Cavalcanti_r' 28 | assert palette.type == 'qualitative' 29 | assert len(palette.colors) == 5 30 | assert palette.url == \ 31 | ('http://wesandersonpalettes.tumblr.com/post/' 32 | '79348553036/castello-cavalcanti-how-can-i-help') 33 | 34 | 35 | def test_palettes_loaded(): 36 | assert isinstance(wap.Cavalcanti_5, wap.wesanderson.WesAndersonMap) 37 | assert isinstance(wap.Cavalcanti_5_r, wap.wesanderson.WesAndersonMap) 38 | assert wap.Cavalcanti_5.type == 'qualitative' 39 | 40 | 41 | def test_get_all_maps(): 42 | # Smoke tests. 43 | wap._get_all_maps() 44 | -------------------------------------------------------------------------------- /palettable/wesanderson/wesanderson.py: -------------------------------------------------------------------------------- 1 | from __future__ import absolute_import 2 | from __future__ import print_function 3 | """ 4 | Color palettes derived from http://wesandersonpalettes.tumblr.com/. 5 | 6 | """ 7 | 8 | import webbrowser 9 | 10 | from ..palette import Palette 11 | 12 | 13 | _tumblr_template = 'http://wesandersonpalettes.tumblr.com/post/{0}' 14 | _palette_type = 'qualitative' 15 | 16 | # Tumblr palettes in chronological order 17 | _palettes = { 18 | 'Chevalier': { 19 | 'colors': [ 20 | (53, 82, 67), (254, 202, 73), (201, 213, 213), (187, 162, 137) 21 | ], 22 | 'type': _palette_type, 23 | 'url': _tumblr_template.format('79263620764/hotel-chevalier') 24 | }, 25 | 'Moonrise1': { 26 | 'colors': [ 27 | (114, 202, 221), (240, 165, 176), (140, 133, 54), (195, 180, 119), 28 | (250, 208, 99) 29 | ], 30 | 'type': _palette_type, 31 | 'url': _tumblr_template.format( 32 | '79263667140/sam-i-love-you-but-you-dont-know-what-youre') 33 | }, 34 | 'Mendl': { 35 | 'colors': [ 36 | (222, 141, 185), (184, 192, 246), (207, 147, 135), (92, 128, 204) 37 | ], 38 | 'type': _palette_type, 39 | 'url': _tumblr_template.format('79348206200/mendls-heaven') 40 | }, 41 | 'Margot1': { 42 | 'colors': [ 43 | (137, 119, 18), (243, 194, 164), (246, 159, 151), (254, 214, 140), 44 | (98, 144, 117) 45 | ], 46 | 'type': _palette_type, 47 | 'url': _tumblr_template.format('79348364517/margot-takes-a-bath') 48 | }, 49 | 'Cavalcanti': { 50 | 'colors': [ 51 | (209, 170, 0), (8, 50, 19), (146, 148, 96), (111, 152, 121), 52 | (132, 33, 17) 53 | ], 54 | 'type': _palette_type, 55 | 'url': _tumblr_template.format( 56 | '79348553036/castello-cavalcanti-how-can-i-help') 57 | }, 58 | 'Moonrise2': { 59 | 'colors': [ 60 | (102, 124, 116), (181, 106, 39), (194, 186, 124), (31, 25, 23) 61 | ], 62 | 'type': _palette_type, 63 | 'url': _tumblr_template.format( 64 | '79641731527/sam-why-do-you-always-use-binoculars-suzy-it') 65 | }, 66 | 'Margot2': { 67 | 'colors': [ 68 | (118, 139, 147), (188, 36, 15), (249, 236, 197), (212, 115, 41) 69 | ], 70 | 'type': _palette_type, 71 | 'url': _tumblr_template.format('79641785036/margot-takes-a-break') 72 | }, 73 | 'Moonrise3': { 74 | 'colors': [ 75 | (242, 218, 82), (197, 157, 0), (203, 203, 201), (27, 30, 20) 76 | ], 77 | 'type': _palette_type, 78 | 'url': _tumblr_template.format( 79 | '79783357790/suzy-ive-always-wanted-to-be-an-orphan-most-of') 80 | }, 81 | 'GrandBudapest1': { 82 | 'colors': [ 83 | (238, 174, 101), (251, 79, 85), (72, 19, 19), (204, 95, 39) 84 | ], 85 | 'type': _palette_type, 86 | 'url': _tumblr_template.format('79784389334/the-grand-budapest-hotel') 87 | }, 88 | 'Moonrise4': { 89 | 'colors': [ 90 | (123, 135, 97), (193, 166, 46), (79, 143, 107), (59, 69, 60), 91 | (159, 50, 8) 92 | ], 93 | 'type': _palette_type, 94 | 'url': _tumblr_template.format('79956897654/coming-soon') 95 | }, 96 | 'Zissou': { 97 | 'colors': [ 98 | (0, 153, 230), (18, 37, 90), (242, 56, 20), (223, 183, 139), 99 | (182, 195, 197) 100 | ], 101 | 'type': _palette_type, 102 | 'url': _tumblr_template.format( 103 | '79956949771/steve-zissou-dont-point-that-gun-at-him-hes-an') 104 | }, 105 | 'Royal1': { 106 | 'colors': [ 107 | (121, 164, 58), (242, 214, 175), (94, 72, 41), (24, 20, 1) 108 | ], 109 | 'type': _palette_type, 110 | 'url': _tumblr_template.format( 111 | '79957796915/royal-o-reilly-tenenbaum-1932-2001') 112 | }, 113 | 'Darjeeling1': { 114 | 'colors': [ 115 | (158, 151, 151), (194, 142, 0), (131, 102, 89), (156, 90, 51) 116 | ], 117 | 'type': _palette_type, 118 | 'url': _tumblr_template.format( 119 | '80149649946/jack-i-wonder-if-the-three-of-us-wouldve-been') 120 | }, 121 | 'FantasticFox1': { 122 | 'colors': [ 123 | (249, 219, 32), (147, 75, 78), (66, 23, 13), (194, 121, 34), 124 | (226, 200, 167) 125 | ], 126 | 'type': _palette_type, 127 | 'url': _tumblr_template.format( 128 | '80149872170/mrs-fox-you-know-you-really-are-fantastic-mr') 129 | }, 130 | 'Margot3': { 131 | 'colors': [ 132 | (135, 162, 164), (202, 160, 101), (214, 202, 191), (214, 160, 160) 133 | ], 134 | 'type': _palette_type, 135 | 'url': _tumblr_template.format( 136 | '109473707895/etheline-raleigh-says-youve-been-spending-six') 137 | }, 138 | 'GrandBudapest2': { 139 | 'colors': [ 140 | (255, 166, 142), (251, 204, 183), (140, 17, 8), (41, 11, 4) 141 | ], 142 | 'type': _palette_type, 143 | 'url': _tumblr_template.format( 144 | '109473911685/m-gustave-you-see-there-are-still-faint') 145 | }, 146 | 'Aquatic1': { 147 | 'colors': [ 148 | (52, 36, 25), (28, 64, 39), (241, 201, 14), (102, 88, 153), 149 | (184, 147, 130) 150 | ], 151 | 'type': _palette_type, 152 | 'url': _tumblr_template.format( 153 | '109568074320/steve-zissou-the-deeper-you-go-the-weirder-life') 154 | }, 155 | 'Darjeeling2': { 156 | 'colors': [ 157 | (213, 227, 216), (97, 138, 152), (249, 218, 149), (174, 75, 22), 158 | (120, 112, 100) 159 | ], 160 | 'type': _palette_type, 161 | 'url': _tumblr_template.format('109980167015/peter-fuck-the-itinerary') 162 | }, 163 | 'FantasticFox2': { 164 | 'colors': [ 165 | (228, 191, 68), (198, 87, 66), (154, 208, 187), (51, 39, 55), 166 | (171, 161, 141) 167 | ], 168 | 'type': _palette_type, 169 | 'url': _tumblr_template.format('110716093015/ash-should-we-dance') 170 | }, 171 | 'GrandBudapest3': { 172 | 'colors': [ 173 | (255, 220, 182), (37, 56, 69), (231, 173, 157), (102, 117, 110), 174 | (139, 63, 49), (150, 109, 53) 175 | ], 176 | 'type': _palette_type, 177 | 'url': _tumblr_template.format( 178 | '112305028860/m-gustave-mendls-is-the-best') 179 | }, 180 | 'Royal2': { 181 | 'colors': [ 182 | (194, 171, 186), (140, 59, 73), (182, 172, 166), (33, 32, 83), 183 | (209, 211, 213) 184 | ], 185 | 'type': _palette_type, 186 | 'url': _tumblr_template.format( 187 | '115124780615/royal-anybody-interested-in-grabbing-a-couple-of') 188 | }, 189 | 'Moonrise5': { 190 | 'colors': [ 191 | (223, 140, 144), (216, 210, 142), (245, 190, 37), (61, 74, 28), 192 | (209, 48, 96), (168, 107, 76) 193 | ], 194 | 'type': _palette_type, 195 | 'url': _tumblr_template.format( 196 | '116909186645/walt-bishop-our-daughters-been-abducted-by-one') 197 | }, 198 | 'GrandBudapest4': { 199 | 'colors': [ 200 | (186, 110, 0), (80, 32, 86), (255, 246, 187), (154, 127, 25), 201 | (31, 18, 27) 202 | ], 203 | 'type': _palette_type, 204 | 'url': _tumblr_template.format( 205 | '117849683385/concierge-and-how-long-will-you-be-staying-with') 206 | }, 207 | 'Moonrise6': { 208 | 'colors': [ 209 | (191, 81, 61), (201, 162, 150), (197, 193, 136), (123, 177, 145), 210 | (217, 174, 48) 211 | ], 212 | 'type': _palette_type, 213 | 'url': _tumblr_template.format( 214 | '118877161325/sam-im-not-that-strong-of-a-swimmer-so-i-wear-a') 215 | }, 216 | 'GrandBudapest5': { 217 | 'colors': [ 218 | (225, 146, 131), (140, 27, 76), (209, 147, 54), (231, 199, 190), 219 | (51, 12, 0) 220 | ], 221 | 'type': _palette_type, 222 | 'url': _tumblr_template.format( 223 | '122169507295/m-gustave-its-quite-a-thing-winning-the-loyalty') 224 | }, 225 | 'Aquatic2': { 226 | 'colors': [ 227 | (139, 156, 184), (233, 229, 65), (88, 159, 194), (160, 141, 94), 228 | (189, 185, 206) 229 | ], 230 | 'type': _palette_type, 231 | 'url': _tumblr_template.format( 232 | '125170837755/steve-zissou-please-dont-make-fun-of-me-i-just') 233 | }, 234 | 'Royal3': { 235 | 'colors': [ 236 | (252, 87, 108), (237, 126, 83), (226, 153, 139), (46, 23, 24), 237 | (251, 214, 202) 238 | ], 239 | 'type': _palette_type, 240 | 'url': _tumblr_template.format( 241 | '129921576355/royal-ive-always-been-considered-an-asshole-for') 242 | }, 243 | 'Moonrise7': { 244 | 'colors': [ 245 | (35, 35, 85), (97, 104, 96), (167, 91, 68), (145, 43, 41), 246 | (255, 227, 143) 247 | ], 248 | 'type': _palette_type, 249 | 'url': _tumblr_template.format( 250 | '137096576550/social-services-access-denied') 251 | }, 252 | 'Aquatic3': { 253 | 'colors': [ 254 | (214, 161, 66), (194, 128, 114), (200, 183, 161), (189, 68, 45), 255 | (100, 84, 60) 256 | ], 257 | 'type': _palette_type, 258 | 'url': _tumblr_template.format( 259 | '139482629630/ah-weve-never-made-great-husbands-have-we-of') 260 | }, 261 | 'Darjeeling3': { 262 | 'colors': [ 263 | (168, 171, 80), (255, 232, 61), (169, 211, 210), (36, 71, 125), 264 | (90, 145, 124) 265 | ], 266 | 'type': _palette_type, 267 | 'url': _tumblr_template.format( 268 | '143938510215/the-chief-steward-welcome-aboard') 269 | }, 270 | 'Darjeeling4': { 271 | 'colors': [ 272 | (116, 103, 104), (104, 71, 98), (128, 8, 6), (188, 132, 14), 273 | (174, 89, 92) 274 | ], 275 | 'type': _palette_type, 276 | 'url': _tumblr_template.format( 277 | '160334044570/i-wonder-if-the-three-of-us-wouldve-been-friends') 278 | }, 279 | 'IsleOfDogs1': { 280 | 'colors': [ 281 | (254, 197, 175), (174, 126, 113), (210, 103, 50), (50, 35, 35), 282 | (24, 18, 19) 283 | ], 284 | 'type': _palette_type, 285 | 'url': _tumblr_template.format( 286 | '172304342835/were-a-pack-of-scary-indestructible-alpha-dogs') 287 | }, 288 | 'IsleOfDogs2': { 289 | 'colors': [ 290 | (152, 108, 150), (138, 31, 31), (213, 171, 85), (14, 12, 12), 291 | (220, 194, 201), (130, 114, 108) 292 | ], 293 | 'type': _palette_type, 294 | 'url': _tumblr_template.format( 295 | '172586941620/be-advised-that-small-dogs-still-pose-a-threat-to') 296 | }, 297 | 'IsleOfDogs3': { 298 | 'colors': [ 299 | (229, 142, 167), (224, 193, 160), (30, 18, 99), (216, 177, 72) 300 | ], 301 | 'type': _palette_type, 302 | 'url': _tumblr_template.format( 303 | '184134532240/tracy-walker-that-crook-hes-stealing-the') 304 | }, 305 | } 306 | 307 | _map_names = {} 308 | for k in _palettes: 309 | _map_names[k.lower()] = k 310 | 311 | 312 | class WesAndersonMap(Palette): 313 | """ 314 | Representation of a color map with matplotlib compatible 315 | views of the map. 316 | 317 | Parameters 318 | ---------- 319 | name : str 320 | map_type : str 321 | colors : list 322 | Colors as list of 0-255 RGB triplets. 323 | url : str 324 | URL on the web where this color map can be viewed. 325 | 326 | Attributes 327 | ---------- 328 | name : str 329 | type : str 330 | number : int 331 | Number of colors in color map. 332 | colors : list 333 | Colors as list of 0-255 RGB triplets. 334 | hex_colors : list 335 | mpl_colors : list 336 | mpl_colormap : matplotlib LinearSegmentedColormap 337 | wap_url : str 338 | URL on the web where this color map can be viewed. 339 | 340 | """ 341 | def __init__(self, name, map_type, colors, url): 342 | super(WesAndersonMap, self).__init__(name, map_type, colors) 343 | self.url = url 344 | 345 | def wap(self): 346 | """ 347 | View this color palette on the web. 348 | Will open a new tab in your web browser. 349 | 350 | """ 351 | webbrowser.open_new_tab(self.url) # pragma: no cover 352 | 353 | 354 | def print_maps(): 355 | """ 356 | Print a list of Wes Anderson palettes. 357 | 358 | """ 359 | namelen = max(len(k) for k in _palettes) 360 | fmt = '{0:' + str(namelen + 4) + '}{1:16}{2:}' 361 | 362 | for k in sorted(_palettes.keys()): 363 | print(fmt.format(k, _palettes[k]['type'], len(_palettes[k]['colors']))) 364 | 365 | 366 | def get_map(name, reverse=False): 367 | """ 368 | Get a Wes Anderson palette by name. 369 | 370 | Parameters 371 | ---------- 372 | name : str 373 | Name of map. Use palettable.wesanderson.print_maps 374 | to see available names. 375 | reverse : bool, optional 376 | If True reverse colors from their default order. 377 | 378 | Returns 379 | ------- 380 | palette : WesAndersonMap 381 | 382 | """ 383 | name = _map_names[name.lower()] 384 | palette = _palettes[name] 385 | 386 | if reverse: 387 | name += '_r' 388 | palette['colors'] = list(reversed(palette['colors'])) 389 | 390 | return WesAndersonMap( 391 | name, palette['type'], palette['colors'], palette['url']) 392 | 393 | 394 | def _get_all_maps(): 395 | """ 396 | Returns a dictionary of all Wes Anderson palettes, 397 | including reversed ones. 398 | 399 | """ 400 | fmt = '{0}_{1}'.format 401 | d = dict( 402 | (fmt(name, m.number), m) 403 | for name, m in ((name, get_map(name)) for name in _palettes)) 404 | fmt = '{0}_{1}_r'.format 405 | d.update( 406 | dict( 407 | (fmt(name, m.number), m) 408 | for name, m in ( 409 | (name, get_map(name, reverse=True)) for name in _palettes))) 410 | return d 411 | -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | [build-system] 2 | requires = ["setuptools"] 3 | build-backend = "setuptools.build_meta" 4 | 5 | [project] 6 | name = "palettable" 7 | authors = [ 8 | {name = "Matt Davis", email = "jiffyclub@gmail.com"}, 9 | ] 10 | description = "Color palettes for Python" 11 | readme = "README.rst" 12 | license = { file = "license.txt" } 13 | requires-python = ">=3.7" 14 | dynamic = ["version"] 15 | classifiers = [ 16 | "License :: OSI Approved :: MIT License", 17 | "Programming Language :: Python", 18 | "Programming Language :: Python :: 3", 19 | "Programming Language :: Python :: 3.7", 20 | "Programming Language :: Python :: 3.8", 21 | "Programming Language :: Python :: 3.9", 22 | "Programming Language :: Python :: 3.10", 23 | "Programming Language :: Python :: 3.11", 24 | "Programming Language :: Python :: 3.12", 25 | "Topic :: Scientific/Engineering :: Visualization" 26 | ] 27 | 28 | [project.urls] 29 | homepage = "https://jiffyclub.github.io/palettable/" 30 | repository = "https://github.com/jiffyclub/palettable.git" 31 | changelog = "https://github.com/jiffyclub/palettable/blob/master/CHANGELOG.rst" 32 | 33 | [tool.setuptools.dynamic] 34 | version = {attr = "palettable.VERSION"} 35 | 36 | [tool.setuptools.packages.find] 37 | include = ["palettable*"] 38 | exclude = ["*.test"] 39 | -------------------------------------------------------------------------------- /scripts/scientific.py: -------------------------------------------------------------------------------- 1 | """ 2 | Script for translating the .txt RGB files in 3 | http://www.fabiocrameri.ch/colourmaps.php to a colordata.py file. 4 | 5 | This means converting 0-1 floats to 0-255 integers and formatting the 6 | data as lists of lists. 7 | 8 | """ 9 | import sys 10 | from pathlib import Path 11 | from typing import Iterable, TextIO, Tuple 12 | 13 | import click 14 | 15 | 16 | def float_rgb_to_int(value: float) -> int: 17 | return round(value * 255) 18 | 19 | 20 | def read_rgb_txt(filename: Path) -> Iterable[Tuple[float, float, float]]: 21 | with filename.open('r') as fp: 22 | yield from ( 23 | tuple(float_rgb_to_int(float(x)) for x in row.split()) for row in fp 24 | ) 25 | 26 | 27 | def process_file(filename: str, dest: TextIO): 28 | filename: Path = Path(filename) 29 | dest.write(f'{filename.stem.upper()} = (\n') 30 | 31 | for rgb in read_rgb_txt(filename): 32 | dest.write(f' {rgb},\n') 33 | dest.write(')\n\n') 34 | 35 | 36 | @click.command() 37 | @click.argument("dest", type=click.File("w")) 38 | @click.argument("sources", nargs=-1) 39 | def main(dest: TextIO, sources: Tuple): 40 | dest.write('# Via http://www.fabiocrameri.ch/colourmaps.php\n\n') 41 | 42 | for filename in sources: 43 | process_file(filename, dest) 44 | 45 | 46 | if __name__ == "__main__": 47 | sys.exit(main()) 48 | -------------------------------------------------------------------------------- /setup.cfg: -------------------------------------------------------------------------------- 1 | [bdist_wheel] 2 | universal=1 3 | -------------------------------------------------------------------------------- /test/test_installed.py: -------------------------------------------------------------------------------- 1 | """ 2 | Test installed palettable to make sure everything is accessible. 3 | 4 | """ 5 | 6 | import palettable 7 | from palettable.palette import Palette 8 | 9 | 10 | def test_cartocolors(): 11 | assert isinstance(palettable.cartocolors.sequential.Mint_7, Palette) 12 | assert isinstance(palettable.cartocolors.diverging.Earth_7, Palette) 13 | 14 | 15 | def test_cmocean(): 16 | assert isinstance(palettable.cmocean.sequential.Amp_8, Palette) 17 | assert isinstance(palettable.cmocean.diverging.Balance_8, Palette) 18 | 19 | 20 | def test_colorbrewer(): 21 | assert isinstance(palettable.colorbrewer.diverging.PuOr_6, Palette) 22 | assert isinstance(palettable.colorbrewer.qualitative.Pastel1_9, Palette) 23 | assert isinstance(palettable.colorbrewer.sequential.PuBuGn_9, Palette) 24 | 25 | 26 | def test_cubehelix(): 27 | assert isinstance(palettable.cubehelix.classic_16, Palette) 28 | 29 | 30 | def test_matplotlib(): 31 | assert isinstance(palettable.matplotlib.Viridis_8, Palette) 32 | 33 | 34 | def test_mycarta(): 35 | assert isinstance(palettable.mycarta.CubeYF_8, Palette) 36 | 37 | 38 | def test_plotly(): 39 | assert isinstance(palettable.plotly.diverging.Picnic_3, Palette) 40 | assert isinstance(palettable.plotly.qualitative.Plotly_3, Palette) 41 | assert isinstance(palettable.plotly.sequential.Blackbody_3, Palette) 42 | 43 | 44 | def test_tableau(): 45 | assert isinstance(palettable.tableau.ColorBlind_10, Palette) 46 | 47 | 48 | def test_wes_anderson(): 49 | assert isinstance(palettable.wesanderson.Aquatic1_5, Palette) 50 | --------------------------------------------------------------------------------